From aaf191b6dc5b27bb6d32a4c1e15191dae9689e31 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 3 Apr 2015 14:31:43 -0700 Subject: [PATCH 001/401] first cut at new avatar preferences UI --- interface/src/Application.cpp | 29 +--- interface/src/Application.h | 5 +- interface/src/avatar/MyAvatar.cpp | 71 +++++++- interface/src/avatar/MyAvatar.h | 24 ++- interface/src/ui/PreferencesDialog.cpp | 125 ++++++++++---- interface/src/ui/PreferencesDialog.h | 18 +- interface/ui/preferencesDialog.ui | 223 ++++++++++++++++++++++++- 7 files changed, 418 insertions(+), 77 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f0324b7361..c2560a9a54 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3743,30 +3743,16 @@ bool Application::askToSetAvatarUrl(const QString& url) { if (msgBox.clickedButton() == headButton) { qDebug() << "Chose to use for head: " << url; - _myAvatar->setFaceModelURL(url); - UserActivityLogger::getInstance().changedModel("head", url); - _myAvatar->sendIdentityPacket(); - emit faceURLChanged(url); + _myAvatar->useHeadURL(url); + emit headURLChanged(url); } else if (msgBox.clickedButton() == bodyButton) { qDebug() << "Chose to use for body: " << url; - _myAvatar->setSkeletonModelURL(url); - // if the head is empty, reset it to the default head. - if (_myAvatar->getFaceModelURLString().isEmpty()) { - _myAvatar->setFaceModelURL(DEFAULT_HEAD_MODEL_URL); - emit faceURLChanged(DEFAULT_HEAD_MODEL_URL.toString()); - UserActivityLogger::getInstance().changedModel("head", DEFAULT_HEAD_MODEL_URL.toString()); - } - UserActivityLogger::getInstance().changedModel("skeleton", url); - _myAvatar->sendIdentityPacket(); - emit skeletonURLChanged(url); + _myAvatar->useBodyURL(url); + emit bodyURLChanged(url); } else if (msgBox.clickedButton() == bodyAndHeadButton) { qDebug() << "Chose to use for body + head: " << url; - _myAvatar->setFaceModelURL(QString()); - _myAvatar->setSkeletonModelURL(url); - UserActivityLogger::getInstance().changedModel("skeleton", url); - _myAvatar->sendIdentityPacket(); - emit faceURLChanged(QString()); - emit skeletonURLChanged(url); + _myAvatar->useFullAvatarURL(url); + emit fullAvatarURLChanged(url); } else { qDebug() << "Declined to use the avatar: " << url; } @@ -4281,8 +4267,7 @@ void Application::checkSkeleton() { msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); - _myAvatar->setSkeletonModelURL(DEFAULT_BODY_MODEL_URL); - _myAvatar->sendIdentityPacket(); + _myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL); } else { _myAvatar->updateCharacterController(); _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); diff --git a/interface/src/Application.h b/interface/src/Application.h index e9b8deff55..387de78e49 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -335,8 +335,9 @@ signals: void checkBackgroundDownloads(); void domainConnectionRefused(const QString& reason); - void faceURLChanged(const QString& newValue); - void skeletonURLChanged(const QString& newValue); + void headURLChanged(const QString& newValue); + void bodyURLChanged(const QString& newValue); + void fullAvatarURLChanged(const QString& newValue); public slots: void domainChanged(const QString& domainHostname); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f92523c58f..418f978451 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "Application.h" #include "AvatarManager.h" @@ -604,9 +605,11 @@ void MyAvatar::saveData() { settings.setValue("leanScale", _leanScale); settings.setValue("scale", _targetScale); - - settings.setValue("faceModelURL", _faceModelURL); - settings.setValue("skeletonModelURL", _skeletonModelURL); + + settings.setValue("useFullAvatar", _useFullAvatar); + settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences); + settings.setValue("faceModelURL", _headURLFromPreferences); + settings.setValue("skeletonModelURL", _skeletonURLFromPreferences); settings.beginWriteArray("attachmentData"); for (int i = 0; i < _attachmentData.size(); i++) { @@ -667,9 +670,26 @@ void MyAvatar::loadData() { _targetScale = loadSetting(settings, "scale", 1.0f); setScale(_scale); Application::getInstance()->getCamera()->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... + _headURLFromPreferences = settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl(); - setFaceModelURL(settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl()); - setSkeletonModelURL(settings.value("skeletonModelURL").toUrl()); + bool assumeFullAvatar = _headURLFromPreferences.isEmpty(); + + _useFullAvatar = settings.value("useFullAvatar", assumeFullAvatar).toBool(); + _fullAvatarURLFromPreferences = settings.value("fullAvatarURL").toUrl(); + _skeletonURLFromPreferences = settings.value("skeletonModelURL").toUrl(); + + if (_useFullAvatar) { + setFaceModelURL(QUrl()); + setSkeletonModelURL(_fullAvatarURLFromPreferences); + } else { + setFaceModelURL(_headURLFromPreferences); + setSkeletonModelURL(_skeletonURLFromPreferences); + } QVector attachmentData; int attachmentCount = settings.beginReadArray("attachmentData"); @@ -902,6 +922,47 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _billboardValid = false; } +void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL) { + _useFullAvatar = true; + _fullAvatarURLFromPreferences = fullAvatarURL; + + if (!getFaceModelURLString().isEmpty()) { + setFaceModelURL(QString()); + } + + if (fullAvatarURL != getSkeletonModelURL()) { + setSkeletonModelURL(fullAvatarURL); + UserActivityLogger::getInstance().changedModel("skeleton", fullAvatarURL.toString()); + } + sendIdentityPacket(); +} + +void MyAvatar::useHeadURL(const QUrl& headURL) { + useHeadAndBodyURLs(headURL, _skeletonURLFromPreferences); +} + +void MyAvatar::useBodyURL(const QUrl& bodyURL) { + useHeadAndBodyURLs(_headURLFromPreferences, bodyURL); +} + +void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL) { + _useFullAvatar = false; + _headURLFromPreferences = headURL; + _skeletonURLFromPreferences = bodyURL; + + 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()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 2bc3a4e4ba..57c8ca9e96 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -116,8 +116,17 @@ public: virtual void setJointData(int index, const glm::quat& rotation); virtual void clearJointData(int index); virtual void clearJointsData(); - virtual void setFaceModelURL(const QUrl& faceModelURL); - virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); + + void useFullAvatarURL(const QUrl& fullAvatarURL); + void useHeadURL(const QUrl& headURL); + void useBodyURL(const QUrl& bodyURL); + void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL); + + bool getUseFullAvatar() const { return _useFullAvatar; } + const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; } + const QUrl& getHeadURLFromPreferences() const { return _headURLFromPreferences; } + const QUrl& getBodyURLFromPreferences() const { return _skeletonURLFromPreferences; } + virtual void setAttachmentData(const QVector& attachmentData); virtual glm::vec3 getSkeletonPosition() const; @@ -185,6 +194,11 @@ protected: virtual void renderAttachments(RenderMode renderMode, RenderArgs* args); private: + + // These are made private for MyAvatar so that you will use the "use" methods instead + virtual void setFaceModelURL(const QUrl& faceModelURL); + virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); + float _turningKeyPressTime; glm::vec3 _gravity; @@ -229,6 +243,12 @@ private: void updatePosition(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void maybeUpdateBillboard(); + + // Avatar Preferences + bool _useFullAvatar = false; + QUrl _fullAvatarURLFromPreferences; + QUrl _headURLFromPreferences; + QUrl _skeletonURLFromPreferences; }; #endif // hifi_MyAvatar_h diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index bd32fc7c34..4879bbfffc 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -43,28 +43,71 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &PreferencesDialog::openHeadModelBrowser); connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &PreferencesDialog::openBodyModelBrowser); + connect(ui.buttonBrowseFullAvatar, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser); + connect(ui.buttonBrowseLocation, &QPushButton::clicked, this, &PreferencesDialog::openSnapshotLocationBrowser); connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser); - connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, - Application::getInstance(), &Application::loadDefaultScripts); + connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, Application::getInstance(), &Application::loadDefaultScripts); - - connect(Application::getInstance(), &Application::faceURLChanged, this, &PreferencesDialog::faceURLChanged); - connect(Application::getInstance(), &Application::skeletonURLChanged, this, &PreferencesDialog::skeletonURLChanged); + connect(ui.useSeparateBodyAndHead, &QRadioButton::clicked, this, &PreferencesDialog::useSeparateBodyAndHead); + connect(ui.useFullAvatar, &QRadioButton::clicked, this, &PreferencesDialog::useFullAvatar); + + + connect(Application::getInstance(), &Application::headURLChanged, this, &PreferencesDialog::headURLChanged); + connect(Application::getInstance(), &Application::bodyURLChanged, this, &PreferencesDialog::bodyURLChanged); + 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.bodyNameLabel->setText("Body - name of model here"); + ui.headNameLabel->setText("Head - name of model here"); + ui.fullAvatarNameLabel->setText("Full Avatar - name of model here"); + + UIUtil::scaleWidgetFontSizes(this); } -void PreferencesDialog::faceURLChanged(const QString& newValue) { - ui.faceURLEdit->setText(newValue); +void PreferencesDialog::useSeparateBodyAndHead(bool checked) { + setUseFullAvatar(!checked); + + QUrl headURL(ui.faceURLEdit->text()); + QUrl bodyURL(ui.skeletonURLEdit->text()); + + DependencyManager::get()->getMyAvatar()->useHeadAndBodyURLs(headURL, bodyURL); } -void PreferencesDialog::skeletonURLChanged(const QString& newValue) { +void PreferencesDialog::useFullAvatar(bool checked) { + setUseFullAvatar(checked); + QUrl fullAvatarURL(ui.fullAvatarURLEdit->text()); + DependencyManager::get()->getMyAvatar()->useFullAvatarURL(fullAvatarURL); +} + +void PreferencesDialog::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); +} + +void PreferencesDialog::headURLChanged(const QString& newValue) { + ui.faceURLEdit->setText(newValue); + setUseFullAvatar(false); +} + +void PreferencesDialog::bodyURLChanged(const QString& newValue) { ui.skeletonURLEdit->setText(newValue); + setUseFullAvatar(false); +} + +void PreferencesDialog::fullAvatarURLChanged(const QString& newValue) { + ui.fullAvatarURLEdit->setText(newValue); + setUseFullAvatar(true); } void PreferencesDialog::accept() { @@ -82,6 +125,16 @@ void PreferencesDialog::setSkeletonUrl(QString modelUrl) { ui.skeletonURLEdit->setText(modelUrl); } +void PreferencesDialog::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 PreferencesDialog::openHeadModelBrowser() { auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars"; auto WIDTH = 900; @@ -143,11 +196,18 @@ void PreferencesDialog::loadPreferences() { _displayNameString = myAvatar->getDisplayName(); ui.displayNameEdit->setText(_displayNameString); - _faceURLString = myAvatar->getHead()->getFaceModel().getURL().toString(); - ui.faceURLEdit->setText(_faceURLString); - _skeletonURLString = myAvatar->getSkeletonModel().getURL().toString(); - ui.skeletonURLEdit->setText(_skeletonURLString); + _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); + + // TODO: load the names for the models. ui.sendDataCheckBox->setChecked(!menuInstance->isOptionChecked(MenuOption::DisableActivityLogger)); @@ -217,31 +277,26 @@ void PreferencesDialog::savePreferences() { shouldDispatchIdentityPacket = true; } - auto AVATAR_FILE_EXTENSION = ".fst"; - - QUrl faceModelURL(ui.faceURLEdit->text()); - QString faceModelURLString = faceModelURL.toString(); - if (faceModelURLString != _faceURLString) { - if (faceModelURLString.isEmpty() || faceModelURLString.toLower().contains(AVATAR_FILE_EXTENSION)) { - // change the faceModelURL in the profile, it will also update this user's BlendFace - myAvatar->setFaceModelURL(faceModelURL); - UserActivityLogger::getInstance().changedModel("head", faceModelURLString); - shouldDispatchIdentityPacket = true; - } else { - qDebug() << "ERROR: Head model not FST or blank - " << faceModelURLString; - } - } + QUrl headURL(ui.faceURLEdit->text()); + QString headURLString = headURL.toString(); - QUrl skeletonModelURL(ui.skeletonURLEdit->text()); - QString skeletonModelURLString = skeletonModelURL.toString(); - if (skeletonModelURLString != _skeletonURLString) { - if (skeletonModelURLString.isEmpty() || skeletonModelURLString.toLower().contains(AVATAR_FILE_EXTENSION)) { - // change the skeletonModelURL in the profile, it will also update this user's Body - myAvatar->setSkeletonModelURL(skeletonModelURL); - UserActivityLogger::getInstance().changedModel("skeleton", skeletonModelURLString); - shouldDispatchIdentityPacket = true; + 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 { - qDebug() << "ERROR: Skeleton model not FST or blank - " << skeletonModelURLString; + myAvatar->useHeadAndBodyURLs(headURL, bodyURL); } } diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index 4daa2d9696..961ef6287d 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -33,10 +33,17 @@ private: void savePreferences(); void openHeadModelBrowser(); void openBodyModelBrowser(); + void openFullAvatarModelBrowser(); + void setUseFullAvatar(bool useFullAvatar); Ui_PreferencesDialog ui; - QString _faceURLString; - QString _skeletonURLString; + + bool _useFullAvatar; + QString _headURLString; + QString _bodyURLString; + QString _fullAvatarURLString; + + QString _displayNameString; WebWindowClass* _marketplaceWindow = NULL; @@ -47,8 +54,11 @@ private slots: void setSkeletonUrl(QString modelUrl); void openSnapshotLocationBrowser(); void openScriptsLocationBrowser(); - void faceURLChanged(const QString& newValue); - void skeletonURLChanged(const QString& newValue); + void headURLChanged(const QString& newValue); + void bodyURLChanged(const QString& newValue); + void fullAvatarURLChanged(const QString& newValue); + void useSeparateBodyAndHead(bool checked); + void useFullAvatar(bool checked); }; diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index d295d094c2..4a0b1e961a 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -198,8 +198,194 @@ 7 + + + + + + + + 0 + 0 + + + + + 32 + 28 + + + + + 0 + 0 + + + + + Arial + + + + Use single avatar with Body and Head + + + + 0 + 0 + + + + + + + + + + + 0 + + + 10 + + + 7 + + + 7 + + + - + + + + Arial + + + + Full Avatar + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + fullAvatarURLEdit + + + + + + + + 0 + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + Arial + + + + Browse + + + + 0 + 0 + + + + + + + + + + + + + + 0 + 0 + + + + + 32 + 28 + + + + + 0 + 0 + + + + + Arial + + + + Use separate Body and Head avatar files + + + + 0 + 0 + + + + + + + + + + 0 + + + 10 + + + 7 + + + 7 + + + + + + Arial @@ -211,11 +397,11 @@ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - snapshotLocationEdit - + + + @@ -260,21 +446,28 @@ + + + - + 0 + + 10 + 7 7 + - + Arial @@ -290,9 +483,10 @@ skeletonURLEdit + - + 0 @@ -344,6 +538,20 @@ + + + + + + + + + + + + + + @@ -665,6 +873,7 @@ + From 1a463a025697043d9848b83275231c58cdf0ea0a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 3 Apr 2015 17:03:22 -0700 Subject: [PATCH 002/401] more work on improved avatar UI adding model names and backward compatible support --- interface/src/Application.cpp | 33 +++++-------- interface/src/Application.h | 6 +-- interface/src/avatar/MyAvatar.cpp | 66 +++++++++++++++++++------- interface/src/avatar/MyAvatar.h | 16 +++++-- interface/src/ui/PreferencesDialog.cpp | 19 ++++---- interface/src/ui/PreferencesDialog.h | 6 +-- libraries/avatars/src/AvatarData.h | 2 + libraries/fbx/src/FSTReader.cpp | 21 ++++++++ libraries/fbx/src/FSTReader.h | 1 + 9 files changed, 115 insertions(+), 55 deletions(-) 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); From 50479d5d5e831b8179fde125c2f3922ecbec1735 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 3 Apr 2015 17:06:54 -0700 Subject: [PATCH 003/401] set name to Default when using default url --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c2bab11065..1f044a5a0f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4258,7 +4258,7 @@ void Application::checkSkeleton() { msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); - _myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL); + _myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default"); } else { _myAvatar->updateCharacterController(); _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); From 0bc1b028954c586d828a27b3e4517f9288185993 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 3 Apr 2015 17:24:53 -0700 Subject: [PATCH 004/401] improvements to tracking model names --- interface/src/Application.cpp | 1 + interface/src/avatar/MyAvatar.cpp | 36 +++++++++++++++++++++----- interface/src/ui/PreferencesDialog.cpp | 1 + 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1f044a5a0f..6befbe2555 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3747,6 +3747,7 @@ bool Application::askToSetAvatarUrl(const QString& url) { } else { qDebug() << "Declined to use the avatar: " << url; } + return true; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 085b7bccab..3073bbb219 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -955,8 +955,16 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) { _useFullAvatar = true; - _fullAvatarURLFromPreferences = fullAvatarURL; - _fullAvatarModelName = modelName; + + if (_fullAvatarURLFromPreferences != fullAvatarURL) { + _fullAvatarURLFromPreferences = fullAvatarURL; + if (modelName.isEmpty()) { + QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString()); + _fullAvatarModelName = fullAvatarFST["name"].toString(); + } else { + _fullAvatarModelName = modelName; + } + } if (!getFaceModelURLString().isEmpty()) { setFaceModelURL(QString()); @@ -979,10 +987,26 @@ void MyAvatar::useBodyURL(const QUrl& bodyURL, const QString& modelName) { 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 (_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); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 9b6cd03dfa..bc10109c36 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -271,6 +271,7 @@ void PreferencesDialog::loadPreferences() { void PreferencesDialog::savePreferences() { MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + bool shouldDispatchIdentityPacket = false; QString displayNameStr(ui.displayNameEdit->text()); From 7f4c577e8073d2398ae8498407ef6f60280059b4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 3 Apr 2015 17:25:39 -0700 Subject: [PATCH 005/401] end of file --- libraries/fbx/src/FSTReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index d7f0ff4e70..32be82b392 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -189,4 +189,4 @@ QVariantHash FSTReader::downloadMapping(const QString& url) { QByteArray fstContents = reply->readAll(); delete reply; return FSTReader::readMapping(fstContents); -} \ No newline at end of file +} From f6bf1d414188415e8e65841cfc6947543e57958a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 3 Apr 2015 17:41:19 -0700 Subject: [PATCH 006/401] Disable DDE code if not Windows or OSX --- interface/src/Application.cpp | 4 +++- interface/src/Menu.cpp | 4 ++-- interface/src/devices/DdeFaceTracker.h | 4 ++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f0324b7361..b49b8188c5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1730,8 +1730,10 @@ FaceTracker* Application::getActiveFaceTracker() { void Application::setActiveFaceTracker() { #ifdef HAVE_FACESHIFT DependencyManager::get()->setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)); -#endif +#endif +#ifdef HAVE_DDE DependencyManager::get()->setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression)); +#endif #ifdef HAVE_VISAGE DependencyManager::get()->updateEnabled(); #endif diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f95ffddbfb..2313cb569e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -370,12 +370,12 @@ Menu::Menu() { qApp, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(faceshiftFaceTracker); #endif - +#ifdef HAVE_DDE QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFaceRegression, 0, false, qApp, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(ddeFaceTracker); - +#endif #ifdef HAVE_VISAGE QAction* visageFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Visage, 0, false, diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 3c95666a6c..1a998d4b7f 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -12,6 +12,10 @@ #ifndef hifi_DdeFaceTracker_h #define hifi_DdeFaceTracker_h +#if defined(Q_OS_WIN) || defined(Q_OS_OSX) + #define HAVE_DDE +#endif + #include #include From 0d42c7a1c1addd1978a26044c360193366b99809 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 3 Apr 2015 19:16:07 -0700 Subject: [PATCH 007/401] Start and stop DDE as separate process --- interface/src/devices/DdeFaceTracker.cpp | 23 +++++++++++++++++++++++ interface/src/devices/DdeFaceTracker.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 9d753d228d..9449084c5d 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -11,6 +11,7 @@ #include +#include #include #include #include @@ -19,6 +20,13 @@ #include "DdeFaceTracker.h" #include "FaceshiftConstants.h" +#if defined(Q_OS_WIN) +static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde.exe"; +static const QString DDE_ARGUMENTS = "--udp=127.0.0.1:5555 --headless"; +#elif defined(Q_OS_MAC) +static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde"; +static const QString DDE_ARGUMENTS = "--udp=127.0.0.1:5555 --headless"; +#endif static const QHostAddress DDE_FEATURE_POINT_SERVER_ADDR("127.0.0.1"); static const quint16 DDE_FEATURE_POINT_SERVER_PORT = 5555; @@ -125,6 +133,7 @@ DdeFaceTracker::DdeFaceTracker() : } DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) : + _ddeProcess(NULL), _host(host), _port(port), _lastReceiveTimestamp(0), @@ -161,11 +170,25 @@ DdeFaceTracker::~DdeFaceTracker() { } void DdeFaceTracker::setEnabled(bool enabled) { +#ifdef HAVE_DDE + if (enabled && !_ddeProcess) { + qDebug() << "[Info] DDE Face Tracker Starting"; + _ddeProcess = new QProcess(qApp); + _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS.split(" ")); + } + // isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket. _udpSocket.close(); if (enabled) { _udpSocket.bind(_host, _port); } + + if (!enabled && _ddeProcess) { + _ddeProcess->kill(); + _ddeProcess = NULL; + qDebug() << "[Info] DDE Face Tracker Stopped"; + } +#endif } bool DdeFaceTracker::isActive() const { diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 1a998d4b7f..d7008a57b9 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -16,6 +16,7 @@ #define HAVE_DDE #endif +#include #include #include @@ -62,6 +63,8 @@ private: DdeFaceTracker(const QHostAddress& host, quint16 port); ~DdeFaceTracker(); + QProcess* _ddeProcess; + QHostAddress _host; quint16 _port; From 00f5469fa82e50995d12db7a6504f25605a755aa Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 4 Apr 2015 17:31:32 -0700 Subject: [PATCH 008/401] Add menu item that resets DDE tracking --- interface/src/Application.h | 4 ++-- interface/src/Menu.cpp | 23 +++++++++++++++++++---- interface/src/Menu.h | 2 ++ interface/src/devices/DdeFaceTracker.cpp | 24 ++++++++++++++++-------- interface/src/devices/DdeFaceTracker.h | 6 ++++-- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index e9b8deff55..b6d2a5cc10 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -210,6 +210,8 @@ public: bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; } FaceTracker* getActiveFaceTracker(); + void setActiveFaceTracker(); + QSystemTrayIcon* getTrayIcon() { return _trayIcon; } ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; } Overlays& getOverlays() { return _overlays; } @@ -388,8 +390,6 @@ public slots: void notifyPacketVersionMismatch(); - void setActiveFaceTracker(); - void domainConnectionDenied(const QString& reason); private slots: diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2313cb569e..ac27030ee3 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -361,28 +361,36 @@ Menu::Menu() { QAction* noFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::NoFaceTracking, 0, true, - qApp, SLOT(setActiveFaceTracker())); + this, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(noFaceTracker); #ifdef HAVE_FACESHIFT QAction* faceshiftFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Faceshift, 0, false, - qApp, SLOT(setActiveFaceTracker())); + this, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(faceshiftFaceTracker); #endif #ifdef HAVE_DDE QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFaceRegression, 0, false, - qApp, SLOT(setActiveFaceTracker())); + this, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(ddeFaceTracker); #endif #ifdef HAVE_VISAGE QAction* visageFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Visage, 0, false, - qApp, SLOT(setActiveFaceTracker())); + this, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(visageFaceTracker); #endif } +#ifdef HAVE_DDE + faceTrackingMenu->addSeparator(); + QAction* ddeFaceTrackerReset = addActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::ResetDDETracking, + Qt::CTRL | Qt::Key_Apostrophe, + DependencyManager::get().data(), SLOT(resetTracking())); + ddeFaceTrackerReset->setVisible(false); + faceTrackingMenu->addAction(ddeFaceTrackerReset); +#endif addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderHeadCollisionShapes); @@ -1002,3 +1010,10 @@ void Menu::visibilityChanged(Discoverability::Mode discoverabilityMode) { qDebug() << "ERROR Menu::visibilityChanged() called with unrecognized value."; } } + +void Menu::setActiveFaceTracker() { + bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression); + Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE); + + qApp->setActiveFaceTracker(); +} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index db126a3c9b..00f876a539 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -68,6 +68,7 @@ public slots: private slots: void setVisibility(); + void setActiveFaceTracker(); private: static Menu* _instance; @@ -230,6 +231,7 @@ namespace MenuOption { const QString RenderAmbientLight8 = "CAMPUS_SUNSET"; const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET"; const QString ResetAvatarSize = "Reset Avatar Size"; + const QString ResetDDETracking = "Reset DDE Tracking"; const QString ResetSensors = "Reset Sensors"; const QString RunningScripts = "Running Scripts"; const QString RunTimingTests = "Run Timing Tests"; diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 9449084c5d..000ddf6069 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -22,13 +22,14 @@ #if defined(Q_OS_WIN) static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde.exe"; -static const QString DDE_ARGUMENTS = "--udp=127.0.0.1:5555 --headless"; +static const QString DDE_ARGUMENTS = "--udp=127.0.0.1:64204 --receiver=64205 --headless"; #elif defined(Q_OS_MAC) static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde"; -static const QString DDE_ARGUMENTS = "--udp=127.0.0.1:5555 --headless"; +static const QString DDE_ARGUMENTS = "--udp=127.0.0.1:64204 --receiver=64205 --headless"; #endif -static const QHostAddress DDE_FEATURE_POINT_SERVER_ADDR("127.0.0.1"); -static const quint16 DDE_FEATURE_POINT_SERVER_PORT = 5555; +static const QHostAddress DDE_SERVER_ADDR("127.0.0.1"); +static const quint16 DDE_SERVER_PORT = 64204; +static const quint16 DDE_CONTROL_PORT = 64205; static const int NUM_EXPRESSIONS = 46; static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSIONS) * sizeof(float) + sizeof(int); @@ -127,15 +128,16 @@ struct Packet { }; DdeFaceTracker::DdeFaceTracker() : - DdeFaceTracker(QHostAddress::Any, DDE_FEATURE_POINT_SERVER_PORT) + DdeFaceTracker(QHostAddress::Any, DDE_SERVER_PORT, DDE_CONTROL_PORT) { } -DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) : +DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort) : _ddeProcess(NULL), _host(host), - _port(port), + _serverPort(serverPort), + _controlPort(controlPort), _lastReceiveTimestamp(0), _reset(false), _leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes @@ -180,7 +182,7 @@ void DdeFaceTracker::setEnabled(bool enabled) { // isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket. _udpSocket.close(); if (enabled) { - _udpSocket.bind(_host, _port); + _udpSocket.bind(_host, _serverPort); } if (!enabled && _ddeProcess) { @@ -191,6 +193,12 @@ void DdeFaceTracker::setEnabled(bool enabled) { #endif } +void DdeFaceTracker::resetTracking() { + qDebug() << "[Info] Reset DDE Tracking"; + const char* DDE_RESET_COMMAND = "reset"; + _udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort); +} + bool DdeFaceTracker::isActive() const { static const quint64 ACTIVE_TIMEOUT_USECS = 3000000; //3 secs return (usecTimestampNow() - _lastReceiveTimestamp < ACTIVE_TIMEOUT_USECS); diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index d7008a57b9..a53fbdb379 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -50,6 +50,7 @@ public: public slots: void setEnabled(bool enabled); + void resetTracking(); private slots: @@ -60,13 +61,14 @@ private slots: private: DdeFaceTracker(); - DdeFaceTracker(const QHostAddress& host, quint16 port); + DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort); ~DdeFaceTracker(); QProcess* _ddeProcess; QHostAddress _host; - quint16 _port; + quint16 _serverPort; + quint16 _controlPort; float getBlendshapeCoefficient(int index) const; void decodePacket(const QByteArray& buffer); From 1eb5716ab77079736a326803e3d83919388991b1 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 4 Apr 2015 19:04:47 -0700 Subject: [PATCH 009/401] Shut down DDE when Interface shuts down --- interface/src/Application.cpp | 2 ++ interface/src/devices/DdeFaceTracker.cpp | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b49b8188c5..a26364cb06 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -610,6 +610,8 @@ void Application::cleanupBeforeQuit() { // destroy the AudioClient so it and its thread have a chance to go down safely DependencyManager::destroy(); + + DependencyManager::destroy(); } Application::~Application() { diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 000ddf6069..cadf48d98b 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -166,9 +166,7 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui } DdeFaceTracker::~DdeFaceTracker() { - if (_udpSocket.isOpen()) { - _udpSocket.close(); - } + setEnabled(false); } void DdeFaceTracker::setEnabled(bool enabled) { From 65c1fea689bf21e2438fb3156ec43b990f29fe8d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 4 Apr 2015 19:08:23 -0700 Subject: [PATCH 010/401] Increase DDE head translation to make avatar better reflect RL --- interface/src/devices/DdeFaceTracker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index cadf48d98b..d654a493ed 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -266,7 +266,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { } // Compute relative translation - float LEAN_DAMPING_FACTOR = 200.0f; + float LEAN_DAMPING_FACTOR = 75.0f; translation -= _referenceTranslation; translation /= LEAN_DAMPING_FACTOR; translation.x *= -1; From 765d66eee55597c4af1fc9cc8811fc5fe9bc661c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 4 Apr 2015 19:20:44 -0700 Subject: [PATCH 011/401] Fix running without DDE available --- interface/src/Application.cpp | 2 ++ interface/src/Menu.cpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a26364cb06..b1f7d65441 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -611,7 +611,9 @@ void Application::cleanupBeforeQuit() { // destroy the AudioClient so it and its thread have a chance to go down safely DependencyManager::destroy(); +#ifdef HAVE_DDE DependencyManager::destroy(); +#endif } Application::~Application() { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ac27030ee3..6e8763426d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1012,8 +1012,9 @@ void Menu::visibilityChanged(Discoverability::Mode discoverabilityMode) { } void Menu::setActiveFaceTracker() { +#ifdef HAVE_DDE bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression); Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE); - +#endif qApp->setActiveFaceTracker(); } From f496175fb94b3307d31948d964bedcfd4c437a61 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 9 Apr 2015 09:17:23 -0700 Subject: [PATCH 012/401] Attempt to stop the crashing on exit caused by the Oculus SDK --- interface/src/devices/OculusManager.cpp | 13 +++++++++++-- interface/src/devices/OculusManager.h | 1 + interface/src/main.cpp | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 3f527c6137..437229a483 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -114,8 +114,11 @@ void OculusManager::initSdk() { } void OculusManager::shutdownSdk() { - ovrHmd_Destroy(_ovrHmd); - ovr_Shutdown(); + if (_ovrHmd) { + ovrHmd_Destroy(_ovrHmd); + _ovrHmd = nullptr; + ovr_Shutdown(); + } } void OculusManager::init() { @@ -124,6 +127,12 @@ void OculusManager::init() { #endif } +void OculusManager::deinit() { +#ifdef OVR_DIRECT_MODE + shutdownSdk(); +#endif +} + void OculusManager::connect() { #ifndef OVR_DIRECT_MODE initSdk(); diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index fe2da31231..4b1bc98fb2 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -51,6 +51,7 @@ class Text3DOverlay; class OculusManager { public: static void init(); + static void deinit(); static void connect(); static void disconnect(); static bool isConnected(); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index b4486ceb2b..7d80b077b8 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -112,6 +112,7 @@ int main(int argc, const char* argv[]) { exitCode = app.exec(); } + OculusManager::deinit(); #ifdef Q_OS_WIN ReleaseMutex(mutex); #endif From b472edbebb045e39660310dc77967933a20c8f29 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 9 Apr 2015 09:26:14 -0700 Subject: [PATCH 013/401] remove debug print for something that no longer exists --- libraries/entities/src/EntityItem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 2fb943c0b6..5fae58c5f4 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -766,7 +766,6 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) { qCDebug(entities) << " damping:" << _damping; qCDebug(entities) << " velocity AFTER dampingResistance:" << velocity; qCDebug(entities) << " glm::length(velocity):" << glm::length(velocity); - qCDebug(entities) << " velocityEspilon :" << ENTITY_ITEM_EPSILON_VELOCITY_LENGTH; #endif } From 55b92f7d1e75668412d688c4c50b651daaefcf03 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 9 Apr 2015 15:18:31 -0700 Subject: [PATCH 014/401] Circle of origin for rain --- examples/example/entities/rain.js | 69 +++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/example/entities/rain.js diff --git a/examples/example/entities/rain.js b/examples/example/entities/rain.js new file mode 100644 index 0000000000..4cc8827293 --- /dev/null +++ b/examples/example/entities/rain.js @@ -0,0 +1,69 @@ +// +// rain.js +// examples +// +// Created by David Rowe on 9 Apr 2015. +// Copyright 2015 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 +// + +var RainSquall = function (properties) { + var // Properties + origin, + radius, + debug = false, // Display origin circle + // Other + squallCircle, + SQUALL_CIRCLE_COLOR = { red: 255, green: 0, blue: 0 }, + SQUALL_CIRCLE_ALPHA = 0.3, + SQUALL_CIRCLE_ROTATION = Quat.fromPitchYawRollDegrees(90, 0, 0); + + function processProperties() { + if (!properties.hasOwnProperty("origin")) { + print("ERROR: Rain squall origin must be specified"); + return; + } + origin = properties.origin; + + if (!properties.hasOwnProperty("radius")) { + print("ERROR: Rain squall radius must be specified"); + return; + } + radius = properties.radius; + + if (properties.hasOwnProperty("debug")) { + debug = properties.debug; + } + } + + function setUp() { + squallCircle = Overlays.addOverlay("circle3d", { + size: { x: radius, y: radius }, + color: SQUALL_CIRCLE_COLOR, + alpha: SQUALL_CIRCLE_ALPHA, + solid: true, + visible: debug, + position: origin, + rotation: SQUALL_CIRCLE_ROTATION + }); + } + + function tearDown() { + Overlays.deleteOverlay(squallCircle); + } + + processProperties(); + setUp(); + Script.scriptEnding.connect(tearDown); + + return { + }; +}; + +var rainSquall1 = new RainSquall({ + origin: { x: 8192, y: 8200, z: 8192 }, + radius: 2.5, + debug: true +}); \ No newline at end of file From e4e372b2a38fbc205157131d03144270800ed3bd Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 9 Apr 2015 15:51:19 -0700 Subject: [PATCH 015/401] Create a raindrop with a lifetime --- examples/example/entities/rain.js | 34 +++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/examples/example/entities/rain.js b/examples/example/entities/rain.js index 4cc8827293..a4860a1eac 100644 --- a/examples/example/entities/rain.js +++ b/examples/example/entities/rain.js @@ -13,12 +13,17 @@ var RainSquall = function (properties) { var // Properties origin, radius, + dropSize = { x: 0.1, y: 0.1, z: 0.1 }, + dropLifetime = 60, // Seconds debug = false, // Display origin circle // Other squallCircle, SQUALL_CIRCLE_COLOR = { red: 255, green: 0, blue: 0 }, - SQUALL_CIRCLE_ALPHA = 0.3, - SQUALL_CIRCLE_ROTATION = Quat.fromPitchYawRollDegrees(90, 0, 0); + SQUALL_CIRCLE_ALPHA = 0.5, + SQUALL_CIRCLE_ROTATION = Quat.fromPitchYawRollDegrees(90, 0, 0), + raindropProperties, + RAINDROP_MODEL_URL = "https://s3.amazonaws.com/hifi-public/ozan/Polyworld/Sets/sky/tetrahedron_v1-Faceted2.fbx", + raindropTimer; function processProperties() { if (!properties.hasOwnProperty("origin")) { @@ -33,9 +38,29 @@ var RainSquall = function (properties) { } radius = properties.radius; + if (properties.hasOwnProperty("dropSize")) { + dropSize = properties.dropSize; + } + + if (properties.hasOwnProperty("dropLifetime")) { + dropLifetime = properties.dropLifetime; + } + if (properties.hasOwnProperty("debug")) { debug = properties.debug; } + + raindropProperties = { + type: "Model", + modelURL: RAINDROP_MODEL_URL, + lifetime: dropLifetime, + dimensions: dropSize + }; + } + + function createRaindrop() { + raindropProperties.position = Vec3.sum(origin, { x: 0, y: -0.1, z: 0 }); + Entities.addEntity(raindropProperties); } function setUp() { @@ -48,9 +73,12 @@ var RainSquall = function (properties) { position: origin, rotation: SQUALL_CIRCLE_ROTATION }); + + raindropTimer = Script.setInterval(createRaindrop, 3000); } function tearDown() { + Script.clearInterval(raindropTimer); Overlays.deleteOverlay(squallCircle); } @@ -65,5 +93,7 @@ var RainSquall = function (properties) { var rainSquall1 = new RainSquall({ origin: { x: 8192, y: 8200, z: 8192 }, radius: 2.5, + dropSize: { x: 0.1, y: 0.1, z: 0.1 }, + dropLifetime: 2, debug: true }); \ No newline at end of file From 00f42c1e6cfd6211060570ab58c09121e6ba5a21 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 9 Apr 2015 15:52:59 -0700 Subject: [PATCH 016/401] Move to acScripts --- examples/{example/entities => acScripts}/rain.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{example/entities => acScripts}/rain.js (100%) diff --git a/examples/example/entities/rain.js b/examples/acScripts/rain.js similarity index 100% rename from examples/example/entities/rain.js rename to examples/acScripts/rain.js From 66ea84977a75cb9300bd971cb4613fd7859690c0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 9 Apr 2015 16:18:10 -0700 Subject: [PATCH 017/401] Create raindrops at specified rate --- examples/acScripts/rain.js | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/examples/acScripts/rain.js b/examples/acScripts/rain.js index a4860a1eac..b2aa4427de 100644 --- a/examples/acScripts/rain.js +++ b/examples/acScripts/rain.js @@ -11,10 +11,11 @@ var RainSquall = function (properties) { var // Properties - origin, - radius, + squallOrigin, + squallRadius, dropSize = { x: 0.1, y: 0.1, z: 0.1 }, dropLifetime = 60, // Seconds + dropsPerMinute = 60, debug = false, // Display origin circle // Other squallCircle, @@ -30,13 +31,13 @@ var RainSquall = function (properties) { print("ERROR: Rain squall origin must be specified"); return; } - origin = properties.origin; + squallOrigin = properties.origin; if (!properties.hasOwnProperty("radius")) { print("ERROR: Rain squall radius must be specified"); return; } - radius = properties.radius; + squallRadius = properties.radius; if (properties.hasOwnProperty("dropSize")) { dropSize = properties.dropSize; @@ -46,6 +47,10 @@ var RainSquall = function (properties) { dropLifetime = properties.dropLifetime; } + if (properties.hasOwnProperty("dropsPerMinute")) { + dropsPerMinute = properties.dropsPerMinute; + } + if (properties.hasOwnProperty("debug")) { debug = properties.debug; } @@ -59,22 +64,28 @@ var RainSquall = function (properties) { } function createRaindrop() { - raindropProperties.position = Vec3.sum(origin, { x: 0, y: -0.1, z: 0 }); + var angle, + radius, + offset; + angle = Math.random() * 360; + radius = Math.random() * squallRadius; + offset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, angle, 0), { x: 0, y: -0.1, z: radius }); + raindropProperties.position = Vec3.sum(squallOrigin, offset); Entities.addEntity(raindropProperties); } function setUp() { squallCircle = Overlays.addOverlay("circle3d", { - size: { x: radius, y: radius }, + size: { x: 2 * squallRadius, y: 2 * squallRadius }, color: SQUALL_CIRCLE_COLOR, alpha: SQUALL_CIRCLE_ALPHA, solid: true, visible: debug, - position: origin, + position: squallOrigin, rotation: SQUALL_CIRCLE_ROTATION }); - raindropTimer = Script.setInterval(createRaindrop, 3000); + raindropTimer = Script.setInterval(createRaindrop, 60000 / dropsPerMinute); } function tearDown() { @@ -94,6 +105,7 @@ var rainSquall1 = new RainSquall({ origin: { x: 8192, y: 8200, z: 8192 }, radius: 2.5, dropSize: { x: 0.1, y: 0.1, z: 0.1 }, - dropLifetime: 2, + dropLifetime: 10, + dropsPerMinute: 120, debug: true }); \ No newline at end of file From 54980f46a91e132d66b7fd958e6042d2618eb235 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 9 Apr 2015 17:29:14 -0700 Subject: [PATCH 018/401] Set raindrops falling --- examples/acScripts/rain.js | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/examples/acScripts/rain.js b/examples/acScripts/rain.js index b2aa4427de..d7d0c9d44d 100644 --- a/examples/acScripts/rain.js +++ b/examples/acScripts/rain.js @@ -13,9 +13,10 @@ var RainSquall = function (properties) { var // Properties squallOrigin, squallRadius, - dropSize = { x: 0.1, y: 0.1, z: 0.1 }, - dropLifetime = 60, // Seconds dropsPerMinute = 60, + dropSize = { x: 0.1, y: 0.1, z: 0.1 }, + dropFallSpeed = 1, // m/s + dropLifetime = 60, // Seconds debug = false, // Display origin circle // Other squallCircle, @@ -39,16 +40,20 @@ var RainSquall = function (properties) { } squallRadius = properties.radius; + if (properties.hasOwnProperty("dropsPerMinute")) { + dropsPerMinute = properties.dropsPerMinute; + } + if (properties.hasOwnProperty("dropSize")) { dropSize = properties.dropSize; } - if (properties.hasOwnProperty("dropLifetime")) { - dropLifetime = properties.dropLifetime; + if (properties.hasOwnProperty("dropFallSpeed")) { + dropFallSpeed = properties.dropFallSpeed; } - if (properties.hasOwnProperty("dropsPerMinute")) { - dropsPerMinute = properties.dropsPerMinute; + if (properties.hasOwnProperty("dropLifetime")) { + dropLifetime = properties.dropLifetime; } if (properties.hasOwnProperty("debug")) { @@ -59,7 +64,10 @@ var RainSquall = function (properties) { type: "Model", modelURL: RAINDROP_MODEL_URL, lifetime: dropLifetime, - dimensions: dropSize + dimensions: dropSize, + velocity: { x: 0, y: -dropFallSpeed, z: 0 }, + damping: 0, + ignoreForCollisions: true }; } @@ -67,6 +75,7 @@ var RainSquall = function (properties) { var angle, radius, offset; + angle = Math.random() * 360; radius = Math.random() * squallRadius; offset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, angle, 0), { x: 0, y: -0.1, z: radius }); @@ -104,8 +113,9 @@ var RainSquall = function (properties) { var rainSquall1 = new RainSquall({ origin: { x: 8192, y: 8200, z: 8192 }, radius: 2.5, - dropSize: { x: 0.1, y: 0.1, z: 0.1 }, - dropLifetime: 10, dropsPerMinute: 120, + dropSize: { x: 0.1, y: 0.1, z: 0.1 }, + dropFallSpeed: 2, // m/s + dropLifetime: 10, debug: true }); \ No newline at end of file From 10ac6bc9cadeb78baa2c344c7521eae2686bacf0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 9 Apr 2015 18:17:45 -0700 Subject: [PATCH 019/401] Don't render overlay unless debug --- examples/acScripts/rain.js | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/examples/acScripts/rain.js b/examples/acScripts/rain.js index d7d0c9d44d..6e03219934 100644 --- a/examples/acScripts/rain.js +++ b/examples/acScripts/rain.js @@ -17,7 +17,7 @@ var RainSquall = function (properties) { dropSize = { x: 0.1, y: 0.1, z: 0.1 }, dropFallSpeed = 1, // m/s dropLifetime = 60, // Seconds - debug = false, // Display origin circle + debug = false, // Display origin circle; don't use running on Stack Manager // Other squallCircle, SQUALL_CIRCLE_COLOR = { red: 255, green: 0, blue: 0 }, @@ -84,22 +84,26 @@ var RainSquall = function (properties) { } function setUp() { - squallCircle = Overlays.addOverlay("circle3d", { - size: { x: 2 * squallRadius, y: 2 * squallRadius }, - color: SQUALL_CIRCLE_COLOR, - alpha: SQUALL_CIRCLE_ALPHA, - solid: true, - visible: debug, - position: squallOrigin, - rotation: SQUALL_CIRCLE_ROTATION - }); + if (debug) { + squallCircle = Overlays.addOverlay("circle3d", { + size: { x: 2 * squallRadius, y: 2 * squallRadius }, + color: SQUALL_CIRCLE_COLOR, + alpha: SQUALL_CIRCLE_ALPHA, + solid: true, + visible: debug, + position: squallOrigin, + rotation: SQUALL_CIRCLE_ROTATION + }); + } raindropTimer = Script.setInterval(createRaindrop, 60000 / dropsPerMinute); } function tearDown() { Script.clearInterval(raindropTimer); - Overlays.deleteOverlay(squallCircle); + if (debug) { + Overlays.deleteOverlay(squallCircle); + } } processProperties(); From 54c0aeaa03a0bb7765c4cde0b0f8cef344b578d7 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 9 Apr 2015 18:57:58 -0700 Subject: [PATCH 020/401] Work around entities not always getting velocity set at creation --- examples/acScripts/rain.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/examples/acScripts/rain.js b/examples/acScripts/rain.js index 6e03219934..fc7333fd65 100644 --- a/examples/acScripts/rain.js +++ b/examples/acScripts/rain.js @@ -25,7 +25,8 @@ var RainSquall = function (properties) { SQUALL_CIRCLE_ROTATION = Quat.fromPitchYawRollDegrees(90, 0, 0), raindropProperties, RAINDROP_MODEL_URL = "https://s3.amazonaws.com/hifi-public/ozan/Polyworld/Sets/sky/tetrahedron_v1-Faceted2.fbx", - raindropTimer; + raindropTimer, + rainDrops = []; function processProperties() { if (!properties.hasOwnProperty("origin")) { @@ -74,13 +75,26 @@ var RainSquall = function (properties) { function createRaindrop() { var angle, radius, - offset; + offset, + drop, + i; + + // HACK: Work around rain drops not always getting velocity set at creation + for (i = 0; i < rainDrops.length; i += 1) { + Entities.editEntity(rainDrops[i], { velocity: raindropProperties.velocity }); + } angle = Math.random() * 360; radius = Math.random() * squallRadius; offset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, angle, 0), { x: 0, y: -0.1, z: radius }); raindropProperties.position = Vec3.sum(squallOrigin, offset); - Entities.addEntity(raindropProperties); + drop = Entities.addEntity(raindropProperties); + + // HACK: Work around rain drops not always getting velocity set at creation + rainDrops.push(drop); + if (rainDrops.length > 5) { + drop = rainDrops.shift(); + } } function setUp() { From d057573825f6d9c08fcf9c1ad6a88c625a5ee59d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 9 Apr 2015 19:38:15 -0700 Subject: [PATCH 021/401] Set raindrops spinning --- examples/acScripts/rain.js | 52 ++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/examples/acScripts/rain.js b/examples/acScripts/rain.js index fc7333fd65..ee8a1e19a6 100644 --- a/examples/acScripts/rain.js +++ b/examples/acScripts/rain.js @@ -17,6 +17,7 @@ var RainSquall = function (properties) { dropSize = { x: 0.1, y: 0.1, z: 0.1 }, dropFallSpeed = 1, // m/s dropLifetime = 60, // Seconds + dropSpinMax = 0, // Maximum angular velocity per axis; deg/s debug = false, // Display origin circle; don't use running on Stack Manager // Other squallCircle, @@ -26,7 +27,9 @@ var RainSquall = function (properties) { raindropProperties, RAINDROP_MODEL_URL = "https://s3.amazonaws.com/hifi-public/ozan/Polyworld/Sets/sky/tetrahedron_v1-Faceted2.fbx", raindropTimer, - rainDrops = []; + raindrops = [], // HACK: Work around raindrops not always getting velocities + raindropVelocities = [], // HACK: Work around raindrops not always getting velocities + DEGREES_TO_RADIANS = Math.PI / 180; function processProperties() { if (!properties.hasOwnProperty("origin")) { @@ -57,6 +60,10 @@ var RainSquall = function (properties) { dropLifetime = properties.dropLifetime; } + if (properties.hasOwnProperty("dropSpinMax")) { + dropSpinMax = properties.dropSpinMax; + } + if (properties.hasOwnProperty("debug")) { debug = properties.debug; } @@ -68,6 +75,7 @@ var RainSquall = function (properties) { dimensions: dropSize, velocity: { x: 0, y: -dropFallSpeed, z: 0 }, damping: 0, + angularDamping: 0, ignoreForCollisions: true }; } @@ -77,23 +85,38 @@ var RainSquall = function (properties) { radius, offset, drop, + spin = { x: 0, y: 0, z: 0 }, + maxSpinRadians = properties.dropSpinMax * DEGREES_TO_RADIANS, i; - // HACK: Work around rain drops not always getting velocity set at creation - for (i = 0; i < rainDrops.length; i += 1) { - Entities.editEntity(rainDrops[i], { velocity: raindropProperties.velocity }); + // HACK: Work around rain drops not always getting velocities set at creation + for (i = 0; i < raindrops.length; i += 1) { + Entities.editEntity(raindrops[i], raindropVelocities[i]); } angle = Math.random() * 360; radius = Math.random() * squallRadius; offset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, angle, 0), { x: 0, y: -0.1, z: radius }); raindropProperties.position = Vec3.sum(squallOrigin, offset); + if (properties.dropSpinMax > 0) { + spin = { + x: Math.random() * maxSpinRadians, + y: Math.random() * maxSpinRadians, + z: Math.random() * maxSpinRadians + }; + raindropProperties.angularVelocity = spin; + } drop = Entities.addEntity(raindropProperties); - // HACK: Work around rain drops not always getting velocity set at creation - rainDrops.push(drop); - if (rainDrops.length > 5) { - drop = rainDrops.shift(); + // HACK: Work around rain drops not always getting velocities set at creation + raindrops.push(drop); + raindropVelocities.push({ + velocity: raindropProperties.velocity, + angularVelocity: spin + }); + if (raindrops.length > 5) { + raindrops.shift(); + raindropVelocities.shift(); } } @@ -129,11 +152,12 @@ var RainSquall = function (properties) { }; var rainSquall1 = new RainSquall({ - origin: { x: 8192, y: 8200, z: 8192 }, - radius: 2.5, + origin: { x: 1195, y: 1223, z: 1020 }, + radius: 25, dropsPerMinute: 120, dropSize: { x: 0.1, y: 0.1, z: 0.1 }, - dropFallSpeed: 2, // m/s - dropLifetime: 10, - debug: true -}); \ No newline at end of file + dropFallSpeed: 3, + dropLifetime: 30, + dropSpinMax: 180, + debug: false +}); From 69484ad00b960a00423405342533d939a13ed303 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sun, 12 Apr 2015 17:36:45 -0700 Subject: [PATCH 022/401] Creating the Framebuffer class and the companion Swapbuffer --- libraries/gpu/src/gpu/Format.h | 1 + libraries/gpu/src/gpu/Framebuffer.cpp | 267 ++++++++++++++++++++++++++ libraries/gpu/src/gpu/Framebuffer.h | 195 +++++++++++++++++++ 3 files changed, 463 insertions(+) create mode 100755 libraries/gpu/src/gpu/Framebuffer.cpp create mode 100755 libraries/gpu/src/gpu/Framebuffer.h diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 7f36797374..aee6f3bdf4 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -34,6 +34,7 @@ typedef glm::mat3 Mat3; typedef glm::vec4 Vec4; typedef glm::vec3 Vec3; typedef glm::vec2 Vec2; +typedef glm::ivec2 Vec2i; // Description of a scalar type enum Type { diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp new file mode 100755 index 0000000000..597a31788e --- /dev/null +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -0,0 +1,267 @@ +// +// Framebuffer.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 4/12/2015. +// 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 "Framebuffer.h" +#include +#include + +using namespace gpu; + +Framebuffer::Framebuffer() +{ +} + +Framebuffer::~Framebuffer() +{ +} + +Framebuffer* Framebuffer::create() { + auto framebuffer = new Framebuffer(); + framebuffer->_renderBuffers.resize(MAX_NUM_RENDER_BUFFERS); + framebuffer->_renderBuffersSubresource.resize(MAX_NUM_RENDER_BUFFERS, 0); + return framebuffer; +} + +Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height, uint16 numSamples) { + auto framebuffer = Framebuffer::create(); + + auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height)); + auto depthTexture = TexturePointer(Texture::create2D(depthStencilBufferFormat, width, height)); + + framebuffer->setRenderBuffer(0, colorTexture); + framebuffer->setDepthStencilBuffer(depthTexture); + + return framebuffer; +} + + +bool Framebuffer::isSwapchain() const { + return _swapchain != 0; +} + +uint32 Framebuffer::getFrameCount() const { + if (_swapchain) { + return _swapchain->getFrameCount(); + } else { + return _frameCount; + } +} + +bool Framebuffer::isEmpty() const { + return (_buffersMask == 0); +} + +bool Framebuffer::validateTargetCompatibility(const Texture& texture, uint32 subresource) const { + if (texture.getType() == Texture::TEX_1D) { + return false; + } + + if (isEmpty()) { + return true; + } else { + if ((texture.getWidth() == getWidth()) && + (texture.getHeight() == getHeight()) && + (texture.getNumSamples() == getNumSamples())) { + return true; + } else { + return false; + } + } +} + +void Framebuffer::updateSize(const TexturePointer& texture) { + if (!isEmpty()) { + return; + } + + if (texture) { + _width = texture->getWidth(); + _height = texture->getHeight(); + _numSamples = texture->getNumSamples(); + } else { + _width = _height = _numSamples = 0; + } +} + +void Framebuffer::resize(uint16 width, uint16 height, uint16 numSamples) { + if (width && height && numSamples && !isEmpty() && !isSwapchain()) { + if ((width != _width) || (height != _height) || (numSamples != _numSamples)) { + for (uint32 i = 0; i < _renderBuffers.size(); ++i) { + if (_renderBuffers[i]) { + _renderBuffers[i]->resize2D(width, height, numSamples); + _numSamples = _renderBuffers[i]->getNumSamples(); + } + } + + if (_depthStencilBuffer) { + _depthStencilBuffer->resize2D(width, height, numSamples); + _numSamples = _depthStencilBuffer->getNumSamples(); + } + + _width = width; + _height = height; + // _numSamples = numSamples; + } + } +} + +uint16 Framebuffer::getWidth() const { + if (isSwapchain()) { + return getSwapchain()->getWidth(); + } else { + return _width; + } +} + +uint16 Framebuffer::getHeight() const { + if (isSwapchain()) { + return getSwapchain()->getHeight(); + } else { + return _height; + } +} + +uint16 Framebuffer::getNumSamples() const { + if (isSwapchain()) { + return getSwapchain()->getNumSamples(); + } else { + return _numSamples; + } +} + +// Render buffers +int Framebuffer::setRenderBuffer(uint32 slot, const TexturePointer& texture, uint32 subresource) { + if (isSwapchain()) { + return -1; + } + + // Check for the slot + if (slot >= getMaxNumRenderBuffers()) { + return -1; + } + + // Check for the compatibility of size + if (texture) { + if (!validateTargetCompatibility(*texture, subresource)) { + return -1; + } + } + + // everything works, assign + // dereference the previously used buffer if exists + if (_renderBuffers[slot]) { + _renderBuffers[slot].reset(); + _renderBuffersSubresource[slot] = 0; + } + + updateSize(texture); + + // assign the new one + _renderBuffers[slot] = texture; + + // Assign the subresource + _renderBuffersSubresource[slot] = subresource; + + // update the mask + int mask = (1< + +namespace gpu { + +typedef Element Format; + +class Viewport { +public: + int32 width = 1; + int32 height = 1; + int32 top = 0; + int32 left = 0; + float zmin = 0.f; + float zmax = 1.f; + + Viewport() {} + Viewport(int32 w, int32 h, int32 t = 0, int32 l = 0, float zin = 0.f, float zax = 1.f): + width(w), + height(h), + top(t), + left(l), + zmin(zin), + zmax(zax) + {} + Viewport(const Vec2i& wh, const Vec2i& tl = Vec2i(0), const Vec2& zrange = Vec2(0.f, 1.f)): + width(wh.x), + height(wh.y), + top(tl.x), + left(tl.y), + zmin(zrange.x), + zmax(zrange.y) + {} + ~Viewport() {} +}; + +class Swapchain { +public: + // Properties + uint16 getWidth() const { return _width; } + uint16 getHeight() const { return _height; } + uint16 getNumSamples() const { return _numSamples; } + + bool hasDepthStencil() const { return _hasDepthStencil; } + bool isFullscreen() const { return _isFullscreen; } + + uint32 getSwapInterval() const { return _swapInterval; } + + bool isStereo() const { return _isStereo; } + + uint32 getFrameCount() const { return _frameCount; } + + // Pure interface + void setSwapInterval(uint32 interval); + + void resize(uint16 width, uint16 height); + void setFullscreen(bool fullscreen); + + Swapchain() {} + Swapchain(const Swapchain& swapchain) {} + virtual ~Swapchain() {} + +protected: + mutable uint32 _frameCount = 0; + + Format _colorFormat; + uint16 _width = 1; + uint16 _height = 1; + uint16 _numSamples = 1; + uint16 _swapInterval = 0; + + bool _hasDepthStencil = false; + bool _isFullscreen = false; + bool _isStereo = false; + + // Non exposed + + friend class Framebuffer; +}; +typedef std::shared_ptr SwapchainPointer; + + +class Framebuffer { +public: + enum BufferMask { + BUFFER_COLOR0 = 1, + BUFFER_COLOR1 = 2, + BUFFER_COLOR2 = 4, + BUFFER_COLOR3 = 8, + BUFFER_COLOR4 = 16, + BUFFER_COLOR5 = 32, + BUFFER_COLOR6 = 64, + BUFFER_COLOR7 = 128, + BUFFER_COLORS = 0x000000FF, + + BUFFER_DEPTH = 0x40000000, + BUFFER_STENCIL = 0x80000000, + BUFFER_DEPTHSTENCIL = 0xC0000000, + }; + + ~Framebuffer(); + + static Framebuffer* create(const SwapchainPointer& swapchain); + static Framebuffer* create(); + static Framebuffer* create(const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height, uint16 samples ); + + bool isSwapchain() const; + SwapchainPointer getSwapchain() const { return _swapchain; } + + uint32 getFrameCount() const; + + // Render buffers + int32 setRenderBuffer(uint32 slot, const TexturePointer& texture, uint32 subresource = 0); + void removeRenderBuffers(); + uint32 getNumRenderBuffers() const; + + TexturePointer getRenderBuffer(uint32 slot) const; + uint32 getRenderBufferSubresource(uint32 slot) const; + + bool setDepthStencilBuffer(const TexturePointer& texture, uint32 subresource = 0); + TexturePointer getDepthStencilBuffer() const; + uint32 getDepthStencilBufferSubresource() const; + + // Properties + uint32 getBuffersMask() const { return _buffersMask; } + bool isEmpty() const; + + bool validateTargetCompatibility(const Texture& texture, uint32 subresource = 0) const; + + uint16 getWidth() const; + uint16 getHeight() const; + uint16 getNumSamples() const; + + float getAspectRatio() const { return getWidth() / (float) getHeight() ; } + + // If not a swapchain canvas, resize can resize all the render buffers and depth stencil attached in one call + void resize( uint16 width, uint16 height, uint16 samples = 1 ); + + static const uint32 MAX_NUM_RENDER_BUFFERS = 8; + static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } + + // Get viewport covering the ful Canvas + Viewport getViewport() const { return Viewport(getWidth(), getHeight(), 0, 0); } + + +protected: + + Viewport _viewport; + + uint16 _width; + uint16 _height; + uint16 _numSamples; + + uint32 _buffersMask; + + uint32 _frameCount; + + SwapchainPointer _swapchain; + + Textures _renderBuffers; + std::vector _renderBuffersSubresource; + + TexturePointer _depthStencilBuffer; + uint32 _depthStencilBufferSubresource; + + + void updateSize(const TexturePointer& texture); + + // Non exposed + Framebuffer(const Framebuffer& framebuffer) {} + Framebuffer(); + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = NULL; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; +}; + +} + +#endif \ No newline at end of file From 05689c0413034de614601e4b89d984208e9ffefd Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 13 Apr 2015 11:13:30 -0700 Subject: [PATCH 023/401] Bringin the Framebuffer to GLBackend and refining the interface --- libraries/gpu/src/gpu/Batch.cpp | 13 +++- libraries/gpu/src/gpu/Batch.h | 8 +++ libraries/gpu/src/gpu/Context.h | 31 ++++++---- libraries/gpu/src/gpu/Framebuffer.cpp | 38 ++++-------- libraries/gpu/src/gpu/Framebuffer.h | 13 ++-- libraries/gpu/src/gpu/GLBackend.cpp | 6 +- libraries/gpu/src/gpu/GLBackend.h | 29 +++++++-- libraries/gpu/src/gpu/GLBackendOutput.cpp | 72 +++++++++++++++++++++++ libraries/gpu/src/gpu/Texture.h | 14 ++++- 9 files changed, 169 insertions(+), 55 deletions(-) create mode 100755 libraries/gpu/src/gpu/GLBackendOutput.cpp diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 9eb9648478..4b145b55a0 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -25,7 +25,8 @@ Batch::Batch() : _textures(), _streamFormats(), _transforms(), - _pipelines() + _pipelines(), + _framebuffers() { } @@ -41,7 +42,8 @@ void Batch::clear() { _textures.clear(); _streamFormats.clear(); _transforms.clear(); - _pipelines.clear(); + _pipelines.clear(); + _framebuffers.clear(); } uint32 Batch::cacheData(uint32 size, const void* data) { @@ -186,3 +188,10 @@ void Batch::setUniformTexture(uint32 slot, const TextureView& view) { setUniformTexture(slot, view._texture); } +void Batch::setFramebuffer(const FramebufferPointer& framebuffer) { + ADD_COMMAND(setUniformTexture); + + _params.push_back(_framebuffers.cache(framebuffer)); + +} + diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 6e8a2d1da6..b6bc05ab40 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -23,6 +23,8 @@ #include "Pipeline.h" +#include "Framebuffer.h" + #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" class ProfileRange { @@ -112,6 +114,8 @@ public: void setUniformTexture(uint32 slot, const TexturePointer& view); void setUniformTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView + // Framebuffer Stage + void setFramebuffer(const FramebufferPointer& framebuffer); // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long @@ -170,6 +174,8 @@ public: COMMAND_setUniformBuffer, COMMAND_setUniformTexture, + COMMAND_setFramebuffer, + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API @@ -266,6 +272,7 @@ public: typedef Cache::Vector StreamFormatCaches; typedef Cache::Vector TransformCaches; typedef Cache::Vector PipelineCaches; + typedef Cache::Vector FramebufferCaches; // Cache Data in a byte array if too big to fit in Param // FOr example Mat4s are going there @@ -289,6 +296,7 @@ public: StreamFormatCaches _streamFormats; TransformCaches _transforms; PipelineCaches _pipelines; + FramebufferCaches _framebuffers; protected: }; diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 8276ff5f95..022ca02d6d 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -15,8 +15,8 @@ #include "Resource.h" #include "Texture.h" -#include "Shader.h" #include "Pipeline.h" +#include "Framebuffer.h" namespace gpu { @@ -47,8 +47,8 @@ public: }; template< typename T > - static void setGPUObject(const Buffer& buffer, T* bo) { - buffer.setGPUObject(bo); + static void setGPUObject(const Buffer& buffer, T* object) { + buffer.setGPUObject(object); } template< typename T > static T* getGPUObject(const Buffer& buffer) { @@ -56,8 +56,8 @@ public: } template< typename T > - static void setGPUObject(const Texture& texture, T* to) { - texture.setGPUObject(to); + static void setGPUObject(const Texture& texture, T* object) { + texture.setGPUObject(object); } template< typename T > static T* getGPUObject(const Texture& texture) { @@ -65,8 +65,8 @@ public: } template< typename T > - static void setGPUObject(const Shader& shader, T* so) { - shader.setGPUObject(so); + static void setGPUObject(const Shader& shader, T* object) { + shader.setGPUObject(object); } template< typename T > static T* getGPUObject(const Shader& shader) { @@ -74,8 +74,8 @@ public: } template< typename T > - static void setGPUObject(const Pipeline& pipeline, T* po) { - pipeline.setGPUObject(po); + static void setGPUObject(const Pipeline& pipeline, T* object) { + pipeline.setGPUObject(object); } template< typename T > static T* getGPUObject(const Pipeline& pipeline) { @@ -83,14 +83,23 @@ public: } template< typename T > - static void setGPUObject(const State& state, T* so) { - state.setGPUObject(so); + static void setGPUObject(const State& state, T* object) { + state.setGPUObject(object); } template< typename T > static T* getGPUObject(const State& state) { return reinterpret_cast(state.getGPUObject()); } + template< typename T > + static void setGPUObject(const Framebuffer& framebuffer, T* object) { + framebuffer.setGPUObject(object); + } + template< typename T > + static T* getGPUObject(const Framebuffer& framebuffer) { + return reinterpret_cast(framebuffer.getGPUObject()); + } + protected: }; diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index 597a31788e..de8961886b 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -26,7 +26,6 @@ Framebuffer::~Framebuffer() Framebuffer* Framebuffer::create() { auto framebuffer = new Framebuffer(); framebuffer->_renderBuffers.resize(MAX_NUM_RENDER_BUFFERS); - framebuffer->_renderBuffersSubresource.resize(MAX_NUM_RENDER_BUFFERS, 0); return framebuffer; } @@ -96,14 +95,14 @@ void Framebuffer::resize(uint16 width, uint16 height, uint16 numSamples) { if ((width != _width) || (height != _height) || (numSamples != _numSamples)) { for (uint32 i = 0; i < _renderBuffers.size(); ++i) { if (_renderBuffers[i]) { - _renderBuffers[i]->resize2D(width, height, numSamples); - _numSamples = _renderBuffers[i]->getNumSamples(); + _renderBuffers[i]._texture->resize2D(width, height, numSamples); + _numSamples = _renderBuffers[i]._texture->getNumSamples(); } } if (_depthStencilBuffer) { - _depthStencilBuffer->resize2D(width, height, numSamples); - _numSamples = _depthStencilBuffer->getNumSamples(); + _depthStencilBuffer._texture->resize2D(width, height, numSamples); + _numSamples = _depthStencilBuffer._texture->getNumSamples(); } _width = width; @@ -155,20 +154,10 @@ int Framebuffer::setRenderBuffer(uint32 slot, const TexturePointer& texture, uin } } - // everything works, assign - // dereference the previously used buffer if exists - if (_renderBuffers[slot]) { - _renderBuffers[slot].reset(); - _renderBuffersSubresource[slot] = 0; - } - updateSize(texture); // assign the new one - _renderBuffers[slot] = texture; - - // Assign the subresource - _renderBuffersSubresource[slot] = subresource; + _renderBuffers[slot] = TextureView(texture, subresource); // update the mask int mask = (1< _renderBuffersSubresource; - - TexturePointer _depthStencilBuffer; - uint32 _depthStencilBufferSubresource; + TextureViews _renderBuffers; + TextureView _depthStencilBuffer; + bool _isDefined = false; void updateSize(const TexturePointer& texture); @@ -189,6 +185,7 @@ protected: GPUObject* getGPUObject() const { return _gpuObject; } friend class Backend; }; +typedef std::shared_ptr FramebufferPointer; } diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 8fcc2362c1..c9de132b73 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -32,6 +32,9 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_setUniformBuffer), (&::gpu::GLBackend::do_setUniformTexture), + (&::gpu::GLBackend::do_setFramebuffer), + + (&::gpu::GLBackend::do_glEnable), (&::gpu::GLBackend::do_glDisable), @@ -67,7 +70,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = GLBackend::GLBackend() : _input(), _transform(), - _pipeline() + _pipeline(), + _output() { initTransform(); } diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index ea97fd8908..e3069f5205 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -133,14 +133,25 @@ public: class GLPipeline : public GPUObject { public: - GLShader* _program; - GLState* _state; + GLShader* _program = 0; + GLState* _state = 0; GLPipeline(); ~GLPipeline(); }; static GLPipeline* syncGPUObject(const Pipeline& pipeline); + + class GLFramebuffer : public GPUObject { + public: + GLuint _fbo = 0; + + GLFramebuffer(); + ~GLFramebuffer(); + }; + static GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer); + static GLuint getFramebufferID(const FramebufferPointer& framebuffer); + static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS; static const int MAX_NUM_INPUT_BUFFERS = 16; @@ -276,8 +287,8 @@ protected: State::Signature _stateSignatureCache; GLState* _state; - bool _invalidState; - bool _needStateSync; + bool _invalidState = false; + bool _needStateSync = true; PipelineStageState() : _pipeline(), @@ -291,6 +302,16 @@ protected: {} } _pipeline; + // Output stage + void do_setFramebuffer(Batch& batch, uint32 paramOffset); + + struct OutputStageState { + + FramebufferPointer _framebuffer = nullptr; + + OutputStageState() {} + } _output; + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp new file mode 100755 index 0000000000..8865008e49 --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -0,0 +1,72 @@ +// +// GLBackendTexture.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 1/19/2015. +// 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 "GPULogging.h" +#include "GLBackendShared.h" + + +GLBackend::GLFramebuffer::GLFramebuffer() +{} + +GLBackend::GLFramebuffer::~GLFramebuffer() { + if (_fbo != 0) { + glDeleteFramebuffers(1, &_fbo); + } +} + +GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffer) { + GLFramebuffer* object = Backend::getGPUObject(framebuffer); + + // If GPU object already created and in sync + bool needUpdate = false; + if (object) { + return object; + } else if (!framebuffer.isDefined()) { + // NO framebuffer definition yet so let's avoid thinking + return nullptr; + } + + // need to have a gpu object? + if (!object) { + object = new GLFramebuffer(); + glGenFramebuffers(1, &object->_fbo); + CHECK_GL_ERROR(); + Backend::setGPUObject(framebuffer, object); + } + + + CHECK_GL_ERROR(); + + return object; +} + + + +GLuint GLBackend::getFramebufferID(const FramebufferPointer& framebuffer) { + if (!framebuffer) { + return 0; + } + GLFramebuffer* object = GLBackend::syncGPUObject(*framebuffer); + if (object) { + return object->_fbo; + } else { + return 0; + } +} + +void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) { + auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); + + if (_output._framebuffer != framebuffer) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getFramebufferID(framebuffer)); + _output._framebuffer = framebuffer; + } +} + diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 3eed52c686..cb124b7b08 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -240,15 +240,25 @@ public: _subresource(0), _element(element) {}; - TextureView(const TexturePointer& texture, const Element& element) : + TextureView(const TexturePointer& texture, uint16 subresource, const Element& element) : _texture(texture), - _subresource(0), + _subresource(subresource), _element(element) {}; + + TextureView(const TexturePointer& texture, uint16 subresource) : + _texture(texture), + _subresource(subresource) + {}; + ~TextureView() {} TextureView(const TextureView& view) = default; TextureView& operator=(const TextureView& view) = default; + + explicit operator bool() const { return (_texture); } + bool operator !() const { return (!_texture); } }; +typedef std::vector TextureViews; }; From e2af93db5f449bcf9f7a9156be771a513c998837 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 11:38:30 -0700 Subject: [PATCH 024/401] some debugging --- libraries/physics/src/EntityMotionState.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d84daa6b42..f0daaa6b4c 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -180,6 +180,11 @@ float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const { } void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) { + + qDebug() << "-------------------------------------------"; + qDebug() << "EntityMotionState::sendUpdate" << _type << _motionType << _isKinematic; + auto nodeList = DependencyManager::get(); + if (!_entity->isKnownID()) { return; // never update entities that are unknown } From 51ce3129b9c3e715ba5610d1cd98ec4be09142bd Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 13 Apr 2015 12:22:08 -0700 Subject: [PATCH 025/401] connecting the dots for a framebuffer GLBackend, need to be tested --- libraries/gpu/src/gpu/Framebuffer.cpp | 29 ++++--- libraries/gpu/src/gpu/Framebuffer.h | 14 ++-- libraries/gpu/src/gpu/GLBackendOutput.cpp | 99 +++++++++++++++++++++-- 3 files changed, 119 insertions(+), 23 deletions(-) diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index de8961886b..cb33a930ca 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -36,7 +36,7 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& auto depthTexture = TexturePointer(Texture::create2D(depthStencilBufferFormat, width, height)); framebuffer->setRenderBuffer(0, colorTexture); - framebuffer->setDepthStencilBuffer(depthTexture); + framebuffer->setDepthStencilBuffer(depthTexture, depthStencilBufferFormat); return framebuffer; } @@ -54,10 +54,6 @@ uint32 Framebuffer::getFrameCount() const { } } -bool Framebuffer::isEmpty() const { - return (_buffersMask == 0); -} - bool Framebuffer::validateTargetCompatibility(const Texture& texture, uint32 subresource) const { if (texture.getType() == Texture::TEX_1D) { return false; @@ -161,9 +157,9 @@ int Framebuffer::setRenderBuffer(uint32 slot, const TexturePointer& texture, uin // update the mask int mask = (1<getDepthStencilBufferFormat(); + return _depthStencilBuffer._element; + } else { + return _depthStencilBuffer._element; + } +} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index 46303b0d81..9253cd021e 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -123,20 +123,24 @@ public: uint32 getFrameCount() const; // Render buffers - int32 setRenderBuffer(uint32 slot, const TexturePointer& texture, uint32 subresource = 0); void removeRenderBuffers(); uint32 getNumRenderBuffers() const; + const TextureViews& getRenderBuffers() const { return _renderBuffers; } + int32 setRenderBuffer(uint32 slot, const TexturePointer& texture, uint32 subresource = 0); TexturePointer getRenderBuffer(uint32 slot) const; uint32 getRenderBufferSubresource(uint32 slot) const; - bool setDepthStencilBuffer(const TexturePointer& texture, uint32 subresource = 0); + bool setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0); TexturePointer getDepthStencilBuffer() const; uint32 getDepthStencilBufferSubresource() const; + Format getDepthStencilBufferFormat() const; // Properties - uint32 getBuffersMask() const { return _buffersMask; } - bool isEmpty() const; + uint32 getBufferMask() const { return _bufferMask; } + bool isEmpty() const { return (_bufferMask == 0); } + bool hasColor() const { return (getBufferMask() & BUFFER_COLORS); } + bool hasDepthStencil() const { return (getBufferMask() & BUFFER_DEPTHSTENCIL); } bool validateTargetCompatibility(const Texture& texture, uint32 subresource = 0) const; @@ -162,7 +166,7 @@ protected: uint16 _height; uint16 _numSamples; - uint32 _buffersMask; + uint32 _bufferMask; uint32 _frameCount; diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 8865008e49..877ecce950 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -35,15 +35,102 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe // need to have a gpu object? if (!object) { - object = new GLFramebuffer(); - glGenFramebuffers(1, &object->_fbo); + GLuint fbo; + glGenFramebuffers(1, &fbo); CHECK_GL_ERROR(); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); + + unsigned int nbColorBuffers = 0; + GLenum colorBuffers[16]; + if (framebuffer.hasColor()) { + static const GLenum colorAttachments[] = { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7, + GL_COLOR_ATTACHMENT8, + GL_COLOR_ATTACHMENT9, + GL_COLOR_ATTACHMENT10, + GL_COLOR_ATTACHMENT11, + GL_COLOR_ATTACHMENT12, + GL_COLOR_ATTACHMENT13, + GL_COLOR_ATTACHMENT14, + GL_COLOR_ATTACHMENT15 }; + + int unit = 0; + for (auto& b : framebuffer.getRenderBuffers()) { + auto surface = b._texture; + if (surface) { + auto gltexture = GLBackend::syncGPUObject(*surface); + if (gltexture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); + } + colorBuffers[nbColorBuffers] = colorAttachments[unit]; + nbColorBuffers++; + unit++; + } + } + } + + if (framebuffer.hasDepthStencil()) { + auto surface = framebuffer.getDepthStencilBuffer(); + if (surface) { + auto gltexture = GLBackend::syncGPUObject(*surface); + if (gltexture) { + if (surface) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, gltexture->_texture, 0); + } + } + } + + // Last but not least, define where we draw + if (nbColorBuffers > 0) { + glDrawBuffers(nbColorBuffers, colorBuffers); + } else { + glDrawBuffer( GL_NONE ); + } + + // Now check for completness + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + bool result = false; + switch (status) { + case GL_FRAMEBUFFER_COMPLETE : + // Success ! + result = true; + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT : + qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT."; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : + qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT."; + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER : + qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER."; + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER : + qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER."; + break; + case GL_FRAMEBUFFER_UNSUPPORTED : + qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED."; + break; + } + if (!result && fbo) { + glDeleteFramebuffers( 1, &fbo ); + return nullptr; + } + + + // All is green, assign the gpuobject to the Framebuffer + object = new GLFramebuffer(); + object->_fbo = fbo; Backend::setGPUObject(framebuffer, object); } - - CHECK_GL_ERROR(); - return object; } @@ -69,4 +156,4 @@ void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) { _output._framebuffer = framebuffer; } } - + From eace91e833061a2c058df151517e023bbb3ecbce Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 12:25:44 -0700 Subject: [PATCH 026/401] if an entity is being moved and has no sim-id, set sim-id to local node-id. if it has a sim-id, and it's not the same as the local node's, don't broadcast the change --- libraries/physics/src/EntityMotionState.cpp | 41 +++++++++++++++++++-- libraries/physics/src/EntityMotionState.h | 1 + 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f0daaa6b4c..c2206c90f7 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -179,12 +179,41 @@ float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const { return _entity->computeMass(); } -void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) { - qDebug() << "-------------------------------------------"; - qDebug() << "EntityMotionState::sendUpdate" << _type << _motionType << _isKinematic; +bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { + bool baseResult = this->ObjectMotionState::shouldSendUpdate(simulationFrame); + + if (!baseResult) { + return false; + } + auto nodeList = DependencyManager::get(); + QString myNodeID = nodeList->getSessionUUID().toString(); + QString simulatorID = _entity->getSimulatorID(); + if (simulatorID.isEmpty() && _body->isActive()) { + // The object is moving and nobody thinks they own the motion. set this Node as the simulator + _entity->setSimulatorID(myNodeID); + simulatorID = myNodeID; + } else if (simulatorID == myNodeID && !_body->isActive()) { + // we are the simulator and the object has stopped. give up "simulator" status + _entity->setSimulatorID(""); + simulatorID = ""; + } + + if (simulatorID != myNodeID) { + // some other Node is simulating this, so don't broadcast our computations. + qDebug() << "EntityMotionState::shouldSendUpdate baseResult=" << baseResult << "but" + << simulatorID << "!=" << myNodeID; + return false; + } + + qDebug() << "EntityMotionState::shouldSendUpdate baseResult=" << baseResult; + return baseResult; +} + + +void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) { if (!_entity->isKnownID()) { return; // never update entities that are unknown } @@ -218,6 +247,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } _sentMoving = ! (zeroSpeed && zeroSpin); + + + qDebug() << "-------------------------------------------"; + qDebug() << "EntityMotionState::sendUpdate" << _sentMoving << _body->isActive(); + + } else { _sentVelocity = _sentAngularVelocity = glm::vec3(0.0f); _sentMoving = false; diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 7214626fc4..84da86ecae 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -56,6 +56,7 @@ public: virtual void computeShapeInfo(ShapeInfo& shapeInfo); virtual float computeMass(const ShapeInfo& shapeInfo) const; + virtual bool shouldSendUpdate(uint32_t simulationFrame); virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame); virtual uint32_t getIncomingDirtyFlags() const; From f42a43e180a0c1a13a8c9a8f4e9593b19a56bbf0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 12:39:40 -0700 Subject: [PATCH 027/401] cause changes to _simulatorID to be broadcast --- libraries/entities/src/EntityItem.cpp | 6 ++++++ libraries/entities/src/EntityItem.h | 1 + libraries/physics/src/EntityMotionState.cpp | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5fae58c5f4..02e525be3d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1194,3 +1194,9 @@ void EntityItem::updateLifetime(float value) { } } +void EntityItem::updateSimulatorID(QString value) { + if (_simulatorID != value) { + _simulatorID = value; + _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; + } +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 8f7feb2ed8..8388985432 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -294,6 +294,7 @@ public: void updateCollisionsWillMove(bool value); void updateLifetime(float value); virtual void updateShapeType(ShapeType type) { /* do nothing */ } + void updateSimulatorID(QString value); uint32_t getDirtyFlags() const { return _dirtyFlags; } void clearDirtyFlags(uint32_t mask = 0xffff) { _dirtyFlags &= ~mask; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c2206c90f7..de806bb857 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -193,11 +193,11 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { if (simulatorID.isEmpty() && _body->isActive()) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator - _entity->setSimulatorID(myNodeID); + _entity->updateSimulatorID(myNodeID); simulatorID = myNodeID; } else if (simulatorID == myNodeID && !_body->isActive()) { // we are the simulator and the object has stopped. give up "simulator" status - _entity->setSimulatorID(""); + _entity->updateSimulatorID(""); simulatorID = ""; } From 9c2fec36fdce8617bb6e61ca9416da881a8ec8f8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 12:52:31 -0700 Subject: [PATCH 028/401] adjust debugging, try a different DIRTY flag --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 02e525be3d..023d60e22c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1197,6 +1197,6 @@ void EntityItem::updateLifetime(float value) { void EntityItem::updateSimulatorID(QString value) { if (_simulatorID != value) { _simulatorID = value; - _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; + _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index de806bb857..32bd36570b 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -208,7 +208,6 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { return false; } - qDebug() << "EntityMotionState::shouldSendUpdate baseResult=" << baseResult; return baseResult; } @@ -248,11 +247,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _sentMoving = ! (zeroSpeed && zeroSpin); - - qDebug() << "-------------------------------------------"; qDebug() << "EntityMotionState::sendUpdate" << _sentMoving << _body->isActive(); - } else { _sentVelocity = _sentAngularVelocity = glm::vec3(0.0f); _sentMoving = false; From 86f89a1d6f52427966966ec8d64b96d53543b562 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 13 Apr 2015 13:23:15 -0700 Subject: [PATCH 029/401] fix bug where fly speed is limited to walk speed --- libraries/physics/src/DynamicCharacterController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/DynamicCharacterController.cpp b/libraries/physics/src/DynamicCharacterController.cpp index db84bea540..aaabe21e9b 100644 --- a/libraries/physics/src/DynamicCharacterController.cpp +++ b/libraries/physics/src/DynamicCharacterController.cpp @@ -245,7 +245,6 @@ void DynamicCharacterController::setEnabled(bool enabled) { // Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit. // Setting the ADD bit here works for all cases so we don't even bother checking other bits. _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; - setHovering(true); } else { if (_dynamicsWorld) { _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; @@ -253,6 +252,7 @@ void DynamicCharacterController::setEnabled(bool enabled) { _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; _isOnGround = false; } + setHovering(true); _enabled = enabled; } } From 396f6b1987b7aa7aa013d11c372f71340e69556b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 15:22:54 -0700 Subject: [PATCH 030/401] mess with debugging prints --- libraries/entities/src/EntityEditPacketSender.cpp | 2 ++ libraries/entities/src/EntityItem.cpp | 3 ++- libraries/entities/src/EntityItemProperties.h | 1 + libraries/physics/src/EntityMotionState.cpp | 4 ++++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index e94725782d..d2dc367aa3 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -18,6 +18,8 @@ #include "EntityItem.h" +#define WANT_DEBUG 1 + void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type, unsigned char* editBuffer, size_t length, int clockSkew) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 023d60e22c..fb8e430959 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -680,6 +680,7 @@ void EntityItem::simulate(const quint64& now) { #ifdef WANT_DEBUG qCDebug(entities) << "********** EntityItem::simulate()"; qCDebug(entities) << " entity ID=" << getEntityItemID(); + qCDebug(entities) << " simulator ID=" << getSimulatorID(); qCDebug(entities) << " now=" << now; qCDebug(entities) << " _lastSimulated=" << _lastSimulated; qCDebug(entities) << " timeElapsed=" << timeElapsed; @@ -1197,6 +1198,6 @@ void EntityItem::updateLifetime(float value) { void EntityItem::updateSimulatorID(QString value) { if (_simulatorID != value) { _simulatorID = value; - _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; + _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; } } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 7de0fc0e8b..09a1b17ae5 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -343,6 +343,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitStrength, emitStrength, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalGravity, localGravity, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulatorID, simulatorID, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, ""); debug << " last edited:" << properties.getLastEdited() << "\n"; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 32bd36570b..ca22831d38 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -219,6 +219,10 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); + // if (_outgoingPacketFlags & EntityItem::DIRTY_UPDATEABLE) { + // properties.setSimulatorID(_entity->getSimulatorID()); + // } + if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); _sentPosition = bulletToGLM(worldTrans.getOrigin()); From d2b643d389833bc7479f7cd1f278b02b4061e872 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Mon, 13 Apr 2015 23:57:08 +0100 Subject: [PATCH 031/401] Add targetVelocity into MyAvatar simulation MyAvatar sets a target velocity to achieve, this is parsed in the preSimulation controller step. --- interface/src/avatar/MyAvatar.cpp | 14 +++++++------- libraries/avatars/src/AvatarData.cpp | 1 + libraries/avatars/src/AvatarData.h | 2 ++ .../physics/src/DynamicCharacterController.cpp | 3 ++- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6b70577754..be438f3297 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -126,7 +126,7 @@ void MyAvatar::reset() { _skeletonModel.reset(); getHead()->reset(); - _velocity = glm::vec3(0.0f); + _targetVelocity = glm::vec3(0.0f); setThrust(glm::vec3(0.0f)); // Reset the pitch and roll components of the avatar's orientation, preserve yaw direction glm::vec3 eulers = safeEulerAngles(getOrientation()); @@ -1240,28 +1240,28 @@ glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVe void MyAvatar::updatePosition(float deltaTime) { // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); - glm::vec3 localVelocity = glm::inverse(rotation) * _velocity; + glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity; bool isHovering = _characterController.isHovering(); glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering); newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); // rotate back into world-frame - _velocity = rotation * newLocalVelocity; + _targetVelocity = rotation * newLocalVelocity; - _velocity += _thrust * deltaTime; + _targetVelocity += _thrust * deltaTime; _thrust = glm::vec3(0.0f); // cap avatar speed - float speed = glm::length(_velocity); + float speed = glm::length(_targetVelocity); if (speed > MAX_AVATAR_SPEED) { - _velocity *= MAX_AVATAR_SPEED / speed; + _targetVelocity *= MAX_AVATAR_SPEED / speed; speed = MAX_AVATAR_SPEED; } if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) { // update position ourselves - applyPositionDelta(deltaTime * _velocity); + applyPositionDelta(deltaTime * _targetVelocity); measureMotionDerivatives(deltaTime); } // else physics will move avatar later diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index bc49fb3514..a8d2c209c3 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -60,6 +60,7 @@ AvatarData::AvatarData() : _owningAvatarMixer(), _lastUpdateTimer(), _velocity(0.0f), + _targetVelocity(0.0f), _localAABox(DEFAULT_LOCAL_AABOX_CORNER, DEFAULT_LOCAL_AABOX_SCALE) { } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index ad90c88aaa..881b68d52f 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -294,6 +294,7 @@ public: void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; } + glm::vec3 getTargetVelocity() const { return _targetVelocity; } public slots: void sendAvatarDataPacket(); @@ -384,6 +385,7 @@ protected: void changeReferential(Referential* ref); glm::vec3 _velocity; + glm::vec3 _targetVelocity; AABox _localAABox; diff --git a/libraries/physics/src/DynamicCharacterController.cpp b/libraries/physics/src/DynamicCharacterController.cpp index db84bea540..15b7eb86b6 100644 --- a/libraries/physics/src/DynamicCharacterController.cpp +++ b/libraries/physics/src/DynamicCharacterController.cpp @@ -386,7 +386,7 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) { setHovering(true); } - _walkVelocity = glmToBullet(_avatarData->getVelocity()); + _walkVelocity = glmToBullet(_avatarData->getTargetVelocity()); if (_pendingFlags & PENDING_FLAG_JUMP) { _pendingFlags &= ~ PENDING_FLAG_JUMP; @@ -408,6 +408,7 @@ void DynamicCharacterController::postSimulation() { _avatarData->setOrientation(rotation); _avatarData->setPosition(position - rotation * _shapeLocalOffset); + _avatarData->setVelocity(bulletToGLM(_rigidBody->getLinearVelocity())); } } From a30e807051b9f828013106139d8ff9c301ca881b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 16:20:30 -0700 Subject: [PATCH 032/401] get rid of unneeded updateSimulatorID, set changed simulator id in properties so it gets included in outgoing packet --- libraries/entities/src/EntityItem.cpp | 7 ----- libraries/entities/src/EntityItem.h | 1 - libraries/physics/src/EntityMotionState.cpp | 35 +++++++++++++++------ 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index fb8e430959..da98b4f350 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1194,10 +1194,3 @@ void EntityItem::updateLifetime(float value) { _dirtyFlags |= EntityItem::DIRTY_LIFETIME; } } - -void EntityItem::updateSimulatorID(QString value) { - if (_simulatorID != value) { - _simulatorID = value; - _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; - } -} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 8388985432..8f7feb2ed8 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -294,7 +294,6 @@ public: void updateCollisionsWillMove(bool value); void updateLifetime(float value); virtual void updateShapeType(ShapeType type) { /* do nothing */ } - void updateSimulatorID(QString value); uint32_t getDirtyFlags() const { return _dirtyFlags; } void clearDirtyFlags(uint32_t mask = 0xffff) { _dirtyFlags &= ~mask; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index ca22831d38..17cc06267d 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -191,13 +191,13 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { QString myNodeID = nodeList->getSessionUUID().toString(); QString simulatorID = _entity->getSimulatorID(); - if (simulatorID.isEmpty() && _body->isActive()) { + if (simulatorID.isEmpty() && _sentMoving) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator - _entity->updateSimulatorID(myNodeID); + // _entity->updateSimulatorID(myNodeID); simulatorID = myNodeID; - } else if (simulatorID == myNodeID && !_body->isActive()) { + } else if (simulatorID == myNodeID && !_sentMoving) { // we are the simulator and the object has stopped. give up "simulator" status - _entity->updateSimulatorID(""); + // _entity->updateSimulatorID(""); simulatorID = ""; } @@ -219,9 +219,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); - // if (_outgoingPacketFlags & EntityItem::DIRTY_UPDATEABLE) { - // properties.setSimulatorID(_entity->getSimulatorID()); - // } + + + if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); @@ -250,9 +250,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } _sentMoving = ! (zeroSpeed && zeroSpin); - - qDebug() << "EntityMotionState::sendUpdate" << _sentMoving << _body->isActive(); - } else { _sentVelocity = _sentAngularVelocity = glm::vec3(0.0f); _sentMoving = false; @@ -263,6 +260,24 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setAngularVelocity(_sentAngularVelocity); } + + qDebug() << "EntityMotionState::sendUpdate" << _sentMoving << _body->isActive(); + + auto nodeList = DependencyManager::get(); + QString myNodeID = nodeList->getSessionUUID().toString(); + QString simulatorID = _entity->getSimulatorID(); + + if (simulatorID.isEmpty() && _sentMoving) { + // The object is moving and nobody thinks they own the motion. set this Node as the simulator + _entity->setSimulatorID(myNodeID); + properties.setSimulatorID(myNodeID); + } else if (simulatorID == myNodeID && !_sentMoving) { + // we are the simulator and the object has stopped. give up "simulator" status + _entity->setSimulatorID(""); + properties.setSimulatorID(""); + } + + // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. if (_sentMoving) { _numNonMovingUpdates = 0; From 4677324a87a1ac33cfa5fe0f731f491f1ca36d19 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 16:30:16 -0700 Subject: [PATCH 033/401] try different login for deciding when to update/clear simulatorID --- libraries/physics/src/EntityMotionState.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 17cc06267d..e776232c01 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -191,13 +191,11 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { QString myNodeID = nodeList->getSessionUUID().toString(); QString simulatorID = _entity->getSimulatorID(); - if (simulatorID.isEmpty() && _sentMoving) { + if (simulatorID.isEmpty() && baseResult) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator - // _entity->updateSimulatorID(myNodeID); simulatorID = myNodeID; - } else if (simulatorID == myNodeID && !_sentMoving) { + } else if (simulatorID == myNodeID && _numNonMovingUpdates > 0) { // we are the simulator and the object has stopped. give up "simulator" status - // _entity->updateSimulatorID(""); simulatorID = ""; } @@ -262,16 +260,14 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ qDebug() << "EntityMotionState::sendUpdate" << _sentMoving << _body->isActive(); - auto nodeList = DependencyManager::get(); QString myNodeID = nodeList->getSessionUUID().toString(); QString simulatorID = _entity->getSimulatorID(); - - if (simulatorID.isEmpty() && _sentMoving) { + if (simulatorID.isEmpty()) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); - } else if (simulatorID == myNodeID && !_sentMoving) { + } else if (simulatorID == myNodeID && _numNonMovingUpdates > 0) { // we are the simulator and the object has stopped. give up "simulator" status _entity->setSimulatorID(""); properties.setSimulatorID(""); From 256a7f5198893f5ec292f8192b7d26c04215acff Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 16:37:44 -0700 Subject: [PATCH 034/401] try different login for deciding when to update/clear simulatorID --- libraries/physics/src/EntityMotionState.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index e776232c01..617b3b1a9a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -199,10 +199,8 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { simulatorID = ""; } - if (simulatorID != myNodeID) { + if (!simulatorID.isEmpty() && simulatorID != myNodeID) { // some other Node is simulating this, so don't broadcast our computations. - qDebug() << "EntityMotionState::shouldSendUpdate baseResult=" << baseResult << "but" - << simulatorID << "!=" << myNodeID; return false; } From cf6259c5d73999baf1c17ae924803b009527bc2e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 16:41:38 -0700 Subject: [PATCH 035/401] turn down debugging --- libraries/entities/src/EntityEditPacketSender.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index d2dc367aa3..e94725782d 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -18,8 +18,6 @@ #include "EntityItem.h" -#define WANT_DEBUG 1 - void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type, unsigned char* editBuffer, size_t length, int clockSkew) { From 05ef357854c9cb4ee312bea7ea8edb41db9abafa Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 16:47:06 -0700 Subject: [PATCH 036/401] debug prints --- libraries/physics/src/EntityMotionState.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 617b3b1a9a..40010e46df 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -215,10 +215,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); - - - - if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); _sentPosition = bulletToGLM(worldTrans.getOrigin()); @@ -263,10 +259,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ QString simulatorID = _entity->getSimulatorID(); if (simulatorID.isEmpty()) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator + qDebug() << "claiming simulator ownership"; _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); } else if (simulatorID == myNodeID && _numNonMovingUpdates > 0) { // we are the simulator and the object has stopped. give up "simulator" status + qDebug() << "releasing simulator ownership"; _entity->setSimulatorID(""); properties.setSimulatorID(""); } From f7c0637952197c7675d8b2363626acc096c13f13 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Apr 2015 16:51:05 -0700 Subject: [PATCH 037/401] oops --- libraries/entities/src/EntityItemProperties.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 09a1b17ae5..7de0fc0e8b 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -343,7 +343,6 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitStrength, emitStrength, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalGravity, localGravity, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulatorID, simulatorID, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, ""); debug << " last edited:" << properties.getLastEdited() << "\n"; From 2c4f049851efed0c15b390b2c5d0379deb66d5c4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 13 Apr 2015 17:11:27 -0700 Subject: [PATCH 038/401] Change OSX DDE program path per build system requirements --- interface/src/devices/DdeFaceTracker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index d654a493ed..7228358532 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -24,7 +24,7 @@ static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde.exe"; static const QString DDE_ARGUMENTS = "--udp=127.0.0.1:64204 --receiver=64205 --headless"; #elif defined(Q_OS_MAC) -static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde"; +static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde.app/Contents/MacOS/dde"; static const QString DDE_ARGUMENTS = "--udp=127.0.0.1:64204 --receiver=64205 --headless"; #endif static const QHostAddress DDE_SERVER_ADDR("127.0.0.1"); From 13c038879dbcbec386e697191eaf577db2703275 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 13 Apr 2015 17:13:03 -0700 Subject: [PATCH 039/401] Don't repeat constant values --- interface/src/devices/DdeFaceTracker.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 7228358532..78c665b7a0 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -20,16 +20,18 @@ #include "DdeFaceTracker.h" #include "FaceshiftConstants.h" -#if defined(Q_OS_WIN) -static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde.exe"; -static const QString DDE_ARGUMENTS = "--udp=127.0.0.1:64204 --receiver=64205 --headless"; -#elif defined(Q_OS_MAC) -static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde.app/Contents/MacOS/dde"; -static const QString DDE_ARGUMENTS = "--udp=127.0.0.1:64204 --receiver=64205 --headless"; -#endif static const QHostAddress DDE_SERVER_ADDR("127.0.0.1"); static const quint16 DDE_SERVER_PORT = 64204; static const quint16 DDE_CONTROL_PORT = 64205; +#if defined(Q_OS_WIN) +static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde.exe"; +#elif defined(Q_OS_MAC) +static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde.app/Contents/MacOS/dde"; +#endif +static const QStringList DDE_ARGUMENTS = QStringList() + << "--udp=" + DDE_SERVER_ADDR.toString() + ":" + QString::number(DDE_SERVER_PORT) + << "--receiver=" + QString::number(DDE_CONTROL_PORT) + << "--headless"; static const int NUM_EXPRESSIONS = 46; static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSIONS) * sizeof(float) + sizeof(int); @@ -174,7 +176,7 @@ void DdeFaceTracker::setEnabled(bool enabled) { if (enabled && !_ddeProcess) { qDebug() << "[Info] DDE Face Tracker Starting"; _ddeProcess = new QProcess(qApp); - _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS.split(" ")); + _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS); } // isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket. From b7f7cebb808cbbe5e051bee86dcc39ba1fe6f157 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 13 Apr 2015 22:41:17 -0700 Subject: [PATCH 040/401] Handle DDE stopping unexpectedly --- interface/src/devices/DdeFaceTracker.cpp | 12 ++++++++++++ interface/src/devices/DdeFaceTracker.h | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 55a9b7979b..4ab2d70509 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -20,6 +20,7 @@ #include "DdeFaceTracker.h" #include "FaceshiftConstants.h" #include "InterfaceLogging.h" +#include "Menu.h" static const QHostAddress DDE_SERVER_ADDR("127.0.0.1"); @@ -178,6 +179,7 @@ void DdeFaceTracker::setEnabled(bool enabled) { if (enabled && !_ddeProcess) { qDebug() << "[Info] DDE Face Tracker Starting"; _ddeProcess = new QProcess(qApp); + connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus))); _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS); } @@ -195,6 +197,16 @@ void DdeFaceTracker::setEnabled(bool enabled) { #endif } +void DdeFaceTracker::processFinished(int exitCode, QProcess::ExitStatus exitStatus) { + if (_ddeProcess) { + // DDE crashed or was manually terminated + qDebug() << "[Info] DDE Face Tracker Stopped Unexpectedly"; + _udpSocket.close(); + _ddeProcess = NULL; + Menu::getInstance()->setIsOptionChecked(MenuOption::NoFaceTracking, true); + } +} + void DdeFaceTracker::resetTracking() { qDebug() << "[Info] Reset DDE Tracking"; const char* DDE_RESET_COMMAND = "reset"; diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index a53fbdb379..490020e511 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -53,7 +53,8 @@ public slots: void resetTracking(); private slots: - + void processFinished(int exitCode, QProcess::ExitStatus exitStatus); + //sockets void socketErrorOccurred(QAbstractSocket::SocketError socketError); void readPendingDatagrams(); From f509d08378c62523b50e1132b3996b9463f3dd8b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 13 Apr 2015 23:12:13 -0700 Subject: [PATCH 041/401] Handle DDE already running --- interface/src/devices/DdeFaceTracker.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 4ab2d70509..a701160198 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -176,21 +176,25 @@ DdeFaceTracker::~DdeFaceTracker() { void DdeFaceTracker::setEnabled(bool enabled) { #ifdef HAVE_DDE - if (enabled && !_ddeProcess) { - qDebug() << "[Info] DDE Face Tracker Starting"; - _ddeProcess = new QProcess(qApp); - connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus))); - _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS); - } - // isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket. _udpSocket.close(); if (enabled) { _udpSocket.bind(_host, _serverPort); } + if (enabled && !_ddeProcess) { + // Terminate any existing DDE process, perhaps left running after an Interface crash + const char* DDE_EXIT_COMMAND = "exit"; + _udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort); + + qDebug() << "[Info] DDE Face Tracker Starting"; + _ddeProcess = new QProcess(qApp); + connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus))); + _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS); + } + if (!enabled && _ddeProcess) { - _ddeProcess->kill(); + _ddeProcess->kill(); // More robust than trying to send an "exit" command to DDE _ddeProcess = NULL; qDebug() << "[Info] DDE Face Tracker Stopped"; } From c34c5f60758039f4aaddb4aa4396d79dea09cd88 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 14 Apr 2015 08:47:52 -0700 Subject: [PATCH 042/401] adding the Fremabuffer to be used for shadows and main rendering --- interface/src/Application.cpp | 21 ++- libraries/gpu/src/gpu/Format.h | 3 +- libraries/gpu/src/gpu/Framebuffer.cpp | 8 ++ libraries/gpu/src/gpu/Framebuffer.h | 18 ++- libraries/gpu/src/gpu/GLBackendOutput.cpp | 5 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 34 +++++ .../src/DeferredLightingEffect.cpp | 23 +++- libraries/render-utils/src/GlowEffect.cpp | 23 +++- libraries/render-utils/src/Model.cpp | 125 ++++-------------- libraries/render-utils/src/TextureCache.cpp | 124 ++++++++++++++++- libraries/render-utils/src/TextureCache.h | 31 ++++- 11 files changed, 276 insertions(+), 139 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 82447257fb..3fe03476a3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -798,7 +798,8 @@ void Application::paintGL() { DependencyManager::get()->prepare(); // Viewport is assigned to the size of the framebuffer - QSize size = DependencyManager::get()->getPrimaryFramebufferObject()->size(); + // QSize size = DependencyManager::get()->getPrimaryFramebufferObject()->size(); + QSize size = DependencyManager::get()->getFrameBufferSize(); glViewport(0, 0, size.width(), size.height()); glMatrixMode(GL_MODELVIEW); @@ -2636,8 +2637,12 @@ void Application::updateShadowMap() { activeRenderingThread = QThread::currentThread(); PerformanceTimer perfTimer("shadowMap"); - QOpenGLFramebufferObject* fbo = DependencyManager::get()->getShadowFramebufferObject(); - fbo->bind(); +// QOpenGLFramebufferObject* fbo = DependencyManager::get()->getShadowFramebufferObject(); +// fbo->bind(); + auto shadowFramebuffer = DependencyManager::get()->getShadowFramebuffer(); + GLuint shadowFBO = gpu::GLBackend::getFramebufferID(shadowFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO); + glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT); @@ -2653,16 +2658,18 @@ void Application::updateShadowMap() { loadViewFrustum(_myCamera, _viewFrustum); int matrixCount = 1; - int targetSize = fbo->width(); + //int targetSize = fbo->width(); + int sourceSize = shadowFramebuffer->getWidth(); + int targetSize = shadowFramebuffer->getWidth(); float targetScale = 1.0f; if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { matrixCount = CASCADED_SHADOW_MATRIX_COUNT; - targetSize = fbo->width() / 2; + targetSize = sourceSize / 2; targetScale = 0.5f; } for (int i = 0; i < matrixCount; i++) { const glm::vec2& coord = MAP_COORDS[i]; - glViewport(coord.s * fbo->width(), coord.t * fbo->height(), targetSize, targetSize); + glViewport(coord.s * sourceSize, coord.t * sourceSize, targetSize, targetSize); // if simple shadow then since the resolution is twice as much as with cascaded, cover 2 regions with the map, not just one int regionIncrement = (matrixCount == 1 ? 2 : 1); @@ -2785,7 +2792,7 @@ void Application::updateShadowMap() { glMatrixMode(GL_MODELVIEW); } - fbo->release(); + // fbo->release(); glViewport(0, 0, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); activeRenderingThread = nullptr; diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index aee6f3bdf4..d3330fd147 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -119,7 +119,8 @@ enum Semantic { INDEX, //used by index buffer of a mesh PART, // used by part buffer of a mesh - DEPTH, // Depth buffer + DEPTH, // Depth only buffer + STENCIL, // Stencil only buffer DEPTH_STENCIL, // Depth Stencil buffer SRGB, diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index cb33a930ca..f671dba28e 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -41,6 +41,14 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& return framebuffer; } +Framebuffer* Framebuffer::createShadowmap(uint16 width) { + auto framebuffer = Framebuffer::create(); + auto depthTexture = TexturePointer(Texture::create2D(Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH), width, width)); + + framebuffer->setDepthStencilBuffer(depthTexture, Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH)); + + return framebuffer; +} bool Framebuffer::isSwapchain() const { return _swapchain != 0; diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index 9253cd021e..8028d1b478 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -116,6 +116,7 @@ public: static Framebuffer* create(const SwapchainPointer& swapchain); static Framebuffer* create(); static Framebuffer* create(const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height, uint16 samples ); + static Framebuffer* createShadowmap(uint16 width); bool isSwapchain() const; SwapchainPointer getSwapchain() const { return _swapchain; } @@ -136,6 +137,7 @@ public: uint32 getDepthStencilBufferSubresource() const; Format getDepthStencilBufferFormat() const; + // Properties uint32 getBufferMask() const { return _bufferMask; } bool isEmpty() const { return (_bufferMask == 0); } @@ -157,26 +159,22 @@ public: static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } // Get viewport covering the ful Canvas - Viewport getViewport() const { return Viewport(getWidth(), getHeight(), 0, 0); } - - bool isDefined() const { return _isDefined; } + Viewport getViewport() const { return Viewport(getWidth(), getHeight(), 0, 0); } protected: - uint16 _width; - uint16 _height; - uint16 _numSamples; + uint16 _width = 0; + uint16 _height = 0; + uint16 _numSamples = 0; - uint32 _bufferMask; + uint32 _bufferMask = 0; - uint32 _frameCount; + uint32 _frameCount = 0; SwapchainPointer _swapchain; TextureViews _renderBuffers; TextureView _depthStencilBuffer; - bool _isDefined = false; - void updateSize(const TexturePointer& texture); // Non exposed diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 877ecce950..9b3fb5fe34 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -28,7 +28,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe bool needUpdate = false; if (object) { return object; - } else if (!framebuffer.isDefined()) { + } else if (framebuffer.isEmpty()) { // NO framebuffer definition yet so let's avoid thinking return nullptr; } @@ -39,7 +39,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe glGenFramebuffers(1, &fbo); CHECK_GL_ERROR(); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); unsigned int nbColorBuffers = 0; GLenum colorBuffers[16]; @@ -82,7 +82,6 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe if (surface) { auto gltexture = GLBackend::syncGPUObject(*surface); if (gltexture) { - if (surface) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, gltexture->_texture, 0); } } diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 2bbb3d633f..da6d993171 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -144,7 +144,38 @@ public: texel.internalFormat = GL_RED; break; case gpu::DEPTH: + texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it texel.internalFormat = GL_DEPTH_COMPONENT; + switch (dstFormat.getType()) { + case gpu::UINT32: + case gpu::INT32: + case gpu::NUINT32: + case gpu::NINT32: { + texel.internalFormat = GL_DEPTH_COMPONENT32; + break; + } + case gpu::NFLOAT: + case gpu::FLOAT: { + texel.internalFormat = GL_DEPTH_COMPONENT32F; + break; + } + case gpu::UINT16: + case gpu::INT16: + case gpu::NUINT16: + case gpu::NINT16: + case gpu::HALF: + case gpu::NHALF: { + texel.internalFormat = GL_DEPTH_COMPONENT16; + break; + } + case gpu::UINT8: + case gpu::INT8: + case gpu::NUINT8: + case gpu::NINT8: { + texel.internalFormat = GL_DEPTH_COMPONENT24; + break; + } + } break; default: qCDebug(gpulogging) << "Unknown combination of texel format"; @@ -306,6 +337,9 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { if (bytes && texture.isAutogenerateMips()) { glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } // At this point the mip piels have been loaded, we can notify diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a4f45802a4..c5a09a4f0f 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -183,15 +183,17 @@ void DeferredLightingEffect::render() { auto textureCache = DependencyManager::get(); - QOpenGLFramebufferObject* primaryFBO = textureCache->getPrimaryFramebufferObject(); - primaryFBO->release(); + // QOpenGLFramebufferObject* primaryFBO = textureCache->getPrimaryFramebufferObject(); + // primaryFBO->release(); + QSize framebufferSize = textureCache->getFrameBufferSize(); QOpenGLFramebufferObject* freeFBO = DependencyManager::get()->getFreeFramebufferObject(); freeFBO->bind(); glClear(GL_COLOR_BUFFER_BIT); // glEnable(GL_FRAMEBUFFER_SRGB); - glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); + // glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); + glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryColorTextureID()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryNormalTextureID()); @@ -209,11 +211,17 @@ void DeferredLightingEffect::render() { const int VIEWPORT_Y_INDEX = 1; const int VIEWPORT_WIDTH_INDEX = 2; const int VIEWPORT_HEIGHT_INDEX = 3; - float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width(); + /* float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width(); float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width(); float tMin = viewport[VIEWPORT_Y_INDEX] / (float)primaryFBO->height(); float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)primaryFBO->height(); - + */ + float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width(); + float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width(); + float tMin = viewport[VIEWPORT_Y_INDEX] / (float)framebufferSize.height(); + float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)framebufferSize.height(); + + // Fetch the ViewMatrix; glm::mat4 invViewMat; _viewState->getViewTransform().getMatrix(invViewMat); @@ -437,7 +445,10 @@ void DeferredLightingEffect::render() { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glColorMask(true, true, true, false); - primaryFBO->bind(); + auto primaryFBO = gpu::GLBackend::getFramebufferID(textureCache->getPrimaryOpaqueFramebuffer()); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, primaryFBO); + + //primaryFBO->bind(); glBindTexture(GL_TEXTURE_2D, freeFBO->texture()); glEnable(GL_TEXTURE_2D); diff --git a/libraries/render-utils/src/GlowEffect.cpp b/libraries/render-utils/src/GlowEffect.cpp index 2ba1d7df13..2399cfa1a7 100644 --- a/libraries/render-utils/src/GlowEffect.cpp +++ b/libraries/render-utils/src/GlowEffect.cpp @@ -24,6 +24,7 @@ #include "TextureCache.h" #include "RenderUtilsLogging.h" +#include "gpu/GLBackend.h" GlowEffect::GlowEffect() : _initialized(false), @@ -105,7 +106,11 @@ int GlowEffect::getDeviceHeight() const { void GlowEffect::prepare() { - DependencyManager::get()->getPrimaryFramebufferObject()->bind(); + //DependencyManager::get()->getPrimaryFramebufferObject()->bind(); + auto primaryFBO = DependencyManager::get()->getPrimaryOpaqueFramebuffer(); + GLuint fbo = gpu::GLBackend::getFramebufferID(primaryFBO); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _isEmpty = true; @@ -140,9 +145,11 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { PerformanceTimer perfTimer("glowEffect"); auto textureCache = DependencyManager::get(); - QOpenGLFramebufferObject* primaryFBO = textureCache->getPrimaryFramebufferObject(); - primaryFBO->release(); - glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); + // QOpenGLFramebufferObject* primaryFBO = textureCache->getPrimaryFramebufferObject(); + // primaryFBO->release(); + auto primaryFBO = gpu::GLBackend::getFramebufferID(textureCache->getPrimaryOpaqueFramebuffer()); + glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryColorTextureID()); + auto framebufferSize = textureCache->getFrameBufferSize(); glPushMatrix(); glLoadIdentity(); @@ -160,7 +167,10 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { if (!_enabled || _isEmpty) { // copy the primary to the screen if (destFBO && QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { - QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO); + glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destFBO->handle()); + glBlitFramebuffer(0, 0, framebufferSize.width(), framebufferSize.height(), 0, 0, framebufferSize.width(), framebufferSize.height(), GL_COLOR_BUFFER_BIT, GL_NEAREST); + // QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO); } else { maybeBind(destFBO); if (!destFBO) { @@ -192,7 +202,8 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { glBindTexture(GL_TEXTURE_2D, oldDiffusedFBO->texture()); _diffuseProgram->bind(); - QSize size = primaryFBO->size(); + //QSize size = primaryFBO->size(); + QSize size = framebufferSize; _diffuseProgram->setUniformValue(_diffusionScaleLocation, 1.0f / size.width(), 1.0f / size.height()); renderFullscreenQuad(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b98123803f..bddbc2a0ff 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -673,8 +673,6 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { return false; } - // auto glowEffectIntensity = DependencyManager::get()->getIntensity(); - // Let's introduce a gpu::Batch to capture all the calls to the graphics api _renderBatch.clear(); gpu::Batch& batch = _renderBatch; @@ -703,35 +701,12 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { batch.setViewTransform(_transforms[0]); - // GLBATCH(glDisable)(GL_COLOR_MATERIAL); - - // taking care of by the state? - /* if (mode == RenderArgs::DIFFUSE_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE) { - GLBATCH(glDisable)(GL_CULL_FACE); - } else { - GLBATCH(glEnable)(GL_CULL_FACE); - if (mode == RenderArgs::SHADOW_RENDER_MODE) { - GLBATCH(glCullFace)(GL_FRONT); - } - } - */ - - // render opaque meshes with alpha testing - -// GLBATCH(glDisable)(GL_BLEND); -// GLBATCH(glEnable)(GL_ALPHA_TEST); - - /* if (mode == RenderArgs::SHADOW_RENDER_MODE) { - GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f); - } - */ - /*DependencyManager::get()->setPrimaryDrawBuffers( mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE, mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE, mode == RenderArgs::DEFAULT_RENDER_MODE); */ - { + /*if (mode != RenderArgs::SHADOW_RENDER_MODE)*/ { GLenum buffers[3]; int bufferCount = 0; @@ -748,6 +723,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; } GLBATCH(glDrawBuffers)(bufferCount, buffers); + // batch.setFramebuffer(DependencyManager::get()->getPrimaryOpaqueFramebuffer()); } const float DEFAULT_ALPHA_THRESHOLD = 0.5f; @@ -790,12 +766,6 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args, true); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args, true); - // GLBATCH(glDisable)(GL_ALPHA_TEST); - /* GLBATCH(glEnable)(GL_BLEND); - GLBATCH(glDepthMask)(false); - GLBATCH(glDepthFunc)(GL_LEQUAL); - */ - //DependencyManager::get()->setPrimaryDrawBuffers(true); { GLenum buffers[1]; int bufferCount = 0; @@ -805,6 +775,8 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { // if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE) { if (mode != RenderArgs::SHADOW_RENDER_MODE) { + // batch.setFramebuffer(DependencyManager::get()->getPrimaryTransparentFramebuffer()); + const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args, true); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args, true); @@ -814,6 +786,8 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, args, true); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, args, true); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, args, true); + + // batch.setFramebuffer(DependencyManager::get()->getPrimaryOpaqueFramebuffer()); } GLBATCH(glDepthMask)(true); @@ -1758,14 +1732,6 @@ void Model::setupBatchTransform(gpu::Batch& batch, RenderArgs* args) { void Model::endScene(RenderMode mode, RenderArgs* args) { PROFILE_RANGE(__FUNCTION__); - // auto glowEffectIntensity = DependencyManager::get()->getIntensity(); - - - #if defined(ANDROID) - #else - glPushMatrix(); - #endif - RenderArgs::RenderSide renderSide = RenderArgs::MONO; if (args) { renderSide = args->_renderSide; @@ -1792,34 +1758,15 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { _sceneRenderBatch.clear(); gpu::Batch& batch = _sceneRenderBatch; - // GLBATCH(glDisable)(GL_COLOR_MATERIAL); - - /* if (mode == RenderArgs::DIFFUSE_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE) { - GLBATCH(glDisable)(GL_CULL_FACE); - } else { - GLBATCH(glEnable)(GL_CULL_FACE); - if (mode == RenderArgs::SHADOW_RENDER_MODE) { - GLBATCH(glCullFace)(GL_FRONT); - } - }*/ - - // render opaque meshes with alpha testing - - // GLBATCH(glDisable)(GL_BLEND); - // GLBATCH(glEnable)(GL_ALPHA_TEST); - - /* if (mode == RenderArgs::SHADOW_RENDER_MODE) { - GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f); - } -*/ - /*DependencyManager::get()->setPrimaryDrawBuffers( mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE, mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE, mode == RenderArgs::DEFAULT_RENDER_MODE); */ - { + + /* if (mode != RenderArgs::SHADOW_RENDER_MODE) */{ GLenum buffers[3]; + int bufferCount = 0; // if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE) { if (mode != RenderArgs::SHADOW_RENDER_MODE) { @@ -1834,6 +1781,8 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; } GLBATCH(glDrawBuffers)(bufferCount, buffers); + + // batch.setFramebuffer(DependencyManager::get()->getPrimaryOpaqueFramebuffer()); } const float DEFAULT_ALPHA_THRESHOLD = 0.5f; @@ -1856,7 +1805,6 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, false, args); // render translucent meshes afterwards - //DependencyManager::get()->setPrimaryDrawBuffers(false, true, true); { GLenum buffers[2]; int bufferCount = 0; @@ -1876,21 +1824,19 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args); translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args); - // GLBATCH(glDisable)(GL_ALPHA_TEST); - /* GLBATCH(glEnable)(GL_BLEND); - GLBATCH(glDepthMask)(false); - GLBATCH(glDepthFunc)(GL_LEQUAL); - */ - //DependencyManager::get()->setPrimaryDrawBuffers(true); + { GLenum buffers[1]; int bufferCount = 0; buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; GLBATCH(glDrawBuffers)(bufferCount, buffers); + // batch.setFramebuffer(DependencyManager::get()->getPrimaryTransparentFramebuffer()); } // if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE) { if (mode != RenderArgs::SHADOW_RENDER_MODE) { + // batch.setFramebuffer(DependencyManager::get()->getPrimaryTransparentFramebuffer()); + const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args); translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args); @@ -1900,6 +1846,8 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, args); translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, args); translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, args); + + // batch.setFramebuffer(DependencyManager::get()->getPrimaryOpaqueFramebuffer()); } GLBATCH(glDepthMask)(true); @@ -1938,10 +1886,10 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { // Back to no program GLBATCH(glUseProgram)(0); - if (args) { - args->_translucentMeshPartsRendered = translucentParts; - args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered; - } + if (args) { + args->_translucentMeshPartsRendered = translucentParts; + args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered; + } } @@ -1951,12 +1899,6 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { backend.render(_sceneRenderBatch); } - - #if defined(ANDROID) - #else - glPopMatrix(); - #endif - // restore all the default material settings _viewState->setupWorldLight(); @@ -2334,17 +2276,15 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned); auto pipeline = _renderPipelineLib.find(key.getRaw()); if (pipeline == _renderPipelineLib.end()) { - qDebug() << "No good, couldn;t find a pipeline from the key ?" << key.getRaw(); + qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw(); return; } gpu::ShaderPointer program = (*pipeline).second._pipeline->getProgram(); locations = (*pipeline).second._locations.get(); - //GLuint glprogram = gpu::GLBackend::getShaderID(program); - //GLBATCH(glUseProgram)(glprogram); - // dare! + // Setup the One pipeline batch.setPipeline((*pipeline).second._pipeline); if ((locations->alphaThreshold > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { @@ -2354,9 +2294,6 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f if ((locations->glowIntensity > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { GLBATCH(glUniform1f)(locations->glowIntensity, DependencyManager::get()->getIntensity()); } - // if (!(translucent && alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { - // GLBATCH(glAlphaFunc)(GL_EQUAL, DependencyManager::get()->getIntensity()); - // } } int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, @@ -2383,10 +2320,7 @@ int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool } } } - // if we selected a program, then unselect it - if (!pickProgramsNeeded) { - // GLBATCH(glUseProgram)(0); - } + return meshPartsRendered; } @@ -2415,8 +2349,6 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl args, locations); meshPartsRendered = renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, args, locations, forceRenderSomeMeshes); - // GLBATCH(glUseProgram)(0); - return meshPartsRendered; } @@ -2427,7 +2359,7 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod PROFILE_RANGE(__FUNCTION__); auto textureCache = DependencyManager::get(); - // auto glowEffect = DependencyManager::get(); + QString lastMaterialID; int meshPartsRendered = 0; updateVisibleJointStates(); @@ -2531,13 +2463,6 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod qCDebug(renderutils) << "NEW part.materialID:" << part.materialID; } -/* if (locations->glowIntensity >= 0) { - GLBATCH(glUniform1f)(locations->glowIntensity, glowEffect->getIntensity()); - } - if (!(translucent && alphaThreshold == 0.0f)) { - GLBATCH(glAlphaFunc)(GL_EQUAL, glowEffect->getIntensity()); - } -*/ if (locations->materialBufferUnit >= 0) { batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer()); } diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 9b2a458231..28da6977f2 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -72,6 +72,15 @@ void TextureCache::setFrameBufferSize(QSize frameBufferSize) { if (_frameBufferSize != frameBufferSize) { _frameBufferSize = frameBufferSize; + if (_primaryOpaqueFramebuffer) { + _primaryOpaqueFramebuffer.reset(); + _primaryTransparentFramebuffer.reset(); + _primaryDepthTexture.reset(); + _primaryColorTexture.reset(); + _primaryNormalTexture.reset(); + _primarySpecularTexture.reset(); + } + if (_primaryFramebufferObject) { delete _primaryFramebufferObject; _primaryFramebufferObject = NULL; @@ -243,20 +252,95 @@ QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() { return _primaryFramebufferObject; } +void TextureCache::createPrimaryFramebuffer() { + _primaryOpaqueFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _primaryTransparentFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + + auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = _frameBufferSize.width(); + auto height = _frameBufferSize.height(); + _primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height)); + _primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height)); + _primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height)); + + _primaryOpaqueFramebuffer->setRenderBuffer(0, _primaryColorTexture); + _primaryOpaqueFramebuffer->setRenderBuffer(1, _primaryNormalTexture); + _primaryOpaqueFramebuffer->setRenderBuffer(2, _primarySpecularTexture); + + _primaryTransparentFramebuffer->setRenderBuffer(0, _primaryColorTexture); + + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); + _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height)); + + _primaryOpaqueFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); + + _primaryTransparentFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); +} + +gpu::FramebufferPointer TextureCache::getPrimaryOpaqueFramebuffer() { + if (!_primaryOpaqueFramebuffer) { + createPrimaryFramebuffer(); + } + return _primaryOpaqueFramebuffer; +} + +gpu::FramebufferPointer TextureCache::getPrimaryTransparentFramebuffer() { + if (!_primaryTransparentFramebuffer) { + createPrimaryFramebuffer(); + } + return _primaryTransparentFramebuffer; +} + +gpu::TexturePointer TextureCache::getPrimaryDepthTexture() { + if (!_primaryDepthTexture) { + createPrimaryFramebuffer(); + } + return _primaryDepthTexture; +} + +gpu::TexturePointer TextureCache::getPrimaryColorTexture() { + if (!_primaryColorTexture) { + createPrimaryFramebuffer(); + } + return _primaryColorTexture; +} + +gpu::TexturePointer TextureCache::getPrimaryNormalTexture() { + if (!_primaryNormalTexture) { + createPrimaryFramebuffer(); + } + return _primaryNormalTexture; +} + +gpu::TexturePointer TextureCache::getPrimarySpecularTexture() { + if (!_primarySpecularTexture) { + createPrimaryFramebuffer(); + } + return _primarySpecularTexture; +} + GLuint TextureCache::getPrimaryDepthTextureID() { // ensure that the primary framebuffer object is initialized before returning the depth texture id - getPrimaryFramebufferObject(); + //getPrimaryFramebufferObject(); + + _primaryDepthTextureID = gpu::GLBackend::getTextureID(_primaryDepthTexture); return _primaryDepthTextureID; } +GLuint TextureCache::getPrimaryColorTextureID() { + return gpu::GLBackend::getTextureID(_primaryColorTexture); +} + GLuint TextureCache::getPrimaryNormalTextureID() { // ensure that the primary framebuffer object is initialized before returning the normal texture id - getPrimaryFramebufferObject(); + //getPrimaryFramebufferObject(); + _primaryNormalTextureID = gpu::GLBackend::getTextureID(_primaryNormalTexture); return _primaryNormalTextureID; } GLuint TextureCache::getPrimarySpecularTextureID() { - getPrimaryFramebufferObject(); + //getPrimaryFramebufferObject(); + _primarySpecularTextureID = gpu::GLBackend::getTextureID(_primarySpecularTexture); return _primarySpecularTextureID; } @@ -289,6 +373,36 @@ QOpenGLFramebufferObject* TextureCache::getTertiaryFramebufferObject() { return _tertiaryFramebufferObject; } + +gpu::FramebufferPointer TextureCache::getShadowFramebuffer() { + if (!_shadowFramebuffer) { + const int SHADOW_MAP_SIZE = 2048; + _shadowFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(SHADOW_MAP_SIZE)); + + _shadowTexture = _shadowFramebuffer->getDepthStencilBuffer(); + /* + glGenTextures(1, &_shadowDepthTextureID); + glBindTexture(GL_TEXTURE_2D, _shadowDepthTextureID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, + 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + const float DISTANT_BORDER[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, DISTANT_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + glBindTexture(GL_TEXTURE_2D, 0); + + _shadowFramebufferObject->bind(); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _shadowDepthTextureID, 0); + _shadowFramebufferObject->release(); + */ + } + return _shadowFramebuffer; +} + QOpenGLFramebufferObject* TextureCache::getShadowFramebufferObject() { if (!_shadowFramebufferObject) { const int SHADOW_MAP_SIZE = 2048; @@ -318,7 +432,9 @@ QOpenGLFramebufferObject* TextureCache::getShadowFramebufferObject() { GLuint TextureCache::getShadowDepthTextureID() { // ensure that the shadow framebuffer object is initialized before returning the depth texture id - getShadowFramebufferObject(); + //getShadowFramebufferObject(); + _shadowDepthTextureID = gpu::GLBackend::getTextureID(_shadowTexture); + return _shadowDepthTextureID; } diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index 3ea46a4421..0d0cfc40aa 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -62,9 +63,18 @@ public: /// used for scene rendering. QOpenGLFramebufferObject* getPrimaryFramebufferObject(); + gpu::FramebufferPointer getPrimaryOpaqueFramebuffer(); + gpu::FramebufferPointer getPrimaryTransparentFramebuffer(); + + gpu::TexturePointer getPrimaryDepthTexture(); + gpu::TexturePointer getPrimaryColorTexture(); + gpu::TexturePointer getPrimaryNormalTexture(); + gpu::TexturePointer getPrimarySpecularTexture(); + /// Returns the ID of the primary framebuffer object's depth texture. This contains the Z buffer used in rendering. GLuint getPrimaryDepthTextureID(); - + GLuint getPrimaryColorTextureID(); + /// Returns the ID of the primary framebuffer object's normal texture. GLuint getPrimaryNormalTextureID(); @@ -78,6 +88,7 @@ public: /// screen effects. QOpenGLFramebufferObject* getSecondaryFramebufferObject(); + /// Returns a pointer to the tertiary framebuffer object, used as an additional render target when performing full /// screen effects. QOpenGLFramebufferObject* getTertiaryFramebufferObject(); @@ -85,6 +96,9 @@ public: /// Returns a pointer to the framebuffer object used to render shadow maps. QOpenGLFramebufferObject* getShadowFramebufferObject(); + gpu::FramebufferPointer getShadowFramebuffer(); + + /// Returns the ID of the shadow framebuffer object's depth texture. GLuint getShadowDepthTextureID(); @@ -105,9 +119,18 @@ private: gpu::TexturePointer _permutationNormalTexture; gpu::TexturePointer _whiteTexture; gpu::TexturePointer _blueTexture; + QHash > _dilatableNetworkTextures; - + + gpu::TexturePointer _primaryDepthTexture; + gpu::TexturePointer _primaryColorTexture; + gpu::TexturePointer _primaryNormalTexture; + gpu::TexturePointer _primarySpecularTexture; + gpu::FramebufferPointer _primaryOpaqueFramebuffer; + gpu::FramebufferPointer _primaryTransparentFramebuffer; + void createPrimaryFramebuffer(); + GLuint _primaryDepthTextureID; GLuint _primaryNormalTextureID; GLuint _primarySpecularTextureID; @@ -115,9 +138,13 @@ private: QOpenGLFramebufferObject* _secondaryFramebufferObject; QOpenGLFramebufferObject* _tertiaryFramebufferObject; + QOpenGLFramebufferObject* _shadowFramebufferObject; GLuint _shadowDepthTextureID; + gpu::FramebufferPointer _shadowFramebuffer; + gpu::TexturePointer _shadowTexture; + QSize _frameBufferSize; QGLWidget* _associatedWidget; }; From abb40ca0805c1db540115c22a2e944130cd97c3a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 14 Apr 2015 09:00:36 -0700 Subject: [PATCH 043/401] cleanup: split stats dump out of stepSimulation --- interface/src/Application.cpp | 1 + libraries/physics/src/PhysicsEngine.cpp | 127 ++++++++++++------------ libraries/physics/src/PhysicsEngine.h | 3 +- 3 files changed, 67 insertions(+), 64 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 82447257fb..73be96c26b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2226,6 +2226,7 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("physics"); _myAvatar->relayDriveKeysToCharacterController(); _physicsEngine.stepSimulation(); + _physicsEngine.dumpStatsIfNecessary(); } if (!_aboutToQuit) { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 50f52a7efc..209e23e006 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -288,77 +288,73 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) { } void PhysicsEngine::stepSimulation() { - { - lock(); - CProfileManager::Reset(); - BT_PROFILE("stepSimulation"); - // NOTE: the grand order of operations is: - // (1) pull incoming changes - // (2) step simulation - // (3) synchronize outgoing motion states - // (4) send outgoing packets + lock(); + CProfileManager::Reset(); + BT_PROFILE("stepSimulation"); + // NOTE: the grand order of operations is: + // (1) pull incoming changes + // (2) step simulation + // (3) synchronize outgoing motion states + // (4) send outgoing packets - // This is step (1) pull incoming changes - relayIncomingChangesToSimulation(); - - const int MAX_NUM_SUBSTEPS = 4; - const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * PHYSICS_ENGINE_FIXED_SUBSTEP; - float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds()); - _clock.reset(); - float timeStep = btMin(dt, MAX_TIMESTEP); - - // TODO: move character->preSimulation() into relayIncomingChanges - if (_characterController) { - if (_characterController->needsRemoval()) { - _characterController->setDynamicsWorld(NULL); - } - _characterController->updateShapeIfNecessary(); - if (_characterController->needsAddition()) { - _characterController->setDynamicsWorld(_dynamicsWorld); - } - _characterController->preSimulation(timeStep); + // This is step (1) pull incoming changes + relayIncomingChangesToSimulation(); + + const int MAX_NUM_SUBSTEPS = 4; + const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * PHYSICS_ENGINE_FIXED_SUBSTEP; + float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds()); + _clock.reset(); + float timeStep = btMin(dt, MAX_TIMESTEP); + + // TODO: move character->preSimulation() into relayIncomingChanges + if (_characterController) { + if (_characterController->needsRemoval()) { + _characterController->setDynamicsWorld(NULL); } - - // This is step (2) step simulation - int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); - _numSubsteps += (uint32_t)numSubsteps; - stepNonPhysicalKinematics(usecTimestampNow()); - unlock(); - - // TODO: make all of this harvest stuff into one function: relayOutgoingChanges() - if (numSubsteps > 0) { - BT_PROFILE("postSimulation"); - // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. - // - // Unfortunately we have to unlock the simulation (above) before we try to lock the _entityTree - // to avoid deadlock -- the _entityTree may try to lock its EntitySimulation (from which this - // PhysicsEngine derives) when updating/adding/deleting entities so we need to wait for our own - // lock on the tree before we re-lock ourselves. - // - // TODO: untangle these lock sequences. - _entityTree->lockForWrite(); - lock(); - _dynamicsWorld->synchronizeMotionStates(); - - if (_characterController) { - _characterController->postSimulation(); - } - - unlock(); - _entityTree->unlock(); - - computeCollisionEvents(); + _characterController->updateShapeIfNecessary(); + if (_characterController->needsAddition()) { + _characterController->setDynamicsWorld(_dynamicsWorld); } + _characterController->preSimulation(timeStep); } - if (_dumpNextStats) { - _dumpNextStats = false; - CProfileManager::dumpAll(); + + // This is step (2) step simulation + int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); + _numSubsteps += (uint32_t)numSubsteps; + stepNonPhysicalKinematics(usecTimestampNow()); + unlock(); + + // TODO: make all of this harvest stuff into one function: relayOutgoingChanges() + if (numSubsteps > 0) { + BT_PROFILE("postSimulation"); + // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. + // + // Unfortunately we have to unlock the simulation (above) before we try to lock the _entityTree + // to avoid deadlock -- the _entityTree may try to lock its EntitySimulation (from which this + // PhysicsEngine derives) when updating/adding/deleting entities so we need to wait for our own + // lock on the tree before we re-lock ourselves. + // + // TODO: untangle these lock sequences. + ObjectMotionState::setSimulationStep(_numSubsteps); + _entityTree->lockForWrite(); + lock(); + _dynamicsWorld->synchronizeMotionStates(); + + if (_characterController) { + _characterController->postSimulation(); + } + + unlock(); + _entityTree->unlock(); + + computeCollisionEvents(); } } void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { BT_PROFILE("nonPhysicalKinematics"); QSet::iterator stateItr = _nonPhysicalKinematicObjects.begin(); + // TODO?: need to occasionally scan for stopped non-physical kinematics objects while (stateItr != _nonPhysicalKinematicObjects.end()) { ObjectMotionState* motionState = *stateItr; motionState->stepKinematicSimulation(now); @@ -366,8 +362,6 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { } } -// TODO?: need to occasionally scan for stopped non-physical kinematics objects - void PhysicsEngine::computeCollisionEvents() { BT_PROFILE("computeCollisionEvents"); // update all contacts every frame @@ -445,6 +439,13 @@ void PhysicsEngine::computeCollisionEvents() { } } +void PhysicsEngine::dumpStatsIfNecessary() { + if (_dumpNextStats) { + _dumpNextStats = false; + CProfileManager::dumpAll(); + } +} + // Bullet collision flags are as follows: // CF_STATIC_OBJECT= 1, // CF_KINEMATIC_OBJECT= 2, diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 01717be175..6e1f430237 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -68,9 +68,10 @@ public: void stepSimulation(); void stepNonPhysicalKinematics(const quint64& now); - void computeCollisionEvents(); + void dumpStatsIfNecessary(); + /// \param offset position of simulation origin in domain-frame void setOriginOffset(const glm::vec3& offset) { _originOffset = offset; } From de2e5ae718115c6d299dfe4d6199e796f4604533 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 14 Apr 2015 09:00:48 -0700 Subject: [PATCH 044/401] adjust logic for when to claim or release simulator status --- libraries/physics/src/EntityMotionState.cpp | 25 +++++++-------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 40010e46df..b4394d52d3 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -191,20 +191,12 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { QString myNodeID = nodeList->getSessionUUID().toString(); QString simulatorID = _entity->getSimulatorID(); - if (simulatorID.isEmpty() && baseResult) { - // The object is moving and nobody thinks they own the motion. set this Node as the simulator - simulatorID = myNodeID; - } else if (simulatorID == myNodeID && _numNonMovingUpdates > 0) { - // we are the simulator and the object has stopped. give up "simulator" status - simulatorID = ""; - } - if (!simulatorID.isEmpty() && simulatorID != myNodeID) { // some other Node is simulating this, so don't broadcast our computations. return false; } - return baseResult; + return true; } @@ -223,6 +215,11 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _sentRotation = bulletToGLM(worldTrans.getRotation()); properties.setRotation(_sentRotation); } + + const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec + bool zeroSpeed = (glm::length2(_sentVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); + const float MINIMUM_EXTRAPOLATION_SPIN_SQUARED = 0.004f; // ~0.01 rotation/sec + bool zeroSpin = glm::length2(_sentAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; if (_outgoingPacketFlags & EntityItem::DIRTY_VELOCITY) { if (_body->isActive()) { @@ -230,13 +227,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); // if the speeds are very small we zero them out - const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec - bool zeroSpeed = (glm::length2(_sentVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); if (zeroSpeed) { _sentVelocity = glm::vec3(0.0f); } - const float MINIMUM_EXTRAPOLATION_SPIN_SQUARED = 0.004f; // ~0.01 rotation/sec - bool zeroSpin = glm::length2(_sentAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; if (zeroSpin) { _sentAngularVelocity = glm::vec3(0.0f); } @@ -252,24 +245,22 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setAngularVelocity(_sentAngularVelocity); } - qDebug() << "EntityMotionState::sendUpdate" << _sentMoving << _body->isActive(); auto nodeList = DependencyManager::get(); QString myNodeID = nodeList->getSessionUUID().toString(); QString simulatorID = _entity->getSimulatorID(); - if (simulatorID.isEmpty()) { + if (simulatorID.isEmpty() && _sentMoving) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator qDebug() << "claiming simulator ownership"; _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); - } else if (simulatorID == myNodeID && _numNonMovingUpdates > 0) { + } else if (simulatorID == myNodeID && zeroSpin && zeroSpin) { // we are the simulator and the object has stopped. give up "simulator" status qDebug() << "releasing simulator ownership"; _entity->setSimulatorID(""); properties.setSimulatorID(""); } - // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. if (_sentMoving) { _numNonMovingUpdates = 0; From d330319ed964d8a9127704803fda9a0bfb66252a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 14 Apr 2015 09:56:39 -0700 Subject: [PATCH 045/401] when a script creates and object, set the local Node as the simulation owner --- libraries/entities/src/EntityScriptingInterface.cpp | 12 ++++++++++-- libraries/physics/src/EntityMotionState.cpp | 5 +++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index c41b9a5c41..d0c3457a5c 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -65,17 +65,25 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro // The application will keep track of creatorTokenID uint32_t creatorTokenID = EntityItemID::getNextCreatorTokenID(); + // This Node is creating a new object. If it's in motion, set this Node as the simulator. + auto nodeList = DependencyManager::get(); + const QString myNodeID = nodeList->getSessionUUID().toString(); + // QString simulatorID = _entity->getSimulatorID(); + + EntityItemProperties propertiesWithSimID = properties; + propertiesWithSimID.setSimulatorID(myNodeID); + EntityItemID id(NEW_ENTITY, creatorTokenID, false ); // If we have a local entity tree set, then also update it. if (_entityTree) { _entityTree->lockForWrite(); - _entityTree->addEntity(id, properties); + _entityTree->addEntity(id, propertiesWithSimID); _entityTree->unlock(); } // queue the packet - queueEntityMessage(PacketTypeEntityAddOrEdit, id, properties); + queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID); return id; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index b4394d52d3..c02748afe3 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -245,11 +245,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setAngularVelocity(_sentAngularVelocity); } - qDebug() << "EntityMotionState::sendUpdate" << _sentMoving << _body->isActive(); + auto nodeList = DependencyManager::get(); QString myNodeID = nodeList->getSessionUUID().toString(); QString simulatorID = _entity->getSimulatorID(); - if (simulatorID.isEmpty() && _sentMoving) { + qDebug() << "EntityMotionState::sendUpdate" << (zeroSpin && zeroSpin) << "me:" << myNodeID << "owner:" << simulatorID; + if (simulatorID.isEmpty() && !(zeroSpin && zeroSpin)) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator qDebug() << "claiming simulator ownership"; _entity->setSimulatorID(myNodeID); From b6942e2300ef061aadde288c9b36a6450ccd504c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 14 Apr 2015 10:11:52 -0700 Subject: [PATCH 046/401] Fix stuck-spinners in entity properties --- examples/html/entityProperties.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 4ac1b70e33..dd5bced393 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -508,18 +508,22 @@ // To make this work we block the first mouseup event after the elements // received focus. If we block all mouseup events the user will not // be able to click within the selected text. + // We also check to see if the value has changed to make sure we aren't + // blocking a mouse-up event when clicking on an input spinner. var els = document.querySelectorAll("input, textarea"); for (var i = 0; i < els.length; i++) { var clicked = false; + var originalText; els[i].onfocus = function() { + originalText = this.value; this.select(); clicked = false; }; els[i].onmouseup = function(e) { - if (!clicked) { + if (!clicked && originalText == this.value) { e.preventDefault(); - clicked = true; } + clicked = true; }; } } From b5bfbba7595b30e5d6a35a44af6b1401031f3716 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 14 Apr 2015 10:17:54 -0700 Subject: [PATCH 047/401] only set simulationID on scripted entity creation if the entity has velocity or rotation --- libraries/entities/src/EntityScriptingInterface.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index d0c3457a5c..06c5493720 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -68,10 +68,13 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro // This Node is creating a new object. If it's in motion, set this Node as the simulator. auto nodeList = DependencyManager::get(); const QString myNodeID = nodeList->getSessionUUID().toString(); - // QString simulatorID = _entity->getSimulatorID(); EntityItemProperties propertiesWithSimID = properties; - propertiesWithSimID.setSimulatorID(myNodeID); + + // if this object is moving, set this Node as the simulation owner + if (properties.velocityChanged() || properties.rotationChanged()) { + propertiesWithSimID.setSimulatorID(myNodeID); + } EntityItemID id(NEW_ENTITY, creatorTokenID, false ); From 9262585bab80a823fb88898721f573c60d7f354e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 Apr 2015 10:38:22 -0700 Subject: [PATCH 048/401] first cut at moving avatar appearance into separate dialog box --- interface/src/ui/AvatarAppearanceDialog.cpp | 212 +++++++++ interface/src/ui/AvatarAppearanceDialog.h | 63 +++ interface/src/ui/DialogsManager.cpp | 10 + interface/src/ui/DialogsManager.h | 3 + interface/src/ui/PreferencesDialog.cpp | 127 +----- interface/src/ui/PreferencesDialog.h | 15 - interface/ui/avatarAppearance.ui | 471 ++++++++++++++++++++ interface/ui/preferencesDialog.ui | 461 ++++--------------- 8 files changed, 865 insertions(+), 497 deletions(-) create mode 100644 interface/src/ui/AvatarAppearanceDialog.cpp create mode 100644 interface/src/ui/AvatarAppearanceDialog.h create mode 100644 interface/ui/avatarAppearance.ui diff --git a/interface/src/ui/AvatarAppearanceDialog.cpp b/interface/src/ui/AvatarAppearanceDialog.cpp new file mode 100644 index 0000000000..1200c71cac --- /dev/null +++ b/interface/src/ui/AvatarAppearanceDialog.cpp @@ -0,0 +1,212 @@ +// +// 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 + +#include "Application.h" +#include "MainWindow.h" +#include "LODManager.h" +#include "Menu.h" +#include "AvatarAppearanceDialog.h" +#include "Snapshot.h" +#include "UserActivityLogger.h" +#include "UIUtil.h" + + +const int PREFERENCES_HEIGHT_PADDING = 20; + +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); + + // move dialog to left side + //move(parentWidget()->geometry().topLeft()); + //setFixedHeight(parentWidget()->size().height() - PREFERENCES_HEIGHT_PADDING); + + 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) { + setUseFullAvatar(!checked); + + QUrl headURL(ui.faceURLEdit->text()); + QUrl bodyURL(ui.skeletonURLEdit->text()); + + DependencyManager::get()->getMyAvatar()->useHeadAndBodyURLs(headURL, bodyURL); +} + +void AvatarAppearanceDialog::useFullAvatar(bool checked) { + setUseFullAvatar(checked); + QUrl fullAvatarURL(ui.fullAvatarURLEdit->text()); + DependencyManager::get()->getMyAvatar()->useFullAvatarURL(fullAvatarURL); +} + +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); +} + +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(); + 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 new file mode 100644 index 0000000000..f7a735e611 --- /dev/null +++ b/interface/src/ui/AvatarAppearanceDialog.h @@ -0,0 +1,63 @@ +// +// 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 701ceb0189..ad86e83ec0 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -18,6 +18,7 @@ #include "AddressBarDialog.h" #include "AnimationsDialog.h" #include "AttachmentsDialog.h" +#include "AvatarAppearanceDialog.h" #include "BandwidthDialog.h" #include "CachesSizeDialog.h" #include "DiskCacheEditor.h" @@ -85,6 +86,15 @@ 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 897215cbff..e7f017d54d 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -33,6 +33,7 @@ class OctreeStatsDialog; class PreferencesDialog; class ScriptEditorWindow; class QMessageBox; +class AvatarAppearanceDialog; class DialogsManager : public QObject, public Dependency { Q_OBJECT @@ -59,6 +60,7 @@ public slots: void hmdTools(bool showTools); void showScriptEditor(); void showIRCLink(); + void changeAvatarAppearance(); private slots: void toggleToolWindow(); @@ -94,6 +96,7 @@ private: QPointer _octreeStatsDialog; QPointer _preferencesDialog; QPointer _scriptEditor; + QPointer _avatarAppearanceDialog; }; #endif // hifi_DialogsManager_h \ No newline at end of file diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index bc10109c36..99ad98ef2d 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -19,6 +19,7 @@ #include #include "Application.h" +#include "DialogsManager.h" #include "MainWindow.h" #include "LODManager.h" #include "Menu.h" @@ -41,18 +42,13 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : ui.outputBufferSizeSpinner->setMinimum(MIN_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES); ui.outputBufferSizeSpinner->setMaximum(MAX_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES); - connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &PreferencesDialog::openHeadModelBrowser); - connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &PreferencesDialog::openBodyModelBrowser); - connect(ui.buttonBrowseFullAvatar, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser); - connect(ui.buttonBrowseLocation, &QPushButton::clicked, this, &PreferencesDialog::openSnapshotLocationBrowser); connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser); connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, Application::getInstance(), &Application::loadDefaultScripts); - connect(ui.useSeparateBodyAndHead, &QRadioButton::clicked, this, &PreferencesDialog::useSeparateBodyAndHead); - connect(ui.useFullAvatar, &QRadioButton::clicked, this, &PreferencesDialog::useFullAvatar); - - + 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(Application::getInstance(), &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged); @@ -63,54 +59,21 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : auto myAvatar = DependencyManager::get()->getMyAvatar(); - ui.bodyNameLabel->setText("Body - " + myAvatar->getBodyModelName()); - ui.headNameLabel->setText("Head - " + myAvatar->getHeadModelName()); - ui.fullAvatarNameLabel->setText("Full Avatar - " + myAvatar->getFullAvartarModelName()); + ui.apperanceDescription->setText("Body - " + myAvatar->getBodyModelName()); UIUtil::scaleWidgetFontSizes(this); } -void PreferencesDialog::useSeparateBodyAndHead(bool checked) { - setUseFullAvatar(!checked); - - QUrl headURL(ui.faceURLEdit->text()); - QUrl bodyURL(ui.skeletonURLEdit->text()); - - DependencyManager::get()->getMyAvatar()->useHeadAndBodyURLs(headURL, bodyURL); -} - -void PreferencesDialog::useFullAvatar(bool checked) { - setUseFullAvatar(checked); - QUrl fullAvatarURL(ui.fullAvatarURLEdit->text()); - DependencyManager::get()->getMyAvatar()->useFullAvatarURL(fullAvatarURL); -} - -void PreferencesDialog::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); -} - void PreferencesDialog::headURLChanged(const QString& newValue, const QString& modelName) { - ui.faceURLEdit->setText(newValue); - setUseFullAvatar(false); - ui.headNameLabel->setText("Head - " + modelName); + ui.apperanceDescription->setText("Head - " + modelName); } void PreferencesDialog::bodyURLChanged(const QString& newValue, const QString& modelName) { - ui.skeletonURLEdit->setText(newValue); - setUseFullAvatar(false); - ui.bodyNameLabel->setText("Body - " + modelName); + ui.apperanceDescription->setText("Body - " + modelName); } void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) { - ui.fullAvatarURLEdit->setText(newValue); - setUseFullAvatar(true); - ui.fullAvatarNameLabel->setText("Full Avatar - " + modelName); + ui.apperanceDescription->setText("Full Avatar - " + modelName); } void PreferencesDialog::accept() { @@ -120,44 +83,6 @@ void PreferencesDialog::accept() { _marketplaceWindow = NULL; } -void PreferencesDialog::setHeadUrl(QString modelUrl) { - ui.faceURLEdit->setText(modelUrl); -} - -void PreferencesDialog::setSkeletonUrl(QString modelUrl) { - ui.skeletonURLEdit->setText(modelUrl); -} - -void PreferencesDialog::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 PreferencesDialog::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 PreferencesDialog::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 PreferencesDialog::openSnapshotLocationBrowser() { QString dir = QFileDialog::getExistingDirectory(this, tr("Snapshots Location"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), @@ -199,19 +124,6 @@ void PreferencesDialog::loadPreferences() { _displayNameString = myAvatar->getDisplayName(); ui.displayNameEdit->setText(_displayNameString); - - _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); - - // TODO: load the names for the models. - ui.sendDataCheckBox->setChecked(!menuInstance->isOptionChecked(MenuOption::DisableActivityLogger)); ui.snapshotLocationEdit->setText(Snapshot::snapshotsLocation.get()); @@ -281,29 +193,6 @@ void PreferencesDialog::savePreferences() { shouldDispatchIdentityPacket = true; } - 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); - } - } - if (shouldDispatchIdentityPacket) { myAvatar->sendIdentityPacket(); } diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index 3f097ca9ab..22efe3489d 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -31,35 +31,20 @@ protected: private: void loadPreferences(); void savePreferences(); - void openHeadModelBrowser(); - void openBodyModelBrowser(); - void openFullAvatarModelBrowser(); - void setUseFullAvatar(bool useFullAvatar); Ui_PreferencesDialog 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 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); - void useSeparateBodyAndHead(bool checked); - void useFullAvatar(bool checked); - }; #endif // hifi_PreferencesDialog_h diff --git a/interface/ui/avatarAppearance.ui b/interface/ui/avatarAppearance.ui new file mode 100644 index 0000000000..5ebf2c705b --- /dev/null +++ b/interface/ui/avatarAppearance.ui @@ -0,0 +1,471 @@ + + + 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 4a0b1e961a..6f0ec7d792 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -128,6 +128,8 @@ + + @@ -187,370 +189,98 @@ - - - - 0 - - - 7 - - - 7 - - - - - - - - - 0 - 0 - - - - - 32 - 28 - - - - - 0 - 0 - - - - - Arial - - - - Use single avatar with Body and Head - - - - 0 - 0 - - - - - - - - - - - 0 - - - 10 - - - 7 - - - 7 - - - - - - - - Arial - - - - Full Avatar - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - fullAvatarURLEdit - - - - - - - - 0 - - - - - - 0 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - - Arial - - - - Browse - - - - 0 - 0 - - - - - - - - - - - - - - 0 - 0 - - - - - 32 - 28 - - - - - 0 - 0 - - - - - Arial - - - - Use separate Body and Head avatar files - - - - 0 - 0 - - - - - - - - - - 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 - - - - - - - - - - - - - - - - - - - - + + + + 0 + + + 7 + + + 7 + + + + + + Arial + + + + <html><head/><body><p>Appearance</p></body></html> + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + apperanceDescription + + + + + + + + + + 0 + + + + + + Arial + + + + + false + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + Arial + + + + Change + + + + 0 + 0 + + + + + + + + + + @@ -621,6 +351,7 @@ + @@ -671,6 +402,10 @@ + + + + From 4d34ba7bdf646dff089b2d8ebe50949828dd8b67 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 14 Apr 2015 10:57:47 -0700 Subject: [PATCH 049/401] Update main window to quit app when closed --- interface/src/MainWindow.cpp | 4 ++++ interface/src/MainWindow.h | 1 + 2 files changed, 5 insertions(+) diff --git a/interface/src/MainWindow.cpp b/interface/src/MainWindow.cpp index 41b1249af1..f60716dc48 100644 --- a/interface/src/MainWindow.cpp +++ b/interface/src/MainWindow.cpp @@ -55,6 +55,10 @@ void MainWindow::saveGeometry() { } } +void MainWindow::closeEvent(QCloseEvent* event) { + qApp->quit(); +} + void MainWindow::moveEvent(QMoveEvent* event) { emit windowGeometryChanged(QRect(event->pos(), size())); QMainWindow::moveEvent(event); diff --git a/interface/src/MainWindow.h b/interface/src/MainWindow.h index 4437fa6a1f..c6faf8e01a 100644 --- a/interface/src/MainWindow.h +++ b/interface/src/MainWindow.h @@ -30,6 +30,7 @@ signals: void windowShown(bool shown); protected: + virtual void closeEvent(QCloseEvent* event); virtual void moveEvent(QMoveEvent* event); virtual void resizeEvent(QResizeEvent* event); virtual void showEvent(QShowEvent* event); From 174e9f21333eecb7a9a93f9c1efae3a89e5b7db5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 Apr 2015 12:38:29 -0700 Subject: [PATCH 050/401] more tweaks to preferences UI --- interface/src/avatar/MyAvatar.cpp | 23 +++++++++++++++++++++ interface/src/avatar/MyAvatar.h | 2 ++ interface/src/ui/AvatarAppearanceDialog.cpp | 20 ++++++++---------- interface/src/ui/AvatarAppearanceDialog.h | 1 + interface/src/ui/DialogsManager.h | 1 + interface/src/ui/PreferencesDialog.cpp | 14 +++++++------ interface/src/ui/PreferencesDialog.h | 2 ++ 7 files changed, 46 insertions(+), 17 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3073bbb219..5a372ae274 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -943,6 +943,29 @@ 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); _billboardValid = false; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9c1f78c696..066bfdd930 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -131,6 +131,8 @@ public: const QString& getBodyModelName() const { return _bodyModelName; } const QString& getFullAvartarModelName() const { return _fullAvatarModelName; } + QString getModelDescription() const; + virtual void setAttachmentData(const QVector& attachmentData); virtual glm::vec3 getSkeletonPosition() const; diff --git a/interface/src/ui/AvatarAppearanceDialog.cpp b/interface/src/ui/AvatarAppearanceDialog.cpp index 1200c71cac..ceaaf140c4 100644 --- a/interface/src/ui/AvatarAppearanceDialog.cpp +++ b/interface/src/ui/AvatarAppearanceDialog.cpp @@ -26,9 +26,8 @@ #include "Snapshot.h" #include "UserActivityLogger.h" #include "UIUtil.h" - - -const int PREFERENCES_HEIGHT_PADDING = 20; +#include "ui/DialogsManager.h" +#include "ui/PreferencesDialog.h" AvatarAppearanceDialog::AvatarAppearanceDialog(QWidget* parent) : QDialog(parent) { @@ -52,10 +51,6 @@ AvatarAppearanceDialog::AvatarAppearanceDialog(QWidget* parent) : connect(Application::getInstance(), &Application::bodyURLChanged, this, &AvatarAppearanceDialog::bodyURLChanged); connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &AvatarAppearanceDialog::fullAvatarURLChanged); - // move dialog to left side - //move(parentWidget()->geometry().topLeft()); - //setFixedHeight(parentWidget()->size().height() - PREFERENCES_HEIGHT_PADDING); - auto myAvatar = DependencyManager::get()->getMyAvatar(); ui.bodyNameLabel->setText("Body - " + myAvatar->getBodyModelName()); @@ -66,18 +61,16 @@ AvatarAppearanceDialog::AvatarAppearanceDialog(QWidget* parent) : } void AvatarAppearanceDialog::useSeparateBodyAndHead(bool checked) { - setUseFullAvatar(!checked); - QUrl headURL(ui.faceURLEdit->text()); QUrl bodyURL(ui.skeletonURLEdit->text()); - DependencyManager::get()->getMyAvatar()->useHeadAndBodyURLs(headURL, bodyURL); + setUseFullAvatar(!checked); } void AvatarAppearanceDialog::useFullAvatar(bool checked) { - setUseFullAvatar(checked); QUrl fullAvatarURL(ui.fullAvatarURLEdit->text()); DependencyManager::get()->getMyAvatar()->useFullAvatarURL(fullAvatarURL); + setUseFullAvatar(checked); } void AvatarAppearanceDialog::setUseFullAvatar(bool useFullAvatar) { @@ -88,6 +81,8 @@ void AvatarAppearanceDialog::setUseFullAvatar(bool useFullAvatar) { ui.useFullAvatar->setChecked(_useFullAvatar); ui.useSeparateBodyAndHead->setChecked(!_useFullAvatar); + + DependencyManager::get()->getPreferencesDialog()->avatarDescriptionChanged(); } void AvatarAppearanceDialog::headURLChanged(const QString& newValue, const QString& modelName) { @@ -110,6 +105,9 @@ void AvatarAppearanceDialog::fullAvatarURLChanged(const QString& newValue, const void AvatarAppearanceDialog::accept() { saveAvatarAppearance(); + + DependencyManager::get()->getPreferencesDialog()->avatarDescriptionChanged(); + close(); delete _marketplaceWindow; _marketplaceWindow = NULL; diff --git a/interface/src/ui/AvatarAppearanceDialog.h b/interface/src/ui/AvatarAppearanceDialog.h index f7a735e611..be30caeedb 100644 --- a/interface/src/ui/AvatarAppearanceDialog.h +++ b/interface/src/ui/AvatarAppearanceDialog.h @@ -58,6 +58,7 @@ private slots: void useSeparateBodyAndHead(bool checked); void useFullAvatar(bool checked); + }; #endif // hifi_AvatarAppearanceDialog_h diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index e7f017d54d..d5d9c33a9a 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -44,6 +44,7 @@ public: QPointer getHMDToolsDialog() const { return _hmdToolsDialog; } QPointer getLodToolsDialog() const { return _lodToolsDialog; } QPointer getOctreeStatsDialog() const { return _octreeStatsDialog; } + QPointer getPreferencesDialog() const { return _preferencesDialog; } public slots: void toggleAddressBar(); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 99ad98ef2d..98f7382097 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -57,23 +57,25 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : move(parentWidget()->geometry().topLeft()); setFixedHeight(parentWidget()->size().height() - PREFERENCES_HEIGHT_PADDING); - auto myAvatar = DependencyManager::get()->getMyAvatar(); - - ui.apperanceDescription->setText("Body - " + myAvatar->getBodyModelName()); + 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("Head - " + modelName); + ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); } void PreferencesDialog::bodyURLChanged(const QString& newValue, const QString& modelName) { - ui.apperanceDescription->setText("Body - " + modelName); + ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); } void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) { - ui.apperanceDescription->setText("Full Avatar - " + modelName); + ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); } void PreferencesDialog::accept() { diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index 22efe3489d..8e699c80a2 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -25,6 +25,8 @@ class PreferencesDialog : public QDialog { public: PreferencesDialog(QWidget* parent = nullptr); + void avatarDescriptionChanged(); + protected: void resizeEvent(QResizeEvent* resizeEvent); From 3cf31ff7011cd5315cffbcfb3a38709dd77df11c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 14 Apr 2015 13:32:02 -0700 Subject: [PATCH 051/401] fix to allow modelEntityItems with shape of box into physicsengine. ignore entity updates echoed back to us. stop broadcasting after 3 non-moving updates --- .../src/RenderableModelEntityItem.cpp | 9 +++++++ libraries/entities/src/EntityTree.cpp | 19 --------------- libraries/entities/src/EntityTree.h | 1 - libraries/entities/src/EntityTreeElement.cpp | 11 +++++++-- libraries/physics/src/EntityMotionState.cpp | 24 +++++++++++-------- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 1d601d1294..15c0b79b47 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -289,6 +289,10 @@ const QString& RenderableModelEntityItem::getCollisionModelURL() const { bool RenderableModelEntityItem::isReadyToComputeShape() { + if (_shapeType != SHAPE_TYPE_COMPOUND && _shapeType != SHAPE_TYPE_CONVEX_HULL) { + return true; + } + if (!_model) { return false; // hmm... } @@ -316,6 +320,11 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { } void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { + if (_shapeType != SHAPE_TYPE_COMPOUND && _shapeType != SHAPE_TYPE_CONVEX_HULL) { + info.setParams(getShapeType(), 0.5f * getDimensions()); + return; + } + if (_model->getCollisionURL().isEmpty() || _model->getURL().isEmpty()) { info.setParams(getShapeType(), 0.5f * getDimensions()); } else { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ea811389cb..fa53dd2dda 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -69,25 +69,6 @@ bool EntityTree::handlesEditPacketType(PacketType packetType) const { } } -/// Give an EntityItemID and EntityItemProperties, this will either find the correct entity that already exists -/// in the tree or it will create a new entity of the type specified by the properties and return that item. -/// In the case that it creates a new item, the item will be properly added to the tree and all appropriate lookup hashes. -EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItem* result = NULL; - - // we need to first see if we already have the entity in our tree by finding the containing element of the entity - EntityTreeElement* containingElement = getContainingElement(entityID); - if (containingElement) { - result = containingElement->getEntityWithEntityItemID(entityID); - } - - // if the element does not exist, then create a new one of the specified type... - if (!result) { - result = addEntity(entityID, properties); - } - return result; -} - /// Adds a new entity item to the tree void EntityTree::postAddEntity(EntityItem* entity) { assert(entity); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index c49cfb2600..3f01dec408 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -82,7 +82,6 @@ public: virtual void update(); // The newer API... - EntityItem* getOrCreateEntityItem(const EntityItemID& entityID, const EntityItemProperties& properties); void postAddEntity(EntityItem* entityItem); EntityItem* addEntity(const EntityItemID& entityID, const EntityItemProperties& properties); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 51648c4fa6..d6d5c68ff9 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -731,12 +731,19 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int } // If the item already exists in our tree, we want do the following... + // 0) if this node is the simulator for the entity, ignore the update packet // 1) allow the existing item to read from the databuffer // 2) check to see if after reading the item, the containing element is still correct, fix it if needed // // TODO: Do we need to also do this? // 3) remember the old cube for the entity so we can mark it as dirty - if (entityItem) { + auto nodeList = DependencyManager::get(); + QString myNodeID = nodeList->getSessionUUID().toString(); + if (entityItem && entityItem->getSimulatorID() == myNodeID) { + // do nothing, this was echoed back to us + qDebug() << "IGNORING ECHOED ENTITY UPDATE"; + // _myTree->entityChanged(entityItem); + } else if (entityItem) { QString entityScriptBefore = entityItem->getScript(); bool bestFitBefore = bestFitEntityBounds(entityItem); EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); @@ -750,7 +757,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int if (bestFitBefore != bestFitAfter) { // This is the case where the entity existed, and is in some element in our tree... if (!bestFitBefore && bestFitAfter) { - // This is the case where the entity existed, and is in some element in our tree... + // This is the case where the entity existed, and is in some element in our tree... if (currentContainingElement != this) { currentContainingElement->removeEntityItem(entityItem); addEntityItem(entityItem); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c02748afe3..33f9630e4f 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -216,20 +216,22 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setRotation(_sentRotation); } - const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec - bool zeroSpeed = (glm::length2(_sentVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); - const float MINIMUM_EXTRAPOLATION_SPIN_SQUARED = 0.004f; // ~0.01 rotation/sec - bool zeroSpin = glm::length2(_sentAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; - + bool zeroSpeed = true; + bool zeroSpin = true; + if (_outgoingPacketFlags & EntityItem::DIRTY_VELOCITY) { if (_body->isActive()) { _sentVelocity = bulletToGLM(_body->getLinearVelocity()); _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); // if the speeds are very small we zero them out + const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec + zeroSpeed = (glm::length2(_sentVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); if (zeroSpeed) { _sentVelocity = glm::vec3(0.0f); } + const float MINIMUM_EXTRAPOLATION_SPIN_SQUARED = 0.004f; // ~0.01 rotation/sec + zeroSpin = glm::length2(_sentAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; if (zeroSpin) { _sentAngularVelocity = glm::vec3(0.0f); } @@ -249,15 +251,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ auto nodeList = DependencyManager::get(); QString myNodeID = nodeList->getSessionUUID().toString(); QString simulatorID = _entity->getSimulatorID(); - qDebug() << "EntityMotionState::sendUpdate" << (zeroSpin && zeroSpin) << "me:" << myNodeID << "owner:" << simulatorID; if (simulatorID.isEmpty() && !(zeroSpin && zeroSpin)) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator - qDebug() << "claiming simulator ownership"; _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); } else if (simulatorID == myNodeID && zeroSpin && zeroSpin) { // we are the simulator and the object has stopped. give up "simulator" status - qDebug() << "releasing simulator ownership"; _entity->setSimulatorID(""); properties.setSimulatorID(""); } @@ -279,7 +278,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ #ifdef WANT_DEBUG quint64 now = usecTimestampNow(); qCDebug(physics) << "EntityMotionState::sendUpdate()"; - qCDebug(physics) << " EntityItemId:" << _entity->getEntityItemID() << "---------------------------------------------"; + qCDebug(physics) << " EntityItemId:" << _entity->getEntityItemID() + << "---------------------------------------------"; qCDebug(physics) << " lastSimulated:" << debugTime(lastSimulated, now); #endif //def WANT_DEBUG @@ -287,12 +287,16 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setLastEdited(_entity->getLastEdited()); } - if (EntityItem::getSendPhysicsUpdates()) { + if (EntityItem::getSendPhysicsUpdates() && _numNonMovingUpdates < 4) { EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); #ifdef WANT_DEBUG qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; #endif + qDebug() << "EntityMotionState::sendUpdate" << (zeroSpin && zeroSpin) + << _sentMoving + << _numNonMovingUpdates + << "me:" << myNodeID << "owner:" << simulatorID; entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { #ifdef WANT_DEBUG From e25590f00e6b544c00de3ef663dfd7dce0e282af Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 14 Apr 2015 13:37:57 -0700 Subject: [PATCH 052/401] don't give up ownership of simulation until the last packet is sent --- libraries/physics/src/EntityMotionState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 33f9630e4f..1abbe59f8e 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -255,7 +255,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // The object is moving and nobody thinks they own the motion. set this Node as the simulator _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); - } else if (simulatorID == myNodeID && zeroSpin && zeroSpin) { + } else if (simulatorID == myNodeID && zeroSpin && _numNonMovingUpdates == 3) { // we are the simulator and the object has stopped. give up "simulator" status _entity->setSimulatorID(""); properties.setSimulatorID(""); From 9388ae42128c8ae9430a32ad192ef95c9956edd5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 14 Apr 2015 14:52:21 -0700 Subject: [PATCH 053/401] fix warning about unused variable --- libraries/render-utils/src/Model.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b98123803f..22358f7453 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -151,7 +151,7 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, // create a new RenderPipeline with the same shader side and the mirrorState auto mirrorPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, mirrorState)); - auto it = insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations))); + insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations))); } } From da9091a99db023f5c2dddc8687aa245fc4be29af Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 14 Apr 2015 14:54:43 -0700 Subject: [PATCH 054/401] remove SHAPE_TYPE_CONVEX_HULL from libs and tests --- libraries/physics/src/ShapeInfoUtil.cpp | 140 ++++-------------------- libraries/physics/src/ShapeInfoUtil.h | 8 +- libraries/shared/src/ShapeInfo.cpp | 20 ++-- libraries/shared/src/ShapeInfo.h | 2 +- tests/physics/src/ShapeInfoTests.cpp | 16 +-- tests/physics/src/ShapeManagerTests.cpp | 16 +-- 6 files changed, 39 insertions(+), 163 deletions(-) diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp index 8900c5a0dc..c6c76a98eb 100644 --- a/libraries/physics/src/ShapeInfoUtil.cpp +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -14,107 +14,6 @@ #include "ShapeInfoUtil.h" #include "BulletUtil.h" -int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) { - int bulletShapeType = INVALID_SHAPE_PROXYTYPE; - switch(shapeInfoType) { - case SHAPE_TYPE_BOX: - bulletShapeType = BOX_SHAPE_PROXYTYPE; - break; - case SHAPE_TYPE_SPHERE: - bulletShapeType = SPHERE_SHAPE_PROXYTYPE; - break; - case SHAPE_TYPE_CAPSULE_Y: - bulletShapeType = CAPSULE_SHAPE_PROXYTYPE; - break; - case SHAPE_TYPE_CONVEX_HULL: - bulletShapeType = CONVEX_HULL_SHAPE_PROXYTYPE; - break; - case SHAPE_TYPE_COMPOUND: - bulletShapeType = COMPOUND_SHAPE_PROXYTYPE; - break; - } - return bulletShapeType; -} - -int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) { - int shapeInfoType = SHAPE_TYPE_NONE; - switch(bulletShapeType) { - case BOX_SHAPE_PROXYTYPE: - shapeInfoType = SHAPE_TYPE_BOX; - break; - case SPHERE_SHAPE_PROXYTYPE: - shapeInfoType = SHAPE_TYPE_SPHERE; - break; - case CAPSULE_SHAPE_PROXYTYPE: - shapeInfoType = SHAPE_TYPE_CAPSULE_Y; - break; - case CONVEX_HULL_SHAPE_PROXYTYPE: - shapeInfoType = SHAPE_TYPE_CONVEX_HULL; - break; - case COMPOUND_SHAPE_PROXYTYPE: - shapeInfoType = SHAPE_TYPE_COMPOUND; - break; - } - return shapeInfoType; -} - -void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info) { - if (shape) { - int type = ShapeInfoUtil::fromBulletShapeType(shape->getShapeType()); - switch(type) { - case SHAPE_TYPE_BOX: { - const btBoxShape* boxShape = static_cast(shape); - info.setBox(bulletToGLM(boxShape->getHalfExtentsWithMargin())); - } - break; - case SHAPE_TYPE_SPHERE: { - const btSphereShape* sphereShape = static_cast(shape); - info.setSphere(sphereShape->getRadius()); - } - break; - case SHAPE_TYPE_CONVEX_HULL: { - const btConvexHullShape* convexHullShape = static_cast(shape); - const int numPoints = convexHullShape->getNumPoints(); - const btVector3* btPoints = convexHullShape->getUnscaledPoints(); - QVector> points; - QVector childPoints; - for (int i = 0; i < numPoints; i++) { - glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ()); - childPoints << point; - } - points << childPoints; - info.setConvexHulls(points); - } - break; - case SHAPE_TYPE_COMPOUND: { - const btCompoundShape* compoundShape = static_cast(shape); - const int numChildShapes = compoundShape->getNumChildShapes(); - QVector> points; - for (int i = 0; i < numChildShapes; i ++) { - const btCollisionShape* childShape = compoundShape->getChildShape(i); - const btConvexHullShape* convexHullShape = static_cast(childShape); - const int numPoints = convexHullShape->getNumPoints(); - const btVector3* btPoints = convexHullShape->getUnscaledPoints(); - - QVector childPoints; - for (int j = 0; j < numPoints; j++) { - glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ()); - childPoints << point; - } - points << childPoints; - } - info.setConvexHulls(points); - } - break; - default: { - info.clear(); - } - break; - } - } else { - info.clear(); - } -} btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; @@ -135,33 +34,34 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { shape = new btCapsuleShape(radius, height); } break; - case SHAPE_TYPE_CONVEX_HULL: { - auto hull = new btConvexHullShape(); - const QVector>& points = info.getPoints(); - foreach (glm::vec3 point, points[0]) { - btVector3 btPoint(point[0], point[1], point[2]); - hull->addPoint(btPoint, false); - } - hull->recalcLocalAabb(); - shape = hull; - } - break; case SHAPE_TYPE_COMPOUND: { - auto compound = new btCompoundShape(); const QVector>& points = info.getPoints(); - - btTransform trans; - trans.setIdentity(); - foreach (QVector hullPoints, points) { + uint32_t numSubShapes = info.getNumSubShapes(); + if (numSubShapes == 1) { auto hull = new btConvexHullShape(); - foreach (glm::vec3 point, hullPoints) { + const QVector>& points = info.getPoints(); + foreach (glm::vec3 point, points[0]) { btVector3 btPoint(point[0], point[1], point[2]); hull->addPoint(btPoint, false); } hull->recalcLocalAabb(); - compound->addChildShape (trans, hull); + shape = hull; + } else { + assert(numSubShapes > 1); + auto compound = new btCompoundShape(); + btTransform trans; + trans.setIdentity(); + foreach (QVector hullPoints, points) { + auto hull = new btConvexHullShape(); + foreach (glm::vec3 point, hullPoints) { + btVector3 btPoint(point[0], point[1], point[2]); + hull->addPoint(btPoint, false); + } + hull->recalcLocalAabb(); + compound->addChildShape (trans, hull); + } + shape = compound; } - shape = compound; } break; } diff --git a/libraries/physics/src/ShapeInfoUtil.h b/libraries/physics/src/ShapeInfoUtil.h index 9585161440..39a897019c 100644 --- a/libraries/physics/src/ShapeInfoUtil.h +++ b/libraries/physics/src/ShapeInfoUtil.h @@ -19,16 +19,10 @@ // translates between ShapeInfo and btShape +// TODO: rename this to ShapeFactory namespace ShapeInfoUtil { - // XXX is collectInfoFromShape no longer strictly needed? - void collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info); - btCollisionShape* createShapeFromInfo(const ShapeInfo& info); - - // TODO? just use bullet shape types everywhere? - int toBulletShapeType(int shapeInfoType); - int fromBulletShapeType(int bulletShapeType); }; #endif // hifi_ShapeInfoUtil_h diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 5fe1fc230d..544df35b86 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -37,12 +37,6 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString _halfExtents = glm::vec3(radius); break; } - case SHAPE_TYPE_CONVEX_HULL: - _url = QUrl(url); - // halfExtents aren't used by convex-hull or compound convex-hull except as part of - // the generation of the key for the ShapeManager. - _halfExtents = halfExtents; - break; case SHAPE_TYPE_COMPOUND: _url = QUrl(url); _halfExtents = halfExtents; @@ -78,12 +72,8 @@ void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) { } void ShapeInfo::setConvexHulls(const QVector>& points) { - if (points.size() == 1) { - _type = SHAPE_TYPE_CONVEX_HULL; - } else { - _type = SHAPE_TYPE_COMPOUND; - } _points = points; + _type = (_points.size() > 0) ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; _doubleHashKey.clear(); } @@ -95,6 +85,14 @@ void ShapeInfo::setCapsuleY(float radius, float halfHeight) { _doubleHashKey.clear(); } +uint32_t ShapeInfo::getNumSubShapes() const { + if (_type == SHAPE_TYPE_NONE) { + return 0; + } else if (_type == SHAPE_TYPE_COMPOUND) { + return _points.size(); + } + return 1; +} float ShapeInfo::computeVolume() const { const float DEFAULT_VOLUME = 1.0f; float volume = DEFAULT_VOLUME; diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index 4dce121d64..8770ef62c7 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -24,7 +24,6 @@ enum ShapeType { SHAPE_TYPE_BOX, SHAPE_TYPE_SPHERE, SHAPE_TYPE_ELLIPSOID, - SHAPE_TYPE_CONVEX_HULL, SHAPE_TYPE_PLANE, SHAPE_TYPE_COMPOUND, SHAPE_TYPE_CAPSULE_X, @@ -52,6 +51,7 @@ public: const glm::vec3& getHalfExtents() const { return _halfExtents; } const QVector>& getPoints() const { return _points; } + uint32_t getNumSubShapes() const; void clearPoints () { _points.clear(); } void appendToPoints (const QVector& newPoints) { _points << newPoints; } diff --git a/tests/physics/src/ShapeInfoTests.cpp b/tests/physics/src/ShapeInfoTests.cpp index bf2a98eb10..ef5bd0be39 100644 --- a/tests/physics/src/ShapeInfoTests.cpp +++ b/tests/physics/src/ShapeInfoTests.cpp @@ -147,9 +147,7 @@ void ShapeInfoTests::testBoxShape() { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: NULL Box shape" << std::endl; } - ShapeInfo otherInfo; - ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - + ShapeInfo otherInfo = info; DoubleHashKey otherKey = otherInfo.getHash(); if (key.getHash() != otherKey.getHash()) { std::cout << __FILE__ << ":" << __LINE__ @@ -172,9 +170,7 @@ void ShapeInfoTests::testSphereShape() { btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info); - ShapeInfo otherInfo; - ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - + ShapeInfo otherInfo = info; DoubleHashKey otherKey = otherInfo.getHash(); if (key.getHash() != otherKey.getHash()) { std::cout << __FILE__ << ":" << __LINE__ @@ -198,9 +194,7 @@ void ShapeInfoTests::testCylinderShape() { btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info); - ShapeInfo otherInfo; - ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - + ShapeInfo otherInfo = info; DoubleHashKey otherKey = otherInfo.getHash(); if (key.getHash() != otherKey.getHash()) { std::cout << __FILE__ << ":" << __LINE__ @@ -225,9 +219,7 @@ void ShapeInfoTests::testCapsuleShape() { btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info); - ShapeInfo otherInfo; - ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - + ShapeInfo otherInfo = info; DoubleHashKey otherKey = otherInfo.getHash(); if (key.getHash() != otherKey.getHash()) { std::cout << __FILE__ << ":" << __LINE__ diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index d86f296d0e..d2b4ca70fa 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -187,9 +187,7 @@ void ShapeManagerTests::addBoxShape() { ShapeManager shapeManager; btCollisionShape* shape = shapeManager.getShape(info); - ShapeInfo otherInfo; - ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - + ShapeInfo otherInfo = info; btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { std::cout << __FILE__ << ":" << __LINE__ @@ -205,9 +203,7 @@ void ShapeManagerTests::addSphereShape() { ShapeManager shapeManager; btCollisionShape* shape = shapeManager.getShape(info); - ShapeInfo otherInfo; - ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - + ShapeInfo otherInfo = info; btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { std::cout << __FILE__ << ":" << __LINE__ @@ -225,9 +221,7 @@ void ShapeManagerTests::addCylinderShape() { ShapeManager shapeManager; btCollisionShape* shape = shapeManager.getShape(info); - ShapeInfo otherInfo; - ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - + ShapeInfo otherInfo = info; btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { std::cout << __FILE__ << ":" << __LINE__ @@ -246,9 +240,7 @@ void ShapeManagerTests::addCapsuleShape() { ShapeManager shapeManager; btCollisionShape* shape = shapeManager.getShape(info); - ShapeInfo otherInfo; - ShapeInfoUtil::collectInfoFromShape(shape, otherInfo); - + ShapeInfo otherInfo = info; btCollisionShape* otherShape = shapeManager.getShape(otherInfo); if (shape != otherShape) { std::cout << __FILE__ << ":" << __LINE__ From 7da1c518771b6d2d875b68ca6e264bd363777594 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 14 Apr 2015 14:55:42 -0700 Subject: [PATCH 055/401] whoops, missed a file --- libraries/physics/src/ShapeManager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 2a73f5d28f..dd67c2c73a 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -35,7 +35,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { // Very small or large objects are not supported. float diagonal = 4.0f * glm::length2(info.getHalfExtents()); const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube - const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e6f; // 1000 m cube + //const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e6f; // 1000 m cube if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED /* || diagonal > MAX_SHAPE_DIAGONAL_SQUARED*/ ) { // qCDebug(physics) << "ShapeManager::getShape -- not making shape due to size" << diagonal; return NULL; @@ -104,11 +104,9 @@ void ShapeManager::collectGarbage() { ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef && shapeRef->refCount == 0) { // if the shape we're about to delete is compound, delete the children first. - auto shapeType = ShapeInfoUtil::fromBulletShapeType(shapeRef->shape->getShapeType()); - if (shapeType == SHAPE_TYPE_COMPOUND) { + if (shapeRef->shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shapeRef->shape); const int numChildShapes = compoundShape->getNumChildShapes(); - QVector> points; for (int i = 0; i < numChildShapes; i ++) { const btCollisionShape* childShape = compoundShape->getChildShape(i); delete childShape; From 5b81b5b11b5236247044d065afc080609b084d5a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 14 Apr 2015 14:56:32 -0700 Subject: [PATCH 056/401] removing SHAPE_TYPE_CONVEX_HULL from entities lib --- .../src/RenderableModelEntityItem.cpp | 86 ++++++++----------- .../src/RenderableModelEntityItem.h | 3 - .../entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/ModelEntityItem.cpp | 10 +++ libraries/entities/src/ModelEntityItem.h | 4 +- 5 files changed, 49 insertions(+), 56 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 1d601d1294..3dd8f79fff 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -274,54 +274,50 @@ void RenderableModelEntityItem::setCollisionModelURL(const QString& url) { } } -bool RenderableModelEntityItem::hasCollisionModel() const { - if (_model) { - return ! _model->getCollisionURL().isEmpty(); - } else { - return !_collisionModelURL.isEmpty(); - } -} - -const QString& RenderableModelEntityItem::getCollisionModelURL() const { - // assert (!_model || _collisionModelURL == _model->getCollisionURL().toString()); - return _collisionModelURL; -} - bool RenderableModelEntityItem::isReadyToComputeShape() { + ShapeType type = getShapeType(); + if (type == SHAPE_TYPE_COMPOUND) { - if (!_model) { - return false; // hmm... + if (!_model) { + return false; // hmm... + } + + assert(!_model->getCollisionURL().isEmpty()); + + if (_model->getURL().isEmpty()) { + // we need a render geometry with a scale to proceed, so give up. + return false; + } + + const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); + const QSharedPointer renderNetworkGeometry = _model->getGeometry(); + + if ((! collisionNetworkGeometry.isNull() && collisionNetworkGeometry->isLoadedWithTextures()) && + (! renderNetworkGeometry.isNull() && renderNetworkGeometry->isLoadedWithTextures())) { + // we have both URLs AND both geometries AND they are both fully loaded. + return true; + } + + // the model is still being downloaded. + std::cout << "adebug still being downloaded" << std::endl; // adebug + return false; } - - if (_model->getCollisionURL().isEmpty()) { - // no collision-model url, so we're ready to compute a shape (of type None). - return true; - } - if (_model->getURL().isEmpty()) { - // we need a render geometry with a scale to proceed, so give up. - return true; - } - - const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); - const QSharedPointer renderNetworkGeometry = _model->getGeometry(); - - if ((! collisionNetworkGeometry.isNull() && collisionNetworkGeometry->isLoadedWithTextures()) && - (! renderNetworkGeometry.isNull() && renderNetworkGeometry->isLoadedWithTextures())) { - // we have both URLs AND both geometries AND they are both fully loaded. - return true; - } - - // the model is still being downloaded. - return false; + return true; } void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { - if (_model->getCollisionURL().isEmpty() || _model->getURL().isEmpty()) { - info.setParams(getShapeType(), 0.5f * getDimensions()); + ShapeType type = getShapeType(); + if (type != SHAPE_TYPE_COMPOUND) { + ModelEntityItem::computeShapeInfo(info); + info.setParams(_shapeType, 0.5f * getDimensions()); } else { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); - const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); + // should never fall in here when collision model not fully loaded + // hence we assert collisionNetworkGeometry is not NULL + assert(!collisionNetworkGeometry.isNull()); + + const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); const QSharedPointer renderNetworkGeometry = _model->getGeometry(); const FBXGeometry& renderGeometry = renderNetworkGeometry->getFBXGeometry(); @@ -415,18 +411,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } glm::vec3 collisionModelDimensions = box.getDimensions(); - info.setParams(getShapeType(), collisionModelDimensions, _collisionModelURL); + info.setParams(_shapeType, collisionModelDimensions, _collisionModelURL); info.setConvexHulls(_points); } } -ShapeType RenderableModelEntityItem::getShapeType() const { - // XXX make hull an option in edit.js ? - if (!_model || _model->getCollisionURL().isEmpty()) { - return _shapeType; - } else if (_points.size() == 1) { - return SHAPE_TYPE_CONVEX_HULL; - } else { - return SHAPE_TYPE_COMPOUND; - } -} diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 9146a04cf8..b632357942 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -53,12 +53,9 @@ public: bool needsToCallUpdate() const; virtual void setCollisionModelURL(const QString& url); - virtual bool hasCollisionModel() const; - virtual const QString& getCollisionModelURL() const; bool isReadyToComputeShape(); void computeShapeInfo(ShapeInfo& info); - ShapeType getShapeType() const; private: void remapTextures(); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index bf2ea640f1..8a25d59f26 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -192,7 +192,7 @@ void buildStringToShapeTypeLookup() { stringToShapeTypeLookup["box"] = SHAPE_TYPE_BOX; stringToShapeTypeLookup["sphere"] = SHAPE_TYPE_SPHERE; stringToShapeTypeLookup["ellipsoid"] = SHAPE_TYPE_ELLIPSOID; - stringToShapeTypeLookup["convex-hull"] = SHAPE_TYPE_CONVEX_HULL; + stringToShapeTypeLookup["convex-hull"] = SHAPE_TYPE_COMPOUND; stringToShapeTypeLookup["plane"] = SHAPE_TYPE_PLANE; stringToShapeTypeLookup["compound"] = SHAPE_TYPE_COMPOUND; stringToShapeTypeLookup["capsule-x"] = SHAPE_TYPE_CAPSULE_X; diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index cdbc3d9441..acee2a594f 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -282,6 +282,16 @@ void ModelEntityItem::updateShapeType(ShapeType type) { } } +// virtual +ShapeType ModelEntityItem::getShapeType() const { + if (_shapeType == SHAPE_TYPE_COMPOUND) { + return hasCollisionModel() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; + } + else { + return _shapeType; + } +} + void ModelEntityItem::setCollisionModelURL(const QString& url) { if (_collisionModelURL != url) { _collisionModelURL = url; diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 9e34de445b..057c5babaf 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -49,7 +49,7 @@ public: virtual void debugDump() const; void updateShapeType(ShapeType type); - virtual ShapeType getShapeType() const { return _shapeType; } + virtual ShapeType getShapeType() const; // TODO: Move these to subclasses, or other appropriate abstraction // getters/setters applicable to models and particles @@ -63,7 +63,7 @@ public: const QString& getModelURL() const { return _modelURL; } static const QString DEFAULT_COLLISION_MODEL_URL; - virtual const QString& getCollisionModelURL() const { return _collisionModelURL; } + const QString& getCollisionModelURL() const { return _collisionModelURL; } bool hasAnimation() const { return !_animationURL.isEmpty(); } static const QString DEFAULT_ANIMATION_URL; From 8623a0606cd48be6fa43ec7095419a40b9a85bc2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 14 Apr 2015 15:39:24 -0700 Subject: [PATCH 057/401] remove accidentally commited debug code --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 3dd8f79fff..c67e1f04e5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -299,7 +299,6 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { } // the model is still being downloaded. - std::cout << "adebug still being downloaded" << std::endl; // adebug return false; } return true; From aec42cf2dc64935fa22dfc4beb422d207b86c330 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 14 Apr 2015 15:39:49 -0700 Subject: [PATCH 058/401] enforce ShapeType agreement for ModeEntityItem --- libraries/entities/src/ModelEntityItem.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index acee2a594f..e98f784765 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -276,6 +276,16 @@ void ModelEntityItem::debugDump() const { } void ModelEntityItem::updateShapeType(ShapeType type) { + // BEGIN_TEMPORARY_WORKAROUND + // we have allowed inconsistent ShapeType's to be stored in SVO files in the past (this was a bug) + // but we are now enforcing the entity properties to be consistent. To make the possible we're + // introducing a temporary workaround: we will ignore ShapeType updates that conflict with the + // _collisionModelURL. + if (hasCollisionModel()) { + type = SHAPE_TYPE_COMPOUND; + } + // END_TEMPORARY_WORKAROUND + if (type != _shapeType) { _shapeType = type; _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; @@ -296,6 +306,7 @@ void ModelEntityItem::setCollisionModelURL(const QString& url) { if (_collisionModelURL != url) { _collisionModelURL = url; _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; + _shapeType = _collisionModelURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND; } } From 87030236cbfda76af44eefc8036fac425ea3609e Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 14 Apr 2015 15:53:24 -0700 Subject: [PATCH 059/401] working version with the gpu::SAmpler and the gpu::Framebuffer --- libraries/gpu/src/gpu/Format.h | 14 ++ libraries/gpu/src/gpu/Framebuffer.cpp | 13 +- libraries/gpu/src/gpu/GLBackend.h | 4 + libraries/gpu/src/gpu/GLBackendState.cpp | 20 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 186 ++++++++++++------ libraries/gpu/src/gpu/State.h | 16 +- libraries/gpu/src/gpu/Texture.cpp | 25 ++- libraries/gpu/src/gpu/Texture.h | 99 +++++++++- .../src/DeferredLightingEffect.cpp | 2 +- libraries/render-utils/src/Model.cpp | 2 +- libraries/render-utils/src/TextureCache.cpp | 33 +--- 11 files changed, 292 insertions(+), 122 deletions(-) diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index d3330fd147..e982f27ec2 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -179,6 +179,20 @@ public: uint8 _type : 4; }; + +enum ComparisonFunction { + NEVER = 0, + LESS, + EQUAL, + LESS_EQUAL, + GREATER, + NOT_EQUAL, + GREATER_EQUAL, + ALWAYS, + + NUM_COMPARISON_FUNCS, +}; + }; diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index f671dba28e..84e0fcca7a 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -32,8 +32,8 @@ Framebuffer* Framebuffer::create() { Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height, uint16 numSamples) { auto framebuffer = Framebuffer::create(); - auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height)); - auto depthTexture = TexturePointer(Texture::create2D(depthStencilBufferFormat, width, height)); + auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); + auto depthTexture = TexturePointer(Texture::create2D(depthStencilBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); framebuffer->setRenderBuffer(0, colorTexture); framebuffer->setDepthStencilBuffer(depthTexture, depthStencilBufferFormat); @@ -44,6 +44,15 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& Framebuffer* Framebuffer::createShadowmap(uint16 width) { auto framebuffer = Framebuffer::create(); auto depthTexture = TexturePointer(Texture::create2D(Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH), width, width)); + + Sampler::Desc samplerDesc; + samplerDesc._borderColor = glm::vec4(1.0f); + samplerDesc._wrapModeU = Sampler::WRAP_BORDER; + samplerDesc._wrapModeV = Sampler::WRAP_BORDER; + samplerDesc._filter = Sampler::FILTER_MIN_MAG_LINEAR; + samplerDesc._comparisonFunc = LESS_EQUAL; + + depthTexture->setSampler(Sampler(samplerDesc)); framebuffer->setDepthStencilBuffer(depthTexture, Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH)); diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index e3069f5205..b725fa46d0 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -53,6 +53,7 @@ public: Stamp _storageStamp; Stamp _contentStamp; GLuint _texture; + GLenum _target; GLuint _size; GLTexture(); @@ -61,6 +62,9 @@ public: static GLTexture* syncGPUObject(const Texture& texture); static GLuint getTextureID(const TexturePointer& texture); + // very specific for now + static void syncSampler(const Sampler& sampler, Texture::Type type, GLTexture* object); + class GLShader : public GPUObject { public: GLuint _shader; diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 7707922b81..fb85d30fe2 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -237,26 +237,26 @@ void GLBackend::resetPipelineState(State::Signature nextSignature) { } } -State::ComparisonFunction comparisonFuncFromGL(GLenum func) { +ComparisonFunction comparisonFuncFromGL(GLenum func) { if (func == GL_NEVER) { - return State::NEVER; + return NEVER; } else if (func == GL_LESS) { - return State::LESS; + return LESS; } else if (func == GL_EQUAL) { - return State::EQUAL; + return EQUAL; } else if (func == GL_LEQUAL) { - return State::LESS_EQUAL; + return LESS_EQUAL; } else if (func == GL_GREATER) { - return State::GREATER; + return GREATER; } else if (func == GL_NOTEQUAL) { - return State::NOT_EQUAL; + return NOT_EQUAL; } else if (func == GL_GEQUAL) { - return State::GREATER_EQUAL; + return GREATER_EQUAL; } else if (func == GL_ALWAYS) { - return State::ALWAYS; + return ALWAYS; } - return State::ALWAYS; + return ALWAYS; } State::StencilOp stencilOpFromGL(GLenum stencilOp) { diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index da6d993171..b8f9ab0bf1 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -16,7 +16,8 @@ GLBackend::GLTexture::GLTexture() : _storageStamp(0), _contentStamp(0), _texture(0), - _size(0) + _size(0), + _target(GL_TEXTURE_2D) {} GLBackend::GLTexture::~GLTexture() { @@ -285,69 +286,77 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { // GO through the process of allocating the correct storage and/or update the content switch (texture.getType()) { case Texture::TEX_2D: { - if (needUpdate) { - if (texture.isStoredMipAvailable(0)) { - GLint boundTex = -1; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); - - Texture::PixelsPointer mip = texture.accessStoredMip(0); - const GLvoid* bytes = mip->_sysmem.read(); - Element srcFormat = mip->_format; - - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - glBindTexture(GL_TEXTURE_2D, object->_texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, - texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, - texelFormat.format, texelFormat.type, bytes); - - if (texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - - // At this point the mip piels have been loaded, we can notify - texture.notifyGPULoaded(0); - - glBindTexture(GL_TEXTURE_2D, boundTex); - object->_contentStamp = texture.getDataStamp(); - } - } else { - const GLvoid* bytes = 0; - Element srcFormat = texture.getTexelFormat(); - if (texture.isStoredMipAvailable(0)) { - Texture::PixelsPointer mip = texture.accessStoredMip(0); - - bytes = mip->_sysmem.read(); - srcFormat = mip->_format; - - object->_contentStamp = texture.getDataStamp(); - } - + if (texture.getNumSlices() == 1) { GLint boundTex = -1; glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); glBindTexture(GL_TEXTURE_2D, object->_texture); - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - glTexImage2D(GL_TEXTURE_2D, 0, - texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, - texelFormat.format, texelFormat.type, bytes); + if (needUpdate) { + if (texture.isStoredMipAvailable(0)) { + Texture::PixelsPointer mip = texture.accessStoredMip(0); + const GLvoid* bytes = mip->_sysmem.read(); + Element srcFormat = mip->_format; + + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - if (bytes && texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glBindTexture(GL_TEXTURE_2D, object->_texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, + texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, + texelFormat.format, texelFormat.type, bytes); + + if (texture.isAutogenerateMips()) { + glGenerateMipmap(GL_TEXTURE_2D); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } + + object->_target = GL_TEXTURE_2D; + + syncSampler(texture.getSampler(), texture.getType(), object); + + + // At this point the mip piels have been loaded, we can notify + texture.notifyGPULoaded(0); + + object->_contentStamp = texture.getDataStamp(); + } } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + const GLvoid* bytes = 0; + Element srcFormat = texture.getTexelFormat(); + if (texture.isStoredMipAvailable(0)) { + Texture::PixelsPointer mip = texture.accessStoredMip(0); + + bytes = mip->_sysmem.read(); + srcFormat = mip->_format; + + object->_contentStamp = texture.getDataStamp(); + } + + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); + + glTexImage2D(GL_TEXTURE_2D, 0, + texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, + texelFormat.format, texelFormat.type, bytes); + + if (bytes && texture.isAutogenerateMips()) { + glGenerateMipmap(GL_TEXTURE_2D); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + object->_target = GL_TEXTURE_2D; + + syncSampler(texture.getSampler(), texture.getType(), object); + + // At this point the mip piels have been loaded, we can notify + texture.notifyGPULoaded(0); + + object->_storageStamp = texture.getStamp(); + object->_size = texture.getSize(); } - // At this point the mip piels have been loaded, we can notify - texture.notifyGPULoaded(0); - glBindTexture(GL_TEXTURE_2D, boundTex); - object->_storageStamp = texture.getStamp(); - object->_size = texture.getSize(); } break; } @@ -373,3 +382,70 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture) { } } +void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTexture* object) { + if (!object) return; + if (!object->_texture) return; + + class GLFilterMode { + public: + GLint minFilter; + GLint magFilter; + }; + static const GLFilterMode filterModes[] = { + {GL_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_POINT, + {GL_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR, + {GL_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT, + {GL_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR, + + {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, + {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, + {GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_MAG_POINT_MIP_LINEAR, + {GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, + {GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_POINT_MAG_MIP_LINEAR, + {GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_MIP_POINT, + {GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, + {GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR_MIP_POINT, + {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_MIP_LINEAR, + {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} //FILTER_ANISOTROPIC, + }; + + auto fm = filterModes[sampler.getFilter()]; + glTexParameteri(object->_target, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glTexParameteri(object->_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); + + static const GLenum comparisonFuncs[] = { + GL_NEVER, + GL_LESS, + GL_EQUAL, + GL_LEQUAL, + GL_GREATER, + GL_NOTEQUAL, + GL_GEQUAL, + GL_ALWAYS }; + + if (sampler.doComparison()) { + glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(object->_target, GL_TEXTURE_COMPARE_FUNC, comparisonFuncs[sampler.getComparisonFunction()]); + } else { + glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + static const GLenum wrapModes[] = { + GL_REPEAT, // WRAP_REPEAT, + GL_MIRRORED_REPEAT, // WRAP_MIRROR, + GL_CLAMP_TO_EDGE, // WRAP_CLAMP, + GL_CLAMP_TO_BORDER, // WRAP_BORDER, + GL_MIRROR_CLAMP_TO_EDGE_EXT }; // WRAP_MIRROR_ONCE, + + glTexParameteri(object->_target, GL_TEXTURE_WRAP_S, wrapModes[sampler.getWrapModeU()]); + glTexParameteri(object->_target, GL_TEXTURE_WRAP_T, wrapModes[sampler.getWrapModeV()]); + glTexParameteri(object->_target, GL_TEXTURE_WRAP_R, wrapModes[sampler.getWrapModeW()]); + + glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*) &sampler.getBorderColor()); + glTexParameteri(object->_target, GL_TEXTURE_BASE_LEVEL, sampler.getMipOffset()); + glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float) sampler.getMinMip()); + glTexParameterf(object->_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); + CHECK_GL_ERROR(); + +} diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 84f44d8efd..9307882bab 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -42,19 +42,8 @@ public: virtual ~State(); const Stamp getStamp() const { return _stamp; } - - enum ComparisonFunction { - NEVER = 0, - LESS, - EQUAL, - LESS_EQUAL, - GREATER, - NOT_EQUAL, - GREATER_EQUAL, - ALWAYS, - - NUM_COMPARISON_FUNCS, - }; + + typedef ::gpu::ComparisonFunction ComparisonFunction; enum FillMode { FILL_POINT = 0, @@ -415,5 +404,4 @@ typedef std::vector< StatePointer > States; }; - #endif diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 43d8c991b6..76cac74a59 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -93,23 +93,23 @@ bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size s return allocated == size; } -Texture* Texture::create1D(const Element& texelFormat, uint16 width) { - return create(TEX_1D, texelFormat, width, 1, 1, 1, 1); +Texture* Texture::create1D(const Element& texelFormat, uint16 width, const Sampler& sampler) { + return create(TEX_1D, texelFormat, width, 1, 1, 1, 1, sampler); } -Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height) { - return create(TEX_2D, texelFormat, width, height, 1, 1, 1); +Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) { + return create(TEX_2D, texelFormat, width, height, 1, 1, 1, sampler); } -Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth) { - return create(TEX_3D, texelFormat, width, height, depth, 1, 1); +Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler) { + return create(TEX_3D, texelFormat, width, height, depth, 1, 1, sampler); } -Texture* Texture::createCube(const Element& texelFormat, uint16 width) { - return create(TEX_CUBE, texelFormat, width, width, 1, 1, 1); +Texture* Texture::createCube(const Element& texelFormat, uint16 width, const Sampler& sampler) { + return create(TEX_CUBE, texelFormat, width, width, 1, 1, 1, sampler); } -Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) +Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler) { Texture* tex = new Texture(); tex->_storage.reset(new Storage()); @@ -118,6 +118,8 @@ Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, ui tex->_maxMip = 0; tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices); + tex->_sampler = sampler; + return tex; } @@ -346,3 +348,8 @@ uint16 Texture::evalNumSamplesUsed(uint16 numSamplesTried) { return sample; } + +void Texture::setSampler(const Sampler& sampler) { + _sampler = sampler; + _samplerStamp++; +} diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index cb124b7b08..1d1e82123a 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -16,6 +16,85 @@ namespace gpu { +class Sampler { +public: + + enum Filter { + FILTER_MIN_MAG_POINT, // top mip only + FILTER_MIN_POINT_MAG_LINEAR, // top mip only + FILTER_MIN_LINEAR_MAG_POINT, // top mip only + FILTER_MIN_MAG_LINEAR, // top mip only + + FILTER_MIN_MAG_MIP_POINT, + FILTER_MIN_MAG_POINT_MIP_LINEAR, + FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, + FILTER_MIN_POINT_MAG_MIP_LINEAR, + FILTER_MIN_LINEAR_MAG_MIP_POINT, + FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, + FILTER_MIN_MAG_LINEAR_MIP_POINT, + FILTER_MIN_MAG_MIP_LINEAR, + FILTER_ANISOTROPIC, + + NUM_FILTERS, + }; + + enum WrapMode { + WRAP_REPEAT = 0, + WRAP_MIRROR, + WRAP_CLAMP, + WRAP_BORDER, + WRAP_MIRROR_ONCE, + + NUM_WRAP_MODES + }; + + static const uint8 MAX_MIP_LEVEL = 0xFF; + + class Desc { + public: + glm::vec4 _borderColor{ 1.0f }; + uint32 _maxAnisotropy = 16; + + uint8 _wrapModeU = WRAP_REPEAT; + uint8 _wrapModeV = WRAP_REPEAT; + uint8 _wrapModeW = WRAP_REPEAT; + + uint8 _filter = FILTER_MIN_MAG_POINT; + uint8 _comparisonFunc = ALWAYS; + + uint8 _mipOffset = 0; + uint8 _minMip = 0; + uint8 _maxMip = MAX_MIP_LEVEL; + + Desc() {} + Desc(const Filter filter) : _filter(filter) {} + }; + + Sampler() {} + Sampler(const Filter filter) : _desc(filter) {} + Sampler(const Desc& desc) : _desc(desc) {} + ~Sampler() {} + + const glm::vec4& getBorderColor() const { return _desc._borderColor; } + + uint32 getMaxAnisotropy() const { return _desc._maxAnisotropy; } + + WrapMode getWrapModeU() const { return WrapMode(_desc._wrapModeU); } + WrapMode getWrapModeV() const { return WrapMode(_desc._wrapModeV); } + WrapMode getWrapModeW() const { return WrapMode(_desc._wrapModeW); } + + Filter getFilter() const { return Filter(_desc._filter); } + ComparisonFunction getComparisonFunction() const { return ComparisonFunction(_desc._comparisonFunc); } + bool doComparison() const { return getComparisonFunction() != ALWAYS; } + + uint8 getMipOffset() const { return _desc._mipOffset; } + uint8 getMinMip() const { return _desc._minMip; } + uint8 getMaxMip() const { return _desc._maxMip; } + +protected: + Desc _desc; +}; + class Texture : public Resource { public: @@ -61,10 +140,10 @@ public: TEX_CUBE, }; - static Texture* create1D(const Element& texelFormat, uint16 width); - static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height); - static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth); - static Texture* createCube(const Element& texelFormat, uint16 width); + static Texture* create1D(const Element& texelFormat, uint16 width, const Sampler& sampler = Sampler()); + static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler = Sampler()); + static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler = Sampler()); + static Texture* createCube(const Element& texelFormat, uint16 width, const Sampler& sampler = Sampler()); static Texture* createFromStorage(Storage* storage); @@ -181,11 +260,21 @@ public: bool isDefined() const { return _defined; } + + // Own sampler + void setSampler(const Sampler& sampler); + const Sampler& getSampler() const { return _sampler; } + const Stamp getSamplerStamp() const { return _samplerStamp; } + protected: std::unique_ptr< Storage > _storage; Stamp _stamp; + Sampler _sampler; + Stamp _samplerStamp; + + uint32 _size; Element _texelFormat; @@ -202,7 +291,7 @@ protected: bool _autoGenerateMips; bool _defined; - static Texture* create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices); + static Texture* create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler); Texture(); Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index c5a09a4f0f..f1eb0e129f 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -253,7 +253,7 @@ void DeferredLightingEffect::render() { program->bind(); } program->setUniformValue(locations->shadowScale, - 1.0f / textureCache->getShadowFramebufferObject()->width()); + 1.0f / textureCache->getShadowFramebuffer()->getWidth()); } else { if (_ambientLightMode > -1) { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index bddbc2a0ff..cf6ceaa1f1 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -130,7 +130,7 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, } // Z test depends if transparent or not - state->setDepthTest(true, !key.isTranslucent(), gpu::State::LESS_EQUAL); + state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); // Blend on transparent state->setBlendFunction(key.isTranslucent(), diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 28da6977f2..8e251d77ec 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -259,9 +259,11 @@ void TextureCache::createPrimaryFramebuffer() { auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); auto width = _frameBufferSize.width(); auto height = _frameBufferSize.height(); - _primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height)); - _primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height)); - _primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height)); + + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + _primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + _primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _primaryOpaqueFramebuffer->setRenderBuffer(0, _primaryColorTexture); _primaryOpaqueFramebuffer->setRenderBuffer(1, _primaryNormalTexture); @@ -270,7 +272,7 @@ void TextureCache::createPrimaryFramebuffer() { _primaryTransparentFramebuffer->setRenderBuffer(0, _primaryColorTexture); auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); - _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height)); + _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); _primaryOpaqueFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); @@ -380,25 +382,6 @@ gpu::FramebufferPointer TextureCache::getShadowFramebuffer() { _shadowFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(SHADOW_MAP_SIZE)); _shadowTexture = _shadowFramebuffer->getDepthStencilBuffer(); - /* - glGenTextures(1, &_shadowDepthTextureID); - glBindTexture(GL_TEXTURE_2D, _shadowDepthTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, - 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - const float DISTANT_BORDER[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, DISTANT_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - glBindTexture(GL_TEXTURE_2D, 0); - - _shadowFramebufferObject->bind(); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _shadowDepthTextureID, 0); - _shadowFramebufferObject->release(); - */ } return _shadowFramebuffer; } @@ -675,7 +658,7 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } - _gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height())); + _gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); _gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); _gpuTexture->autoGenerateMips(-1); } @@ -714,7 +697,7 @@ QSharedPointer DilatableNetworkTexture::getDilatedTexture(float dilatio formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::BGRA)); } - texture->_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, dilatedImage.width(), dilatedImage.height())); + texture->_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, dilatedImage.width(), dilatedImage.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); texture->_gpuTexture->assignStoredMip(0, formatMip, dilatedImage.byteCount(), dilatedImage.constBits()); texture->_gpuTexture->autoGenerateMips(-1); From b21cc357e4ce0c0412e9d5903e463336df130c33 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 14 Apr 2015 16:08:53 -0700 Subject: [PATCH 060/401] undo stop-sending hack --- libraries/physics/src/EntityMotionState.cpp | 6 ++---- libraries/physics/src/ObjectMotionState.h | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 639df6079f..5d5435eb5e 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -201,8 +201,6 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) { - const int NUM_NONMOVING_UPDATES_TO_SEND = 3; - if (!_entity->isKnownID()) { return; // never update entities that are unknown } @@ -257,7 +255,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // The object is moving and nobody thinks they own the motion. set this Node as the simulator _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); - } else if (simulatorID == myNodeID && _numNonMovingUpdates == NUM_NONMOVING_UPDATES_TO_SEND) { + } else if (simulatorID == myNodeID && _numNonMovingUpdates == MAX_NUM_NON_MOVING_UPDATES) { // we are the simulator and the object has stopped. give up "simulator" status _entity->setSimulatorID(""); properties.setSimulatorID(""); @@ -289,7 +287,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setLastEdited(_entity->getLastEdited()); } - if (EntityItem::getSendPhysicsUpdates() && _numNonMovingUpdates <= NUM_NONMOVING_UPDATES_TO_SEND) { + if (EntityItem::getSendPhysicsUpdates() /* && _numNonMovingUpdates <= MAX_NUM_NON_MOVING_UPDATES*/) { EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); #ifdef WANT_DEBUG diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index fb402a178d..2e7571df5c 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -47,6 +47,8 @@ const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_POSITION | Entit class OctreeEditPacketSender; +extern const int MAX_NUM_NON_MOVING_UPDATES; + class ObjectMotionState : public btMotionState { public: // The WorldOffset is used to keep the positions of objects in the simulation near the origin, to From 2c5201f116880c072e4f1b60f4ce6d09bc2a558b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 14 Apr 2015 16:54:14 -0700 Subject: [PATCH 061/401] Fix animation not automatically starting at start-up --- interface/src/avatar/MyAvatar.cpp | 6 +----- libraries/render-utils/src/AnimationHandle.cpp | 5 +++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6b70577754..201dc3d48d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -640,7 +640,6 @@ void MyAvatar::saveData() { settings.setValue("firstFrame", pointer->getFirstFrame()); settings.setValue("lastFrame", pointer->getLastFrame()); settings.setValue("maskedJoints", pointer->getMaskedJoints()); - settings.setValue("running", pointer->getLoop() && pointer->isRunning()); } settings.endArray(); @@ -710,13 +709,10 @@ void MyAvatar::loadData() { handle->setPriority(loadSetting(settings, "priority", 1.0f)); handle->setLoop(settings.value("loop", true).toBool()); handle->setHold(settings.value("hold", false).toBool()); - handle->setStartAutomatically(settings.value("startAutomatically", true).toBool()); handle->setFirstFrame(settings.value("firstFrame", 0.0f).toFloat()); handle->setLastFrame(settings.value("lastFrame", INT_MAX).toFloat()); handle->setMaskedJoints(settings.value("maskedJoints").toStringList()); - if (settings.value("loop", true).toBool() && settings.value("running", false).toBool()) { - handle->setRunning(true); - } + handle->setStartAutomatically(settings.value("startAutomatically", true).toBool()); } settings.endArray(); diff --git a/libraries/render-utils/src/AnimationHandle.cpp b/libraries/render-utils/src/AnimationHandle.cpp index 1cb3d4654f..037c84ae02 100644 --- a/libraries/render-utils/src/AnimationHandle.cpp +++ b/libraries/render-utils/src/AnimationHandle.cpp @@ -47,10 +47,11 @@ void AnimationHandle::setPriority(float priority) { } void AnimationHandle::setStartAutomatically(bool startAutomatically) { - _animationLoop.setStartAutomatically(startAutomatically); - if (getStartAutomatically() && !isRunning()) { + if (startAutomatically && !isRunning()) { + // Start before setting _animationLoop value so that code in setRunning() is executed start(); } + _animationLoop.setStartAutomatically(startAutomatically); } void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) { From 85e5216fc1b713113e29ed74dfeb6a4620dbdab5 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 14 Apr 2015 16:54:29 -0700 Subject: [PATCH 062/401] Condense logic --- libraries/render-utils/src/AnimationHandle.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/AnimationHandle.cpp b/libraries/render-utils/src/AnimationHandle.cpp index 037c84ae02..55995b87d8 100644 --- a/libraries/render-utils/src/AnimationHandle.cpp +++ b/libraries/render-utils/src/AnimationHandle.cpp @@ -60,13 +60,10 @@ void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) { } void AnimationHandle::setRunning(bool running) { - if (isRunning() == running) { + if (running && isRunning()) { // if we're already running, this is the same as a restart - if (running) { - // move back to the beginning - setFrameIndex(getFirstFrame()); - return; - } + setFrameIndex(getFirstFrame()); + return; } _animationLoop.setRunning(running); if (isRunning()) { From fec52f6b102ba1dfd533b461100d10b3fea9fa4c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 14 Apr 2015 18:27:24 -0700 Subject: [PATCH 063/401] Removing almost all the QFramebufferObject (instead in overlay layer) in favor of gpu::Framebuffer, eveyrthing seems to work properly --- interface/src/Application.cpp | 12 +- interface/src/devices/OculusManager.cpp | 14 +- interface/src/devices/TV3DManager.cpp | 2 - libraries/gpu/src/gpu/Format.h | 2 + libraries/gpu/src/gpu/Framebuffer.cpp | 13 +- libraries/gpu/src/gpu/Framebuffer.h | 3 +- libraries/gpu/src/gpu/Resource.cpp | 2 + .../src/AmbientOcclusionEffect.cpp | 29 ++- .../src/DeferredLightingEffect.cpp | 24 +- libraries/render-utils/src/GlowEffect.cpp | 56 +++-- libraries/render-utils/src/GlowEffect.h | 7 +- libraries/render-utils/src/TextureCache.cpp | 224 +++--------------- libraries/render-utils/src/TextureCache.h | 33 +-- 13 files changed, 133 insertions(+), 288 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3fe03476a3..3fcdfd8c4e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -798,7 +797,6 @@ void Application::paintGL() { DependencyManager::get()->prepare(); // Viewport is assigned to the size of the framebuffer - // QSize size = DependencyManager::get()->getPrimaryFramebufferObject()->size(); QSize size = DependencyManager::get()->getFrameBufferSize(); glViewport(0, 0, size.width(), size.height()); @@ -2637,11 +2635,8 @@ void Application::updateShadowMap() { activeRenderingThread = QThread::currentThread(); PerformanceTimer perfTimer("shadowMap"); -// QOpenGLFramebufferObject* fbo = DependencyManager::get()->getShadowFramebufferObject(); -// fbo->bind(); auto shadowFramebuffer = DependencyManager::get()->getShadowFramebuffer(); - GLuint shadowFBO = gpu::GLBackend::getFramebufferID(shadowFramebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO); + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(shadowFramebuffer)); glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT); @@ -2838,7 +2833,8 @@ PickRay Application::computePickRay(float x, float y) { } QImage Application::renderAvatarBillboard() { - DependencyManager::get()->getPrimaryFramebufferObject()->bind(); + auto primaryFramebuffer = DependencyManager::get()->getPrimaryFramebuffer(); + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer)); // the "glow" here causes an alpha of one Glower glower; @@ -2851,7 +2847,7 @@ QImage Application::renderAvatarBillboard() { QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32); glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits()); - DependencyManager::get()->getPrimaryFramebufferObject()->release(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); return image; } diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index d56ece12fb..0b4e3c1e73 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -35,6 +34,8 @@ #include "InterfaceLogging.h" #include "Application.h" +#include + template void for_each_eye(Function function) { for (ovrEyeType eye = ovrEyeType::ovrEye_Left; @@ -521,7 +522,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { DependencyManager::get()->prepare(); } else { - DependencyManager::get()->getPrimaryFramebufferObject()->bind(); + auto primaryFBO = DependencyManager::get()->getPrimaryFramebuffer(); + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFBO)); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } @@ -612,15 +614,15 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p glPopMatrix(); - QOpenGLFramebufferObject * finalFbo = nullptr; + gpu::FramebufferPointer finalFbo; //Bind the output texture from the glow shader. If glow effect is disabled, we just grab the texture if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { //Full texture viewport for glow effect glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); finalFbo = DependencyManager::get()->render(true); } else { - finalFbo = DependencyManager::get()->getPrimaryFramebufferObject(); - finalFbo->release(); + finalFbo = DependencyManager::get()->getPrimaryFramebuffer(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } glMatrixMode(GL_PROJECTION); @@ -644,7 +646,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p //Left over from when OR was not connected. glClear(GL_COLOR_BUFFER_BIT); - glBindTexture(GL_TEXTURE_2D, finalFbo->texture()); + glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0))); //Renders the distorted mesh onto the screen renderDistortionMesh(eyeRenderPose); diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index f082c6de47..4311e0092f 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -11,8 +11,6 @@ #include "InterfaceConfig.h" -#include - #include #include diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index e982f27ec2..15c218a577 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -173,6 +173,8 @@ public: return getRaw() != right.getRaw(); } + static const Element COLOR_RGBA_32; + protected: uint8 _semantic; uint8 _dimension : 4; diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index 84e0fcca7a..bc263494a1 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -29,7 +29,18 @@ Framebuffer* Framebuffer::create() { return framebuffer; } -Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height, uint16 numSamples) { + +Framebuffer* Framebuffer::create( const Format& colorBufferFormat, uint16 width, uint16 height) { + auto framebuffer = Framebuffer::create(); + + auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); + + framebuffer->setRenderBuffer(0, colorTexture); + + return framebuffer; +} + +Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height) { auto framebuffer = Framebuffer::create(); auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index 8028d1b478..a6fc127b17 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -115,7 +115,8 @@ public: static Framebuffer* create(const SwapchainPointer& swapchain); static Framebuffer* create(); - static Framebuffer* create(const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height, uint16 samples ); + static Framebuffer* create(const Format& colorBufferFormat, uint16 width, uint16 height); + static Framebuffer* create(const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height); static Framebuffer* createShadowmap(uint16 width); bool isSwapchain() const; diff --git a/libraries/gpu/src/gpu/Resource.cpp b/libraries/gpu/src/gpu/Resource.cpp index 708ca0f627..7d2757e15c 100644 --- a/libraries/gpu/src/gpu/Resource.cpp +++ b/libraries/gpu/src/gpu/Resource.cpp @@ -16,6 +16,8 @@ using namespace gpu; +const Element Element::COLOR_RGBA_32 = Element(VEC4, UINT8, RGBA); + Resource::Size Resource::Sysmem::allocateMemory(Byte** dataAllocated, Size size) { if ( !dataAllocated ) { qWarning() << "Buffer::Sysmem::allocateMemory() : Must have a valid dataAllocated pointer."; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 40a02a60a4..f58419ec6e 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -12,7 +12,7 @@ // include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL #include -#include +#include #include @@ -107,8 +107,8 @@ void AmbientOcclusionEffect::render() { glBindTexture(GL_TEXTURE_2D, _rotationTextureID); // render with the occlusion shader to the secondary/tertiary buffer - QOpenGLFramebufferObject* freeFBO = DependencyManager::get()->getFreeFramebufferObject(); - freeFBO->bind(); + auto freeFramebuffer = DependencyManager::get()->getFreeFramebuffer(); + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(freeFramebuffer)); float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; @@ -118,9 +118,10 @@ void AmbientOcclusionEffect::render() { glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_X_INDEX = 0; const int VIEWPORT_WIDTH_INDEX = 2; - QOpenGLFramebufferObject* primaryFBO = DependencyManager::get()->getPrimaryFramebufferObject(); - float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width(); - float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width(); + + auto framebufferSize = DependencyManager::get()->getFrameBufferSize(); + float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width(); + float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width(); _occlusionProgram->bind(); _occlusionProgram->setUniformValue(_nearLocation, nearVal); @@ -128,7 +129,7 @@ void AmbientOcclusionEffect::render() { _occlusionProgram->setUniformValue(_leftBottomLocation, left, bottom); _occlusionProgram->setUniformValue(_rightTopLocation, right, top); _occlusionProgram->setUniformValue(_noiseScaleLocation, viewport[VIEWPORT_WIDTH_INDEX] / (float)ROTATION_WIDTH, - primaryFBO->height() / (float)ROTATION_HEIGHT); + framebufferSize.height() / (float)ROTATION_HEIGHT); _occlusionProgram->setUniformValue(_texCoordOffsetLocation, sMin, 0.0f); _occlusionProgram->setUniformValue(_texCoordScaleLocation, sWidth, 1.0f); @@ -136,22 +137,24 @@ void AmbientOcclusionEffect::render() { _occlusionProgram->release(); - freeFBO->release(); - + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); // now render secondary to primary with 4x4 blur - DependencyManager::get()->getPrimaryFramebufferObject()->bind(); - + auto primaryFramebuffer = DependencyManager::get()->getPrimaryFramebuffer(); + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer)); + glEnable(GL_BLEND); glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); - glBindTexture(GL_TEXTURE_2D, freeFBO->texture()); + auto freeFramebufferTexture = freeFramebuffer->getRenderBuffer(0); + glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(freeFramebufferTexture)); _blurProgram->bind(); - _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / primaryFBO->width(), 1.0f / primaryFBO->height()); + _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / framebufferSize.width(), 1.0f / framebufferSize.height()); renderFullscreenQuad(sMin, sMin + sWidth); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index f1eb0e129f..440f75e32e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -12,7 +12,6 @@ // include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL #include -#include #include #include @@ -183,12 +182,13 @@ void DeferredLightingEffect::render() { auto textureCache = DependencyManager::get(); - // QOpenGLFramebufferObject* primaryFBO = textureCache->getPrimaryFramebufferObject(); - // primaryFBO->release(); + glBindFramebuffer(GL_FRAMEBUFFER, 0 ); + QSize framebufferSize = textureCache->getFrameBufferSize(); - QOpenGLFramebufferObject* freeFBO = DependencyManager::get()->getFreeFramebufferObject(); - freeFBO->bind(); + auto freeFBO = DependencyManager::get()->getFreeFramebuffer(); + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(freeFBO)); + glClear(GL_COLOR_BUFFER_BIT); // glEnable(GL_FRAMEBUFFER_SRGB); @@ -211,11 +211,7 @@ void DeferredLightingEffect::render() { const int VIEWPORT_Y_INDEX = 1; const int VIEWPORT_WIDTH_INDEX = 2; const int VIEWPORT_HEIGHT_INDEX = 3; - /* float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width(); - float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width(); - float tMin = viewport[VIEWPORT_Y_INDEX] / (float)primaryFBO->height(); - float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)primaryFBO->height(); - */ + float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width(); float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width(); float tMin = viewport[VIEWPORT_Y_INDEX] / (float)framebufferSize.height(); @@ -436,7 +432,9 @@ void DeferredLightingEffect::render() { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); - freeFBO->release(); + //freeFBO->release(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + // glDisable(GL_FRAMEBUFFER_SRGB); glDisable(GL_CULL_FACE); @@ -445,12 +443,12 @@ void DeferredLightingEffect::render() { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glColorMask(true, true, true, false); - auto primaryFBO = gpu::GLBackend::getFramebufferID(textureCache->getPrimaryOpaqueFramebuffer()); + auto primaryFBO = gpu::GLBackend::getFramebufferID(textureCache->getPrimaryFramebuffer()); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, primaryFBO); //primaryFBO->bind(); - glBindTexture(GL_TEXTURE_2D, freeFBO->texture()); + glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(freeFBO->getRenderBuffer(0))); glEnable(GL_TEXTURE_2D); glPushMatrix(); diff --git a/libraries/render-utils/src/GlowEffect.cpp b/libraries/render-utils/src/GlowEffect.cpp index 2399cfa1a7..6addd84da6 100644 --- a/libraries/render-utils/src/GlowEffect.cpp +++ b/libraries/render-utils/src/GlowEffect.cpp @@ -46,10 +46,10 @@ GlowEffect::~GlowEffect() { } } -QOpenGLFramebufferObject* GlowEffect::getFreeFramebufferObject() const { +gpu::FramebufferPointer GlowEffect::getFreeFramebuffer() const { return (_isOddFrame ? - DependencyManager::get()->getSecondaryFramebufferObject(): - DependencyManager::get()->getTertiaryFramebufferObject()); + DependencyManager::get()->getSecondaryFramebuffer(): + DependencyManager::get()->getTertiaryFramebuffer()); } static ProgramObject* createProgram(const QString& name) { @@ -106,8 +106,7 @@ int GlowEffect::getDeviceHeight() const { void GlowEffect::prepare() { - //DependencyManager::get()->getPrimaryFramebufferObject()->bind(); - auto primaryFBO = DependencyManager::get()->getPrimaryOpaqueFramebuffer(); + auto primaryFBO = DependencyManager::get()->getPrimaryFramebuffer(); GLuint fbo = gpu::GLBackend::getFramebufferID(primaryFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); @@ -129,25 +128,26 @@ void GlowEffect::end() { glBlendColor(0.0f, 0.0f, 0.0f, _intensity = _intensityStack.pop()); } -static void maybeBind(QOpenGLFramebufferObject* fbo) { +static void maybeBind(const gpu::FramebufferPointer& fbo) { if (fbo) { - fbo->bind(); + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(fbo)); } } -static void maybeRelease(QOpenGLFramebufferObject* fbo) { +static void maybeRelease(const gpu::FramebufferPointer& fbo) { if (fbo) { - fbo->release(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } } -QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { +gpu::FramebufferPointer GlowEffect::render(bool toTexture) { PerformanceTimer perfTimer("glowEffect"); auto textureCache = DependencyManager::get(); - // QOpenGLFramebufferObject* primaryFBO = textureCache->getPrimaryFramebufferObject(); - // primaryFBO->release(); - auto primaryFBO = gpu::GLBackend::getFramebufferID(textureCache->getPrimaryOpaqueFramebuffer()); + + auto primaryFBO = gpu::GLBackend::getFramebufferID(textureCache->getPrimaryFramebuffer()); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryColorTextureID()); auto framebufferSize = textureCache->getFrameBufferSize(); @@ -162,15 +162,14 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); - QOpenGLFramebufferObject* destFBO = toTexture ? - textureCache->getSecondaryFramebufferObject() : NULL; + gpu::FramebufferPointer destFBO = toTexture ? + textureCache->getSecondaryFramebuffer() : nullptr; if (!_enabled || _isEmpty) { // copy the primary to the screen if (destFBO && QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destFBO->handle()); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO)); glBlitFramebuffer(0, 0, framebufferSize.width(), framebufferSize.height(), 0, 0, framebufferSize.width(), framebufferSize.height(), GL_COLOR_BUFFER_BIT, GL_NEAREST); - // QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO); } else { maybeBind(destFBO); if (!destFBO) { @@ -185,36 +184,35 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { } } else { // diffuse into the secondary/tertiary (alternating between frames) - QOpenGLFramebufferObject* oldDiffusedFBO = - textureCache->getSecondaryFramebufferObject(); - QOpenGLFramebufferObject* newDiffusedFBO = - textureCache->getTertiaryFramebufferObject(); + auto oldDiffusedFBO = + textureCache->getSecondaryFramebuffer(); + auto newDiffusedFBO = + textureCache->getTertiaryFramebuffer(); if (_isOddFrame) { qSwap(oldDiffusedFBO, newDiffusedFBO); } - newDiffusedFBO->bind(); + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(newDiffusedFBO)); if (_isFirstFrame) { glClear(GL_COLOR_BUFFER_BIT); } else { glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, oldDiffusedFBO->texture()); + glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(oldDiffusedFBO->getRenderBuffer(0))); _diffuseProgram->bind(); - //QSize size = primaryFBO->size(); - QSize size = framebufferSize; - _diffuseProgram->setUniformValue(_diffusionScaleLocation, 1.0f / size.width(), 1.0f / size.height()); + + _diffuseProgram->setUniformValue(_diffusionScaleLocation, 1.0f / framebufferSize.width(), 1.0f / framebufferSize.height()); renderFullscreenQuad(); _diffuseProgram->release(); } - newDiffusedFBO->release(); - + glBindFramebuffer(GL_FRAMEBUFFER, 0); + // add diffused texture to the primary - glBindTexture(GL_TEXTURE_2D, newDiffusedFBO->texture()); + glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(newDiffusedFBO->getRenderBuffer(0))); if (toTexture) { destFBO = oldDiffusedFBO; diff --git a/libraries/render-utils/src/GlowEffect.h b/libraries/render-utils/src/GlowEffect.h index 895cd4bbce..6b7bad7689 100644 --- a/libraries/render-utils/src/GlowEffect.h +++ b/libraries/render-utils/src/GlowEffect.h @@ -13,6 +13,7 @@ #define hifi_GlowEffect_h #include +#include #include #include @@ -20,8 +21,6 @@ #include -class QOpenGLFramebufferObject; - class ProgramObject; /// A generic full screen glow effect. @@ -33,7 +32,7 @@ public: /// Returns a pointer to the framebuffer object that the glow effect is *not* using for persistent state /// (either the secondary or the tertiary). - QOpenGLFramebufferObject* getFreeFramebufferObject() const; + gpu::FramebufferPointer getFreeFramebuffer() const; void init(QGLWidget* widget, bool enabled); @@ -53,7 +52,7 @@ public: /// Renders the glow effect. To be called after rendering the scene. /// \param toTexture whether to render to a texture, rather than to the frame buffer /// \return the framebuffer object to which we rendered, or NULL if to the frame buffer - QOpenGLFramebufferObject* render(bool toTexture = false); + gpu::FramebufferPointer render(bool toTexture = false); public slots: void toggleGlowEffect(bool enabled); diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 8e251d77ec..63ca43725b 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -32,13 +32,6 @@ TextureCache::TextureCache() : _permutationNormalTexture(0), _whiteTexture(0), _blueTexture(0), - _primaryDepthTextureID(0), - _primaryNormalTextureID(0), - _primarySpecularTextureID(0), - _primaryFramebufferObject(NULL), - _secondaryFramebufferObject(NULL), - _tertiaryFramebufferObject(NULL), - _shadowFramebufferObject(NULL), _frameBufferSize(100, 100), _associatedWidget(NULL) { @@ -47,24 +40,6 @@ TextureCache::TextureCache() : } TextureCache::~TextureCache() { - - if (_primaryFramebufferObject) { - glDeleteTextures(1, &_primaryDepthTextureID); - glDeleteTextures(1, &_primaryNormalTextureID); - glDeleteTextures(1, &_primarySpecularTextureID); - } - - if (_primaryFramebufferObject) { - delete _primaryFramebufferObject; - } - - if (_secondaryFramebufferObject) { - delete _secondaryFramebufferObject; - } - - if (_tertiaryFramebufferObject) { - delete _tertiaryFramebufferObject; - } } void TextureCache::setFrameBufferSize(QSize frameBufferSize) { @@ -72,35 +47,15 @@ void TextureCache::setFrameBufferSize(QSize frameBufferSize) { if (_frameBufferSize != frameBufferSize) { _frameBufferSize = frameBufferSize; - if (_primaryOpaqueFramebuffer) { - _primaryOpaqueFramebuffer.reset(); - _primaryTransparentFramebuffer.reset(); - _primaryDepthTexture.reset(); - _primaryColorTexture.reset(); - _primaryNormalTexture.reset(); - _primarySpecularTexture.reset(); - } + _primaryFramebuffer.reset(); + _primaryDepthTexture.reset(); + _primaryColorTexture.reset(); + _primaryNormalTexture.reset(); + _primarySpecularTexture.reset(); - if (_primaryFramebufferObject) { - delete _primaryFramebufferObject; - _primaryFramebufferObject = NULL; - glDeleteTextures(1, &_primaryDepthTextureID); - _primaryDepthTextureID = 0; - glDeleteTextures(1, &_primaryNormalTextureID); - _primaryNormalTextureID = 0; - glDeleteTextures(1, &_primarySpecularTextureID); - _primarySpecularTextureID = 0; - } + _secondaryFramebuffer.reset(); - if (_secondaryFramebufferObject) { - delete _secondaryFramebufferObject; - _secondaryFramebufferObject = NULL; - } - - if (_tertiaryFramebufferObject) { - delete _tertiaryFramebufferObject; - _tertiaryFramebufferObject = NULL; - } + _tertiaryFramebuffer.reset(); } } @@ -215,46 +170,8 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, TextureType type return texture; } -QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() { - - if (!_primaryFramebufferObject) { - _primaryFramebufferObject = createFramebufferObject(); - - glGenTextures(1, &_primaryDepthTextureID); - glBindTexture(GL_TEXTURE_2D, _primaryDepthTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, _frameBufferSize.width(), _frameBufferSize.height(), - 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glGenTextures(1, &_primaryNormalTextureID); - glBindTexture(GL_TEXTURE_2D, _primaryNormalTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _frameBufferSize.width(), _frameBufferSize.height(), - 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &_primarySpecularTextureID); - glBindTexture(GL_TEXTURE_2D, _primarySpecularTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _frameBufferSize.width(), _frameBufferSize.height(), - 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); - - _primaryFramebufferObject->bind(); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _primaryDepthTextureID, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, _primaryNormalTextureID, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, _primarySpecularTextureID, 0); - _primaryFramebufferObject->release(); - } - return _primaryFramebufferObject; -} - void TextureCache::createPrimaryFramebuffer() { - _primaryOpaqueFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); - _primaryTransparentFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); auto width = _frameBufferSize.width(); @@ -265,32 +182,22 @@ void TextureCache::createPrimaryFramebuffer() { _primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _primaryOpaqueFramebuffer->setRenderBuffer(0, _primaryColorTexture); - _primaryOpaqueFramebuffer->setRenderBuffer(1, _primaryNormalTexture); - _primaryOpaqueFramebuffer->setRenderBuffer(2, _primarySpecularTexture); + _primaryFramebuffer->setRenderBuffer(0, _primaryColorTexture); + _primaryFramebuffer->setRenderBuffer(1, _primaryNormalTexture); + _primaryFramebuffer->setRenderBuffer(2, _primarySpecularTexture); - _primaryTransparentFramebuffer->setRenderBuffer(0, _primaryColorTexture); auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); - _primaryOpaqueFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); - - _primaryTransparentFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); + _primaryFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); } -gpu::FramebufferPointer TextureCache::getPrimaryOpaqueFramebuffer() { - if (!_primaryOpaqueFramebuffer) { +gpu::FramebufferPointer TextureCache::getPrimaryFramebuffer() { + if (!_primaryFramebuffer) { createPrimaryFramebuffer(); } - return _primaryOpaqueFramebuffer; -} - -gpu::FramebufferPointer TextureCache::getPrimaryTransparentFramebuffer() { - if (!_primaryTransparentFramebuffer) { - createPrimaryFramebuffer(); - } - return _primaryTransparentFramebuffer; + return _primaryFramebuffer; } gpu::TexturePointer TextureCache::getPrimaryDepthTexture() { @@ -322,28 +229,19 @@ gpu::TexturePointer TextureCache::getPrimarySpecularTexture() { } GLuint TextureCache::getPrimaryDepthTextureID() { - // ensure that the primary framebuffer object is initialized before returning the depth texture id - //getPrimaryFramebufferObject(); - - _primaryDepthTextureID = gpu::GLBackend::getTextureID(_primaryDepthTexture); - return _primaryDepthTextureID; + return gpu::GLBackend::getTextureID(getPrimaryDepthTexture()); } GLuint TextureCache::getPrimaryColorTextureID() { - return gpu::GLBackend::getTextureID(_primaryColorTexture); + return gpu::GLBackend::getTextureID(getPrimaryColorTexture()); } GLuint TextureCache::getPrimaryNormalTextureID() { - // ensure that the primary framebuffer object is initialized before returning the normal texture id - //getPrimaryFramebufferObject(); - _primaryNormalTextureID = gpu::GLBackend::getTextureID(_primaryNormalTexture); - return _primaryNormalTextureID; + return gpu::GLBackend::getTextureID(getPrimaryNormalTexture()); } GLuint TextureCache::getPrimarySpecularTextureID() { - //getPrimaryFramebufferObject(); - _primarySpecularTextureID = gpu::GLBackend::getTextureID(_primarySpecularTexture); - return _primarySpecularTextureID; + return gpu::GLBackend::getTextureID(getPrimarySpecularTexture()); } void TextureCache::setPrimaryDrawBuffers(bool color, bool normal, bool specular) { @@ -361,18 +259,18 @@ void TextureCache::setPrimaryDrawBuffers(bool color, bool normal, bool specular) glDrawBuffers(bufferCount, buffers); } -QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() { - if (!_secondaryFramebufferObject) { - _secondaryFramebufferObject = createFramebufferObject(); +gpu::FramebufferPointer TextureCache::getSecondaryFramebuffer() { + if (!_secondaryFramebuffer) { + _secondaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, _frameBufferSize.width(), _frameBufferSize.height())); } - return _secondaryFramebufferObject; + return _secondaryFramebuffer; } -QOpenGLFramebufferObject* TextureCache::getTertiaryFramebufferObject() { - if (!_tertiaryFramebufferObject) { - _tertiaryFramebufferObject = createFramebufferObject(); +gpu::FramebufferPointer TextureCache::getTertiaryFramebuffer() { + if (!_tertiaryFramebuffer) { + _tertiaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, _frameBufferSize.width(), _frameBufferSize.height())); } - return _tertiaryFramebufferObject; + return _tertiaryFramebuffer; } @@ -386,58 +284,25 @@ gpu::FramebufferPointer TextureCache::getShadowFramebuffer() { return _shadowFramebuffer; } -QOpenGLFramebufferObject* TextureCache::getShadowFramebufferObject() { - if (!_shadowFramebufferObject) { - const int SHADOW_MAP_SIZE = 2048; - _shadowFramebufferObject = new QOpenGLFramebufferObject(SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, - QOpenGLFramebufferObject::NoAttachment, GL_TEXTURE_2D, GL_RGB); - - glGenTextures(1, &_shadowDepthTextureID); - glBindTexture(GL_TEXTURE_2D, _shadowDepthTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, - 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - const float DISTANT_BORDER[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, DISTANT_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - glBindTexture(GL_TEXTURE_2D, 0); - - _shadowFramebufferObject->bind(); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _shadowDepthTextureID, 0); - _shadowFramebufferObject->release(); - } - return _shadowFramebufferObject; -} - GLuint TextureCache::getShadowDepthTextureID() { // ensure that the shadow framebuffer object is initialized before returning the depth texture id - //getShadowFramebufferObject(); - _shadowDepthTextureID = gpu::GLBackend::getTextureID(_shadowTexture); - - return _shadowDepthTextureID; + getShadowFramebuffer(); + return gpu::GLBackend::getTextureID(_shadowTexture); } bool TextureCache::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::Resize) { QSize size = static_cast(event)->size(); - if (_primaryFramebufferObject && _primaryFramebufferObject->size() != size) { - delete _primaryFramebufferObject; - _primaryFramebufferObject = NULL; - glDeleteTextures(1, &_primaryDepthTextureID); - glDeleteTextures(1, &_primaryNormalTextureID); - glDeleteTextures(1, &_primarySpecularTextureID); - } - if (_secondaryFramebufferObject && _secondaryFramebufferObject->size() != size) { - delete _secondaryFramebufferObject; - _secondaryFramebufferObject = NULL; - } - if (_tertiaryFramebufferObject && _tertiaryFramebufferObject->size() != size) { - delete _tertiaryFramebufferObject; - _tertiaryFramebufferObject = NULL; + if (_frameBufferSize != size) { + _primaryFramebuffer.reset(); + _primaryColorTexture.reset(); + _primaryDepthTexture.reset(); + _primaryNormalTexture.reset(); + _primarySpecularTexture.reset(); + + _secondaryFramebuffer.reset(); + + _tertiaryFramebuffer.reset(); } } return false; @@ -458,17 +323,6 @@ void TextureCache::associateWithWidget(QGLWidget* widget) { _associatedWidget->installEventFilter(this); } -QOpenGLFramebufferObject* TextureCache::createFramebufferObject() { - QOpenGLFramebufferObject* fbo = new QOpenGLFramebufferObject(_frameBufferSize); - - glBindTexture(GL_TEXTURE_2D, fbo->texture()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); - - return fbo; -} - Texture::Texture() { } diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index 0d0cfc40aa..42c1cecde3 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -23,8 +23,6 @@ #include #include -class QOpenGLFramebufferObject; - class NetworkTexture; typedef QSharedPointer NetworkTexturePointer; @@ -61,10 +59,7 @@ public: /// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is /// used for scene rendering. - QOpenGLFramebufferObject* getPrimaryFramebufferObject(); - - gpu::FramebufferPointer getPrimaryOpaqueFramebuffer(); - gpu::FramebufferPointer getPrimaryTransparentFramebuffer(); + gpu::FramebufferPointer getPrimaryFramebuffer(); gpu::TexturePointer getPrimaryDepthTexture(); gpu::TexturePointer getPrimaryColorTexture(); @@ -86,16 +81,13 @@ public: /// Returns a pointer to the secondary framebuffer object, used as an additional render target when performing full /// screen effects. - QOpenGLFramebufferObject* getSecondaryFramebufferObject(); + gpu::FramebufferPointer getSecondaryFramebuffer(); - /// Returns a pointer to the tertiary framebuffer object, used as an additional render target when performing full /// screen effects. - QOpenGLFramebufferObject* getTertiaryFramebufferObject(); - - /// Returns a pointer to the framebuffer object used to render shadow maps. - QOpenGLFramebufferObject* getShadowFramebufferObject(); + gpu::FramebufferPointer getTertiaryFramebuffer(); + /// Returns the framebuffer object used to render shadow maps; gpu::FramebufferPointer getShadowFramebuffer(); @@ -113,8 +105,6 @@ private: TextureCache(); virtual ~TextureCache(); friend class DilatableNetworkTexture; - - QOpenGLFramebufferObject* createFramebufferObject(); gpu::TexturePointer _permutationNormalTexture; gpu::TexturePointer _whiteTexture; @@ -127,20 +117,11 @@ private: gpu::TexturePointer _primaryColorTexture; gpu::TexturePointer _primaryNormalTexture; gpu::TexturePointer _primarySpecularTexture; - gpu::FramebufferPointer _primaryOpaqueFramebuffer; - gpu::FramebufferPointer _primaryTransparentFramebuffer; + gpu::FramebufferPointer _primaryFramebuffer; void createPrimaryFramebuffer(); - GLuint _primaryDepthTextureID; - GLuint _primaryNormalTextureID; - GLuint _primarySpecularTextureID; - QOpenGLFramebufferObject* _primaryFramebufferObject; - QOpenGLFramebufferObject* _secondaryFramebufferObject; - QOpenGLFramebufferObject* _tertiaryFramebufferObject; - - - QOpenGLFramebufferObject* _shadowFramebufferObject; - GLuint _shadowDepthTextureID; + gpu::FramebufferPointer _secondaryFramebuffer; + gpu::FramebufferPointer _tertiaryFramebuffer; gpu::FramebufferPointer _shadowFramebuffer; gpu::TexturePointer _shadowTexture; From 598abe672249b436c5cce028795457662d8d11bf Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 14 Apr 2015 18:48:06 -0700 Subject: [PATCH 064/401] Cleaning up Frambuffer.h --- libraries/gpu/src/gpu/Format.h | 1 + libraries/gpu/src/gpu/Framebuffer.h | 49 ++++++----------------------- 2 files changed, 10 insertions(+), 40 deletions(-) diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 15c218a577..e43c190819 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -35,6 +35,7 @@ typedef glm::vec4 Vec4; typedef glm::vec3 Vec3; typedef glm::vec2 Vec2; typedef glm::ivec2 Vec2i; +typedef glm::uvec2 Vec2u; // Description of a scalar type enum Type { diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index a6fc127b17..ef77df7ceb 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -18,35 +18,6 @@ namespace gpu { typedef Element Format; -class Viewport { -public: - int32 width = 1; - int32 height = 1; - int32 top = 0; - int32 left = 0; - float zmin = 0.f; - float zmax = 1.f; - - Viewport() {} - Viewport(int32 w, int32 h, int32 t = 0, int32 l = 0, float zin = 0.f, float zax = 1.f): - width(w), - height(h), - top(t), - left(l), - zmin(zin), - zmax(zax) - {} - Viewport(const Vec2i& wh, const Vec2i& tl = Vec2i(0), const Vec2& zrange = Vec2(0.f, 1.f)): - width(wh.x), - height(wh.y), - top(tl.x), - left(tl.y), - zmin(zrange.x), - zmax(zrange.y) - {} - ~Viewport() {} -}; - class Swapchain { public: // Properties @@ -147,6 +118,7 @@ public: bool validateTargetCompatibility(const Texture& texture, uint32 subresource = 0) const; + Vec2u getSize() const { return Vec2u(getWidth(), getHeight()); } uint16 getWidth() const; uint16 getHeight() const; uint16 getNumSamples() const; @@ -157,24 +129,21 @@ public: void resize( uint16 width, uint16 height, uint16 samples = 1 ); static const uint32 MAX_NUM_RENDER_BUFFERS = 8; - static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } - - // Get viewport covering the ful Canvas - Viewport getViewport() const { return Viewport(getWidth(), getHeight(), 0, 0); } + static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } protected: - uint16 _width = 0; - uint16 _height = 0; - uint16 _numSamples = 0; + SwapchainPointer _swapchain; + + TextureViews _renderBuffers; + TextureView _depthStencilBuffer; uint32 _bufferMask = 0; uint32 _frameCount = 0; - SwapchainPointer _swapchain; - - TextureViews _renderBuffers; - TextureView _depthStencilBuffer; + uint16 _width = 0; + uint16 _height = 0; + uint16 _numSamples = 0; void updateSize(const TexturePointer& texture); From d14d5f3d2952fd1be1043cdefcdc52db2bf46100 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 14 Apr 2015 15:55:42 -0700 Subject: [PATCH 065/401] Working on new-UI implementations of address bar and login --- CMakeLists.txt | 9 + interface/CMakeLists.txt | 2 +- interface/resources/qml/AddressBarDialog.qml | 84 +++++ interface/resources/qml/CustomBorder.qml | 12 + interface/resources/qml/CustomButton.qml | 23 ++ interface/resources/qml/CustomDialog.qml | 98 ++++++ interface/resources/qml/CustomText.qml | 7 + interface/resources/qml/CustomTextArea.qml | 10 + interface/resources/qml/CustomTextEdit.qml | 7 + interface/resources/qml/CustomTextInput.qml | 34 ++ interface/resources/qml/Icon.qml | 8 + interface/resources/qml/IconControl.qml | 24 ++ interface/resources/qml/LoginDialog.qml | 191 ++++++++++ interface/resources/qml/Root.qml | 14 + interface/resources/qml/componentCreation.js | 27 ++ interface/resources/qml/hifiConstants.js | 4 + interface/src/Application.cpp | 112 +++++- interface/src/Application.h | 3 + interface/src/GLCanvas.cpp | 71 ++-- interface/src/GLCanvas.h | 15 - interface/src/Menu.cpp | 50 ++- interface/src/devices/OculusManager.cpp | 15 +- interface/src/devices/OculusManager.h | 1 + interface/src/devices/TV3DManager.cpp | 2 +- interface/src/main.cpp | 1 + interface/src/ui/AddressBarDialog.cpp | 142 ++------ interface/src/ui/AddressBarDialog.h | 42 +-- interface/src/ui/ApplicationOverlay.cpp | 118 ++++--- interface/src/ui/ApplicationOverlay.h | 8 +- interface/src/ui/DialogsManager.cpp | 16 +- interface/src/ui/FramelessDialog.cpp | 166 --------- interface/src/ui/FramelessDialog.h | 50 --- interface/src/ui/LoginDialog.cpp | 148 +++----- interface/src/ui/LoginDialog.h | 49 +-- libraries/render-utils/CMakeLists.txt | 2 +- libraries/render-utils/src/FboCache.cpp | 98 ++++++ libraries/render-utils/src/FboCache.h | 50 +++ .../render-utils/src/OffscreenGlCanvas.cpp | 43 +++ .../render-utils/src/OffscreenGlCanvas.h | 31 ++ libraries/render-utils/src/OffscreenUi.cpp | 325 ++++++++++++++++++ libraries/render-utils/src/OffscreenUi.h | 136 ++++++++ libraries/render-utils/src/RenderUtil.h | 50 +++ libraries/shared/src/GLMHelpers.h | 11 + libraries/shared/src/ThreadHelpers.h | 13 + tests/render-utils/src/main.cpp | 250 +++++++++----- 45 files changed, 1844 insertions(+), 728 deletions(-) create mode 100644 interface/resources/qml/AddressBarDialog.qml create mode 100644 interface/resources/qml/CustomBorder.qml create mode 100644 interface/resources/qml/CustomButton.qml create mode 100644 interface/resources/qml/CustomDialog.qml create mode 100644 interface/resources/qml/CustomText.qml create mode 100644 interface/resources/qml/CustomTextArea.qml create mode 100644 interface/resources/qml/CustomTextEdit.qml create mode 100644 interface/resources/qml/CustomTextInput.qml create mode 100644 interface/resources/qml/Icon.qml create mode 100644 interface/resources/qml/IconControl.qml create mode 100644 interface/resources/qml/LoginDialog.qml create mode 100644 interface/resources/qml/Root.qml create mode 100644 interface/resources/qml/componentCreation.js create mode 100644 interface/resources/qml/hifiConstants.js delete mode 100644 interface/src/ui/FramelessDialog.cpp delete mode 100644 interface/src/ui/FramelessDialog.h create mode 100644 libraries/render-utils/src/FboCache.cpp create mode 100644 libraries/render-utils/src/FboCache.h create mode 100644 libraries/render-utils/src/OffscreenGlCanvas.cpp create mode 100644 libraries/render-utils/src/OffscreenGlCanvas.h create mode 100644 libraries/render-utils/src/OffscreenUi.cpp create mode 100644 libraries/render-utils/src/OffscreenUi.h create mode 100644 libraries/shared/src/ThreadHelpers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 81d532fbe2..d27774e169 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,8 +92,17 @@ else () if (NOT QT_CMAKE_PREFIX_PATH) set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) endif () + if (NOT QT_CMAKE_PREFIX_PATH) + get_filename_component(QT_CMAKE_PREFIX_PATH "${Qt5_DIR}/.." REALPATH) + endif () endif () +if (WIN32) + if (NOT EXISTS ${QT_CMAKE_PREFIX_PATH}) + message(FATAL_ERROR "Could not determine QT_CMAKE_PREFIX_PATH.") + endif () +endif() + # figure out where the qt dir is get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index f4f390607b..5d2fe5ae38 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -54,7 +54,7 @@ else () list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP}) endif () -find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Script Svg WebKitWidgets) +find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Qml Quick Script Svg WebKitWidgets) # grab the ui files in resources/ui file (GLOB_RECURSE QT_UI_FILES ui/*.ui) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml new file mode 100644 index 0000000000..df06fabbe6 --- /dev/null +++ b/interface/resources/qml/AddressBarDialog.qml @@ -0,0 +1,84 @@ +import Hifi 1.0 +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Controls.Styles 1.3 + +AddressBarDialog { + id: addressBarDialog + objectName: "AddressBarDialog" + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + height: 128 + width: 512 + + onVisibleChanged: { + if (!visible) { + reset(); + } else { + addressLine.focus = true + addressLine.forceActiveFocus() + } + } + + Component.onCompleted: { + addressLine.focus = true + addressLine.forceActiveFocus() + } + + function reset() { + addressLine.text = "" + goButton.source = "../images/address-bar-submit.svg" + } + + CustomDialog { + id: dialog + anchors.fill: parent + title: "Go to..." + + // The client area + Item { + id: item1 + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + + CustomBorder { + height: 64 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: goButton.left + anchors.rightMargin: 8 + anchors.verticalCenter: parent.verticalCenter + CustomTextInput { + id: addressLine + anchors.fill: parent + helperText: "domain, location, @user, /x,y,z" + anchors.margins: 8 + onAccepted: { + addressBarDialog.loadAddress(addressLine.text) + } + } + } + + Image { + id: goButton + width: 32 + height: 32 + anchors.right: parent.right + anchors.rightMargin: 8 + source: "../images/address-bar-submit.svg" + anchors.verticalCenter: parent.verticalCenter + + MouseArea { + anchors.fill: parent + onClicked: { + parent.source = "../images/address-bar-submit-active.svg" + addressBarDialog.loadAddress(addressLine.text) + } + } + } + + } + } +} + diff --git a/interface/resources/qml/CustomBorder.qml b/interface/resources/qml/CustomBorder.qml new file mode 100644 index 0000000000..1bb30d1ebc --- /dev/null +++ b/interface/resources/qml/CustomBorder.qml @@ -0,0 +1,12 @@ +import QtQuick 2.3 + + +Rectangle { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + property int margin: 5 + color: myPalette.window + border.color: myPalette.dark + border.width: 5 + radius: border.width * 2 +} + diff --git a/interface/resources/qml/CustomButton.qml b/interface/resources/qml/CustomButton.qml new file mode 100644 index 0000000000..ce57d7ce5e --- /dev/null +++ b/interface/resources/qml/CustomButton.qml @@ -0,0 +1,23 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 +import QtQuick.Window 2.2 +import QtQuick.Controls.Styles 1.3 + +Button { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + text: "Text" + width: 128 + height: 64 + style: ButtonStyle { + background: CustomBorder { + anchors.fill: parent + } + label: CustomText { + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.text + color: control.enabled ? myPalette.text : myPalette.dark + } + } +} diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/CustomDialog.qml new file mode 100644 index 0000000000..71f36b4108 --- /dev/null +++ b/interface/resources/qml/CustomDialog.qml @@ -0,0 +1,98 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 +import "hifiConstants.js" as HifiConstants + +Item { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + + id: dialog + width: 256 + height: 256 + property rect clientArea: clientBorder + property int topMargin: dialog.height - clientBorder.height + 8 + property int margins: 8 + property string title + property int titleSize: titleBorder.height + 12 + property string frameColor: HifiConstants.color + property string backgroundColor: myPalette.window + property string headerBackgroundColor: myPalette.dark + + CustomBorder { + id: windowBorder + anchors.fill: parent + border.color: dialog.frameColor + color: dialog.backgroundColor + + CustomBorder { + id: titleBorder + height: 48 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + border.color: dialog.frameColor + color: dialog.headerBackgroundColor + + CustomText { + id: titleText + color: "white" + text: dialog.title + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + } + + MouseArea { + id: titleDrag + property int startX + property int startY + anchors.right: closeButton.left + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.top: parent.top + anchors.rightMargin: 4 + drag { + target: dialog.parent + minimumX: 0 + minimumY: 0 + maximumX: dialog.parent.parent.width - dialog.parent.width + maximumY: dialog.parent.parent.height - dialog.parent.height + } + } + Image { + id: closeButton + x: 360 + height: 16 + anchors.verticalCenter: parent.verticalCenter + width: 16 + anchors.right: parent.right + anchors.rightMargin: 12 + source: "../styles/close.svg" + MouseArea { + anchors.fill: parent + onClicked: { + dialog.parent.destroy() + } + } + } + + } // header border + + CustomBorder { + id: clientBorder + border.color: dialog.frameColor + color: "#00000000" + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: titleBorder.bottom + anchors.topMargin: -titleBorder.border.width + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + } // client border + } // window border +} diff --git a/interface/resources/qml/CustomText.qml b/interface/resources/qml/CustomText.qml new file mode 100644 index 0000000000..83229b783e --- /dev/null +++ b/interface/resources/qml/CustomText.qml @@ -0,0 +1,7 @@ +import QtQuick 2.3 + +Text { + font.family: "Helvetica" + font.pointSize: 18 +} + diff --git a/interface/resources/qml/CustomTextArea.qml b/interface/resources/qml/CustomTextArea.qml new file mode 100644 index 0000000000..cf3308e2b7 --- /dev/null +++ b/interface/resources/qml/CustomTextArea.qml @@ -0,0 +1,10 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +TextArea { + font.family: "Helvetica" + font.pointSize: 18 + backgroundVisible: false + readOnly: true +} + diff --git a/interface/resources/qml/CustomTextEdit.qml b/interface/resources/qml/CustomTextEdit.qml new file mode 100644 index 0000000000..0602bbc150 --- /dev/null +++ b/interface/resources/qml/CustomTextEdit.qml @@ -0,0 +1,7 @@ +import QtQuick 2.3 + +TextEdit { + font.family: "Helvetica" + font.pointSize: 18 +} + diff --git a/interface/resources/qml/CustomTextInput.qml b/interface/resources/qml/CustomTextInput.qml new file mode 100644 index 0000000000..a706187376 --- /dev/null +++ b/interface/resources/qml/CustomTextInput.qml @@ -0,0 +1,34 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +TextInput { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + property string helperText: "" + font.family: "Helvetica" + font.pointSize: 18 + width: 256 + height: 64 + color: myPalette.text + clip: true + verticalAlignment: TextInput.AlignVCenter + + onTextChanged: { + if (text == "") { + helperText.visible = true; + } else { + helperText.visible = false; + } + } + + Text { + id: helperText + anchors.fill: parent + font.pointSize: parent.font.pointSize + font.family: "Helvetica" + verticalAlignment: TextInput.AlignVCenter + text: parent.helperText + color: myPalette.dark + clip: true + } +} + diff --git a/interface/resources/qml/Icon.qml b/interface/resources/qml/Icon.qml new file mode 100644 index 0000000000..0d60afb2b7 --- /dev/null +++ b/interface/resources/qml/Icon.qml @@ -0,0 +1,8 @@ +import QtQuick 1.0 + +Image { +id: icon +width: 64 +height: 64 +source: "file.svg" +} \ No newline at end of file diff --git a/interface/resources/qml/IconControl.qml b/interface/resources/qml/IconControl.qml new file mode 100644 index 0000000000..346865aacb --- /dev/null +++ b/interface/resources/qml/IconControl.qml @@ -0,0 +1,24 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 +import QtQuick.Window 2.2 +import QtQuick.Controls.Styles 1.3 + +Button { + text: "Text" + style: ButtonStyle { + background: Item { anchors.fill: parent } + label: Text { + id: icon + width: height + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + font.family: iconFont.name + font.pointSize: 18 + property alias unicode: icon.text + FontLoader { id: iconFont; source: "/fonts/fontawesome-webfont.ttf"; } + text: control.text + color: control.enabled ? "white" : "dimgray" + } + } +} + diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml new file mode 100644 index 0000000000..c306f4ed7e --- /dev/null +++ b/interface/resources/qml/LoginDialog.qml @@ -0,0 +1,191 @@ +import Hifi 1.0 +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Controls.Styles 1.3 +import "hifiConstants.js" as HifiConstants + +LoginDialog { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + id: loginDialog + objectName: "LoginDialog" + height: 512 + width: 384 + + onVisibleChanged: { + if (!visible) { + reset() + } else { + username.forceActiveFocus() + } + } + + function reset() { + username.text = "" + password.text = "" + loginDialog.statusText = "" + } + + CustomDialog { + anchors.fill: parent + title: "Login" + Item { + id: item1 + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + Column { + anchors.topMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.top: parent.top + spacing: 8 + + Image { + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + width: 64 + source: "../images/hifi-logo.svg" + } + + CustomBorder { + width: 304 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + CustomTextInput { + id: username + anchors.fill: parent + helperText: "Username or Email" + anchors.margins: 8 + KeyNavigation.tab: password + KeyNavigation.backtab: password + onAccepted: { + password.forceActiveFocus() + } + } + } + + CustomBorder { + width: 304 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + CustomTextInput { + id: password + anchors.fill: parent + echoMode: TextInput.Password + helperText: "Password" + anchors.margins: 8 + KeyNavigation.tab: username + KeyNavigation.backtab: username + onAccepted: { + if (username.text == "") { + username.forceActiveFocus() + } else { + loginDialog.login(username.text, password.text) + } + } + onFocusChanged: { + if (password.focus) { + password.selectAll() + } + } + } + } + + CustomText { + anchors.horizontalCenter: parent.horizontalCenter + textFormat: Text.StyledText + width: parent.width + height: 96 + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: loginDialog.statusText + } + } + + Column { + anchors.bottomMargin: 5 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.bottom: parent.bottom + + Rectangle { + width: 192 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + color: HifiConstants.color + border.width: 0 + radius: 10 + + MouseArea { + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + onClicked: { + loginDialog.login(username.text, password.text) + } + } + + Row { + anchors.centerIn: parent + anchors.verticalCenter: parent.verticalCenter + spacing: 8 + Image { + id: loginIcon + height: 32 + width: 32 + source: "../images/login.svg" + } + CustomText { + text: "Login" + color: "white" + width: 64 + height: parent.height + } + } + + } + + CustomText { + width: parent.width + height: 24 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text:"Create Account" + font.pointSize: 12 + font.bold: true + color: HifiConstants.color + + MouseArea { + anchors.fill: parent + onClicked: { + loginDialog.openUrl(loginDialog.rootUrl + "/signup") + } + } + } + + CustomText { + width: parent.width + height: 24 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.pointSize: 12 + text: "Recover Password" + color: HifiConstants.color + + MouseArea { + anchors.fill: parent + onClicked: { + loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new") + } + } + } + } + } + } +} diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml new file mode 100644 index 0000000000..f290a8b5ca --- /dev/null +++ b/interface/resources/qml/Root.qml @@ -0,0 +1,14 @@ +import QtQuick 2.3 +import "componentCreation.js" as Creator + + +Item { + id: root + width: 1280 + height: 720 + + function loadChild(url) { + Creator.createObject(root, url) + } +} + diff --git a/interface/resources/qml/componentCreation.js b/interface/resources/qml/componentCreation.js new file mode 100644 index 0000000000..6e6469adfb --- /dev/null +++ b/interface/resources/qml/componentCreation.js @@ -0,0 +1,27 @@ +var component; +var instance; +var parent; + +function createObject(parentObject, url) { + parent = parentObject; + component = Qt.createComponent(url); + if (component.status == Component.Ready) + finishCreation(); + else + component.statusChanged.connect(finishCreation); +} + +function finishCreation() { + if (component.status == Component.Ready) { + instance = component.createObject(parent, {"x": 100, "y": 100}); + if (instance == null) { + // Error Handling + console.log("Error creating object"); + } else { + instance.focus = true; + } + } else if (component.status == Component.Error) { + // Error Handling + console.log("Error loading component:", component.errorString()); + } +} \ No newline at end of file diff --git a/interface/resources/qml/hifiConstants.js b/interface/resources/qml/hifiConstants.js new file mode 100644 index 0000000000..860226c963 --- /dev/null +++ b/interface/resources/qml/hifiConstants.js @@ -0,0 +1,4 @@ +var color = "#0e7077" +var Colors = { + hifiBlue: "#0e7077" +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 82447257fb..0766d45ff3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -137,6 +137,7 @@ #include "ui/Snapshot.h" #include "ui/StandAloneJSConsole.h" #include "ui/Stats.h" +#include "ui/AddressBarDialog.h" // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU #if defined(Q_OS_WIN) @@ -209,8 +210,12 @@ public: void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); - + if (!logMessage.isEmpty()) { +#ifdef Q_OS_WIN + OutputDebugStringA(logMessage.toLocal8Bit().constData()); + OutputDebugStringA("\n"); +#endif Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage + "\n")); } } @@ -260,6 +265,7 @@ bool setupEssentials(int& argc, char** argv) { #endif auto discoverabilityManager = DependencyManager::set(); auto sceneScriptingInterface = DependencyManager::set(); + auto offscreenUi = DependencyManager::set(); return true; } @@ -316,8 +322,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : #ifdef Q_OS_WIN installNativeEventFilter(&MyNativeEventFilter::getInstance()); #endif + _logger = new FileLogger(this); // After setting organization name in order to get correct directory + qInstallMessageHandler(messageHandler); QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf"); @@ -562,8 +570,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : #endif this->installEventFilter(this); + // The offscreen UI needs to intercept the mouse and keyboard + // events coming from the onscreen window + _glWidget->installEventFilter( + DependencyManager::get().data()); } + void Application::aboutToQuit() { emit beforeAboutToQuit(); @@ -720,10 +733,35 @@ void Application::initializeGL() { // update before the first render update(1.0f / _fps); + + // The UI can't be created until the primary OpenGL + // context is created, because it needs to share + // texture resources + initializeUi(); InfoView::showFirstTime(INFO_HELP_PATH); } +void Application::initializeUi() { + AddressBarDialog::registerType(); + LoginDialog::registerType(); + + auto offscreenUi = DependencyManager::get(); + offscreenUi->create(_glWidget->context()->contextHandle()); + offscreenUi->resize(_glWidget->size()); + offscreenUi->setProxyWindow(_window->windowHandle()); + auto rootQml = PathUtils::resourcesPath() + "qml/Root.qml"; + offscreenUi->loadQml(QUrl::fromLocalFile(rootQml)); + offscreenUi->setMouseTranslator([this](const QPointF& p){ + if (OculusManager::isConnected()) { + glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p)); + return QPointF(pos.x, pos.y); + } + return QPointF(p); + }); + offscreenUi->resume(); +} + void Application::paintGL() { PROFILE_RANGE(__FUNCTION__); PerformanceTimer perfTimer("paintGL"); @@ -818,7 +856,7 @@ void Application::paintGL() { { PerformanceTimer perfTimer("renderOverlay"); - _applicationOverlay.renderOverlay(true); + _applicationOverlay.renderOverlay(); _applicationOverlay.displayOverlayTexture(); } } @@ -863,6 +901,9 @@ void Application::resizeGL(int width, int height) { updateProjectionMatrix(); glLoadIdentity(); + auto offscreenUi = DependencyManager::get(); + offscreenUi->resize(QSize(width, height)); + // update Stats width // let's set horizontal offset to give stats some margin to mirror int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; @@ -911,6 +952,44 @@ bool Application::importSVOFromURL(const QString& urlString) { } bool Application::event(QEvent* event) { + switch (event->type()) { + case QEvent::MouseMove: + mouseMoveEvent((QMouseEvent*)event); + return true; + case QEvent::MouseButtonPress: + mousePressEvent((QMouseEvent*)event); + return true; + case QEvent::MouseButtonRelease: + mouseReleaseEvent((QMouseEvent*)event); + return true; + case QEvent::KeyPress: + keyPressEvent((QKeyEvent*)event); + return true; + case QEvent::KeyRelease: + keyReleaseEvent((QKeyEvent*)event); + return true; + case QEvent::FocusOut: + focusOutEvent((QFocusEvent*)event); + return true; + case QEvent::TouchBegin: + touchBeginEvent(static_cast(event)); + event->accept(); + return true; + case QEvent::TouchEnd: + touchEndEvent(static_cast(event)); + return true; + case QEvent::TouchUpdate: + touchUpdateEvent(static_cast(event)); + return true; + case QEvent::Wheel: + wheelEvent(static_cast(event)); + return true; + case QEvent::Drop: + dropEvent(static_cast(event)); + return true; + default: + break; + } // handle custom URL if (event->type() == QEvent::FileOpen) { @@ -931,7 +1010,7 @@ bool Application::event(QEvent* event) { if (HFActionEvent::types().contains(event->type())) { _controllerScriptingInterface.handleMetaEvent(static_cast(event)); } - + return QApplication::event(event); } @@ -963,14 +1042,17 @@ void Application::keyPressEvent(QKeyEvent* event) { bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); bool isOption = event->modifiers().testFlag(Qt::AltModifier); + bool isKeypad = event->modifiers().testFlag(Qt::KeypadModifier); switch (event->key()) { break; case Qt::Key_L: - if (isShifted) { - Menu::getInstance()->triggerOption(MenuOption::LodTools); - } else if (isMeta) { + if (isShifted && isMeta) { Menu::getInstance()->triggerOption(MenuOption::Log); - } + } else if (isMeta) { + Menu::getInstance()->triggerOption(MenuOption::AddressBar); + } else if (isShifted) { + Menu::getInstance()->triggerOption(MenuOption::LodTools); + } break; case Qt::Key_E: @@ -1030,11 +1112,6 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; - case Qt::Key_Return: - case Qt::Key_Enter: - Menu::getInstance()->triggerOption(MenuOption::AddressBar); - break; - case Qt::Key_Backslash: Menu::getInstance()->triggerOption(MenuOption::Chat); break; @@ -1494,6 +1571,17 @@ void Application::dropEvent(QDropEvent *event) { } } +void Application::dragEnterEvent(QDragEnterEvent* event) { + const QMimeData* mimeData = event->mimeData(); + foreach(QUrl url, mimeData->urls()) { + auto urlString = url.toString(); + if (canAcceptURL(urlString)) { + event->acceptProposedAction(); + break; + } + } +} + bool Application::acceptSnapshot(const QString& urlString) { QUrl url(urlString); QString snapshotPath = url.toLocalFile(); diff --git a/interface/src/Application.h b/interface/src/Application.h index cf047f02d4..57c6530ad4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -151,6 +152,7 @@ public: void setPreviousScriptLocation(const QString& previousScriptLocation); void clearScriptsBeforeRunning(); void initializeGL(); + void initializeUi(); void paintGL(); void resizeGL(int width, int height); @@ -170,6 +172,7 @@ public: void wheelEvent(QWheelEvent* event); void dropEvent(QDropEvent *event); + void dragEnterEvent(QDragEnterEvent *event); bool event(QEvent* event); bool eventFilter(QObject* object, QEvent* event); diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 12a10681ce..d0c0cb6713 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -82,30 +82,6 @@ void GLCanvas::resizeGL(int width, int height) { Application::getInstance()->resizeGL(width, height); } -void GLCanvas::keyPressEvent(QKeyEvent* event) { - Application::getInstance()->keyPressEvent(event); -} - -void GLCanvas::keyReleaseEvent(QKeyEvent* event) { - Application::getInstance()->keyReleaseEvent(event); -} - -void GLCanvas::focusOutEvent(QFocusEvent* event) { - Application::getInstance()->focusOutEvent(event); -} - -void GLCanvas::mouseMoveEvent(QMouseEvent* event) { - Application::getInstance()->mouseMoveEvent(event); -} - -void GLCanvas::mousePressEvent(QMouseEvent* event) { - Application::getInstance()->mousePressEvent(event); -} - -void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { - Application::getInstance()->mouseReleaseEvent(event); -} - void GLCanvas::activeChanged(Qt::ApplicationState state) { switch (state) { case Qt::ApplicationActive: @@ -151,40 +127,37 @@ void GLCanvas::throttleRender() { int updateTime = 0; bool GLCanvas::event(QEvent* event) { switch (event->type()) { + case QEvent::MouseMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::FocusIn: + case QEvent::FocusOut: + case QEvent::Resize: case QEvent::TouchBegin: - Application::getInstance()->touchBeginEvent(static_cast(event)); - event->accept(); - return true; case QEvent::TouchEnd: - Application::getInstance()->touchEndEvent(static_cast(event)); - return true; case QEvent::TouchUpdate: - Application::getInstance()->touchUpdateEvent(static_cast(event)); - return true; + case QEvent::Wheel: + case QEvent::DragEnter: + case QEvent::Drop: + if (QCoreApplication::sendEvent(QCoreApplication::instance(), event)) { + return true; + } + break; + case QEvent::Paint: + // Ignore paint events that occur after we've decided to quit + if (Application::getInstance()->isAboutToQuit()) { + return true; + } + break; + default: break; } return QGLWidget::event(event); } -void GLCanvas::wheelEvent(QWheelEvent* event) { - Application::getInstance()->wheelEvent(event); -} - -void GLCanvas::dragEnterEvent(QDragEnterEvent* event) { - const QMimeData* mimeData = event->mimeData(); - foreach (QUrl url, mimeData->urls()) { - auto urlString = url.toString(); - if (Application::getInstance()->canAcceptURL(urlString)) { - event->acceptProposedAction(); - break; - } - } -} - -void GLCanvas::dropEvent(QDropEvent* event) { - Application::getInstance()->dropEvent(event); -} // Pressing Alt (and Meta) key alone activates the menubar because its style inherits the // SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 7b86f983e9..6c53a17e04 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -40,23 +40,8 @@ protected: virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL(int width, int height); - - virtual void keyPressEvent(QKeyEvent* event); - virtual void keyReleaseEvent(QKeyEvent* event); - - virtual void focusOutEvent(QFocusEvent* event); - - virtual void mouseMoveEvent(QMouseEvent* event); - virtual void mousePressEvent(QMouseEvent* event); - virtual void mouseReleaseEvent(QMouseEvent* event); - virtual bool event(QEvent* event); - virtual void wheelEvent(QWheelEvent* event); - - virtual void dragEnterEvent(QDragEnterEvent *event); - virtual void dropEvent(QDropEvent* event); - private slots: void activeChanged(Qt::ApplicationState state); void throttleRender(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 1cce0b1f56..64e5accb1b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -97,7 +97,7 @@ Menu::Menu() { addActionToQMenuAndActionHash(fileMenu, MenuOption::AddressBar, - Qt::Key_Enter, + Qt::CTRL | Qt::Key_L, dialogsManager.data(), SLOT(toggleAddressBar())); auto addressManager = DependencyManager::get(); @@ -151,7 +151,8 @@ Menu::Menu() { connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool))); #endif - addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, Qt::Key_Backslash, + addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, + 0, // QML Qt::Key_Backslash, dialogsManager.data(), SLOT(showIRCLink())); addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0, qApp, SLOT(showFriendsWindow())); @@ -194,7 +195,7 @@ Menu::Menu() { addActionToQMenuAndActionHash(toolsMenu, MenuOption::ResetSensors, - Qt::Key_Apostrophe, + 0, // QML Qt::Key_Apostrophe, qApp, SLOT(resetSensors())); @@ -207,17 +208,17 @@ Menu::Menu() { QMenu* avatarSizeMenu = avatarMenu->addMenu("Size"); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::IncreaseAvatarSize, - Qt::Key_Plus, + 0, // QML Qt::Key_Plus, avatar, SLOT(increaseSize())); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::DecreaseAvatarSize, - Qt::Key_Minus, + 0, // QML Qt::Key_Minus, avatar, SLOT(decreaseSize())); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::ResetAvatarSize, - Qt::Key_Equal, + 0, // QML Qt::Key_Equal, avatar, SLOT(resetSize())); @@ -250,13 +251,17 @@ Menu::Menu() { qApp, SLOT(setFullscreen(bool))); #endif - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true, - qApp,SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, - qApp, SLOT(cameraMenuChanged())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, + 0, // QML Qt::Key_P, + true, qApp, SLOT(cameraMenuChanged())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, + 0, //QML Qt::SHIFT | Qt::Key_H, + true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, + 0, // QML Qt::Key_H, + false, qApp, SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H, + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::CTRL | Qt::SHIFT | Qt::Key_H, false, dialogsManager.data(), SLOT(hmdTools(bool))); @@ -283,8 +288,12 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash); - addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, qApp, SLOT(toggleLogDialog())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, + 0); // QML Qt::Key_Slash); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats); + addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, + Qt::CTRL | Qt::SHIFT | Qt::Key_L, + qApp, SLOT(toggleLogDialog())); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, dialogsManager.data(), SLOT(bandwidthDetails())); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, @@ -294,7 +303,9 @@ Menu::Menu() { QMenu* developerMenu = addMenu("Developer"); QMenu* renderOptionsMenu = developerMenu->addMenu("Render"); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, + 0, // QML Qt::SHIFT | Qt::Key_A, + true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges); @@ -346,13 +357,16 @@ Menu::Menu() { resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false)); resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false)); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, + 0, // QML Qt::Key_Asterisk, + true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true, DependencyManager::get().data(), SLOT(toggleGlowEffect(bool))); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Wireframe, Qt::ALT | Qt::Key_W, false); - addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, - dialogsManager.data(), SLOT(lodTools())); + addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, + 0, // QML Qt::SHIFT | Qt::Key_L, + dialogsManager.data(), SLOT(lodTools())); QMenu* avatarDebugMenu = developerMenu->addMenu("Avatar"); diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index d56ece12fb..a309831c14 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -114,8 +114,11 @@ void OculusManager::initSdk() { } void OculusManager::shutdownSdk() { - ovrHmd_Destroy(_ovrHmd); - ovr_Shutdown(); + if (_ovrHmd) { + ovrHmd_Destroy(_ovrHmd); + _ovrHmd = nullptr; + ovr_Shutdown(); + } } void OculusManager::init() { @@ -124,6 +127,12 @@ void OculusManager::init() { #endif } +void OculusManager::deinit() { +#ifdef OVR_DIRECT_MODE + shutdownSdk(); +#endif +} + void OculusManager::connect() { #ifndef OVR_DIRECT_MODE initSdk(); @@ -515,7 +524,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p // We only need to render the overlays to a texture once, then we just render the texture on the hemisphere // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() - applicationOverlay.renderOverlay(true); + applicationOverlay.renderOverlay(); //Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index fe2da31231..4b1bc98fb2 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -51,6 +51,7 @@ class Text3DOverlay; class OculusManager { public: static void init(); + static void deinit(); static void connect(); static void disconnect(); static bool isConnected(); diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index f082c6de47..4f6e566d8c 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -103,7 +103,7 @@ void TV3DManager::display(Camera& whichCamera) { // We only need to render the overlays to a texture once, then we just render the texture as a quad // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() - applicationOverlay.renderOverlay(true); + applicationOverlay.renderOverlay(); DependencyManager::get()->prepare(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index b4486ceb2b..7d80b077b8 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -112,6 +112,7 @@ int main(int argc, const char* argv[]) { exitCode = app.exec(); } + OculusManager::deinit(); #ifdef Q_OS_WIN ReleaseMutex(mutex); #endif diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index b414f95240..49158265ba 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -1,148 +1,50 @@ // // AddressBarDialog.cpp -// interface/src/ui // -// Created by Stojce Slavkovski on 9/22/14. -// Copyright 2014 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 "AddressBarDialog.h" + #include -#include - -#include "AddressBarDialog.h" +#include "DependencyManager.h" #include "AddressManager.h" -#include "Application.h" -#include "MainWindow.h" -const QString ADDRESSBAR_GO_BUTTON_ICON = "images/address-bar-submit.svg"; -const QString ADDRESSBAR_GO_BUTTON_ACTIVE_ICON = "images/address-bar-submit-active.svg"; +QML_DIALOG_DEF(AddressBarDialog) -AddressBarDialog::AddressBarDialog(QWidget* parent) : - FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP) -{ - setAttribute(Qt::WA_DeleteOnClose, false); - setupUI(); - +AddressBarDialog::AddressBarDialog(QQuickItem *parent) : QQuickItem(parent) { auto addressManager = DependencyManager::get(); - connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage); connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage); + connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide); } -void AddressBarDialog::setupUI() { - - const QString DIALOG_STYLESHEET = "font-family: Helvetica, Arial, sans-serif;"; - const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, location, @user, /x,y,z"; - const QString ADDRESSBAR_STYLESHEET = "padding: 5px 10px; font-size: 20px;"; - - const int ADDRESSBAR_MIN_WIDTH = 200; - const int ADDRESSBAR_MAX_WIDTH = 615; - const int ADDRESSBAR_HEIGHT = 42; - const int ADDRESSBAR_STRETCH = 60; - - const int BUTTON_SPACER_SIZE = 5; - const int DEFAULT_SPACER_SIZE = 20; - const int ADDRESS_LAYOUT_RIGHT_MARGIN = 10; - - const int GO_BUTTON_SIZE = 42; - const int CLOSE_BUTTON_SIZE = 16; - const QString CLOSE_BUTTON_ICON = "styles/close.svg"; - - const int DIALOG_HEIGHT = 62; - const int DIALOG_INITIAL_WIDTH = 560; - - QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - setSizePolicy(sizePolicy); - setMinimumSize(QSize(DIALOG_INITIAL_WIDTH, DIALOG_HEIGHT)); - setMaximumHeight(DIALOG_HEIGHT); - setStyleSheet(DIALOG_STYLESHEET); - _verticalLayout = new QVBoxLayout(this); - _verticalLayout->setContentsMargins(0, 0, 0, 0); - - _addressLayout = new QHBoxLayout(); - _addressLayout->setContentsMargins(0, 0, ADDRESS_LAYOUT_RIGHT_MARGIN, 0); - - _leftSpacer = new QSpacerItem(DEFAULT_SPACER_SIZE, - DEFAULT_SPACER_SIZE, - QSizePolicy::MinimumExpanding, - QSizePolicy::Minimum); - - _addressLayout->addItem(_leftSpacer); - - _addressLineEdit = new QLineEdit(this); - _addressLineEdit->setAttribute(Qt::WA_MacShowFocusRect, 0); - _addressLineEdit->setPlaceholderText(ADDRESSBAR_PLACEHOLDER); - QSizePolicy sizePolicyLineEdit(QSizePolicy::Preferred, QSizePolicy::Fixed); - sizePolicyLineEdit.setHorizontalStretch(ADDRESSBAR_STRETCH); - _addressLineEdit->setSizePolicy(sizePolicyLineEdit); - _addressLineEdit->setMinimumSize(QSize(ADDRESSBAR_MIN_WIDTH, ADDRESSBAR_HEIGHT)); - _addressLineEdit->setMaximumSize(QSize(ADDRESSBAR_MAX_WIDTH, ADDRESSBAR_HEIGHT)); - _addressLineEdit->setStyleSheet(ADDRESSBAR_STYLESHEET); - _addressLayout->addWidget(_addressLineEdit); - - _buttonSpacer = new QSpacerItem(BUTTON_SPACER_SIZE, BUTTON_SPACER_SIZE, QSizePolicy::Fixed, QSizePolicy::Minimum); - _addressLayout->addItem(_buttonSpacer); - - _goButton = new QPushButton(this); - _goButton->setSizePolicy(sizePolicy); - _goButton->setMinimumSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE)); - _goButton->setMaximumSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE)); - _goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ICON)); - _goButton->setIconSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE)); - _goButton->setDefault(true); - _goButton->setFlat(true); - _addressLayout->addWidget(_goButton); - - _rightSpacer = new QSpacerItem(DEFAULT_SPACER_SIZE, - DEFAULT_SPACER_SIZE, - QSizePolicy::MinimumExpanding, - QSizePolicy::Minimum); - - _addressLayout->addItem(_rightSpacer); - - _closeButton = new QPushButton(this); - _closeButton->setSizePolicy(sizePolicy); - _closeButton->setMinimumSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE)); - _closeButton->setMaximumSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE)); - QIcon icon(PathUtils::resourcesPath() + CLOSE_BUTTON_ICON); - _closeButton->setIcon(icon); - _closeButton->setIconSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE)); - _closeButton->setFlat(true); - _addressLayout->addWidget(_closeButton, 0, Qt::AlignRight); - - _verticalLayout->addLayout(_addressLayout); - - connect(_goButton, &QPushButton::clicked, this, &AddressBarDialog::accept); - connect(_closeButton, &QPushButton::clicked, this, &QDialog::close); +void AddressBarDialog::hide() { + setEnabled(false); + setVisible(false); } -void AddressBarDialog::showEvent(QShowEvent* event) { - _goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ICON)); - _addressLineEdit->setText(QString()); - _addressLineEdit->setFocus(); - FramelessDialog::showEvent(event); -} - -void AddressBarDialog::accept() { - if (!_addressLineEdit->text().isEmpty()) { - _goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ACTIVE_ICON)); - auto addressManager = DependencyManager::get(); - connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &QDialog::hide); - addressManager->handleLookupString(_addressLineEdit->text()); +void AddressBarDialog::loadAddress(const QString & address) { + qDebug() << "Called LoadAddress with address " << address; + if (!address.isEmpty()) { + DependencyManager::get()->handleLookupString(address); } } +// TODO port to a QML based message box void AddressBarDialog::displayAddressOfflineMessage() { - QMessageBox::information(Application::getInstance()->getWindow(), "Address offline", - "That user or place is currently offline."); + QMessageBox::information(nullptr, "Address offline", + "That user or place is currently offline."); } +// TODO port to a QML based message box void AddressBarDialog::displayAddressNotFoundMessage() { - QMessageBox::information(Application::getInstance()->getWindow(), "Address not found", - "There is no address information for that user or place."); -} \ No newline at end of file + QMessageBox::information(nullptr, "Address not found", + "There is no address information for that user or place."); +} diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index dda807d6e2..00e55ceb10 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -1,9 +1,8 @@ // // AddressBarDialog.h -// interface/src/ui // -// Created by Stojce Slavkovski on 9/22/14. -// Copyright 2014 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 @@ -12,36 +11,25 @@ #ifndef hifi_AddressBarDialog_h #define hifi_AddressBarDialog_h -#include "FramelessDialog.h" +#pragma once +#include -#include -#include -#include -#include +#include "OffscreenUi.h" -class AddressBarDialog : public FramelessDialog { +class AddressBarDialog : public QQuickItem +{ Q_OBJECT + QML_DIALOG_DECL public: - AddressBarDialog(QWidget* parent); - -private: - void setupUI(); - void showEvent(QShowEvent* event); - - QVBoxLayout *_verticalLayout; - QHBoxLayout *_addressLayout; - QSpacerItem *_leftSpacer; - QSpacerItem *_rightSpacer; - QSpacerItem *_buttonSpacer; - QPushButton *_goButton; - QPushButton *_closeButton; - QLineEdit *_addressLineEdit; - -private slots: - void accept(); + AddressBarDialog(QQuickItem *parent = 0); + +protected: void displayAddressOfflineMessage(); void displayAddressNotFoundMessage(); + void hide(); + + Q_INVOKABLE void loadAddress(const QString & address); }; -#endif // hifi_AddressBarDialog_h +#endif diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index f08df229cc..5583790b13 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "AudioClient.h" #include "audio/AudioIOStatsRenderer.h" @@ -161,13 +162,27 @@ ApplicationOverlay::ApplicationOverlay() : _domainStatusBorder = geometryCache->allocateID(); _magnifierBorder = geometryCache->allocateID(); + // Once we move UI rendering and screen rendering to different + // threads, we need to use a sync object to deteremine when + // the current UI texture is no longer being read from, and only + // then release it back to the UI for re-use + auto offscreenUi = DependencyManager::get(); + connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) { + auto offscreenUi = DependencyManager::get(); + offscreenUi->lockTexture(textureId); + assert(!glGetError()); + std::swap(_newUiTexture, textureId); + if (textureId) { + offscreenUi->releaseTexture(textureId); + } + }); } ApplicationOverlay::~ApplicationOverlay() { } // Renders the overlays either to a texture or to the screen -void ApplicationOverlay::renderOverlay(bool renderToTexture) { +void ApplicationOverlay::renderOverlay() { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); Overlays& overlays = qApp->getOverlays(); auto glCanvas = Application::getInstance()->getGLWidget(); @@ -183,11 +198,9 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { glDisable(GL_LIGHTING); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if (renderToTexture) { - _overlays.buildFramebufferObject(); - _overlays.bind(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } + _overlays.buildFramebufferObject(); + _overlays.bind(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); { const float NEAR_CLIP = -10000; @@ -218,9 +231,25 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { glEnable(GL_LIGHTING); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - if (renderToTexture) { - _overlays.release(); + _overlays.release(); +} + +// A quick and dirty solution for compositing the old overlay +// texture with the new one +template +void with_each_texture(GLuint a, GLuint b, F f) { + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + if (a) { + glBindTexture(GL_TEXTURE_2D, a); + f(); } + if (b) { + glBindTexture(GL_TEXTURE_2D, b); + f(); + } + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); } // Draws the FBO texture for the screen @@ -229,30 +258,24 @@ void ApplicationOverlay::displayOverlayTexture() { return; } auto glCanvas = Application::getInstance()->getGLWidget(); - - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - _overlays.bindTexture(); - glMatrixMode(GL_PROJECTION); glPushMatrix(); { glLoadIdentity(); - glOrtho(0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight(), 0, -1.0, 1.0); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); - glEnable(GL_BLEND); - - glm::vec2 topLeft(0.0f, 0.0f); - glm::vec2 bottomRight(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); - glm::vec2 texCoordTopLeft(0.0f, 1.0f); - glm::vec2 texCoordBottomRight(1.0f, 0.0f); + if (_alpha < 1.0) { + glEnable(GL_BLEND); + } - DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, - glm::vec4(1.0f, 1.0f, 1.0f, _alpha)); - + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { + static const glm::vec2 topLeft(-1, 1); + static const glm::vec2 bottomRight(1, -1); + static const glm::vec2 texCoordTopLeft(0.0f, 1.0f); + static const glm::vec2 texCoordBottomRight(1.0f, 0.0f); + DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, + glm::vec4(1.0f, 1.0f, 1.0f, _alpha)); + }); } glPopMatrix(); - - glDisable(GL_TEXTURE_2D); } // Draws the FBO texture for Oculus rift. @@ -260,10 +283,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { if (_alpha == 0.0f) { return; } - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - _overlays.bindTexture(); - + glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glEnable(GL_DEPTH_TEST); @@ -271,8 +291,8 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { glDisable(GL_LIGHTING); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.01f); - - + + //Update and draw the magnifiers MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); const glm::quat& orientation = myAvatar->getOrientation(); @@ -303,8 +323,9 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { //Render magnifier, but dont show border for mouse magnifier glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(), _reticlePosition[MOUSE].y())); - - renderMagnifier(projection, _magSizeMult[i], i != MOUSE); + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { + renderMagnifier(projection, _magSizeMult[i], i != MOUSE); + }); } } @@ -319,12 +340,15 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); } - _overlays.render(); + + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { + _overlays.render(); + }); + if (!Application::getInstance()->isMouseHidden()) { renderPointersOculus(myAvatar->getDefaultEyePosition()); } glDepthMask(GL_TRUE); - _overlays.releaseTexture(); glDisable(GL_TEXTURE_2D); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); @@ -341,14 +365,10 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); const glm::vec3& viewMatrixTranslation = qApp->getViewMatrixTranslation(); - glActiveTexture(GL_TEXTURE0); - glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - _overlays.bindTexture(); glEnable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); - glEnable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); @@ -382,13 +402,15 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as GLfloat y = -halfQuadHeight; glDisable(GL_DEPTH_TEST); - DependencyManager::get()->renderQuad(glm::vec3(x, y + quadHeight, -distance), + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { + DependencyManager::get()->renderQuad(glm::vec3(x, y + quadHeight, -distance), glm::vec3(x + quadWidth, y + quadHeight, -distance), glm::vec3(x + quadWidth, y, -distance), glm::vec3(x, y, -distance), glm::vec2(0.0f, 1.0f), glm::vec2(1.0f, 1.0f), glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f), overlayColor); + }); auto glCanvas = Application::getInstance()->getGLWidget(); if (_crosshairTexture == 0) { @@ -993,14 +1015,6 @@ void ApplicationOverlay::TexturedHemisphere::release() { _framebufferObject->release(); } -void ApplicationOverlay::TexturedHemisphere::bindTexture() { - glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture()); -} - -void ApplicationOverlay::TexturedHemisphere::releaseTexture() { - glBindTexture(GL_TEXTURE_2D, 0); -} - void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, const float aspectRatio, const int slices, @@ -1099,14 +1113,14 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { } _framebufferObject = new QOpenGLFramebufferObject(size, QOpenGLFramebufferObject::Depth); - bindTexture(); + glBindTexture(GL_TEXTURE_2D, getTexture()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - releaseTexture(); + glBindTexture(GL_TEXTURE_2D, 0); } //Renders a hemisphere with texture coordinates. @@ -1137,6 +1151,10 @@ void ApplicationOverlay::TexturedHemisphere::render() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } +GLuint ApplicationOverlay::TexturedHemisphere::getTexture() { + return _framebufferObject->texture(); +} + glm::vec2 ApplicationOverlay::directionToSpherical(glm::vec3 direction) const { glm::vec2 result; // Compute yaw diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index cc424d0c8f..cc4188e8ef 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -28,7 +28,7 @@ public: ApplicationOverlay(); ~ApplicationOverlay(); - void renderOverlay(bool renderToTexture = false); + void renderOverlay(); void displayOverlayTexture(); void displayOverlayTextureOculus(Camera& whichCamera); void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov); @@ -75,8 +75,7 @@ private: void bind(); void release(); - void bindTexture(); - void releaseTexture(); + GLuint getTexture(); void buildFramebufferObject(); void buildVBO(const float fov, const float aspectRatio, const int slices, const int stacks); @@ -122,6 +121,9 @@ private: float _trailingAudioLoudness; GLuint _crosshairTexture; + // TODO, move divide up the rendering, displaying and input handling + // facilities of this class + GLuint _newUiTexture{ 0 }; int _reticleQuad; int _magnifierQuad; diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 701ceb0189..3c54c26379 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DialogsManager.h" + #include #include @@ -28,14 +30,9 @@ #include "PreferencesDialog.h" #include "ScriptEditorWindow.h" -#include "DialogsManager.h" void DialogsManager::toggleAddressBar() { - maybeCreateDialog(_addressBarDialog); - - if (!_addressBarDialog->isVisible()) { - _addressBarDialog->show(); - } + AddressBarDialog::toggle(); } void DialogsManager::toggleDiskCacheEditor() { @@ -44,13 +41,11 @@ void DialogsManager::toggleDiskCacheEditor() { } void DialogsManager::toggleLoginDialog() { - maybeCreateDialog(_loginDialog); - _loginDialog->toggleQAction(); + LoginDialog::toggleAction(); } void DialogsManager::showLoginDialog() { - maybeCreateDialog(_loginDialog); - _loginDialog->showLoginForCurrentDomain(); + LoginDialog::show(); } void DialogsManager::octreeStatsDetails() { @@ -170,3 +165,4 @@ void DialogsManager::showIRCLink() { _ircInfoBox->raise(); } + diff --git a/interface/src/ui/FramelessDialog.cpp b/interface/src/ui/FramelessDialog.cpp deleted file mode 100644 index bae6217083..0000000000 --- a/interface/src/ui/FramelessDialog.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// -// FramelessDialog.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 "Application.h" -#include "FramelessDialog.h" -#include "Menu.h" - -const int RESIZE_HANDLE_WIDTH = 7; - -FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags, Position position) : - QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint), - _allowResize(true), - _isResizing(false), - _resizeInitialWidth(0), - _selfHidden(false), - _position(position), - _hideOnBlur(true) { - - setAttribute(Qt::WA_DeleteOnClose); - - // handle rezize and move events - parentWidget()->installEventFilter(this); - - // handle minimize, restore and focus events - Application::getInstance()->installEventFilter(this); -} - -bool FramelessDialog::eventFilter(QObject* sender, QEvent* event) { - switch (event->type()) { - case QEvent::Move: - if (sender == parentWidget()) { - resizeAndPosition(false); - } - break; - case QEvent::Resize: - if (sender == parentWidget()) { - resizeAndPosition(false); - } - break; - case QEvent::WindowStateChange: - if (_hideOnBlur && parentWidget()->isMinimized()) { - if (isVisible()) { - _selfHidden = true; - setHidden(true); - } - } else if (_selfHidden) { - _selfHidden = false; - setHidden(false); - } - break; - case QEvent::ApplicationDeactivate: - // hide on minimize and focus lost - if (_hideOnBlur && isVisible()) { - _selfHidden = true; - setHidden(true); - } - break; - case QEvent::ApplicationActivate: - if (_selfHidden) { - _selfHidden = false; - setHidden(false); - } - break; - default: - break; - } - - return false; -} - -void FramelessDialog::setStyleSheetFile(const QString& fileName) { - QFile globalStyleSheet(PathUtils::resourcesPath() + "styles/global.qss"); - QFile styleSheet(PathUtils::resourcesPath() + fileName); - if (styleSheet.open(QIODevice::ReadOnly) && globalStyleSheet.open(QIODevice::ReadOnly) ) { - QDir::setCurrent(PathUtils::resourcesPath()); - setStyleSheet(globalStyleSheet.readAll() + styleSheet.readAll()); - } -} - -void FramelessDialog::showEvent(QShowEvent* event) { - resizeAndPosition(); - QDialog::showEvent(event); -} - -void FramelessDialog::resizeAndPosition(bool resizeParent) { - QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry(); - QSize parentSize = parentGeometry.size(); - - // keep full app height or width depending on position - if (_position == POSITION_LEFT || _position == POSITION_RIGHT) { - setFixedHeight(parentSize.height()); - } else { - setFixedWidth(parentSize.width()); - } - - // resize parrent if width is smaller than this dialog - if (resizeParent && parentSize.width() < size().width()) { - parentWidget()->resize(size().width(), parentSize.height()); - } - - if (_position == POSITION_LEFT || _position == POSITION_TOP) { - // move to upper left corner - move(parentGeometry.topLeft()); - } else if (_position == POSITION_RIGHT) { - // move to upper right corner - QPoint pos = parentGeometry.topRight(); - pos.setX(pos.x() - size().width()); - move(pos); - } - repaint(); -} - -void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) { - if (_allowResize && mouseEvent->button() == Qt::LeftButton) { - if (_position == POSITION_LEFT || _position == POSITION_RIGHT) { - bool hitLeft = (_position == POSITION_LEFT) && (abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH); - bool hitRight = (_position == POSITION_RIGHT) && (mouseEvent->pos().x() < RESIZE_HANDLE_WIDTH); - if (hitLeft || hitRight) { - _isResizing = true; - _resizeInitialWidth = size().width(); - setCursor(Qt::SizeHorCursor); - } - } else { - bool hitTop = (_position == POSITION_TOP) && (abs(mouseEvent->pos().y() - size().height()) < RESIZE_HANDLE_WIDTH); - if (hitTop) { - _isResizing = true; - _resizeInitialWidth = size().height(); - setCursor(Qt::SizeHorCursor); - } - } - } -} - -void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) { - unsetCursor(); - _isResizing = false; -} - -void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) { - if (_isResizing) { - if (_position == POSITION_LEFT) { - resize(mouseEvent->pos().x(), size().height()); - } else if (_position == POSITION_RIGHT) { - setUpdatesEnabled(false); - resize(_resizeInitialWidth - mouseEvent->pos().x(), size().height()); - resizeAndPosition(); - _resizeInitialWidth = size().width(); - setUpdatesEnabled(true); - } else if (_position == POSITION_TOP) { - resize(size().width(), mouseEvent->pos().y()); - } - } -} diff --git a/interface/src/ui/FramelessDialog.h b/interface/src/ui/FramelessDialog.h deleted file mode 100644 index 32451f746d..0000000000 --- a/interface/src/ui/FramelessDialog.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// FramelessDialog.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_FramelessDialog_h -#define hifi_FramelessDialog_h - -#include - -class FramelessDialog : public QDialog { - Q_OBJECT - -public: - enum Position { POSITION_LEFT, POSITION_RIGHT, POSITION_TOP }; - - FramelessDialog(QWidget* parent, Qt::WindowFlags flags = 0, Position position = POSITION_LEFT); - void setStyleSheetFile(const QString& fileName); - void setAllowResize(bool allowResize) { _allowResize = allowResize; } - bool getAllowResize() { return _allowResize; } - void setHideOnBlur(bool hideOnBlur) { _hideOnBlur = hideOnBlur; } - bool getHideOnBlur() { return _hideOnBlur; } - void resizeAndPosition(bool resizeParent = true); - -protected: - virtual void mouseMoveEvent(QMouseEvent* mouseEvent); - virtual void mousePressEvent(QMouseEvent* mouseEvent); - virtual void mouseReleaseEvent(QMouseEvent* mouseEvent); - virtual void showEvent(QShowEvent* event); - - bool eventFilter(QObject* sender, QEvent* event); - -private: - bool _allowResize; - bool _isResizing; - int _resizeInitialWidth; - bool _selfHidden; ///< true when the dialog itself because of a window event (deactivation or minimization) - Position _position; - bool _hideOnBlur; - -}; - -#endif // hifi_FramelessDialog_h diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index b134f7f230..3b164041fa 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -1,120 +1,35 @@ // +// // LoginDialog.cpp -// interface/src/ui // -// Created by Ryan Huffman on 4/23/14. -// Copyright 2014 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 "Application.h" -#include "Menu.h" -#include "AccountManager.h" -#include "ui_loginDialog.h" #include "LoginDialog.h" -#include "UIUtil.h" -const QString CREATE_ACCOUNT_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/signup"; -const QString FORGOT_PASSWORD_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/users/password/new"; +#include "DependencyManager.h" +#include "AccountManager.h" +#include "Menu.h" +#include -LoginDialog::LoginDialog(QWidget* parent) : - FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP), - _ui(new Ui::LoginDialog) { - - _ui->setupUi(this); - reset(); - - setAttribute(Qt::WA_DeleteOnClose, false); +QML_DIALOG_DEF(LoginDialog) +LoginDialog::LoginDialog(QQuickItem *parent) : QQuickItem(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) { connect(&AccountManager::getInstance(), &AccountManager::loginComplete, - this, &LoginDialog::handleLoginCompleted); + this, &LoginDialog::handleLoginCompleted); connect(&AccountManager::getInstance(), &AccountManager::loginFailed, - this, &LoginDialog::handleLoginFailed); - connect(_ui->loginButton, &QPushButton::clicked, - this, &LoginDialog::handleLoginClicked); - connect(_ui->closeButton, &QPushButton::clicked, - this, &LoginDialog::close); - - UIUtil::scaleWidgetFontSizes(this); - _ui->accountLabel->setText(_ui->accountLabel->text().arg(CREATE_ACCOUNT_URL, FORGOT_PASSWORD_URL)); - - // Initialize toggle connection - toggleQAction(); -}; - -LoginDialog::~LoginDialog() { - delete _ui; -}; - -void LoginDialog::reset() { - _ui->errorLabel->hide(); - _ui->emailLineEdit->setFocus(); - _ui->logoLabel->setPixmap(QPixmap(PathUtils::resourcesPath() + "images/hifi-logo.svg")); - _ui->loginButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/login.svg")); - _ui->closeButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/close.svg")); - _ui->infoLabel->setVisible(false); - _ui->errorLabel->setVisible(false); - - _ui->emailLineEdit->setText(""); - _ui->passwordLineEdit->setText(""); - _ui->loginArea->setDisabled(false); + this, &LoginDialog::handleLoginFailed); } -void LoginDialog::handleLoginCompleted(const QUrl& authURL) { - reset(); - close(); -}; - -void LoginDialog::handleLoginFailed() { - _ui->infoLabel->setVisible(false); - _ui->errorLabel->setVisible(true); - - _ui->errorLabel->show(); - _ui->loginArea->setDisabled(false); - - // Move focus to password and select the entire line - _ui->passwordLineEdit->setFocus(); - _ui->passwordLineEdit->setSelection(0, _ui->emailLineEdit->maxLength()); -}; - -void LoginDialog::handleLoginClicked() { - // If the email or password inputs are empty, move focus to them, otherwise attempt to login. - if (_ui->emailLineEdit->text().isEmpty()) { - _ui->emailLineEdit->setFocus(); - } else if (_ui->passwordLineEdit->text().isEmpty()) { - _ui->passwordLineEdit->setFocus(); - } else { - _ui->infoLabel->setVisible(true); - _ui->errorLabel->setVisible(false); - - _ui->loginArea->setDisabled(true); - AccountManager::getInstance().requestAccessToken(_ui->emailLineEdit->text(), _ui->passwordLineEdit->text()); - } -}; - -void LoginDialog::moveEvent(QMoveEvent* event) { - // Modal dialogs seemed to get repositioned automatically. Combat this by moving the window if needed. - resizeAndPosition(); -}; - - -void LoginDialog::toggleQAction() { +void LoginDialog::toggleAction() { AccountManager& accountManager = AccountManager::getInstance(); QAction* loginAction = Menu::getInstance()->getActionForOption(MenuOption::Login); Q_CHECK_PTR(loginAction); - disconnect(loginAction, 0, 0, 0); - + if (accountManager.isLoggedIn()) { // change the menu item to logout loginAction->setText("Logout " + accountManager.getAccountInfo().getUsername()); @@ -122,11 +37,40 @@ void LoginDialog::toggleQAction() { } else { // change the menu item to login loginAction->setText("Login"); - connect(loginAction, &QAction::triggered, this, &LoginDialog::showLoginForCurrentDomain); + connect(loginAction, &QAction::triggered, &LoginDialog::show); } } -void LoginDialog::showLoginForCurrentDomain() { - show(); - resizeAndPosition(false); +void LoginDialog::handleLoginCompleted(const QUrl& authURL) { + setEnabled(false); + setVisible(false); +} + +void LoginDialog::handleLoginFailed() { + setStatusText("Invalid username or password.< / font>"); +} + +void LoginDialog::setStatusText(const QString &a) { + if (a != _statusText) { + _statusText = a; + emit statusTextChanged(); + } +} + +QString LoginDialog::statusText() const { + return _statusText; +} + +QString LoginDialog::rootUrl() const { + return _rootUrl; +} + +void LoginDialog::login(const QString & username, const QString & password) { + qDebug() << "Attempting to login " << username; + setStatusText("Authenticating..."); + AccountManager::getInstance().requestAccessToken(username, password); +} + +void LoginDialog::openUrl(const QString & url) { + qDebug() << url; } diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index d5384c4625..3c9a98a9a4 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -1,9 +1,8 @@ // // LoginDialog.h -// interface/src/ui // -// Created by Ryan Huffman on 4/23/14. -// Copyright 2014 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 @@ -12,35 +11,41 @@ #ifndef hifi_LoginDialog_h #define hifi_LoginDialog_h -#include -#include "FramelessDialog.h" +#pragma once +#include -namespace Ui { - class LoginDialog; -} +#include "OffscreenUi.h" -class LoginDialog : public FramelessDialog { +class LoginDialog : public QQuickItem +{ Q_OBJECT + QML_DIALOG_DECL + + Q_PROPERTY(QString statusText READ statusText WRITE setStatusText NOTIFY statusTextChanged) + Q_PROPERTY(QString rootUrl READ rootUrl) public: - LoginDialog(QWidget* parent); - ~LoginDialog(); + static void toggleAction(); -public slots: - void toggleQAction(); - void showLoginForCurrentDomain(); - -protected slots: - void reset(); - void handleLoginClicked(); + LoginDialog(QQuickItem *parent = 0); + + void setStatusText(const QString & a); + QString statusText() const; + + QString rootUrl() const; + +signals: + void statusTextChanged(); + +protected: void handleLoginCompleted(const QUrl& authURL); void handleLoginFailed(); -protected: - void moveEvent(QMoveEvent* event); - + Q_INVOKABLE void login(const QString & username, const QString & password); + Q_INVOKABLE void openUrl(const QString & url); private: - Ui::LoginDialog* _ui = nullptr; + QString _statusText; + const QString _rootUrl; }; #endif // hifi_LoginDialog_h diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index caabff44cf..fd4d447b25 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -6,7 +6,7 @@ AUTOSCRIBE_SHADER_LIB(gpu model) qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(Widgets OpenGL Network Script) +setup_hifi_library(Widgets OpenGL Network Qml Quick Script) add_dependency_external_projects(glm) find_package(GLM REQUIRED) diff --git a/libraries/render-utils/src/FboCache.cpp b/libraries/render-utils/src/FboCache.cpp new file mode 100644 index 0000000000..fdd29d20d8 --- /dev/null +++ b/libraries/render-utils/src/FboCache.cpp @@ -0,0 +1,98 @@ +// +// OffscreenGlCanvas.cpp +// interface/src/renderer +// +// Created by Bradley Austin Davis on 2014/04/09. +// Copyright 2015 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 "FboCache.h" + +#include +#include +#include "ThreadHelpers.h" + +FboCache::FboCache() { + // Why do we even HAVE that lever? +} + +void FboCache::lockTexture(int texture) { + withLock(_lock, [&] { + Q_ASSERT(_fboMap.count(texture)); + if (!_fboLocks.count(texture)) { + Q_ASSERT(_readyFboQueue.front()->texture() == texture); + _readyFboQueue.pop_front(); + _fboLocks[texture] = 1; + } else { + _fboLocks[texture]++; + } + }); +} + +void FboCache::releaseTexture(int texture) { + withLock(_lock, [&] { + Q_ASSERT(_fboMap.count(texture)); + Q_ASSERT(_fboLocks.count(texture)); + int newLockCount = --_fboLocks[texture]; + if (!newLockCount) { + auto fbo = _fboMap[texture].data(); + if (fbo->size() != _size) { + // Move the old FBO to the destruction queue. + // We can't destroy the FBO here because we might + // not be on the right thread or have the context active + _destroyFboQueue.push_back(_fboMap[texture]); + _fboMap.remove(texture); + } else { + _readyFboQueue.push_back(fbo); + } + _fboLocks.remove(texture); + } + }); +} + +QOpenGLFramebufferObject* FboCache::getReadyFbo() { + QOpenGLFramebufferObject* result = nullptr; + withLock(_lock, [&] { + // Delete any FBOs queued for deletion + _destroyFboQueue.clear(); + + if (_readyFboQueue.empty()) { + qDebug() << "Building new offscreen FBO number " << _fboMap.size() + 1; + result = new QOpenGLFramebufferObject(_size, QOpenGLFramebufferObject::CombinedDepthStencil); + _fboMap[result->texture()] = QSharedPointer(result); + _readyFboQueue.push_back(result); + } else { + result = _readyFboQueue.front(); + } + }); + return result; +} + +void FboCache::setSize(const QSize & newSize) { + if (_size == newSize) { + return; + } + _size = newSize; + withLock(_lock, [&] { + // Clear out any fbos with the old id + _readyFboQueue.clear(); + + QSet outdatedFbos; + // FBOs that are locked will be removed as they are unlocked + foreach(int texture, _fboMap.keys()) { + if (!_fboLocks.count(texture)) { + outdatedFbos.insert(texture); + } + } + // Implicitly deletes the FBO via the shared pointer destruction mechanism + foreach(int texture, outdatedFbos) { + _fboMap.remove(texture); + } + }); +} + + diff --git a/libraries/render-utils/src/FboCache.h b/libraries/render-utils/src/FboCache.h new file mode 100644 index 0000000000..bbbb4a943e --- /dev/null +++ b/libraries/render-utils/src/FboCache.h @@ -0,0 +1,50 @@ +// +// OffscreenGlCanvas.h +// interface/src/renderer +// +// Created by Bradley Austin Davis on 2014/04/09. +// Copyright 2015 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 +// +#pragma once +#ifndef hifi_FboCache_h +#define hifi_FboCache_h + +#include +#include +#include +#include +#include + +class QOpenGLFramebufferObject; + +class FboCache : public QObject { +public: + FboCache(); + + // setSize() and getReadyFbo() must consitently be called from only a single + // thread. Additionally, it is the caller's responsibility to ensure that + // the appropriate OpenGL context is active when doing so. + + // Important.... textures are sharable resources, but FBOs ARE NOT. + void setSize(const QSize & newSize); + QOpenGLFramebufferObject* getReadyFbo(); + + // These operations are thread safe and require no OpenGL context. They manipulate the + // internal locks and pointers but execute no OpenGL opreations. + void lockTexture(int texture); + void releaseTexture(int texture); + +protected: + QMap> _fboMap; + QMap _fboLocks; + QQueue _readyFboQueue; + QQueue> _destroyFboQueue; + QMutex _lock; + QSize _size; + +}; + +#endif // hifi_FboCache_h diff --git a/libraries/render-utils/src/OffscreenGlCanvas.cpp b/libraries/render-utils/src/OffscreenGlCanvas.cpp new file mode 100644 index 0000000000..694fa68a5a --- /dev/null +++ b/libraries/render-utils/src/OffscreenGlCanvas.cpp @@ -0,0 +1,43 @@ +// +// OffscreenGlCanvas.cpp +// interface/src/renderer +// +// Created by Bradley Austin Davis on 2014/04/09. +// Copyright 2015 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 "OffscreenGlCanvas.h" + +OffscreenGlCanvas::OffscreenGlCanvas() { +} + +void OffscreenGlCanvas::create(QOpenGLContext * sharedContext) { + QSurfaceFormat format; + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + format.setMajorVersion(4); + format.setMinorVersion(1); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + + _context.setFormat(format); + if (nullptr != sharedContext) { + _context.setShareContext(sharedContext); + } + _context.create(); + + _offscreenSurface.setFormat(_context.format()); + _offscreenSurface.create(); +} + +bool OffscreenGlCanvas::makeCurrent() { + return _context.makeCurrent(&_offscreenSurface); +} + +void OffscreenGlCanvas::doneCurrent() { + _context.doneCurrent(); +} + diff --git a/libraries/render-utils/src/OffscreenGlCanvas.h b/libraries/render-utils/src/OffscreenGlCanvas.h new file mode 100644 index 0000000000..1b2f15f690 --- /dev/null +++ b/libraries/render-utils/src/OffscreenGlCanvas.h @@ -0,0 +1,31 @@ +// +// OffscreenGlCanvas.h +// interface/src/renderer +// +// Created by Bradley Austin Davis on 2014/04/09. +// Copyright 2015 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 +// +#pragma once +#ifndef hifi_OffscreenGlCanvas_h +#define hifi_OffscreenGlCanvas_h + +#include +#include + +class OffscreenGlCanvas : public QObject { +public: + OffscreenGlCanvas(); + void create(QOpenGLContext * sharedContext = nullptr); + bool makeCurrent(); + void doneCurrent(); + +protected: + QOpenGLContext _context; + QOffscreenSurface _offscreenSurface; + +}; + +#endif // hifi_OffscreenGlCanvas_h diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp new file mode 100644 index 0000000000..cb57d86412 --- /dev/null +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -0,0 +1,325 @@ +#include "OffscreenUi.h" +#include +#include +#include + +OffscreenUi::OffscreenUi() { +} + +OffscreenUi::~OffscreenUi() { + // Make sure the context is current while doing cleanup. Note that we use the + // offscreen surface here because passing 'this' at this point is not safe: the + // underlying platform window may already be destroyed. To avoid all the trouble, use + // another surface that is valid for sure. + makeCurrent(); + + // Delete the render control first since it will free the scenegraph resources. + // Destroy the QQuickWindow only afterwards. + delete _renderControl; + + delete _qmlComponent; + delete _quickWindow; + delete _qmlEngine; + + doneCurrent(); +} + +void OffscreenUi::create(QOpenGLContext * shareContext) { + OffscreenGlCanvas::create(shareContext); + + makeCurrent(); + + // Create a QQuickWindow that is associated with out render control. Note that this + // window never gets created or shown, meaning that it will never get an underlying + // native (platform) window. + QQuickWindow::setDefaultAlphaBuffer(true); + _quickWindow = new QQuickWindow(_renderControl); + _quickWindow->setColor(QColor(255, 255, 255, 0)); + _quickWindow->setFlags(_quickWindow->flags() | static_cast(Qt::WA_TranslucentBackground)); + // Create a QML engine. + _qmlEngine = new QQmlEngine; + if (!_qmlEngine->incubationController()) + _qmlEngine->setIncubationController(_quickWindow->incubationController()); + + // When Quick says there is a need to render, we will not render immediately. Instead, + // a timer with a small interval is used to get better performance. + _updateTimer.setSingleShot(true); + _updateTimer.setInterval(5); + connect(&_updateTimer, &QTimer::timeout, this, &OffscreenUi::updateQuick); + + // Now hook up the signals. For simplicy we don't differentiate between + // renderRequested (only render is needed, no sync) and sceneChanged (polish and sync + // is needed too). + connect(_renderControl, &QQuickRenderControl::renderRequested, this, &OffscreenUi::requestRender); + connect(_renderControl, &QQuickRenderControl::sceneChanged, this, &OffscreenUi::requestUpdate); + connect(_quickWindow, &QQuickWindow::focusObjectChanged, this, [this](QObject *object){ + OffscreenUi * p = this; + qDebug() << "Focus changed to " << object; + }); + _quickWindow->focusObject(); + + _qmlComponent = new QQmlComponent(_qmlEngine); + + // Initialize the render control and our OpenGL resources. + makeCurrent(); + _renderControl->initialize(&_context); +} + +void OffscreenUi::resize(const QSize & newSize) { + makeCurrent(); + + // Clear out any fbos with the old size + _fboCache.setSize(newSize); + + // Update our members + if (_rootItem) { + _rootItem->setSize(newSize); + } + + if (_quickWindow) { + _quickWindow->setGeometry(QRect(QPoint(), newSize)); + } + + doneCurrent(); +} + +QQmlContext * OffscreenUi::qmlContext() { + if (nullptr == _rootItem) { + return _qmlComponent->creationContext(); + } + return QQmlEngine::contextForObject(_rootItem); +} + +void OffscreenUi::loadQml(const QUrl & qmlSource, std::function f) { + _qmlComponent->loadUrl(qmlSource); + if (_qmlComponent->isLoading()) + connect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad); + else + finishQmlLoad(); +} + +void OffscreenUi::requestUpdate() { + _polish = true; + if (!_updateTimer.isActive()) + _updateTimer.start(); +} + +void OffscreenUi::requestRender() { + if (!_updateTimer.isActive()) + _updateTimer.start(); +} + +void OffscreenUi::finishQmlLoad() { + disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad); + if (_qmlComponent->isError()) { + QList errorList = _qmlComponent->errors(); + foreach(const QQmlError &error, errorList) { + qWarning() << error.url() << error.line() << error; + } + return; + } + + QObject *rootObject = _qmlComponent->create(); + if (_qmlComponent->isError()) { + QList errorList = _qmlComponent->errors(); + foreach(const QQmlError &error, errorList) + qWarning() << error.url() << error.line() << error; + qFatal("Unable to finish loading QML"); + return; + } + + _rootItem = qobject_cast(rootObject); + if (!_rootItem) { + qWarning("run: Not a QQuickItem"); + delete rootObject; + qFatal("Unable to find root QQuickItem"); + return; + } + + // Make sure we can assign focus to the root item (critical for + // supporting keyboard shortcuts) + _rootItem->setFlag(QQuickItem::ItemIsFocusScope, true); + // The root item is ready. Associate it with the window. + _rootItem->setParentItem(_quickWindow->contentItem()); + _rootItem->setSize(_quickWindow->renderTargetSize()); + qDebug() << "Finished setting up QML provider"; +} + + +void OffscreenUi::updateQuick() { + if (_paused) { + return; + } + if (!makeCurrent()) + return; + + // Polish, synchronize and render the next frame (into our fbo). In this example + // everything happens on the same thread and therefore all three steps are performed + // in succession from here. In a threaded setup the render() call would happen on a + // separate thread. + if (_polish) { + _renderControl->polishItems(); + _renderControl->sync(); + _polish = false; + } + + QOpenGLFramebufferObject* fbo = _fboCache.getReadyFbo(); + + _quickWindow->setRenderTarget(fbo); + fbo->bind(); + + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + _renderControl->render(); + + Q_ASSERT(!glGetError()); + + _quickWindow->resetOpenGLState(); + + QOpenGLFramebufferObject::bindDefault(); + // Force completion of all the operations before we emit the texture as being ready for use + glFinish(); + + emit textureUpdated(fbo->texture()); +} + +QPointF OffscreenUi::mapWindowToUi(const QPointF & p, QObject * dest) { + vec2 sourceSize; + if (dynamic_cast(dest)) { + sourceSize = toGlm(((QWidget*)dest)->size()); + } else if (dynamic_cast(dest)) { + sourceSize = toGlm(((QWindow*)dest)->size()); + } + vec2 pos = toGlm(p); + pos /= sourceSize; + pos *= vec2(toGlm(_quickWindow->renderTargetSize())); + return QPointF(pos.x, pos.y); +} + +/////////////////////////////////////////////////////// +// +// Event handling customization +// + +bool OffscreenUi::eventFilter(QObject * dest, QEvent * e) { + // Only intercept events while we're in an active state + if (_paused) { + return false; + } + + // Don't intercept our own events, or we enter an infinite recursion + if (dest == _quickWindow) { + return false; + } + + switch (e->type()) { + case QEvent::Resize: + { + QResizeEvent * re = (QResizeEvent *)e; + QGLWidget * widget = dynamic_cast(dest); + if (widget) { + this->resize(re->size()); + } + return false; + } + + case QEvent::KeyPress: + case QEvent::KeyRelease: + { + e->ignore(); + if (QApplication::sendEvent(_quickWindow, e)) { + return e->isAccepted(); + } + } + break; + + case QEvent::Wheel: + { + QWheelEvent * we = (QWheelEvent*)e; + QWheelEvent mappedEvent(mapWindowToUi(we->pos(), dest), we->delta(), we->buttons(), we->modifiers(), we->orientation()); + QCoreApplication::sendEvent(_quickWindow, &mappedEvent); + return true; + } + break; + + // Fall through + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + { + QMouseEvent * me = (QMouseEvent *)e; + QPointF originalPos = me->localPos(); + QPointF transformedPos = _mouseTranslator(originalPos); + QMouseEvent mappedEvent(e->type(), mapWindowToUi(transformedPos, dest), me->screenPos(), me->button(), me->buttons(), me->modifiers()); + QCoreApplication::sendEvent(_quickWindow, &mappedEvent); + return QObject::event(e); + } + + default: break; + } + + return false; +} + +void OffscreenUi::lockTexture(int texture) { + _fboCache.lockTexture(texture); +} + +void OffscreenUi::releaseTexture(int texture) { + _fboCache.releaseTexture(texture); +} + +void OffscreenUi::pause() { + _paused = true; +} + +void OffscreenUi::resume() { + _paused = false; + requestRender(); +} + +bool OffscreenUi::isPaused() const { + return _paused; +} + +void OffscreenUi::setProxyWindow(QWindow * window) { + _renderControl->_renderWindow = window; +} + +void OffscreenUi::show(const QUrl & url, const QString & name) { + QQuickItem * item = _rootItem->findChild(name); + if (nullptr != item) { + item->setEnabled(true); + item->setVisible(true); + } else { + load(url); + } +} + +void OffscreenUi::toggle(const QUrl & url, const QString & name) { + QQuickItem * item = _rootItem->findChild(name); + // First load? + if (nullptr == item) { + load(url); + return; + } + + // Toggle the visibity AND the enabled flag (otherwise invisible + // dialogs can still swallow keyboard input) + bool newFlag = !item->isVisible(); + item->setVisible(newFlag); + item->setEnabled(newFlag); +} + + +void OffscreenUi::load(const QUrl & url) { + QVariant returnedValue; + QVariant msg = url; + QMetaObject::invokeMethod(_rootItem, "loadChild", + Q_RETURN_ARG(QVariant, returnedValue), + Q_ARG(QVariant, msg)); + qDebug() << "QML function returned:" << returnedValue.toString(); +} + diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h new file mode 100644 index 0000000000..2e8206f466 --- /dev/null +++ b/libraries/render-utils/src/OffscreenUi.h @@ -0,0 +1,136 @@ +// +// OffscreenUi.h +// interface/src/entities +// +// Created by Bradley Austin Davis on 2015-04-04 +// Copyright 2015 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 +// +#pragma once +#ifndef hifi_OffscreenUi_h +#define hifi_OffscreenUi_h + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FboCache.h" +#include "OffscreenGlCanvas.h" + +#define QML_DIALOG_DECL \ +private: \ + static const QString NAME; \ + static const QUrl QML; \ +public: \ + static void registerType(); \ + static void show(); \ + static void toggle(); \ +private: + +#define QML_DIALOG_DEF(x) \ + const QUrl x::QML = #x ".qml"; \ + const QString x::NAME = #x; \ + \ + void x::registerType() { \ + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ + } \ + \ + void x::show() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->show(QML, NAME); \ + } \ + \ + void x::toggle() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->toggle(QML, NAME); \ + } + + +class OffscreenUi : public OffscreenGlCanvas, public Dependency { + Q_OBJECT + + class QMyQuickRenderControl : public QQuickRenderControl { + protected: + QWindow * renderWindow(QPoint * offset) Q_DECL_OVERRIDE{ + if (nullptr == _renderWindow) { + return QQuickRenderControl::renderWindow(offset); + } + if (nullptr != offset) { + offset->rx() = offset->ry() = 0; + } + return _renderWindow; + } + + private: + QWindow * _renderWindow{ nullptr }; + friend class OffscreenUi; + }; + +public: + using MouseTranslator = std::function < QPointF(const QPointF &) > ; + OffscreenUi(); + virtual ~OffscreenUi(); + void create(QOpenGLContext * context); + void resize(const QSize & size); + void loadQml(const QUrl & qmlSource, std::function f = [](QQmlContext*) {}); + void load(const QUrl & url); + void show(const QUrl & url, const QString & name); + void toggle(const QUrl & url, const QString & name); + + QQmlContext * qmlContext(); + + void pause(); + void resume(); + bool isPaused() const; + void setProxyWindow(QWindow * window); + QPointF mapWindowToUi(const QPointF & p, QObject * dest); + virtual bool eventFilter(QObject * dest, QEvent * e); + void setMouseTranslator(MouseTranslator mt) { + _mouseTranslator = mt; + } + +protected: + +private slots: + void updateQuick(); + void finishQmlLoad(); + +public slots: + void requestUpdate(); + void requestRender(); + void lockTexture(int texture); + void releaseTexture(int texture); + +signals: + void textureUpdated(GLuint texture); + +private: + QMyQuickRenderControl *_renderControl{ new QMyQuickRenderControl }; + QQuickWindow *_quickWindow{ nullptr }; + QQmlEngine *_qmlEngine{ nullptr }; + QQmlComponent *_qmlComponent{ nullptr }; + QQuickItem * _rootItem{ nullptr }; + QTimer _updateTimer; + FboCache _fboCache; + bool _polish{ true }; + bool _paused{ true }; + MouseTranslator _mouseTranslator{ [](const QPointF & p) { return p; } }; +}; + +#endif \ No newline at end of file diff --git a/libraries/render-utils/src/RenderUtil.h b/libraries/render-utils/src/RenderUtil.h index b2f244733a..74d6c23791 100644 --- a/libraries/render-utils/src/RenderUtil.h +++ b/libraries/render-utils/src/RenderUtil.h @@ -15,4 +15,54 @@ /// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, tMin) to (sMax, tMax). void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f, float tMin = 0.0f, float tMax = 1.0f); +template +void withMatrixPush(F f) { + glMatrixMode(matrix); + glPushMatrix(); + f(); + glPopMatrix(); +} + +template +void withProjectionPush(F f) { + withMatrixPush(f); +} + +template +void withProjectionIdentity(F f) { + withProjectionPush([&] { + glLoadIdentity(); + f(); + }); +} + +template +void withProjectionMatrix(GLfloat * matrix, F f) { + withProjectionPush([&] { + glLoadMatrixf(matrix); + f(); + }); +} + +template +void withModelviewPush(F f) { + withMatrixPush(f); +} + +template +void withModelviewIdentity(F f) { + withModelviewPush([&] { + glLoadIdentity(); + f(); + }); +} + +template +void withModelviewMatrix(GLfloat * matrix, F f) { + withModelviewPush([&] { + glLoadMatrixf(matrix); + f(); + }); +} + #endif // hifi_RenderUtil_h diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 50393b7f5f..e5d22d67dc 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -17,6 +17,17 @@ #include #include +// Bring the most commonly used GLM types into the default namespace +using glm::ivec3; +using glm::ivec2; +using glm::uvec2; +using glm::mat3; +using glm::mat4; +using glm::vec2; +using glm::vec3; +using glm::vec4; +using glm::quat; + #include #include #include diff --git a/libraries/shared/src/ThreadHelpers.h b/libraries/shared/src/ThreadHelpers.h new file mode 100644 index 0000000000..862f7bf673 --- /dev/null +++ b/libraries/shared/src/ThreadHelpers.h @@ -0,0 +1,13 @@ +#pragma once +#include + +template +void withLock(L lock, F function) { + throw std::exception(); +} + +template +void withLock(QMutex & lock, F function) { + QMutexLocker locker(&lock); + function(); +} diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index b62ab68c22..304d6f1a07 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -10,6 +10,7 @@ #include "TextRenderer.h" #include "MatrixStack.h" +#include "OffscreenUi.h" #include #include @@ -21,9 +22,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -66,99 +69,143 @@ public: }; // Create a simple OpenGL window that renders text in various ways -class QTestWindow: public QWindow { +class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext * _context; + + QOpenGLContext * _context{ nullptr }; QSize _size; TextRenderer* _textRenderer[4]; RateCounter fps; + OffscreenUi _offscreenUi; + int testQmlTexture{ 0 }; + //ProgramPtr _planeProgam; + //ShapeWrapperPtr _planeShape; protected: - void resizeEvent(QResizeEvent * ev) override { - QWindow::resizeEvent(ev); - _size = ev->size(); - resizeGl(); - } - void resizeGl() { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, _size.width(), _size.height(), 0, 1, -1); - glMatrixMode(GL_MODELVIEW); - glViewport(0, 0, _size.width(), _size.height()); + void renderText(); + void renderQml(); + +private: + void resizeWindow(const QSize & size) { + _size = size; + _offscreenUi.resize(_size); } public: - QTestWindow(); - virtual ~QTestWindow() { + QTestWindow() { + setSurfaceType(QSurface::OpenGLSurface); + QSurfaceFormat format; + // Qt Quick may need a depth and stencil buffer. Always make sure these are available. + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + format.setVersion(4, 5); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + format.setOption(QSurfaceFormat::DebugContext); + + setFormat(format); + + _context = new QOpenGLContext; + _context->setFormat(format); + _context->create(); + + show(); + makeCurrent(); + + { + QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + logger->initialize(); // initializes in the current context, i.e. ctx + logger->enableMessages(); + connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { + qDebug() << debugMessage; + }); + // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); + } + qDebug() << (const char*)glGetString(GL_VERSION); + +#ifdef WIN32 + glewExperimental = true; + GLenum err = glewInit(); + if (GLEW_OK != err) { + /* Problem: glewInit failed, something is seriously wrong. */ + const GLubyte * errStr = glewGetErrorString(err); + qDebug("Error: %s\n", errStr); + } + qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); + + if (wglewGetExtension("WGL_EXT_swap_control")) { + int swapInterval = wglGetSwapIntervalEXT(); + qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); + } + glGetError(); +#endif + + _textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); + _textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false, + TextRenderer::SHADOW_EFFECT); + _textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1, + false, TextRenderer::OUTLINE_EFFECT); + _textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glClearColor(0.2f, 0.2f, 0.2f, 1); + glDisable(GL_DEPTH_TEST); + + _offscreenUi.create(_context); + // FIXME, need to switch to a QWindow for mouse and keyboard input to work + _offscreenUi.setProxyWindow(this); + // "#0e7077" + setFramePosition(QPoint(-1000, 0)); + resize(QSize(800, 600)); + + static const QString f("/Users/bdavis/Git/hifi/interface/resources/qml/Root.qml"); + _offscreenUi.loadQml(QUrl::fromLocalFile(f)); + connect(&_offscreenUi, &OffscreenUi::textureUpdated, this, [&](int textureId) { + _offscreenUi.lockTexture(textureId); + assert(!glGetError()); + GLuint oldTexture = testQmlTexture; + testQmlTexture = textureId; + if (oldTexture) { + _offscreenUi.releaseTexture(oldTexture); + } + }); + installEventFilter(&_offscreenUi); + _offscreenUi.resume(); } + + virtual ~QTestWindow() { + } + + void draw(); void makeCurrent() { _context->makeCurrent(this); } - void draw(); +protected: + + void resizeEvent(QResizeEvent * ev) override { + resizeWindow(ev->size()); + } + + + void keyPressEvent(QKeyEvent *event) { + switch (event->key()) { + case Qt::Key_Slash: + qDebug() << "Foo"; + _offscreenUi.load(QString("Login.qml")); + break; + } + QWindow::keyPressEvent(event); + } + }; #ifndef SERIF_FONT_FAMILY #define SERIF_FONT_FAMILY "Times New Roman" #endif -QTestWindow::QTestWindow() { - setSurfaceType(QSurface::OpenGLSurface); - - QSurfaceFormat format; - // Qt Quick may need a depth and stencil buffer. Always make sure these are available. - format.setDepthBufferSize(16); - format.setStencilBufferSize(8); - format.setVersion(3, 2); - format.setProfile( - QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); - setFormat(format); - - _context = new QOpenGLContext; - _context->setFormat(format); - _context->create(); - - show(); - makeCurrent(); - qDebug() << (const char*) glGetString(GL_VERSION); - -#ifdef WIN32 - glewExperimental = true; - GLenum err = glewInit(); - if (GLEW_OK != err) { - /* Problem: glewInit failed, something is seriously wrong. */ - const GLubyte * errStr = glewGetErrorString(err); - qDebug("Error: %s\n", errStr); - } - qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); - - if (wglewGetExtension("WGL_EXT_swap_control")) { - int swapInterval = wglGetSwapIntervalEXT(); - qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); - } - glGetError(); -#endif - - setFramePosition(QPoint(100, -900)); - resize(QSize(800, 600)); - _size = QSize(800, 600); - - _textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); - _textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false, - TextRenderer::SHADOW_EFFECT); - _textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1, - false, TextRenderer::OUTLINE_EFFECT); - _textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glClearColor(0.2f, 0.2f, 0.2f, 1); - glDisable(GL_DEPTH_TEST); - resizeGl(); -} - static const wchar_t * EXAMPLE_TEXT = L"Hello"; //static const wchar_t * EXAMPLE_TEXT = L"\xC1y Hello 1.0\ny\xC1 line 2\n\xC1y"; static const glm::uvec2 QUAD_OFFSET(10, 10); @@ -166,14 +213,21 @@ static const glm::uvec2 QUAD_OFFSET(10, 10); static const glm::vec3 COLORS[4] = { { 1.0, 1.0, 1.0 }, { 0.5, 1.0, 0.5 }, { 1.0, 0.5, 0.5 }, { 0.5, 0.5, 1.0 } }; -void QTestWindow::draw() { - makeCurrent(); - glClear(GL_COLOR_BUFFER_BIT); +void QTestWindow::renderText() { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, _size.width(), _size.height(), 0, 1, -1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); const glm::uvec2 size = glm::uvec2(_size.width() / 2, _size.height() / 2); - const glm::uvec2 offsets[4] = { { QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x - + QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x + QUAD_OFFSET.x, size.y - + QUAD_OFFSET.y }, { QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, }; + + const glm::uvec2 offsets[4] = { + { QUAD_OFFSET.x, QUAD_OFFSET.y }, + { size.x + QUAD_OFFSET.x, QUAD_OFFSET.y }, + { size.x + QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, + { QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, + }; QString str = QString::fromWCharArray(EXAMPLE_TEXT); for (int i = 0; i < 4; ++i) { @@ -200,17 +254,57 @@ void QTestWindow::draw() { glm::vec4(COLORS[i], 1.0f)); } } +} + +void QTestWindow::renderQml() { + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + if (testQmlTexture > 0) { + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, testQmlTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + glBegin(GL_QUADS); + { + + glTexCoord2f(0, 0); + glVertex2f(-1, -1); + glTexCoord2f(0, 1); + glVertex2f(-1, 1); + glTexCoord2f(1, 1); + glVertex2f(1, 1); + glTexCoord2f(1, 0); + glVertex2f(1, -1); + } + glEnd(); +} + +void QTestWindow::draw() { + makeCurrent(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, _size.width(), _size.height()); + + renderText(); + //renderQml(); + _context->swapBuffers(this); glFinish(); + fps.increment(); if (fps.elapsed() >= 2.0f) { - qDebug() << "FPS: " << fps.rate(); + //qDebug() << "FPS: " << fps.rate(); fps.reset(); } } int main(int argc, char** argv) { QApplication app(argc, argv); + //QLoggingCategory::setFilterRules("qt.quick.mouse.debug = true"); QTestWindow window; QTimer timer; timer.setInterval(1); From bd3b25383ae3c1996589be8c59e7a78a38d7b9a7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 15 Apr 2015 14:20:50 +0200 Subject: [PATCH 066/401] Some code cleanup --- libraries/audio-client/src/AudioClient.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index a02dc912f7..f37172ea4e 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -726,9 +726,9 @@ void AudioClient::handleAudioInput() { int inputSamplesRequired = (int)((float)AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio); QByteArray inputByteArray = _inputDevice->readAll(); - + + // Add audio source injection if enabled if (!_muted && _audioSourceInjectEnabled) { - int16_t* inputFrameData = (int16_t*)inputByteArray.data(); const uint32_t inputFrameCount = inputByteArray.size() / sizeof(int16_t); @@ -737,17 +737,12 @@ void AudioClient::handleAudioInput() { #if ENABLE_INPUT_GAIN _inputGain.render(_inputFrameBuffer); // input/mic gain+mute #endif - // Add audio source injection if enabled - if (_audioSourceInjectEnabled) { - - if (_toneSourceEnabled) { // sine generator - _toneSource.render(_inputFrameBuffer); - } - else if(_noiseSourceEnabled) { // pink noise generator - _noiseSource.render(_inputFrameBuffer); - } - _sourceGain.render(_inputFrameBuffer); // post gain + if (_toneSourceEnabled) { // sine generator + _toneSource.render(_inputFrameBuffer); + } else if(_noiseSourceEnabled) { // pink noise generator + _noiseSource.render(_inputFrameBuffer); } + _sourceGain.render(_inputFrameBuffer); // post gain _inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, true /*copy out*/); } From 8f8e4d8dc66bd8e0a392d6344bdd847c71c251be Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 15 Apr 2015 15:49:11 +0200 Subject: [PATCH 067/401] Add generated audio methods to audio interface --- libraries/audio-client/src/AudioClient.cpp | 4 ++-- libraries/audio-client/src/AudioClient.h | 8 ++++---- libraries/audio/src/AbstractAudioInterface.h | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index f37172ea4e..032c70985e 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -967,8 +967,8 @@ void AudioClient::setIsStereoInput(bool isStereoInput) { } } -void AudioClient::toggleAudioSourceInject() { - _audioSourceInjectEnabled = !_audioSourceInjectEnabled; +void AudioClient::enableAudioSourceInject(bool enable) { + _audioSourceInjectEnabled = enable; } void AudioClient::selectAudioSourcePinkNoise() { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 7ac445a7fc..bb145a209f 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -1,6 +1,6 @@ // // AudioClient.h -// interface/src +// libraries/audio-client/src // // Created by Stephen Birarda on 1/22/13. // Copyright 2013 High Fidelity, Inc. @@ -143,9 +143,9 @@ public slots: void audioMixerKilled(); void toggleMute(); - void toggleAudioSourceInject(); - void selectAudioSourcePinkNoise(); - void selectAudioSourceSine440(); + virtual void enableAudioSourceInject(bool enable); + virtual void selectAudioSourcePinkNoise(); + virtual void selectAudioSourceSine440(); void toggleAudioNoiseReduction() { _isNoiseGateEnabled = !_isNoiseGateEnabled; } diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 656d3c1f58..9649d11ad2 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -27,6 +27,10 @@ public: public slots: virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) = 0; + + virtual void enableAudioSourceInject(bool enable) = 0; + virtual void selectAudioSourcePinkNoise() = 0; + virtual void selectAudioSourceSine440() = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) From b1cfd3343877fa92869ac196edf9683f12d1b18e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 15 Apr 2015 15:49:47 +0200 Subject: [PATCH 068/401] Add generated audio controls to scripting interface --- .../src/AudioScriptingInterface.cpp | 23 ++++++++++++++++++- .../src/AudioScriptingInterface.h | 4 ++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index deb1e1e9e9..8bcc4a20cf 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -9,9 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AudioScriptingInterface.h" + #include "ScriptAudioInjector.h" #include "ScriptEngineLogging.h" -#include "AudioScriptingInterface.h" void registerAudioMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue); @@ -69,3 +70,23 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const Audi return NULL; } } + +void AudioScriptingInterface::injectGeneratedNoise(bool inject) { + if (_localAudioInterface) { + _localAudioInterface->enableAudioSourceInject(inject); + } +} + +void AudioScriptingInterface::selectPinkNoise() { + if (_localAudioInterface) { + _localAudioInterface->selectAudioSourcePinkNoise(); + } +} + +void AudioScriptingInterface::selectSine440() { + if (_localAudioInterface) { + _localAudioInterface->selectAudioSourceSine440(); + } +} + + diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index b74c520670..9d02b8c9a1 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -29,6 +29,10 @@ protected: // this method is protected to stop C++ callers from calling, but invokable from script Q_INVOKABLE ScriptAudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); + Q_INVOKABLE void injectGeneratedNoise(bool inject); + Q_INVOKABLE void selectPinkNoise(); + Q_INVOKABLE void selectSine440(); + signals: void mutedByMixer(); void environmentMuted(); From c2c1ccc2b75d62c665889274f021db94c74228c9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 15 Apr 2015 15:50:22 +0200 Subject: [PATCH 069/401] Remove generated audio options from menu --- interface/src/Menu.cpp | 24 ------------------------ interface/src/Menu.h | 3 --- 2 files changed, 27 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 1cce0b1f56..796c8e6dd6 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -483,30 +483,6 @@ Menu::Menu() { 0, audioIO.data(), SLOT(sendMuteEnvironmentPacket())); - - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioSourceInject, - 0, - false, - audioIO.data(), - SLOT(toggleAudioSourceInject())); - QMenu* audioSourceMenu = audioDebugMenu->addMenu("Generated Audio Source"); - { - QAction *pinkNoise = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourcePinkNoise, - 0, - false, - audioIO.data(), - SLOT(selectAudioSourcePinkNoise())); - - QAction *sine440 = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourceSine440, - 0, - true, - audioIO.data(), - SLOT(selectAudioSourceSine440())); - - QActionGroup* audioSourceGroup = new QActionGroup(audioSourceMenu); - audioSourceGroup->addAction(pinkNoise); - audioSourceGroup->addAction(sine440); - } auto scope = DependencyManager::get(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index db126a3c9b..4589c94b08 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -123,9 +123,6 @@ namespace MenuOption { const QString AudioScopeTwentyFrames = "Twenty"; const QString AudioStats = "Audio Stats"; const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams"; - const QString AudioSourceInject = "Generated Audio"; - const QString AudioSourcePinkNoise = "Pink Noise"; - const QString AudioSourceSine440 = "Sine 440hz"; const QString BandwidthDetails = "Bandwidth Details"; const QString BlueSpeechSphere = "Blue Sphere While Speaking"; const QString BookmarkLocation = "Bookmark Location"; From 9ea72f2a03052c0f37102a3d99d5a917fcf280bb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 15 Apr 2015 16:16:13 +0200 Subject: [PATCH 070/401] Added generated audio to developer menu script --- .../utilities/tools/developerMenuItems.js | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/examples/utilities/tools/developerMenuItems.js b/examples/utilities/tools/developerMenuItems.js index a691031131..4243838601 100644 --- a/examples/utilities/tools/developerMenuItems.js +++ b/examples/utilities/tools/developerMenuItems.js @@ -13,16 +13,25 @@ var createdRenderMenu = false; -var ENTITIES_MENU = "Developer > Entities"; +var DEVELOPER_MENU = "Developer"; + +var ENTITIES_MENU = DEVELOPER_MENU + " > Entities"; var COLLISION_UPDATES_TO_SERVER = "Don't send collision updates to server"; -var RENDER_MENU = "Developer > Render"; +var RENDER_MENU = DEVELOPER_MENU + " > Render"; var ENTITIES_ITEM = "Entities"; var AVATARS_ITEM = "Avatars"; +var AUDIO_MENU = DEVELOPER_MENU + " > Audio"; +var AUDIO_SOURCE_INJECT = "Generated Audio"; +var AUDIO_SOURCE_MENU = AUDIO_MENU + " > Generated Audio Source"; +var AUDIO_SOURCE_PINK_NOISE = "Pink Noise"; +var AUDIO_SOURCE_SINE_440 = "Sine 440hz"; + + function setupMenus() { - if (!Menu.menuExists("Developer")) { - Menu.addMenu("Developer"); + if (!Menu.menuExists(DEVELOPER_MENU)) { + Menu.addMenu(DEVELOPER_MENU); } if (!Menu.menuExists(ENTITIES_MENU)) { Menu.addMenu(ENTITIES_MENU); @@ -54,6 +63,17 @@ function setupMenus() { if (!Menu.menuItemExists(RENDER_MENU, AVATARS_ITEM)) { Menu.addMenuItem({ menuName: RENDER_MENU, menuItemName: AVATARS_ITEM, isCheckable: true, isChecked: Scene.shouldRenderAvatars }) } + + + if (!Menu.menuExists(AUDIO_MENU)) { + Menu.addMenu(AUDIO_MENU); + } + Menu.addMenuItem({ menuName: AUDIO_MENU, menuItemName: AUDIO_SOURCE_INJECT, isCheckable: true, isChecked: false }); + Menu.addMenu(AUDIO_SOURCE_MENU); + Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_PINK_NOISE, isCheckable: true, isChecked: false }); + Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_SINE_440, isCheckable: true, isChecked: false }); + Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, true); + } Menu.menuItemEvent.connect(function (menuItem) { @@ -67,7 +87,15 @@ Menu.menuItemEvent.connect(function (menuItem) { Scene.shouldRenderEntities = Menu.isOptionChecked(ENTITIES_ITEM); } else if (menuItem == AVATARS_ITEM) { Scene.shouldRenderAvatars = Menu.isOptionChecked(AVATARS_ITEM); - } + } else if (menuItem == AUDIO_SOURCE_INJECT) { + Audio.injectGeneratedNoise(Menu.isOptionChecked(AUDIO_SOURCE_INJECT)); + } else if (menuItem == AUDIO_SOURCE_PINK_NOISE) { + Audio.selectPinkNoise(); + Menu.setIsOptionChecked(AUDIO_SOURCE_SINE_440, false); + } else if (menuItem == AUDIO_SOURCE_SINE_440) { + Audio.selectSine440(); + Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, false); + } }); Scene.shouldRenderAvatarsChanged.connect(function(shouldRenderAvatars) { @@ -87,6 +115,10 @@ function scriptEnding() { Menu.removeMenuItem(RENDER_MENU, ENTITIES_ITEM); Menu.removeMenuItem(RENDER_MENU, AVATARS_ITEM); } + + Audio.injectGeneratedNoise(false); + Menu.removeMenuItem(AUDIO_MENU, AUDIO_SOURCE_INJECT); + Menu.removeMenu(AUDIO_SOURCE_MENU); } setupMenus(); From 5f9d7a00fa01c426598a809b9349c1f7970b0087 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 15 Apr 2015 16:22:18 +0200 Subject: [PATCH 071/401] Correct default to pink noise --- examples/utilities/tools/developerMenuItems.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/utilities/tools/developerMenuItems.js b/examples/utilities/tools/developerMenuItems.js index 4243838601..84e1853d64 100644 --- a/examples/utilities/tools/developerMenuItems.js +++ b/examples/utilities/tools/developerMenuItems.js @@ -73,6 +73,7 @@ function setupMenus() { Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_PINK_NOISE, isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_SINE_440, isCheckable: true, isChecked: false }); Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, true); + Audio.selectPinkNoise(); } From 62d3b39c2569a818a183a51fad92dfaa173970c7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 15 Apr 2015 16:22:52 +0200 Subject: [PATCH 072/401] less loud generated noise Prevents the audio mixer from muting you because of too much noise --- libraries/audio-client/src/AudioClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 032c70985e..331e62ec70 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -493,7 +493,7 @@ void AudioClient::start() { _sourceGain.initialize(); _noiseSource.initialize(); _toneSource.initialize(); - _sourceGain.setParameters(0.25f, 0.0f); + _sourceGain.setParameters(0.05f, 0.0f); _inputGain.setParameters(1.0f, 0.0f); } From d2775fe9b337b1be396a1f90c03709fc21c6c1cd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 15 Apr 2015 16:52:41 +0200 Subject: [PATCH 073/401] Fix for people running older version of interface --- .../utilities/tools/developerMenuItems.js | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/utilities/tools/developerMenuItems.js b/examples/utilities/tools/developerMenuItems.js index 84e1853d64..58b5149307 100644 --- a/examples/utilities/tools/developerMenuItems.js +++ b/examples/utilities/tools/developerMenuItems.js @@ -12,6 +12,7 @@ // var createdRenderMenu = false; +var createdGeneratedAudioMenu = false; var DEVELOPER_MENU = "Developer"; @@ -68,13 +69,15 @@ function setupMenus() { if (!Menu.menuExists(AUDIO_MENU)) { Menu.addMenu(AUDIO_MENU); } - Menu.addMenuItem({ menuName: AUDIO_MENU, menuItemName: AUDIO_SOURCE_INJECT, isCheckable: true, isChecked: false }); - Menu.addMenu(AUDIO_SOURCE_MENU); - Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_PINK_NOISE, isCheckable: true, isChecked: false }); - Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_SINE_440, isCheckable: true, isChecked: false }); - Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, true); - Audio.selectPinkNoise(); - + if (!Menu.menuItemExists(AUDIO_MENU, AUDIO_SOURCE_INJECT)) { + Menu.addMenuItem({ menuName: AUDIO_MENU, menuItemName: AUDIO_SOURCE_INJECT, isCheckable: true, isChecked: false }); + Menu.addMenu(AUDIO_SOURCE_MENU); + Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_PINK_NOISE, isCheckable: true, isChecked: false }); + Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_SINE_440, isCheckable: true, isChecked: false }); + Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, true); + Audio.selectPinkNoise(); + createdGeneratedAudioMenu = true; + } } Menu.menuItemEvent.connect(function (menuItem) { @@ -88,12 +91,12 @@ Menu.menuItemEvent.connect(function (menuItem) { Scene.shouldRenderEntities = Menu.isOptionChecked(ENTITIES_ITEM); } else if (menuItem == AVATARS_ITEM) { Scene.shouldRenderAvatars = Menu.isOptionChecked(AVATARS_ITEM); - } else if (menuItem == AUDIO_SOURCE_INJECT) { + } else if (menuItem == AUDIO_SOURCE_INJECT && !createdGeneratedAudioMenu) { Audio.injectGeneratedNoise(Menu.isOptionChecked(AUDIO_SOURCE_INJECT)); - } else if (menuItem == AUDIO_SOURCE_PINK_NOISE) { + } else if (menuItem == AUDIO_SOURCE_PINK_NOISE && !createdGeneratedAudioMenu) { Audio.selectPinkNoise(); Menu.setIsOptionChecked(AUDIO_SOURCE_SINE_440, false); - } else if (menuItem == AUDIO_SOURCE_SINE_440) { + } else if (menuItem == AUDIO_SOURCE_SINE_440 && !createdGeneratedAudioMenu) { Audio.selectSine440(); Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, false); } @@ -117,9 +120,11 @@ function scriptEnding() { Menu.removeMenuItem(RENDER_MENU, AVATARS_ITEM); } - Audio.injectGeneratedNoise(false); - Menu.removeMenuItem(AUDIO_MENU, AUDIO_SOURCE_INJECT); - Menu.removeMenu(AUDIO_SOURCE_MENU); + if (createdGeneratedAudioMenu) { + Audio.injectGeneratedNoise(false); + Menu.removeMenuItem(AUDIO_MENU, AUDIO_SOURCE_INJECT); + Menu.removeMenu(AUDIO_SOURCE_MENU); + } } setupMenus(); From 604a13f8adef63337db66fecb49bda3c7314078e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 15 Apr 2015 17:04:59 +0200 Subject: [PATCH 074/401] Only editor can mute environment --- assignment-client/src/audio/AudioMixer.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index dd566bc40b..06e6f77f69 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -549,14 +549,18 @@ void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const Hif nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); } else if (mixerPacketType == PacketTypeMuteEnvironment) { - QByteArray packet = receivedPacket; - populatePacketHeader(packet, PacketTypeMuteEnvironment); - - nodeList->eachNode([&](const SharedNodePointer& node){ - if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) { - nodeList->writeDatagram(packet, packet.size(), node); - } - }); + SharedNodePointer sendingNode = nodeList->sendingNodeForPacket(receivedPacket); + if (sendingNode->getCanAdjustLocks()) { + QByteArray packet = receivedPacket; + populatePacketHeader(packet, PacketTypeMuteEnvironment); + + nodeList->eachNode([&](const SharedNodePointer& node){ + if (node->getType() == NodeType::Agent && node->getActiveSocket() && + node->getLinkedData() && node != sendingNode) { + nodeList->writeDatagram(packet, packet.size(), node); + } + }); + } } else { // let processNodeData handle it. nodeList->processNodeData(senderSockAddr, receivedPacket); From 1046356abb3f5da1f1f8092f489f67cef6fbafae Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 15 Apr 2015 09:00:20 -0700 Subject: [PATCH 075/401] FIx the include that was using the wrong \ in the path... --- interface/src/devices/OculusManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 0b4e3c1e73..2141127a3b 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -34,7 +34,7 @@ #include "InterfaceLogging.h" #include "Application.h" -#include +#include template void for_each_eye(Function function) { From f8e4ff8072409e5fad07d4b1ca9682eb74755e58 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 15 Apr 2015 09:54:30 -0700 Subject: [PATCH 076/401] Update Application:stopAllScripts to skip finished scripts --- interface/src/Application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4892019ae5..4328be21b4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3889,6 +3889,9 @@ void Application::stopAllScripts(bool restart) { // stops all current running scripts for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); it != _scriptEnginesHash.constEnd(); it++) { + if (it.value()->isFinished()) { + continue; + } if (restart && it.value()->isUserLoaded()) { connect(it.value(), SIGNAL(finished(const QString&)), SLOT(loadScript(const QString&))); } From 2e61ef01daf61ca39fc265d2214c1c6b36112f04 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 15 Apr 2015 09:55:36 -0700 Subject: [PATCH 077/401] Update ScriptEngin::stop to only take effect when not finished --- libraries/script-engine/src/ScriptEngine.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2f9427a63d..ac2c212001 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -647,8 +647,10 @@ void ScriptEngine::stopAllTimers() { } void ScriptEngine::stop() { - _isFinished = true; - emit runningStateChanged(); + if (!_isFinished) { + _isFinished = true; + emit runningStateChanged(); + } } void ScriptEngine::timerFired() { From 8b97d2585af25618ab5ba39ad7402ae42f3964a9 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 15 Apr 2015 10:16:04 -0700 Subject: [PATCH 078/401] fixing syntax issues --- libraries/gpu/src/gpu/Framebuffer.cpp | 7 +------ libraries/gpu/src/gpu/Framebuffer.h | 2 +- libraries/gpu/src/gpu/GLBackendOutput.cpp | 3 +-- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index bc263494a1..96bd3d3002 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -15,12 +15,7 @@ using namespace gpu; -Framebuffer::Framebuffer() -{ -} - -Framebuffer::~Framebuffer() -{ +Framebuffer::~Framebuffer() { } Framebuffer* Framebuffer::create() { diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index ef77df7ceb..69e507f824 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -149,7 +149,7 @@ protected: // Non exposed Framebuffer(const Framebuffer& framebuffer) {} - Framebuffer(); + Framebuffer() {} // This shouldn't be used by anything else than the Backend class with the proper casting. mutable GPUObject* _gpuObject = NULL; diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 9b3fb5fe34..bd8a2ab457 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -12,8 +12,7 @@ #include "GLBackendShared.h" -GLBackend::GLFramebuffer::GLFramebuffer() -{} +GLBackend::GLFramebuffer::GLFramebuffer() {} GLBackend::GLFramebuffer::~GLFramebuffer() { if (_fbo != 0) { From afca5440f0c7b5e70966ea1b86422311e773b1a5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 15 Apr 2015 10:58:56 -0700 Subject: [PATCH 079/401] entity-server will automatically clear simulation-owner ID if it doesn't get an update for 2 seconds --- libraries/entities/src/EntityItem.h | 2 +- .../entities/src/SimpleEntitySimulation.cpp | 28 +++++++++++++++++++ .../entities/src/SimpleEntitySimulation.h | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 8f7feb2ed8..946efea39c 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -323,7 +323,7 @@ protected: quint64 _lastEdited; // last official local or remote edit time quint64 _lastEditedFromRemote; // last time we received and edit from the server - quint64 _lastEditedFromRemoteInRemoteTime; // last time we received and edit from the server (in server-time-frame) + quint64 _lastEditedFromRemoteInRemoteTime; // last time we received an edit from the server (in server-time-frame) quint64 _created; quint64 _changedOnServer; diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 6d45768c26..6846a38cb0 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -13,8 +13,12 @@ #include "EntityItem.h" #include "SimpleEntitySimulation.h" +#include "EntitiesLogging.h" + +const quint64 AUTO_REMOVE_SIMULATION_OWNER_USEC = 2000000; void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { + // now is usecTimestampNow() QSet::iterator itemItr = _movingEntities.begin(); while (itemItr != _movingEntities.end()) { EntityItem* entity = *itemItr; @@ -27,6 +31,22 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { ++itemItr; } } + + // If an Entity has a simulation owner and we don't get an update for some amount of time, + // clear the owner. This guards against an interface failing to release the Entity when it + // has finished simulating it. + itemItr = _hasSimulationOwnerEntities.begin(); + while (itemItr != _hasSimulationOwnerEntities.end()) { + EntityItem* entity = *itemItr; + if (!entity->getSimulatorID().isEmpty() && + usecTimestampNow() - entity->getLastChangedOnServer() >= AUTO_REMOVE_SIMULATION_OWNER_USEC) { + qCDebug(entities) << "auto-removing simulation owner" << entity->getSimulatorID(); + entity->setSimulatorID(""); + itemItr = _hasSimulationOwnerEntities.erase(itemItr); + } else { + ++itemItr; + } + } } void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { @@ -35,11 +55,15 @@ void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { } else if (entity->getCollisionsWillMove()) { _movableButStoppedEntities.insert(entity); } + if (!entity->getSimulatorID().isEmpty()) { + _hasSimulationOwnerEntities.insert(entity); + } } void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { _movingEntities.remove(entity); _movableButStoppedEntities.remove(entity); + _hasSimulationOwnerEntities.remove(entity); } const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITY | EntityItem::DIRTY_MOTION_TYPE; @@ -55,6 +79,9 @@ void SimpleEntitySimulation::entityChangedInternal(EntityItem* entity) { _movingEntities.remove(entity); _movableButStoppedEntities.remove(entity); } + if (!entity->getSimulatorID().isEmpty()) { + _hasSimulationOwnerEntities.insert(entity); + } } entity->clearDirtyFlags(); } @@ -62,5 +89,6 @@ void SimpleEntitySimulation::entityChangedInternal(EntityItem* entity) { void SimpleEntitySimulation::clearEntitiesInternal() { _movingEntities.clear(); _movableButStoppedEntities.clear(); + _hasSimulationOwnerEntities.clear(); } diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index 92b6a28215..af79ec0131 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -30,6 +30,7 @@ protected: QSet _movingEntities; QSet _movableButStoppedEntities; + QSet _hasSimulationOwnerEntities; }; #endif // hifi_SimpleEntitySimulation_h From 62b59b7ccc877b1991757f36348ecccc9410e683 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 15 Apr 2015 11:02:12 -0700 Subject: [PATCH 080/401] remove uneeded debug print --- libraries/entities/src/EntityTreeElement.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index d6d5c68ff9..93c69c9c61 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -740,9 +740,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int auto nodeList = DependencyManager::get(); QString myNodeID = nodeList->getSessionUUID().toString(); if (entityItem && entityItem->getSimulatorID() == myNodeID) { - // do nothing, this was echoed back to us - qDebug() << "IGNORING ECHOED ENTITY UPDATE"; - // _myTree->entityChanged(entityItem); + // do nothing, this was echoed back to us by the entity server } else if (entityItem) { QString entityScriptBefore = entityItem->getScript(); bool bestFitBefore = bestFitEntityBounds(entityItem); From 2f970ae9622197f461ea8037b0f94f22d1da76d7 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 15 Apr 2015 11:07:00 -0700 Subject: [PATCH 081/401] Terminate DDE process gracefully --- interface/src/devices/DdeFaceTracker.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index a701160198..c7a8b7d166 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -182,9 +182,10 @@ void DdeFaceTracker::setEnabled(bool enabled) { _udpSocket.bind(_host, _serverPort); } + const char* DDE_EXIT_COMMAND = "exit"; + if (enabled && !_ddeProcess) { // Terminate any existing DDE process, perhaps left running after an Interface crash - const char* DDE_EXIT_COMMAND = "exit"; _udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort); qDebug() << "[Info] DDE Face Tracker Starting"; @@ -194,7 +195,8 @@ void DdeFaceTracker::setEnabled(bool enabled) { } if (!enabled && _ddeProcess) { - _ddeProcess->kill(); // More robust than trying to send an "exit" command to DDE + _udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort); + delete _ddeProcess; _ddeProcess = NULL; qDebug() << "[Info] DDE Face Tracker Stopped"; } From 51ac44a9b7388a7d372fc103e2b9198dc91439e5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 15 Apr 2015 11:34:42 -0700 Subject: [PATCH 082/401] try to increase chances the interface gives up simulation ownership --- libraries/physics/src/EntityMotionState.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 5d5435eb5e..db79581812 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -255,7 +255,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // The object is moving and nobody thinks they own the motion. set this Node as the simulator _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); - } else if (simulatorID == myNodeID && _numNonMovingUpdates == MAX_NUM_NON_MOVING_UPDATES) { + } else if (simulatorID == myNodeID && _numNonMovingUpdates >= MAX_NUM_NON_MOVING_UPDATES - 1) { // we are the simulator and the object has stopped. give up "simulator" status _entity->setSimulatorID(""); properties.setSimulatorID(""); @@ -287,7 +287,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setLastEdited(_entity->getLastEdited()); } - if (EntityItem::getSendPhysicsUpdates() /* && _numNonMovingUpdates <= MAX_NUM_NON_MOVING_UPDATES*/) { + if (EntityItem::getSendPhysicsUpdates()) { EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); #ifdef WANT_DEBUG From 9213561977ba1c9c2d4744c8b461b0b129a92906 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Apr 2015 11:34:59 -0700 Subject: [PATCH 083/401] add vim plugin files to gitignore --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3b44b99e68..f2f259a0c2 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,8 @@ libraries/audio-client/external/*/* gvr-interface/assets/oculussig* gvr-interface/libs/* -TAGS \ No newline at end of file +# ignore files for various dev environments +TAGS +.ycm_extra_conf.* +*.taghl +*.swp From c87dca5ba0fdafffd8abb081ee56cac9dc33a7d7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 15 Apr 2015 11:58:12 -0700 Subject: [PATCH 084/401] remove debug print --- libraries/physics/src/EntityMotionState.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index db79581812..655db8fd2f 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -293,10 +293,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ #ifdef WANT_DEBUG qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; #endif - qDebug() << "EntityMotionState::sendUpdate" << (zeroSpin && zeroSpin) - << _sentMoving - << _numNonMovingUpdates - << "me:" << myNodeID << "owner:" << simulatorID; entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { #ifdef WANT_DEBUG From 08b155146ae0dd867ab724cd3f3eeef9777f6a60 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Apr 2015 12:12:21 -0700 Subject: [PATCH 085/401] move externals from build-ext inside the build folder --- cmake/macros/SetupExternalsBinaryDir.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/macros/SetupExternalsBinaryDir.cmake b/cmake/macros/SetupExternalsBinaryDir.cmake index 04bd00643c..a118dcf543 100644 --- a/cmake/macros/SetupExternalsBinaryDir.cmake +++ b/cmake/macros/SetupExternalsBinaryDir.cmake @@ -22,11 +22,11 @@ macro(SETUP_EXTERNALS_BINARY_DIR) endif () endif () - set(EXTERNALS_BINARY_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build-ext") + set(EXTERNALS_BINARY_ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}/ext") if (ANDROID) set(EXTERNALS_BINARY_DIR "${EXTERNALS_BINARY_ROOT_DIR}/android/${CMAKE_GENERATOR_FOLDER_NAME}") else () set(EXTERNALS_BINARY_DIR "${EXTERNALS_BINARY_ROOT_DIR}/${CMAKE_GENERATOR_FOLDER_NAME}") endif () -endmacro() \ No newline at end of file +endmacro() From 8b41a952b32e6dc4adc00f4877cf23d1e7c824b8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Apr 2015 12:19:38 -0700 Subject: [PATCH 086/401] update instructions for new build folder placement --- .gitignore | 1 + BUILD.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f2f259a0c2..b774d7cdbd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ CMakeFiles/ CMakeScripts/ cmake_install.cmake build*/ +ext/ Makefile *.user diff --git a/BUILD.md b/BUILD.md index fe0459e7db..ed3fea5c5f 100644 --- a/BUILD.md +++ b/BUILD.md @@ -19,9 +19,9 @@ The following external projects are optional dependencies. You can indicate to C * [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3 * Enables game controller support in Interface -The above dependencies will be downloaded, built, linked and included automatically by CMake where we require them. The CMakeLists files that handle grabbing each of the following external dependencies can be found in the [cmake/externals folder](cmake/externals). The resulting downloads, source files and binaries will be placed in the `build-ext` directory in each of the subfolders for each external project. +The above dependencies will be downloaded, built, linked and included automatically by CMake where we require them. The CMakeLists files that handle grabbing each of the following external dependencies can be found in the [cmake/externals folder](cmake/externals). The resulting downloads, source files and binaries will be placed in the `build/ext` folder in each of the subfolders for each external project. -These are not placed in your normal build tree when doing an out of source build so that they do not need to be re-downloaded and re-compiled every time the CMake build folder is cleared. Should you want to force a re-download and re-compile of a specific external, you can simply remove that directory from the appropriate subfolder in `build-ext`. Should you want to force a re-download and re-compile of all externals, just remove the `build-ext` folder. +These are not placed in your normal build tree when doing an out of source build so that they do not need to be re-downloaded and re-compiled every time the CMake build folder is cleared. Should you want to force a re-download and re-compile of a specific external, you can simply remove that directory from the appropriate subfolder in `build/ext`. Should you want to force a re-download and re-compile of all externals, just remove the `build/ext` folder. If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DGET_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project. From aba2b395a6769bd91df352506e63fd47391e240c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 15 Apr 2015 12:35:30 -0700 Subject: [PATCH 087/401] Working on testing the QML ui --- interface/resources/qml/Palettes.qml | 236 +++++++++++++++++++++ interface/resources/qml/TestDialog.qml | 112 ++++++++++ interface/resources/qml/TestRoot.qml | 26 +++ interface/src/ui/ApplicationOverlay.h | 3 +- libraries/render-utils/src/OffscreenUi.cpp | 5 +- tests/render-utils/src/main.cpp | 11 +- 6 files changed, 384 insertions(+), 9 deletions(-) create mode 100644 interface/resources/qml/Palettes.qml create mode 100644 interface/resources/qml/TestDialog.qml create mode 100644 interface/resources/qml/TestRoot.qml diff --git a/interface/resources/qml/Palettes.qml b/interface/resources/qml/Palettes.qml new file mode 100644 index 0000000000..c4b0953df7 --- /dev/null +++ b/interface/resources/qml/Palettes.qml @@ -0,0 +1,236 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 + +Rectangle { + color: "teal" + height: 512 + width: 192 + SystemPalette { id: sp; colorGroup: SystemPalette.Active } + SystemPalette { id: spi; colorGroup: SystemPalette.Inactive } + SystemPalette { id: spd; colorGroup: SystemPalette.Disabled } + + Column { + anchors.margins: 8 + anchors.fill: parent + spacing: 8 + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "base" } + Rectangle { height: parent.height; width: 16; color: sp.base } + Rectangle { height: parent.height; width: 16; color: spi.base } + Rectangle { height: parent.height; width: 16; color: spd.base } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "alternateBase" } + Rectangle { height: parent.height; width: 16; color: sp.alternateBase } + Rectangle { height: parent.height; width: 16; color: spi.alternateBase } + Rectangle { height: parent.height; width: 16; color: spd.alternateBase } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "dark" } + Rectangle { height: parent.height; width: 16; color: sp.dark } + Rectangle { height: parent.height; width: 16; color: spi.dark } + Rectangle { height: parent.height; width: 16; color: spd.dark } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "mid" } + Rectangle { height: parent.height; width: 16; color: sp.mid } + Rectangle { height: parent.height; width: 16; color: spi.mid } + Rectangle { height: parent.height; width: 16; color: spd.mid } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "mid light" } + Rectangle { height: parent.height; width: 16; color: sp.midlight } + Rectangle { height: parent.height; width: 16; color: spi.midlight } + Rectangle { height: parent.height; width: 16; color: spd.midlight } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "light" } + Rectangle { height: parent.height; width: 16; color: sp.light} + Rectangle { height: parent.height; width: 16; color: spi.light} + Rectangle { height: parent.height; width: 16; color: spd.light} + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "shadow" } + Rectangle { height: parent.height; width: 16; color: sp.shadow} + Rectangle { height: parent.height; width: 16; color: spi.shadow} + Rectangle { height: parent.height; width: 16; color: spd.shadow} + } + Item { + height: 16 + width:parent.width + } + + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "text" } + Rectangle { height: parent.height; width: 16; color: sp.text } + Rectangle { height: parent.height; width: 16; color: spi.text } + Rectangle { height: parent.height; width: 16; color: spd.text } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "window" } + Rectangle { height: parent.height; width: 16; color: sp.window } + Rectangle { height: parent.height; width: 16; color: spi.window } + Rectangle { height: parent.height; width: 16; color: spd.window } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "window text" } + Rectangle { height: parent.height; width: 16; color: sp.windowText } + Rectangle { height: parent.height; width: 16; color: spi.windowText } + Rectangle { height: parent.height; width: 16; color: spd.windowText } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "button" } + Rectangle { height: parent.height; width: 16; color: sp.button } + Rectangle { height: parent.height; width: 16; color: spi.button } + Rectangle { height: parent.height; width: 16; color: spd.button } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "buttonText" } + Rectangle { height: parent.height; width: 16; color: sp.buttonText } + Rectangle { height: parent.height; width: 16; color: spi.buttonText } + Rectangle { height: parent.height; width: 16; color: spd.buttonText } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "highlight" } + Rectangle { height: parent.height; width: 16; color: sp.highlight } + Rectangle { height: parent.height; width: 16; color: spi.highlight } + Rectangle { height: parent.height; width: 16; color: spd.highlight } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "highlighted text" } + Rectangle { height: parent.height; width: 16; color: sp.highlightedText} + Rectangle { height: parent.height; width: 16; color: spi.highlightedText} + Rectangle { height: parent.height; width: 16; color: spd.highlightedText} + } + } + + +/* + CustomDialog { + title: "Test Dlg" + anchors.fill: parent + + Rectangle { + property int d: 100 + id: square + objectName: "testRect" + width: d + height: d + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } + + + CustomTextEdit { + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + clip: true + text: "test edit" + anchors.top: parent.top + anchors.topMargin: parent.titleSize + 12 + } + + CustomButton { + x: 128 + y: 192 + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + onClicked: { + console.log("Click"); + if (square.visible) { + square.visible = false + } else { + square.visible = true + } + } + } + + CustomButton { + id: customButton2 + y: 192 + text: "Close" + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + onClicked: { + onClicked: testDialog.x == 0 ? testDialog.x = 200 : testDialog.x = 0 + } + } + + Keys.onPressed: { + console.log("Key " + event.key); + switch (event.key) { + case Qt.Key_Q: + if (Qt.ControlModifier == event.modifiers) { + event.accepted = true; + break; + } + } + } + } +*/ + +} + + +/* + +// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property + +MouseArea { + anchors.fill: parent +} +*/ diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml new file mode 100644 index 0000000000..9c8bcccd75 --- /dev/null +++ b/interface/resources/qml/TestDialog.qml @@ -0,0 +1,112 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 + +Item { + objectName: "TestDialog" + id: testDialog + width: 384 + height: 384 + scale: 0.0 + + onEnabledChanged: { + scale = enabled ? 1.0 : 0.0 + } + onScaleChanged: { + visible = (scale != 0.0); + } + Component.onCompleted: { + scale = 1.0 + } + Behavior on scale { + NumberAnimation { + //This specifies how long the animation takes + duration: 400 + //This selects an easing curve to interpolate with, the default is Easing.Linear + easing.type: Easing.InOutBounce + } + } + + CustomDialog { + title: "Test Dlg" + anchors.fill: parent + + Rectangle { + property int d: 100 + id: square + objectName: "testRect" + width: d + height: d + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } + + + CustomTextEdit { + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + clip: true + text: "test edit" + anchors.top: parent.top + anchors.topMargin: parent.titleSize + 12 + } + + CustomButton { + x: 128 + y: 192 + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + onClicked: { + console.log("Click"); + if (square.visible) { + square.visible = false + } else { + square.visible = true + } + } + } + + CustomButton { + id: customButton2 + y: 192 + text: "Close" + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + onClicked: { + onClicked: testDialog.x == 0 ? testDialog.x = 200 : testDialog.x = 0 + } + } + + Keys.onPressed: { + console.log("Key " + event.key); + switch (event.key) { + case Qt.Key_Q: + if (Qt.ControlModifier == event.modifiers) { + event.accepted = true; + break; + } + } + } + } + + +} + + +/* + +// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property + +MouseArea { + anchors.fill: parent +} +*/ diff --git a/interface/resources/qml/TestRoot.qml b/interface/resources/qml/TestRoot.qml new file mode 100644 index 0000000000..a3ef5f8fe9 --- /dev/null +++ b/interface/resources/qml/TestRoot.qml @@ -0,0 +1,26 @@ +import QtQuick 2.3 +import "componentCreation.js" as Creator + + +Item { + id: root + width: 1280 + height: 720 + + function loadChild(url) { + Creator.createObject(root, url) + } + + + CustomButton { + anchors.right: parent.right + anchors.rightMargin: 24 + anchors.bottom: parent.bottom + anchors.bottomMargin: 24 + text: "Test" + onClicked: { + loadChild("TestDialog.qml"); + } + } +} + diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index cc4188e8ef..e6c7526c5d 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -23,7 +23,8 @@ const float MAGNIFY_MULT = 2.0f; const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; // Handles the drawing of the overlays to the screen -class ApplicationOverlay { +class ApplicationOverlay : public QObject { + Q_OBJECT public: ApplicationOverlay(); ~ApplicationOverlay(); diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index cb57d86412..718a70f4e1 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -308,9 +308,10 @@ void OffscreenUi::toggle(const QUrl & url, const QString & name) { // Toggle the visibity AND the enabled flag (otherwise invisible // dialogs can still swallow keyboard input) - bool newFlag = !item->isVisible(); - item->setVisible(newFlag); + bool newFlag = !item->isEnabled(); item->setEnabled(newFlag); + // item->setVisible(newFlag); + } diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 304d6f1a07..dd413a9f57 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -160,7 +160,7 @@ public: setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); - static const QString f("/Users/bdavis/Git/hifi/interface/resources/qml/Root.qml"); + static const QString f("/Users/bdavis/Git/hifi/interface/resources/qml/TestRoot.qml"); _offscreenUi.loadQml(QUrl::fromLocalFile(f)); connect(&_offscreenUi, &OffscreenUi::textureUpdated, this, [&](int textureId) { _offscreenUi.lockTexture(textureId); @@ -193,8 +193,7 @@ protected: void keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Slash: - qDebug() << "Foo"; - _offscreenUi.load(QString("Login.qml")); + _offscreenUi.toggle(QString("TestDialog.qml"), "TestDialog"); break; } QWindow::keyPressEvent(event); @@ -289,15 +288,15 @@ void QTestWindow::draw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, _size.width(), _size.height()); - renderText(); - //renderQml(); + //renderText(); + renderQml(); _context->swapBuffers(this); glFinish(); fps.increment(); if (fps.elapsed() >= 2.0f) { - //qDebug() << "FPS: " << fps.rate(); + qDebug() << "FPS: " << fps.rate(); fps.reset(); } } From faf7850d7c0af3e36754f22fa98822460bf8f402 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Apr 2015 12:38:24 -0700 Subject: [PATCH 088/401] remove plugin specific ignored files --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index f2f259a0c2..44561daabc 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,4 @@ gvr-interface/libs/* # ignore files for various dev environments TAGS -.ycm_extra_conf.* -*.taghl *.swp From 03129f98d4605635a5ecb75c556b1c0b0cb7d903 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Apr 2015 13:51:51 -0700 Subject: [PATCH 089/401] make VHACD an external project --- CMakeLists.txt | 1 + cmake/externals/vhacd/CMakeLists.txt | 30 ++++++++++++++++ cmake/modules/FindVHACD.cmake | 34 ++----------------- tools/CMakeLists.txt | 8 ++--- tools/vhacd-util/CMakeLists.txt | 21 ++++++++++++ tools/{vhacd => vhacd-util}/src/VHACDUtil.cpp | 0 tools/{vhacd => vhacd-util}/src/VHACDUtil.h | 0 .../src/VHACDUtilApp.cpp | 0 .../{vhacd => vhacd-util}/src/VHACDUtilApp.h | 0 tools/{vhacd => vhacd-util}/src/main.cpp | 0 tools/vhacd/CMakeLists.txt | 23 ------------- 11 files changed, 57 insertions(+), 60 deletions(-) create mode 100644 cmake/externals/vhacd/CMakeLists.txt create mode 100644 tools/vhacd-util/CMakeLists.txt rename tools/{vhacd => vhacd-util}/src/VHACDUtil.cpp (100%) rename tools/{vhacd => vhacd-util}/src/VHACDUtil.h (100%) rename tools/{vhacd => vhacd-util}/src/VHACDUtilApp.cpp (100%) rename tools/{vhacd => vhacd-util}/src/VHACDUtilApp.h (100%) rename tools/{vhacd => vhacd-util}/src/main.cpp (100%) delete mode 100644 tools/vhacd/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 81d532fbe2..ebf830e354 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,6 +168,7 @@ option(GET_SOXR "Get Soxr library automatically as external project" 1) option(GET_TBB "Get Threading Building Blocks library automatically as external project" 1) option(GET_LIBOVR "Get LibOVR library automatically as external project" 1) option(USE_NSIGHT "Attempt to find the nSight libraries" 1) +option(GET_VHACD "Get V-HACD library automatically as external project" 1) if (WIN32) option(GET_GLEW "Get GLEW library automatically as external project" 1) diff --git a/cmake/externals/vhacd/CMakeLists.txt b/cmake/externals/vhacd/CMakeLists.txt new file mode 100644 index 0000000000..eae9d7e59a --- /dev/null +++ b/cmake/externals/vhacd/CMakeLists.txt @@ -0,0 +1,30 @@ +set(EXTERNAL_NAME vhacd) + +if (ANDROID) + set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19") +endif () + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + URL http://hifi-public.s3.amazonaws.com/dependencies/v-hacd-master.zip + URL_MD5 81d6244ac204db5ba27305e2e8e210ad + CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH= + BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +if (WIN32) + set(LIBRARY_FILENAME ${EXTERNAL_NAME_UPPER}.lib) +else () + set(LIBRARY_FILENAME lib${EXTERNAL_NAME_UPPER}.a) +endif () + +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to V-HACD include directory") +set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/${LIBRARY_FILENAME} CACHE FILEPATH "Path to V-HACD library") diff --git a/cmake/modules/FindVHACD.cmake b/cmake/modules/FindVHACD.cmake index 03e30b41d4..2a920381d7 100644 --- a/cmake/modules/FindVHACD.cmake +++ b/cmake/modules/FindVHACD.cmake @@ -19,38 +19,8 @@ include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") hifi_library_search_hints("vhacd") -macro(_FIND_VHACD_LIBRARY _var) - set(_${_var}_NAMES ${ARGN}) - find_library(${_var}_LIBRARY_RELEASE - NAMES ${_${_var}_NAMES} - HINTS - ${VHACD_SEARCH_DIRS} - $ENV{VHACD_ROOT_DIR} - PATH_SUFFIXES lib lib/Release - ) - - find_library(${_var}_LIBRARY_DEBUG - NAMES ${_${_var}_NAMES} - HINTS - ${VHACD_SEARCH_DIRS} - $ENV{VHACD_ROOT_DIR} - PATH_SUFFIXES lib lib/Debug - ) - - select_library_configurations(${_var}) - - mark_as_advanced(${_var}_LIBRARY) - mark_as_advanced(${_var}_LIBRARY) -endmacro() - - -find_path(VHACD_INCLUDE_DIRS VHACD.h PATH_SUFFIXES include HINTS ${VHACD_SEARCH_DIRS} $ENV{VHACD_ROOT_DIR}) -if(NOT WIN32) -_FIND_VHACD_LIBRARY(VHACD libVHACD.a) -else() -_FIND_VHACD_LIBRARY(VHACD VHACD_LIB) -endif() -set(VHACD_LIBRARIES ${VHACD_LIBRARY}) +find_path(VHACD_INCLUDE_DIRS VHACD.h PATH_SUFFIXES include HINTS ${VHACD_SEARCH_DIRS}) +find_library(VHACD_LIBRARIES VHACD PATH_SUFFIXES lib HINTS ${VHACD_SEARCH_DIRS}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(VHACD "Could NOT find VHACD, try to set the path to VHACD root folder in the system variable VHACD_ROOT_DIR or create a directory vhacd in HIFI_LIB_DIR and paste the necessary files there" diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index ba2938aaa6..55994f3d89 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,12 +1,10 @@ # add the tool directories add_subdirectory(mtc) set_target_properties(mtc PROPERTIES FOLDER "Tools") + add_subdirectory(scribe) set_target_properties(scribe PROPERTIES FOLDER "Tools") +add_subdirectory(vhacd-util) +set_target_properties(vhacd-util PROPERTIES FOLDER "Tools") -find_package(VHACD) -if(VHACD_FOUND) -add_subdirectory(vhacd) -# set_target_properties(vhacd PROPERTIES FOLDER "Tools") -endif() diff --git a/tools/vhacd-util/CMakeLists.txt b/tools/vhacd-util/CMakeLists.txt new file mode 100644 index 0000000000..b511922520 --- /dev/null +++ b/tools/vhacd-util/CMakeLists.txt @@ -0,0 +1,21 @@ +set(TARGET_NAME vhacd-util) +setup_hifi_project(Core Widgets) +link_hifi_libraries(shared fbx model gpu) + +add_dependency_external_projects(vhacd) + +find_package(VHACD REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${VHACD_INCLUDE_DIRS}) +target_link_libraries(${TARGET_NAME} ${VHACD_LIBRARIES}) + +if (NOT WIN32) + find_package(Threads) + target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) + + # include(FindOpenMP) + # if(OPENMP_FOUND) + # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") + # endif() +endif () diff --git a/tools/vhacd/src/VHACDUtil.cpp b/tools/vhacd-util/src/VHACDUtil.cpp similarity index 100% rename from tools/vhacd/src/VHACDUtil.cpp rename to tools/vhacd-util/src/VHACDUtil.cpp diff --git a/tools/vhacd/src/VHACDUtil.h b/tools/vhacd-util/src/VHACDUtil.h similarity index 100% rename from tools/vhacd/src/VHACDUtil.h rename to tools/vhacd-util/src/VHACDUtil.h diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd-util/src/VHACDUtilApp.cpp similarity index 100% rename from tools/vhacd/src/VHACDUtilApp.cpp rename to tools/vhacd-util/src/VHACDUtilApp.cpp diff --git a/tools/vhacd/src/VHACDUtilApp.h b/tools/vhacd-util/src/VHACDUtilApp.h similarity index 100% rename from tools/vhacd/src/VHACDUtilApp.h rename to tools/vhacd-util/src/VHACDUtilApp.h diff --git a/tools/vhacd/src/main.cpp b/tools/vhacd-util/src/main.cpp similarity index 100% rename from tools/vhacd/src/main.cpp rename to tools/vhacd-util/src/main.cpp diff --git a/tools/vhacd/CMakeLists.txt b/tools/vhacd/CMakeLists.txt deleted file mode 100644 index f003b685e0..0000000000 --- a/tools/vhacd/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -set(TARGET_NAME vhacd-util) -setup_hifi_project(Core Widgets) -link_hifi_libraries(shared model fbx gpu networking octree) - -#find_package(VHACD REQUIRED) done in CMakeList.txt in parent directory -target_include_directories(${TARGET_NAME} PUBLIC ${VHACD_INCLUDE_DIRS}) -target_link_libraries(${TARGET_NAME} ${VHACD_LIBRARIES}) - -if(NOT WIN32) - find_package( Threads) - target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) - - include(FindOpenMP) - if(OPENMP_FOUND) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") - endif() -endif() - -add_dependency_external_projects(glm) -find_package(GLM REQUIRED) -target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) From b25d22aa53858b2bf549b987883a03b00292e669 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Apr 2015 14:38:24 -0700 Subject: [PATCH 090/401] use debug/release for IDE handling of V-HACD --- cmake/externals/vhacd/CMakeLists.txt | 9 +++++---- cmake/modules/FindVHACD.cmake | 10 ++++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cmake/externals/vhacd/CMakeLists.txt b/cmake/externals/vhacd/CMakeLists.txt index eae9d7e59a..3bd17937d7 100644 --- a/cmake/externals/vhacd/CMakeLists.txt +++ b/cmake/externals/vhacd/CMakeLists.txt @@ -8,7 +8,7 @@ include(ExternalProject) ExternalProject_Add( ${EXTERNAL_NAME} URL http://hifi-public.s3.amazonaws.com/dependencies/v-hacd-master.zip - URL_MD5 81d6244ac204db5ba27305e2e8e210ad + URL_MD5 3bfc94f8dd3dfbfe8f4dc088f4820b3e CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH= BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build LOG_DOWNLOAD 1 @@ -21,10 +21,11 @@ ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) if (WIN32) - set(LIBRARY_FILENAME ${EXTERNAL_NAME_UPPER}.lib) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/VHACD_LIB.lib CACHE FILEPATH "Path to V-HACD debug library") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/VHACD_LIB.lib CACHE FILEPATH "Path to V-HACD release library") else () - set(LIBRARY_FILENAME lib${EXTERNAL_NAME_UPPER}.a) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Path to V-HACD debug library") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libVHACD.a CACHE FILEPATH "Path to V-HACD release library") endif () set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to V-HACD include directory") -set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/${LIBRARY_FILENAME} CACHE FILEPATH "Path to V-HACD library") diff --git a/cmake/modules/FindVHACD.cmake b/cmake/modules/FindVHACD.cmake index 2a920381d7..8572387f91 100644 --- a/cmake/modules/FindVHACD.cmake +++ b/cmake/modules/FindVHACD.cmake @@ -20,9 +20,15 @@ include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") hifi_library_search_hints("vhacd") find_path(VHACD_INCLUDE_DIRS VHACD.h PATH_SUFFIXES include HINTS ${VHACD_SEARCH_DIRS}) -find_library(VHACD_LIBRARIES VHACD PATH_SUFFIXES lib HINTS ${VHACD_SEARCH_DIRS}) -include(FindPackageHandleStandardArgs) +find_library(VHACD_LIBRARY_DEBUG NAMES VHACD VHACD_LIB PATH_SUFFIXES lib/Debug HINTS ${VHACD_SEARCH_DIRS}) +find_library(VHACD_LIBRARY_RELEASE NAMES VHACD VHACD_LIB PATH_SUFFIXES lib/Release lib HINTS ${VHACD_SEARCH_DIRS}) + +include(SelectLibraryConfigurations) +select_library_configurations(VHACD) + +set(VHACD_LIBRARIES ${VHACD_LIBRARY}) + find_package_handle_standard_args(VHACD "Could NOT find VHACD, try to set the path to VHACD root folder in the system variable VHACD_ROOT_DIR or create a directory vhacd in HIFI_LIB_DIR and paste the necessary files there" VHACD_INCLUDE_DIRS VHACD_LIBRARIES) From 6d53bb28096df7fb9d7aa7a0d2db7bd3080cafbe Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Apr 2015 14:48:42 -0700 Subject: [PATCH 091/401] remove extra directives from vhacd-util cmake --- tools/vhacd-util/CMakeLists.txt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tools/vhacd-util/CMakeLists.txt b/tools/vhacd-util/CMakeLists.txt index b511922520..73233a1fd8 100644 --- a/tools/vhacd-util/CMakeLists.txt +++ b/tools/vhacd-util/CMakeLists.txt @@ -7,15 +7,3 @@ add_dependency_external_projects(vhacd) find_package(VHACD REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${VHACD_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${VHACD_LIBRARIES}) - -if (NOT WIN32) - find_package(Threads) - target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) - - # include(FindOpenMP) - # if(OPENMP_FOUND) - # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") - # endif() -endif () From 134704412ac3f0ac103439834d3c32dd2f3adb94 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Apr 2015 15:13:39 -0700 Subject: [PATCH 092/401] check for OpenMP on non Win32 platforms --- tools/vhacd-util/CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/vhacd-util/CMakeLists.txt b/tools/vhacd-util/CMakeLists.txt index 73233a1fd8..4c3f1cbcef 100644 --- a/tools/vhacd-util/CMakeLists.txt +++ b/tools/vhacd-util/CMakeLists.txt @@ -7,3 +7,12 @@ add_dependency_external_projects(vhacd) find_package(VHACD REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${VHACD_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${VHACD_LIBRARIES}) + +if (NOT WIN32) + include(FindOpenMP) + if(OPENMP_FOUND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") + endif() +endif () From 1058a61ddd09d4bc4cac60b3ca318a188bd63917 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Apr 2015 15:21:35 -0700 Subject: [PATCH 093/401] only look for OpenMP on UNIX --- tools/vhacd-util/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/vhacd-util/CMakeLists.txt b/tools/vhacd-util/CMakeLists.txt index 4c3f1cbcef..c94b2ad083 100644 --- a/tools/vhacd-util/CMakeLists.txt +++ b/tools/vhacd-util/CMakeLists.txt @@ -8,7 +8,7 @@ find_package(VHACD REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${VHACD_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${VHACD_LIBRARIES}) -if (NOT WIN32) +if (UNIX AND NOT APPLE) include(FindOpenMP) if(OPENMP_FOUND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") From e3a90b80a490619b5bc051ecd0e195f5e88c102e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 15 Apr 2015 16:04:18 -0700 Subject: [PATCH 094/401] fix typo in comment --- libraries/entities/src/EntityTreeElement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 93c69c9c61..c09b1701bc 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -359,7 +359,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData if (extraEncodeData && entityTreeElementExtraEncodeData) { // After processing, if we are PARTIAL or COMPLETED then we need to re-include our extra data. - // Only our patent can remove our extra data in these cases and only after it knows that all of it's + // Only our parent can remove our extra data in these cases and only after it knows that all of its // children have been encoded. // If we weren't able to encode ANY data about ourselves, then we go ahead and remove our element data // since that will signal that the entire element needs to be encoded on the next attempt From 6c4d232ad982a15c9dca39f07d61f54af6ac4aaf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 15 Apr 2015 16:08:15 -0700 Subject: [PATCH 095/401] respond to code review --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++-- libraries/entities/src/EntityTreeElement.cpp | 6 ++++-- libraries/entities/src/ModelEntityItem.cpp | 3 +-- libraries/entities/src/SimpleEntitySimulation.cpp | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c67e1f04e5..86b0be4dd8 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -308,7 +308,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ShapeType type = getShapeType(); if (type != SHAPE_TYPE_COMPOUND) { ModelEntityItem::computeShapeInfo(info); - info.setParams(_shapeType, 0.5f * getDimensions()); + info.setParams(type, 0.5f * getDimensions()); } else { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); @@ -410,7 +410,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } glm::vec3 collisionModelDimensions = box.getDimensions(); - info.setParams(_shapeType, collisionModelDimensions, _collisionModelURL); + info.setParams(type, collisionModelDimensions, _collisionModelURL); info.setConvexHulls(_points); } } diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index c09b1701bc..3dcd2899d3 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -717,6 +717,10 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesRead += sizeof(numberOfEntities); if (bytesLeftToRead >= (int)(numberOfEntities * expectedBytesPerEntity)) { + // look up the Id of this Node + auto nodeList = DependencyManager::get(); + QString myNodeID = nodeList->getSessionUUID().toString(); + for (uint16_t i = 0; i < numberOfEntities; i++) { int bytesForThisEntity = 0; EntityItemID entityItemID; @@ -737,8 +741,6 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int // // TODO: Do we need to also do this? // 3) remember the old cube for the entity so we can mark it as dirty - auto nodeList = DependencyManager::get(); - QString myNodeID = nodeList->getSessionUUID().toString(); if (entityItem && entityItem->getSimulatorID() == myNodeID) { // do nothing, this was echoed back to us by the entity server } else if (entityItem) { diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index e98f784765..f95eeea8e4 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -296,8 +296,7 @@ void ModelEntityItem::updateShapeType(ShapeType type) { ShapeType ModelEntityItem::getShapeType() const { if (_shapeType == SHAPE_TYPE_COMPOUND) { return hasCollisionModel() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; - } - else { + } else { return _shapeType; } } diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 6846a38cb0..0406aaa443 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -15,7 +15,7 @@ #include "SimpleEntitySimulation.h" #include "EntitiesLogging.h" -const quint64 AUTO_REMOVE_SIMULATION_OWNER_USEC = 2000000; +const quint64 AUTO_REMOVE_SIMULATION_OWNER_USEC = 2 * USECS_PER_SECOND; void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { // now is usecTimestampNow() From 1a1fe11111658d59a886593ac37be57c271c3d4e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 15 Apr 2015 17:00:20 -0700 Subject: [PATCH 096/401] switch HMD tools hot-key --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index da0c669f35..d50cb48118 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -256,7 +256,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, qApp, SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H, + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::CTRL | Qt::Key_H, false, dialogsManager.data(), SLOT(hmdTools(bool))); From ffb5ea50b1240882d6b1aa272c0b313117d6692d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 15 Apr 2015 17:00:50 -0700 Subject: [PATCH 097/401] expose avatar settings to JS --- interface/src/avatar/MyAvatar.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f12941d748..886d8ad590 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -117,21 +117,21 @@ public: virtual void clearJointData(int index); virtual void clearJointsData(); - 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()); + 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()); - bool getUseFullAvatar() const { return _useFullAvatar; } - const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; } - const QUrl& getHeadURLFromPreferences() const { return _headURLFromPreferences; } - const QUrl& getBodyURLFromPreferences() const { return _skeletonURLFromPreferences; } + Q_INVOKABLE 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; } - const QString& getHeadModelName() const { return _headModelName; } - const QString& getBodyModelName() const { return _bodyModelName; } - const QString& getFullAvartarModelName() const { return _fullAvatarModelName; } + Q_INVOKABLE const QString& getHeadModelName() const { return _headModelName; } + Q_INVOKABLE const QString& getBodyModelName() const { return _bodyModelName; } + Q_INVOKABLE const QString& getFullAvartarModelName() const { return _fullAvatarModelName; } - QString getModelDescription() const; + Q_INVOKABLE QString getModelDescription() const; virtual void setAttachmentData(const QVector& attachmentData); From f700607a65c7cfe9087e360cef921964092d9078 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 15 Apr 2015 23:00:10 -0700 Subject: [PATCH 098/401] Working on OSX functionality --- interface/resources/qml/CustomDialog.qml | 1 - interface/src/Application.cpp | 1 + libraries/render-utils/src/FboCache.h | 1 + .../render-utils/src/OffscreenGlCanvas.cpp | 18 ++++++++++-------- libraries/render-utils/src/OffscreenUi.h | 2 +- tests/render-utils/src/main.cpp | 9 +++++++-- 6 files changed, 20 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/CustomDialog.qml index 71f36b4108..828cd80231 100644 --- a/interface/resources/qml/CustomDialog.qml +++ b/interface/resources/qml/CustomDialog.qml @@ -11,7 +11,6 @@ Item { id: dialog width: 256 height: 256 - property rect clientArea: clientBorder property int topMargin: dialog.height - clientBorder.height + 8 property int margins: 8 property string title diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0f75de9696..36b4eaec91 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -650,6 +650,7 @@ Application::~Application() { // stop the glWidget frame timer so it doesn't call paintGL _glWidget->stopFrameTimer(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/libraries/render-utils/src/FboCache.h b/libraries/render-utils/src/FboCache.h index bbbb4a943e..975d602278 100644 --- a/libraries/render-utils/src/FboCache.h +++ b/libraries/render-utils/src/FboCache.h @@ -17,6 +17,7 @@ #include #include #include +#include class QOpenGLFramebufferObject; diff --git a/libraries/render-utils/src/OffscreenGlCanvas.cpp b/libraries/render-utils/src/OffscreenGlCanvas.cpp index 694fa68a5a..d6b268d4e9 100644 --- a/libraries/render-utils/src/OffscreenGlCanvas.cpp +++ b/libraries/render-utils/src/OffscreenGlCanvas.cpp @@ -16,16 +16,18 @@ OffscreenGlCanvas::OffscreenGlCanvas() { } void OffscreenGlCanvas::create(QOpenGLContext * sharedContext) { - QSurfaceFormat format; - format.setDepthBufferSize(16); - format.setStencilBufferSize(8); - format.setMajorVersion(4); - format.setMinorVersion(1); - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); - - _context.setFormat(format); if (nullptr != sharedContext) { + sharedContext->doneCurrent(); + _context.setFormat(sharedContext->format()); _context.setShareContext(sharedContext); + } else { + QSurfaceFormat format; + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + format.setMajorVersion(4); + format.setMinorVersion(1); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + _context.setFormat(format); } _context.create(); diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index 2e8206f466..60302d9860 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -44,7 +44,7 @@ public: \ private: #define QML_DIALOG_DEF(x) \ - const QUrl x::QML = #x ".qml"; \ + const QUrl x::QML = QUrl(#x ".qml"); \ const QString x::NAME = #x; \ \ void x::registerType() { \ diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index dd413a9f57..62c1fcf1c5 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -31,6 +31,7 @@ #include #include #include +#include class RateCounter { std::vector times; @@ -159,8 +160,12 @@ public: // "#0e7077" setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); - - static const QString f("/Users/bdavis/Git/hifi/interface/resources/qml/TestRoot.qml"); + + QApplication::applicationDirPath(); + QDir path(__FILE__); + path.cdUp(); + static const QString f(path.cleanPath(path.absoluteFilePath("../../../interface/resources/qml/TestRoot.qml"))); + _offscreenUi.loadQml(QUrl::fromLocalFile(f)); connect(&_offscreenUi, &OffscreenUi::textureUpdated, this, [&](int textureId) { _offscreenUi.lockTexture(textureId); From 36ca9132cc97ed13f4af50b2401b58104a3361ea Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 16 Apr 2015 01:02:13 -0700 Subject: [PATCH 099/401] More build failure fixes --- libraries/render-utils/src/OffscreenUi.cpp | 10 ++++++++++ libraries/shared/src/ThreadHelpers.h | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 718a70f4e1..d0e54b08a9 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -1,3 +1,13 @@ +// +// OffscreenUi.cpp +// interface/src/render-utils +// +// Created by Bradley Austin Davis on 2015-04-04 +// Copyright 2015 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 "OffscreenUi.h" #include #include diff --git a/libraries/shared/src/ThreadHelpers.h b/libraries/shared/src/ThreadHelpers.h index 862f7bf673..8a64691da7 100644 --- a/libraries/shared/src/ThreadHelpers.h +++ b/libraries/shared/src/ThreadHelpers.h @@ -1,5 +1,19 @@ +// +// ThreadHelpers.h +// +// Created by Bradley Austin Davis on 2015-04-04 +// Copyright 2015 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 +// #pragma once +#ifndef hifi_ThreadHelpers_h +#define hifi_ThreadHelpers_h + #include +#include +#include template void withLock(L lock, F function) { @@ -11,3 +25,5 @@ void withLock(QMutex & lock, F function) { QMutexLocker locker(&lock); function(); } + +#endif \ No newline at end of file From df37b853f750e4433ac9c70c3f89c53a2c14ec29 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 08:57:57 -0700 Subject: [PATCH 100/401] setup test of lockout-period oafter simulator-owner-id change --- libraries/entities/src/EntityItem.cpp | 2 ++ libraries/entities/src/EntityItem.h | 4 +++- libraries/entities/src/EntityTree.cpp | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index da98b4f350..2503e0e30d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -75,6 +75,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { _dirtyFlags = 0; _changedOnServer = 0; _element = NULL; + _simulatorIDChangedTime = 0; initFromEntityItemID(entityItemID); } @@ -90,6 +91,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert _dirtyFlags = 0; _changedOnServer = 0; _element = NULL; + _simulatorIDChangedTime = 0; initFromEntityItemID(entityItemID); setProperties(properties); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 946efea39c..8391187860 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -256,7 +256,8 @@ public: void setUserData(const QString& value) { _userData = value; } QString getSimulatorID() const { return _simulatorID; } - void setSimulatorID(const QString& id) { _simulatorID = id; } + void setSimulatorID(const QString& id) { _simulatorID = id; _simulatorIDChangedTime = usecTimestampNow(); } + quint64 getSimulatorIDChangedTime() const { return _simulatorIDChangedTime; } const QString& getMarketplaceID() const { return _marketplaceID; } void setMarketplaceID(const QString& value) { _marketplaceID = value; } @@ -352,6 +353,7 @@ protected: bool _locked; QString _userData; QString _simulatorID; // id of Node which is currently responsible for simulating this Entity + quint64 _simulatorIDChangedTime; // when was _simulatorID last updated? QString _marketplaceID; // NOTE: Damping is applied like this: v *= pow(1 - damping, dt) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index fa53dd2dda..ff9d098c01 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -130,6 +130,17 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro } } } else { + if (properties.simulatorIDChanged() && + !entity->getSimulatorID().isEmpty() && + properties.getSimulatorID() != entity->getSimulatorID()) { + // A Node is trying to take ownership of the simulation of this entity from another Node. Only allow this + // if ownership hasn't recently changed. + quint64 now = usecTimestampNow(); + if (now - entity->getSimulatorIDChangedTime() < 0.1 * USECS_PER_SECOND) { // XXX pick time and put in constant + qDebug() << "TOO SOON"; + } + } + QString entityScriptBefore = entity->getScript(); uint32_t preFlags = entity->getDirtyFlags(); UpdateEntityOperator theOperator(this, containingElement, entity, properties); From b30b9a0a3079a8c6d99a55cc54b03f5926350d33 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 12:03:34 -0700 Subject: [PATCH 101/401] don't update _simulatorIDChangedTime unless the value is different than the current one. if a script changes an entity, attempt to claim ownership --- libraries/entities/src/EntityItem.cpp | 7 +++++++ libraries/entities/src/EntityItem.h | 2 +- .../entities/src/EntityScriptingInterface.cpp | 17 +++++++++++------ libraries/entities/src/EntityTree.cpp | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 2503e0e30d..e8427e0982 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1196,3 +1196,10 @@ void EntityItem::updateLifetime(float value) { _dirtyFlags |= EntityItem::DIRTY_LIFETIME; } } + +void EntityItem::setSimulatorID(const QString& value) { + if (_simulatorID != value) { + _simulatorID = value; + _simulatorIDChangedTime = usecTimestampNow(); + } +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 8391187860..124d37d762 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -256,7 +256,7 @@ public: void setUserData(const QString& value) { _userData = value; } QString getSimulatorID() const { return _simulatorID; } - void setSimulatorID(const QString& id) { _simulatorID = id; _simulatorIDChangedTime = usecTimestampNow(); } + void setSimulatorID(const QString& value); quint64 getSimulatorIDChangedTime() const { return _simulatorIDChangedTime; } const QString& getMarketplaceID() const { return _marketplaceID; } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 06c5493720..fa142d3abd 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -66,13 +66,10 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro uint32_t creatorTokenID = EntityItemID::getNextCreatorTokenID(); // This Node is creating a new object. If it's in motion, set this Node as the simulator. - auto nodeList = DependencyManager::get(); - const QString myNodeID = nodeList->getSessionUUID().toString(); - EntityItemProperties propertiesWithSimID = properties; - - // if this object is moving, set this Node as the simulation owner if (properties.velocityChanged() || properties.rotationChanged()) { + auto nodeList = DependencyManager::get(); + const QString myNodeID = nodeList->getSessionUUID().toString(); propertiesWithSimID.setSimulatorID(myNodeID); } @@ -148,12 +145,20 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E entityID.isKnownID = true; } } + + // If this node is changing a physics-related property, claim simulation ownership + EntityItemProperties propertiesWithSimID = properties; + if (properties.velocityChanged() || properties.rotationChanged()) { + auto nodeList = DependencyManager::get(); + const QString myNodeID = nodeList->getSessionUUID().toString(); + propertiesWithSimID.setSimulatorID(myNodeID); + } // If we have a local entity tree set, then also update it. We can do this even if we don't know // the actual id, because we can edit out local entities just with creatorTokenID if (_entityTree) { _entityTree->lockForWrite(); - _entityTree->updateEntity(entityID, properties, canAdjustLocks()); + _entityTree->updateEntity(entityID, propertiesWithSimID, canAdjustLocks()); _entityTree->unlock(); } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ff9d098c01..2227107537 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -136,7 +136,7 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro // A Node is trying to take ownership of the simulation of this entity from another Node. Only allow this // if ownership hasn't recently changed. quint64 now = usecTimestampNow(); - if (now - entity->getSimulatorIDChangedTime() < 0.1 * USECS_PER_SECOND) { // XXX pick time and put in constant + if (now - entity->getSimulatorIDChangedTime() < 2 * USECS_PER_SECOND) { // XXX pick time and put in constant qDebug() << "TOO SOON"; } } From 21d669f2f13e0395f47e72a32d6e7dbd0771a308 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 16 Apr 2015 12:13:41 -0700 Subject: [PATCH 102/401] use computed shape type --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c67e1f04e5..86b0be4dd8 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -308,7 +308,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ShapeType type = getShapeType(); if (type != SHAPE_TYPE_COMPOUND) { ModelEntityItem::computeShapeInfo(info); - info.setParams(_shapeType, 0.5f * getDimensions()); + info.setParams(type, 0.5f * getDimensions()); } else { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); @@ -410,7 +410,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } glm::vec3 collisionModelDimensions = box.getDimensions(); - info.setParams(_shapeType, collisionModelDimensions, _collisionModelURL); + info.setParams(type, collisionModelDimensions, _collisionModelURL); info.setConvexHulls(_points); } } From 94c6053d5259b07917e99a04c55a79ed2cef823a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 16 Apr 2015 12:15:03 -0700 Subject: [PATCH 103/401] fix formatting --- libraries/entities/src/ModelEntityItem.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index e98f784765..f95eeea8e4 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -296,8 +296,7 @@ void ModelEntityItem::updateShapeType(ShapeType type) { ShapeType ModelEntityItem::getShapeType() const { if (_shapeType == SHAPE_TYPE_COMPOUND) { return hasCollisionModel() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; - } - else { + } else { return _shapeType; } } From 5180e7e7152bcb3d1382ebd4d0d869b71b4bd40c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 16 Apr 2015 13:44:17 -0700 Subject: [PATCH 104/401] measure linear velocity of moving objects --- libraries/physics/src/EntityMotionState.cpp | 18 ++++--- libraries/physics/src/EntityMotionState.h | 4 +- libraries/physics/src/ObjectMotionState.cpp | 57 ++++++++++++++++----- libraries/physics/src/ObjectMotionState.h | 13 ++++- libraries/physics/src/PhysicsEngine.cpp | 4 ++ 5 files changed, 72 insertions(+), 24 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d84daa6b42..6838d977eb 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -62,6 +62,9 @@ void EntityMotionState::stepKinematicSimulation(quint64 now) { // which is different from physical kinematic motion (inside getWorldTransform()) // which steps in physics simulation time. _entity->simulate(now); + // TODO: we can't use ObjectMotionState::measureVelocityAndAcceleration() here because the entity + // has no RigidBody and the timestep is a little bit out of sync with the physics simulation anyway. + // Hence we must manually measure kinematic velocity and acceleration. } bool EntityMotionState::isMoving() const { @@ -71,7 +74,7 @@ bool EntityMotionState::isMoving() const { // This callback is invoked by the physics simulation in two cases: // (1) when the RigidBody is first added to the world // (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC) -// (2) at the beginning of each simulation frame for KINEMATIC RigidBody's -- +// (2) at the beginning of each simulation step for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { if (_isKinematic) { @@ -89,9 +92,10 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { worldTrans.setRotation(glmToBullet(_entity->getRotation())); } -// This callback is invoked by the physics simulation at the end of each simulation frame... +// This callback is invoked by the physics simulation at the end of each simulation step... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { + measureVelocityAndAcceleration(); _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset()); _entity->setRotation(bulletToGLM(worldTrans.getRotation())); @@ -116,7 +120,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { #endif } -void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t frame) { +void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { if (flags & EntityItem::DIRTY_POSITION) { _sentPosition = _entity->getPosition() - ObjectMotionState::getWorldOffset(); @@ -131,7 +135,7 @@ void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t frame) { if (flags & EntityItem::DIRTY_VELOCITY) { updateObjectVelocities(); } - _sentFrame = frame; + _sentStep = step; } // TODO: entity support for friction and restitution @@ -179,7 +183,7 @@ float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const { return _entity->computeMass(); } -void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) { +void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step) { if (!_entity->isKnownID()) { return; // never update entities that are unknown } @@ -231,7 +235,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } if (_numNonMovingUpdates <= 1) { // we only update lastEdited when we're sending new physics data - // (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data) + // (i.e. NOT when we just simulate the positions forward, nor when we resend non-moving data) // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly quint64 lastSimulated = _entity->getLastSimulated(); _entity->setLastEdited(lastSimulated); @@ -264,7 +268,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // The outgoing flags only itemized WHAT to send, not WHETHER to send, hence we always set them // to the full set. These flags may be momentarily cleared by incoming external changes. _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; - _sentFrame = frame; + _sentStep = step; } } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 7214626fc4..710362e056 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -50,13 +50,13 @@ public: virtual void setWorldTransform(const btTransform& worldTrans); // these relay incoming values to the RigidBody - virtual void updateObjectEasy(uint32_t flags, uint32_t frame); + virtual void updateObjectEasy(uint32_t flags, uint32_t step); virtual void updateObjectVelocities(); virtual void computeShapeInfo(ShapeInfo& shapeInfo); virtual float computeMass(const ShapeInfo& shapeInfo) const; - virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame); + virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step); virtual uint32_t getIncomingDirtyFlags() const; virtual void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index c9f416cc37..a66e60e93c 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -22,7 +22,7 @@ const float MAX_FRICTION = 10.0f; const float DEFAULT_RESTITUTION = 0.5f; -// origin of physics simulation in world frame +// origin of physics simulation in world-frame glm::vec3 _worldOffset(0.0f); // static @@ -35,6 +35,12 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { return _worldOffset; } +// static +uint32_t _simulationStep = 0; +void ObjectMotionState::setSimulationStep(uint32_t step) { + assert(step > _simulationStep); + _simulationStep = step; +} ObjectMotionState::ObjectMotionState() : _friction(DEFAULT_FRICTION), @@ -46,12 +52,15 @@ ObjectMotionState::ObjectMotionState() : _sentMoving(false), _numNonMovingUpdates(0), _outgoingPacketFlags(DIRTY_PHYSICS_FLAGS), - _sentFrame(0), + _sentStep(0), _sentPosition(0.0f), _sentRotation(), _sentVelocity(0.0f), _sentAngularVelocity(0.0f), - _sentAcceleration(0.0f) { + _sentAcceleration(0.0f), + _lastSimulationStep(0), + _lastVelocity(0.0f), + _measuredAcceleration(0.0f) } ObjectMotionState::~ObjectMotionState() { @@ -59,6 +68,27 @@ ObjectMotionState::~ObjectMotionState() { assert(_body == NULL); } +void ObjectMotionState::measureVelocityAndAcceleration() { + // try to manually measure the true acceleration of the object + uint32_t numSubsteps = _simulationStep - _lastSimulationStep; + if (numSubsteps > 0) { + float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP); + float invDt = 1.0f / dt; + _lastSimulationStep = _simulationStep; + + // Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt + // hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt + glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity()); + _measuredAcceleration = (velocity / powf(1.0f - _linearDamping, dt) - _lastVelocity) * invDt; + _lastVelocity = velocity; + } +} + +void ObjectMotionState::resetMeasuredVelocityAndAcceleration() { + _lastSimulationStep = _simulationStep; + _lastVelocity = bulletToGLM(_body->getLinearVelocity()); +} + void ObjectMotionState::setFriction(float friction) { _friction = btMax(btMin(fabsf(friction), MAX_FRICTION), 0.0f); } @@ -103,15 +133,16 @@ bool ObjectMotionState::doesNotNeedToSendUpdate() const { return !_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES; } -bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) { +bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) { assert(_body); - // if we've never checked before, our _sentFrame will be 0, and we need to initialize our state - if (_sentFrame == 0) { - _sentPosition = bulletToGLM(_body->getWorldTransform().getOrigin()); + // if we've never checked before, our _sentStep will be 0, and we need to initialize our state + if (_sentStep == 0) { + btTransform xform = _body->getWorldTransform(); + _sentPosition = bulletToGLM(xform.getOrigin()); + _sentRotation = bulletToGLM(xform.getRotation()); _sentVelocity = bulletToGLM(_body->getLinearVelocity()); - _sentRotation = bulletToGLM(_body->getWorldTransform().getRotation()); _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); - _sentFrame = simulationFrame; + _sentStep = simulationStep; return false; } @@ -121,9 +152,9 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) { glm::vec3 wasAngularVelocity = _sentAngularVelocity; #endif - int numFrames = simulationFrame - _sentFrame; - float dt = (float)(numFrames) * PHYSICS_ENGINE_FIXED_SUBSTEP; - _sentFrame = simulationFrame; + int numSteps = simulationStep - _sentStep; + float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP; + _sentStep = simulationStep; bool isActive = _body->isActive(); if (!isActive) { @@ -179,7 +210,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) { // Bullet caps the effective rotation velocity inside its rotation integration step, therefore // we must integrate with the same algorithm and timestep in order achieve similar results. - for (int i = 0; i < numFrames; ++i) { + for (int i = 0; i < numSteps; ++i) { _sentRotation = glm::normalize(computeBulletRotationStep(_sentAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _sentRotation); } } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index fb402a178d..2c77ca6b5e 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -57,9 +57,14 @@ public: static void setWorldOffset(const glm::vec3& offset); static const glm::vec3& getWorldOffset(); + static void setSimulationStep(uint32_t step); + ObjectMotionState(); ~ObjectMotionState(); + void measureVelocityAndAcceleration(); + void resetMeasuredVelocityAndAcceleration(); + // An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0; virtual void updateObjectVelocities() = 0; @@ -87,7 +92,7 @@ public: void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; } bool doesNotNeedToSendUpdate() const; - virtual bool shouldSendUpdate(uint32_t simulationFrame); + virtual bool shouldSendUpdate(uint32_t simulationStep); virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0; virtual MotionType computeMotionType() const = 0; @@ -126,12 +131,16 @@ protected: int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects uint32_t _outgoingPacketFlags; - uint32_t _sentFrame; + uint32_t _sentStep; glm::vec3 _sentPosition; // in simulation-frame (not world-frame) glm::quat _sentRotation;; glm::vec3 _sentVelocity; glm::vec3 _sentAngularVelocity; // radians per second glm::vec3 _sentAcceleration; + + uint32_t _lastSimulationStep; + glm::vec3 _lastVelocity; + glm::vec3 _measuredAcceleration; }; #endif // hifi_ObjectMotionState_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 209e23e006..34ac6732a7 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -193,6 +193,9 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { // hence the MotionState has all the knowledge and authority to perform the update. motionState->updateObjectEasy(flags, _numSubsteps); } + if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { + motionState->resetMeasuredVelocityAndAcceleration(); + } } else { // the only way we should ever get here (motionState exists but no body) is when the object // is undergoing non-physical kinematic motion. @@ -508,6 +511,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap body->setFriction(motionState->_friction); body->setDamping(motionState->_linearDamping, motionState->_angularDamping); _dynamicsWorld->addRigidBody(body); + motionState->resetMeasuredVelocityAndAcceleration(); } void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { From b7ca69d4e1c9511d9af93ca8de732c9a39d96017 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 16 Apr 2015 13:46:26 -0700 Subject: [PATCH 105/401] fix typo --- libraries/physics/src/ObjectMotionState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index a66e60e93c..9d9e7e6798 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -60,7 +60,7 @@ ObjectMotionState::ObjectMotionState() : _sentAcceleration(0.0f), _lastSimulationStep(0), _lastVelocity(0.0f), - _measuredAcceleration(0.0f) + _measuredAcceleration(0.0f) { } ObjectMotionState::~ObjectMotionState() { From 619d1ba19110e5b406f9ad5e051dcb9e7446d091 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 16 Apr 2015 14:09:33 -0700 Subject: [PATCH 106/401] rename to measureAcceleration --- libraries/physics/src/EntityMotionState.cpp | 4 ++-- libraries/physics/src/ObjectMotionState.cpp | 4 ++-- libraries/physics/src/ObjectMotionState.h | 4 ++-- libraries/physics/src/PhysicsEngine.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 6838d977eb..871ee21c45 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -62,7 +62,7 @@ void EntityMotionState::stepKinematicSimulation(quint64 now) { // which is different from physical kinematic motion (inside getWorldTransform()) // which steps in physics simulation time. _entity->simulate(now); - // TODO: we can't use ObjectMotionState::measureVelocityAndAcceleration() here because the entity + // TODO: we can't use ObjectMotionState::measureAcceleration() here because the entity // has no RigidBody and the timestep is a little bit out of sync with the physics simulation anyway. // Hence we must manually measure kinematic velocity and acceleration. } @@ -95,7 +95,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { // This callback is invoked by the physics simulation at the end of each simulation step... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { - measureVelocityAndAcceleration(); + measureAcceleration(); _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset()); _entity->setRotation(bulletToGLM(worldTrans.getRotation())); diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 9d9e7e6798..3d790ff7d4 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -68,7 +68,7 @@ ObjectMotionState::~ObjectMotionState() { assert(_body == NULL); } -void ObjectMotionState::measureVelocityAndAcceleration() { +void ObjectMotionState::measureAcceleration() { // try to manually measure the true acceleration of the object uint32_t numSubsteps = _simulationStep - _lastSimulationStep; if (numSubsteps > 0) { @@ -84,7 +84,7 @@ void ObjectMotionState::measureVelocityAndAcceleration() { } } -void ObjectMotionState::resetMeasuredVelocityAndAcceleration() { +void ObjectMotionState::resetMeasuredAcceleration() { _lastSimulationStep = _simulationStep; _lastVelocity = bulletToGLM(_body->getLinearVelocity()); } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 2c77ca6b5e..c5dd31d1f2 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -62,8 +62,8 @@ public: ObjectMotionState(); ~ObjectMotionState(); - void measureVelocityAndAcceleration(); - void resetMeasuredVelocityAndAcceleration(); + void measureAcceleration(); + void resetMeasuredAcceleration(); // An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 34ac6732a7..aa9921be64 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -194,7 +194,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { motionState->updateObjectEasy(flags, _numSubsteps); } if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { - motionState->resetMeasuredVelocityAndAcceleration(); + motionState->resetMeasuredAcceleration(); } } else { // the only way we should ever get here (motionState exists but no body) is when the object @@ -511,7 +511,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap body->setFriction(motionState->_friction); body->setDamping(motionState->_linearDamping, motionState->_angularDamping); _dynamicsWorld->addRigidBody(body); - motionState->resetMeasuredVelocityAndAcceleration(); + motionState->resetMeasuredAcceleration(); } void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { From a624ff43c4c891b179be56e6b159b3d3a2f421f7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 16 Apr 2015 14:10:29 -0700 Subject: [PATCH 107/401] Nothing to see here, move along --- interface/src/Menu.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index aa24c8ca2c..5d02cf9094 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -251,7 +251,6 @@ Menu::Menu() { qApp, SLOT(setFullscreen(bool))); #endif -<<<<<<< HEAD addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, 0, // QML Qt::Key_P, true, qApp, SLOT(cameraMenuChanged())); From f06556ba1245bebcbb11414f63255f5c896b1acc Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 16 Apr 2015 14:37:39 -0700 Subject: [PATCH 108/401] migrate the various list to sort the rendering from explicit names to a more generic key based map --- libraries/fbx/src/FBXReader.cpp | 7 +- libraries/render-utils/CMakeLists.txt | 12 + libraries/render-utils/src/Model.cpp | 344 ++++---------------------- libraries/render-utils/src/Model.h | 79 ++---- 4 files changed, 94 insertions(+), 348 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index b9b2f24034..25ea9ef8e1 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1705,7 +1705,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, material._material->setDiffuse(material.diffuse); material._material->setSpecular(material.specular); material._material->setShininess(material.shininess); - material._material->setOpacity(material.opacity); + + if (material.opacity <= 0.0f) { + material._material->setOpacity(1.0f); + } else { + material._material->setOpacity(material.opacity); + } materials.insert(material.id, material); diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index caabff44cf..423e8fcfb6 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -12,4 +12,16 @@ add_dependency_external_projects(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) +if (WIN32) + if (USE_NSIGHT) + # try to find the Nsight package and add it to the build if we find it + find_package(NSIGHT) + if (NSIGHT_FOUND) + include_directories(${NSIGHT_INCLUDE_DIRS}) + add_definitions(-DNSIGHT_FOUND) + target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") + endif () + endif() +endif (WIN32) + link_hifi_libraries(animation fbx shared gpu) \ No newline at end of file diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index cf6ceaa1f1..53139b788e 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -244,13 +244,6 @@ void Model::initJointTransforms() { void Model::init() { if (_renderPipelineLib.empty()) { - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1)); - slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); - slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3)); - // Vertex shaders auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert))); auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert))); @@ -291,10 +284,24 @@ void Model::init() { RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), modelNormalMapVertex, modelNormalSpecularMapPixel); + _renderPipelineLib.addRenderPipeline( RenderKey(RenderKey::IS_TRANSLUCENT), modelVertex, modelTranslucentPixel); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), + modelNormalMapVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + modelVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + modelNormalMapVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( RenderKey(RenderKey::HAS_LIGHTMAP), modelLightmapVertex, modelLightmapPixel); @@ -310,6 +317,7 @@ void Model::init() { RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); + _renderPipelineLib.addRenderPipeline( RenderKey(RenderKey::IS_SKINNED), skinModelVertex, modelPixel); @@ -326,15 +334,29 @@ void Model::init() { RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), skinModelNormalMapVertex, modelNormalSpecularMapPixel); + _renderPipelineLib.addRenderPipeline( RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_TRANSLUCENT), skinModelVertex, modelTranslucentPixel); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), + skinModelNormalMapVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + skinModelVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + skinModelNormalMapVertex, modelTranslucentPixel); + _renderPipelineLib.addRenderPipeline( RenderKey(RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), modelShadowVertex, modelShadowPixel); + _renderPipelineLib.addRenderPipeline( RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), skinModelShadowVertex, modelShadowPixel); @@ -1935,55 +1957,7 @@ bool Model::renderInScene(float alpha, RenderArgs* args) { } void Model::segregateMeshGroups() { - _meshesTranslucentTangents.clear(); - _meshesTranslucent.clear(); - _meshesTranslucentTangentsSpecular.clear(); - _meshesTranslucentSpecular.clear(); - - _meshesTranslucentTangentsSkinned.clear(); - _meshesTranslucentSkinned.clear(); - _meshesTranslucentTangentsSpecularSkinned.clear(); - _meshesTranslucentSpecularSkinned.clear(); - - _meshesOpaqueTangents.clear(); - _meshesOpaque.clear(); - _meshesOpaqueTangentsSpecular.clear(); - _meshesOpaqueSpecular.clear(); - - _meshesOpaqueTangentsSkinned.clear(); - _meshesOpaqueSkinned.clear(); - _meshesOpaqueTangentsSpecularSkinned.clear(); - _meshesOpaqueSpecularSkinned.clear(); - - _meshesOpaqueLightmapTangents.clear(); - _meshesOpaqueLightmap.clear(); - _meshesOpaqueLightmapTangentsSpecular.clear(); - _meshesOpaqueLightmapSpecular.clear(); - - _unsortedMeshesTranslucentTangents.clear(); - _unsortedMeshesTranslucent.clear(); - _unsortedMeshesTranslucentTangentsSpecular.clear(); - _unsortedMeshesTranslucentSpecular.clear(); - - _unsortedMeshesTranslucentTangentsSkinned.clear(); - _unsortedMeshesTranslucentSkinned.clear(); - _unsortedMeshesTranslucentTangentsSpecularSkinned.clear(); - _unsortedMeshesTranslucentSpecularSkinned.clear(); - - _unsortedMeshesOpaqueTangents.clear(); - _unsortedMeshesOpaque.clear(); - _unsortedMeshesOpaqueTangentsSpecular.clear(); - _unsortedMeshesOpaqueSpecular.clear(); - - _unsortedMeshesOpaqueTangentsSkinned.clear(); - _unsortedMeshesOpaqueSkinned.clear(); - _unsortedMeshesOpaqueTangentsSpecularSkinned.clear(); - _unsortedMeshesOpaqueSpecularSkinned.clear(); - - _unsortedMeshesOpaqueLightmapTangents.clear(); - _unsortedMeshesOpaqueLightmap.clear(); - _unsortedMeshesOpaqueLightmapTangentsSpecular.clear(); - _unsortedMeshesOpaqueLightmapSpecular.clear(); + _renderBuckets.clear(); const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); @@ -2017,201 +1991,19 @@ void Model::segregateMeshGroups() { qCDebug(renderutils) << "materialID:" << materialID << "parts:" << mesh.parts.size(); } - if (!hasLightmap) { - if (translucentMesh && !hasTangents && !hasSpecular && !isSkinned) { + RenderKey key(translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned); - _unsortedMeshesTranslucent.insertMulti(materialID, i); - - } else if (translucentMesh && hasTangents && !hasSpecular && !isSkinned) { - - _unsortedMeshesTranslucentTangents.insertMulti(materialID, i); - - } else if (translucentMesh && hasTangents && hasSpecular && !isSkinned) { - - _unsortedMeshesTranslucentTangentsSpecular.insertMulti(materialID, i); - - } else if (translucentMesh && !hasTangents && hasSpecular && !isSkinned) { - - _unsortedMeshesTranslucentSpecular.insertMulti(materialID, i); - - } else if (translucentMesh && hasTangents && !hasSpecular && isSkinned) { - - _unsortedMeshesTranslucentTangentsSkinned.insertMulti(materialID, i); - - } else if (translucentMesh && !hasTangents && !hasSpecular && isSkinned) { - - _unsortedMeshesTranslucentSkinned.insertMulti(materialID, i); - - } else if (translucentMesh && hasTangents && hasSpecular && isSkinned) { - - _unsortedMeshesTranslucentTangentsSpecularSkinned.insertMulti(materialID, i); - - } else if (translucentMesh && !hasTangents && hasSpecular && isSkinned) { - - _unsortedMeshesTranslucentSpecularSkinned.insertMulti(materialID, i); - - } else if (!translucentMesh && !hasTangents && !hasSpecular && !isSkinned) { - - _unsortedMeshesOpaque.insertMulti(materialID, i); - - } else if (!translucentMesh && hasTangents && !hasSpecular && !isSkinned) { - - _unsortedMeshesOpaqueTangents.insertMulti(materialID, i); - - } else if (!translucentMesh && hasTangents && hasSpecular && !isSkinned) { - - _unsortedMeshesOpaqueTangentsSpecular.insertMulti(materialID, i); - - } else if (!translucentMesh && !hasTangents && hasSpecular && !isSkinned) { - - _unsortedMeshesOpaqueSpecular.insertMulti(materialID, i); - - } else if (!translucentMesh && hasTangents && !hasSpecular && isSkinned) { - - _unsortedMeshesOpaqueTangentsSkinned.insertMulti(materialID, i); - - } else if (!translucentMesh && !hasTangents && !hasSpecular && isSkinned) { - - _unsortedMeshesOpaqueSkinned.insertMulti(materialID, i); - - } else if (!translucentMesh && hasTangents && hasSpecular && isSkinned) { - - _unsortedMeshesOpaqueTangentsSpecularSkinned.insertMulti(materialID, i); - - } else if (!translucentMesh && !hasTangents && hasSpecular && isSkinned) { - - _unsortedMeshesOpaqueSpecularSkinned.insertMulti(materialID, i); - } else { - qCDebug(renderutils) << "unexpected!!! this mesh didn't fall into any or our groups???"; - } - } else { - if (!translucentMesh && !hasTangents && !hasSpecular && !isSkinned) { - - _unsortedMeshesOpaqueLightmap.insertMulti(materialID, i); - - } else if (!translucentMesh && hasTangents && !hasSpecular && !isSkinned) { - - _unsortedMeshesOpaqueLightmapTangents.insertMulti(materialID, i); - - } else if (!translucentMesh && hasTangents && hasSpecular && !isSkinned) { - - _unsortedMeshesOpaqueLightmapTangentsSpecular.insertMulti(materialID, i); - - } else if (!translucentMesh && !hasTangents && hasSpecular && !isSkinned) { - - _unsortedMeshesOpaqueLightmapSpecular.insertMulti(materialID, i); - - } else { - qCDebug(renderutils) << "unexpected!!! this mesh didn't fall into any or our groups???"; - } - } + // reuse or create the bucket corresponding to that key and insert the mesh as unsorted + _renderBuckets[key.getRaw()]._unsortedMeshes.insertMulti(materialID, i); } - foreach(int i, _unsortedMeshesTranslucent) { - _meshesTranslucent.append(i); + for(auto& b : _renderBuckets) { + foreach(auto i, b.second._unsortedMeshes) { + b.second._meshes.append(i); + b.second._unsortedMeshes.clear(); + } } - foreach(int i, _unsortedMeshesTranslucentTangents) { - _meshesTranslucentTangents.append(i); - } - - foreach(int i, _unsortedMeshesTranslucentTangentsSpecular) { - _meshesTranslucentTangentsSpecular.append(i); - } - - foreach(int i, _unsortedMeshesTranslucentSpecular) { - _meshesTranslucentSpecular.append(i); - } - - foreach(int i, _unsortedMeshesTranslucentSkinned) { - _meshesTranslucentSkinned.append(i); - } - - foreach(int i, _unsortedMeshesTranslucentTangentsSkinned) { - _meshesTranslucentTangentsSkinned.append(i); - } - - foreach(int i, _unsortedMeshesTranslucentTangentsSpecularSkinned) { - _meshesTranslucentTangentsSpecularSkinned.append(i); - } - - foreach(int i, _unsortedMeshesTranslucentSpecularSkinned) { - _meshesTranslucentSpecularSkinned.append(i); - } - - foreach(int i, _unsortedMeshesOpaque) { - _meshesOpaque.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueTangents) { - _meshesOpaqueTangents.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueTangentsSpecular) { - _meshesOpaqueTangentsSpecular.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueSpecular) { - _meshesOpaqueSpecular.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueSkinned) { - _meshesOpaqueSkinned.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueTangentsSkinned) { - _meshesOpaqueTangentsSkinned.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueTangentsSpecularSkinned) { - _meshesOpaqueTangentsSpecularSkinned.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueSpecularSkinned) { - _meshesOpaqueSpecularSkinned.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueLightmap) { - _meshesOpaqueLightmap.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueLightmapTangents) { - _meshesOpaqueLightmapTangents.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueLightmapTangentsSpecular) { - _meshesOpaqueLightmapTangentsSpecular.append(i); - } - - foreach(int i, _unsortedMeshesOpaqueLightmapSpecular) { - _meshesOpaqueLightmapSpecular.append(i); - } - - _unsortedMeshesTranslucentTangents.clear(); - _unsortedMeshesTranslucent.clear(); - _unsortedMeshesTranslucentTangentsSpecular.clear(); - _unsortedMeshesTranslucentSpecular.clear(); - - _unsortedMeshesTranslucentTangentsSkinned.clear(); - _unsortedMeshesTranslucentSkinned.clear(); - _unsortedMeshesTranslucentTangentsSpecularSkinned.clear(); - _unsortedMeshesTranslucentSpecularSkinned.clear(); - - _unsortedMeshesOpaqueTangents.clear(); - _unsortedMeshesOpaque.clear(); - _unsortedMeshesOpaqueTangentsSpecular.clear(); - _unsortedMeshesOpaqueSpecular.clear(); - - _unsortedMeshesOpaqueTangentsSkinned.clear(); - _unsortedMeshesOpaqueSkinned.clear(); - _unsortedMeshesOpaqueTangentsSpecularSkinned.clear(); - _unsortedMeshesOpaqueSpecularSkinned.clear(); - - _unsortedMeshesOpaqueLightmapTangents.clear(); - _unsortedMeshesOpaqueLightmap.clear(); - _unsortedMeshesOpaqueLightmapTangentsSpecular.clear(); - _unsortedMeshesOpaqueLightmapSpecular.clear(); - _meshGroupsKnown = true; } @@ -2220,52 +2012,14 @@ QVector* Model::pickMeshList(bool translucent, float alphaThreshold, bool h // depending on which parameters we were called with, pick the correct mesh group to render QVector* whichList = NULL; - if (translucent && !hasTangents && !hasSpecular && !isSkinned) { - whichList = &_meshesTranslucent; - } else if (translucent && hasTangents && !hasSpecular && !isSkinned) { - whichList = &_meshesTranslucentTangents; - } else if (translucent && hasTangents && hasSpecular && !isSkinned) { - whichList = &_meshesTranslucentTangentsSpecular; - } else if (translucent && !hasTangents && hasSpecular && !isSkinned) { - whichList = &_meshesTranslucentSpecular; - } else if (translucent && hasTangents && !hasSpecular && isSkinned) { - whichList = &_meshesTranslucentTangentsSkinned; - } else if (translucent && !hasTangents && !hasSpecular && isSkinned) { - whichList = &_meshesTranslucentSkinned; - } else if (translucent && hasTangents && hasSpecular && isSkinned) { - whichList = &_meshesTranslucentTangentsSpecularSkinned; - } else if (translucent && !hasTangents && hasSpecular && isSkinned) { - whichList = &_meshesTranslucentSpecularSkinned; - } else if (!translucent && !hasLightmap && !hasTangents && !hasSpecular && !isSkinned) { - whichList = &_meshesOpaque; - } else if (!translucent && !hasLightmap && hasTangents && !hasSpecular && !isSkinned) { - whichList = &_meshesOpaqueTangents; - } else if (!translucent && !hasLightmap && hasTangents && hasSpecular && !isSkinned) { - whichList = &_meshesOpaqueTangentsSpecular; - } else if (!translucent && !hasLightmap && !hasTangents && hasSpecular && !isSkinned) { - whichList = &_meshesOpaqueSpecular; - } else if (!translucent && !hasLightmap && hasTangents && !hasSpecular && isSkinned) { - whichList = &_meshesOpaqueTangentsSkinned; - } else if (!translucent && !hasLightmap && !hasTangents && !hasSpecular && isSkinned) { - whichList = &_meshesOpaqueSkinned; - } else if (!translucent && !hasLightmap && hasTangents && hasSpecular && isSkinned) { - whichList = &_meshesOpaqueTangentsSpecularSkinned; - } else if (!translucent && !hasLightmap && !hasTangents && hasSpecular && isSkinned) { - whichList = &_meshesOpaqueSpecularSkinned; + RenderKey key(translucent, hasLightmap, hasTangents, hasSpecular, isSkinned); - } else if (!translucent && hasLightmap && !hasTangents && !hasSpecular && !isSkinned) { - whichList = &_meshesOpaqueLightmap; - } else if (!translucent && hasLightmap && hasTangents && !hasSpecular && !isSkinned) { - whichList = &_meshesOpaqueLightmapTangents; - } else if (!translucent && hasLightmap && hasTangents && hasSpecular && !isSkinned) { - whichList = &_meshesOpaqueLightmapTangentsSpecular; - } else if (!translucent && hasLightmap && !hasTangents && hasSpecular && !isSkinned) { - whichList = &_meshesOpaqueLightmapSpecular; - - } else { - qCDebug(renderutils) << "unexpected!!! this mesh didn't fall into any or our groups???"; + auto bucket = _renderBuckets.find(key.getRaw()); + if (bucket != _renderBuckets.end()) { + whichList = &(*bucket).second._meshes; } + return whichList; } @@ -2277,6 +2031,7 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f auto pipeline = _renderPipelineLib.find(key.getRaw()); if (pipeline == _renderPipelineLib.end()) { qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw(); + locations = 0; return; } @@ -2303,7 +2058,7 @@ int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool int meshPartsRendered = 0; bool pickProgramsNeeded = true; - Locations* locations; + Locations* locations = nullptr; foreach(Model* model, _modelsInScene) { QVector* whichList = model->pickMeshList(translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned); @@ -2331,20 +2086,19 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl PROFILE_RANGE(__FUNCTION__); int meshPartsRendered = 0; - QVector* whichList = pickMeshList(translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned); - + //Pick the mesh list with the requested render flags + QVector* whichList = pickMeshList(translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned); if (!whichList) { - qCDebug(renderutils) << "unexpected!!! we don't know which list of meshes to render..."; return 0; } QVector& list = *whichList; // If this list has nothing to render, then don't bother proceeding. This saves us on binding to programs - if (list.size() == 0) { + if (list.empty()) { return 0; } - Locations* locations; + Locations* locations = nullptr; pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, args, locations); meshPartsRendered = renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index fce5629b8d..9ca817a8e7 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -350,58 +350,6 @@ private: bool _meshGroupsKnown; - QMap _unsortedMeshesTranslucent; - QMap _unsortedMeshesTranslucentTangents; - QMap _unsortedMeshesTranslucentTangentsSpecular; - QMap _unsortedMeshesTranslucentSpecular; - - QMap _unsortedMeshesTranslucentSkinned; - QMap _unsortedMeshesTranslucentTangentsSkinned; - QMap _unsortedMeshesTranslucentTangentsSpecularSkinned; - QMap _unsortedMeshesTranslucentSpecularSkinned; - - QMap _unsortedMeshesOpaque; - QMap _unsortedMeshesOpaqueTangents; - QMap _unsortedMeshesOpaqueTangentsSpecular; - QMap _unsortedMeshesOpaqueSpecular; - - QMap _unsortedMeshesOpaqueSkinned; - QMap _unsortedMeshesOpaqueTangentsSkinned; - QMap _unsortedMeshesOpaqueTangentsSpecularSkinned; - QMap _unsortedMeshesOpaqueSpecularSkinned; - - QMap _unsortedMeshesOpaqueLightmap; - QMap _unsortedMeshesOpaqueLightmapTangents; - QMap _unsortedMeshesOpaqueLightmapTangentsSpecular; - QMap _unsortedMeshesOpaqueLightmapSpecular; - - typedef std::unordered_map> MeshListMap; - MeshListMap _sortedMeshes; - - QVector _meshesTranslucent; - QVector _meshesTranslucentTangents; - QVector _meshesTranslucentTangentsSpecular; - QVector _meshesTranslucentSpecular; - - QVector _meshesTranslucentSkinned; - QVector _meshesTranslucentTangentsSkinned; - QVector _meshesTranslucentTangentsSpecularSkinned; - QVector _meshesTranslucentSpecularSkinned; - - QVector _meshesOpaque; - QVector _meshesOpaqueTangents; - QVector _meshesOpaqueTangentsSpecular; - QVector _meshesOpaqueSpecular; - - QVector _meshesOpaqueSkinned; - QVector _meshesOpaqueTangentsSkinned; - QVector _meshesOpaqueTangentsSpecularSkinned; - QVector _meshesOpaqueSpecularSkinned; - - QVector _meshesOpaqueLightmap; - QVector _meshesOpaqueLightmapTangents; - QVector _meshesOpaqueLightmapTangentsSpecular; - QVector _meshesOpaqueLightmapSpecular; // debug rendering support void renderDebugMeshBoxes(); @@ -490,6 +438,17 @@ private: int getRaw() { return *reinterpret_cast(this); } + + RenderKey( + bool translucent, bool hasLightmap, + bool hasTangents, bool hasSpecular, bool isSkinned) : + RenderKey( (translucent ? IS_TRANSLUCENT : 0) + | (hasLightmap ? HAS_LIGHTMAP : 0) + | (hasTangents ? HAS_TANGENTS : 0) + | (hasSpecular ? HAS_SPECULAR : 0) + | (isSkinned ? IS_SKINNED : 0) + ) {} + RenderKey(RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned) : @@ -527,6 +486,22 @@ private: }; static RenderPipelineLib _renderPipelineLib; + + class RenderBucket { + public: + QVector _meshes; + QMap _unsortedMeshes; + }; + typedef std::unordered_map BaseRenderBucketMap; + class RenderBucketMap : public BaseRenderBucketMap { + public: + typedef RenderKey Key; + + + void addRenderBucket(Key key, RenderBucket& bucket); + }; + RenderBucketMap _renderBuckets; + bool _renderCollisionHull; }; From d7059d8f2de924a953d39ab49823a7547cdc7d92 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 14:46:38 -0700 Subject: [PATCH 109/401] add code for uuids in wire protocol. some debugging prints --- examples/dice.js | 2 +- .../entities/src/EntityEditPacketSender.cpp | 9 +++++ libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityItem.h | 6 +-- .../entities/src/EntityItemProperties.cpp | 6 +-- libraries/entities/src/EntityItemProperties.h | 5 ++- .../src/EntityItemPropertiesDefaults.h | 2 +- .../entities/src/EntityItemPropertiesMacros.h | 39 +++++++++++++++++++ .../entities/src/EntityScriptingInterface.cpp | 29 ++++++++------ libraries/entities/src/EntityTree.cpp | 2 +- libraries/entities/src/EntityTreeElement.cpp | 2 +- .../entities/src/SimpleEntitySimulation.cpp | 6 +-- libraries/octree/src/OctreePacketData.cpp | 11 ++++++ libraries/octree/src/OctreePacketData.h | 3 ++ libraries/physics/src/EntityMotionState.cpp | 15 +++---- 15 files changed, 104 insertions(+), 35 deletions(-) diff --git a/examples/dice.js b/examples/dice.js index b118a6b289..2b6d4d478e 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -13,7 +13,7 @@ // var isDice = false; -var NUMBER_OF_DICE = 2; +var NUMBER_OF_DICE = 1; var dice = []; var DIE_SIZE = 0.20; diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index e94725782d..6f58a5a626 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -36,6 +36,15 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityItemI unsigned char bufferOut[MAX_PACKET_SIZE]; int sizeOut = 0; + + //// XXX + auto nodeList = DependencyManager::get(); + QUuid myNodeID = nodeList->getSessionUUID(); + QString x = properties.getSimulatorID() == myNodeID ? "me" : properties.getSimulatorID().toString(); + qDebug() << "sending update:" << properties.simulatorIDChanged() << properties.getSimulatorID(); + //// XXX + + if (EntityItemProperties::encodeEntityEditPacket(type, modelID, properties, &bufferOut[0], _maxPacketSize, sizeOut)) { #ifdef WANT_DEBUG qCDebug(entities) << "calling queueOctreeEditMessage()..."; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e8427e0982..94d4d7f8a7 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1197,7 +1197,7 @@ void EntityItem::updateLifetime(float value) { } } -void EntityItem::setSimulatorID(const QString& value) { +void EntityItem::setSimulatorID(const QUuid& value) { if (_simulatorID != value) { _simulatorID = value; _simulatorIDChangedTime = usecTimestampNow(); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 124d37d762..634b7e7d3d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -255,8 +255,8 @@ public: const QString& getUserData() const { return _userData; } void setUserData(const QString& value) { _userData = value; } - QString getSimulatorID() const { return _simulatorID; } - void setSimulatorID(const QString& value); + QUuid getSimulatorID() const { return _simulatorID; } + void setSimulatorID(const QUuid& value); quint64 getSimulatorIDChangedTime() const { return _simulatorIDChangedTime; } const QString& getMarketplaceID() const { return _marketplaceID; } @@ -352,7 +352,7 @@ protected: bool _collisionsWillMove; bool _locked; QString _userData; - QString _simulatorID; // id of Node which is currently responsible for simulating this Entity + QUuid _simulatorID; // id of Node which is currently responsible for simulating this Entity quint64 _simulatorIDChangedTime; // when was _simulatorID last updated? QString _marketplaceID; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8a25d59f26..2ea8e5f578 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -307,7 +307,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying); COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS); COPY_PROPERTY_TO_QSCRIPTVALUE(animationFrameIndex); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(animationSettings,getAnimationSettings()); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(animationSettings, getAnimationSettings()); COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions); @@ -319,7 +319,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(locked); COPY_PROPERTY_TO_QSCRIPTVALUE(textures); COPY_PROPERTY_TO_QSCRIPTVALUE(userData); - COPY_PROPERTY_TO_QSCRIPTVALUE(simulatorID); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(simulatorID, getSimulatorIDAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(text); COPY_PROPERTY_TO_QSCRIPTVALUE(lineHeight); COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(textColor, getTextColor()); @@ -403,7 +403,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(locked, setLocked); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(textures, setTextures); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(userData, setUserData); - COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(simulatorID, setSimulatorID); + COPY_PROPERTY_FROM_QSCRIPTVALUE_UUID(simulatorID, setSimulatorID); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(text, setText); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(lineHeight, setLineHeight); COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(textColor, setTextColor); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 7de0fc0e8b..3788916807 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -200,7 +200,7 @@ public: DEFINE_PROPERTY_REF(PROP_TEXTURES, Textures, textures, QString); DEFINE_PROPERTY_REF_WITH_SETTER_AND_GETTER(PROP_ANIMATION_SETTINGS, AnimationSettings, animationSettings, QString); DEFINE_PROPERTY_REF(PROP_USER_DATA, UserData, userData, QString); - DEFINE_PROPERTY_REF(PROP_SIMULATOR_ID, SimulatorID, simulatorID, QString); + DEFINE_PROPERTY_REF(PROP_SIMULATOR_ID, SimulatorID, simulatorID, QUuid); DEFINE_PROPERTY_REF(PROP_TEXT, Text, text, QString); DEFINE_PROPERTY(PROP_LINE_HEIGHT, LineHeight, lineHeight, float); DEFINE_PROPERTY_REF(PROP_TEXT_COLOR, TextColor, textColor, xColor); @@ -257,6 +257,7 @@ public: const QStringList& getTextureNames() const { return _textureNames; } void setTextureNames(const QStringList& value) { _textureNames = value; } + QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); } private: QUuid _id; @@ -330,7 +331,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, Locked, locked, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Textures, textures, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, UserData, userData, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulatorID, simulatorID, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulatorID, simulatorID, QUuid()); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Text, text, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LineHeight, lineHeight, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, TextColor, textColor, ""); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 4b595ae0b8..001f963ecb 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -23,7 +23,7 @@ const glm::vec3 ENTITY_ITEM_ZERO_VEC3(0.0f); const bool ENTITY_ITEM_DEFAULT_LOCKED = false; const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString(""); const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString(""); -const QString ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QString(""); +const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid(); const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f; diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index e3e54f5bc8..8b9d9847bd 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -88,6 +88,22 @@ } \ } +// TODO: this doesn't need a length. See OctreePacketData::appendValue(const QUuid& uuid) +#define READ_ENTITY_PROPERTY_UUID(P,O) \ + if (propertyFlags.getHasProperty(P)) { \ + uint16_t length; \ + memcpy(&length, dataAt, sizeof(length)); \ + dataAt += sizeof(length); \ + bytesRead += sizeof(length); \ + QByteArray ba((const char*)dataAt, length); \ + QUuid value = QUUid::fromRfc4122(ba); \ + dataAt += length; \ + bytesRead += length; \ + if (overwriteLocalData) { \ + O(value); \ + } \ + } + #define READ_ENTITY_PROPERTY_COLOR(P,M) \ if (propertyFlags.getHasProperty(P)) { \ if (overwriteLocalData) { \ @@ -127,6 +143,20 @@ properties.O(value); \ } + +// TODO: make a version of this that does a binary unpacking of the uuid +#define READ_ENTITY_PROPERTY_UUID_TO_PROPERTIES(P,O) \ + if (propertyFlags.getHasProperty(P)) { \ + uint16_t length; \ + memcpy(&length, dataAt, sizeof(length)); \ + dataAt += sizeof(length); \ + processedBytes += sizeof(length); \ + QUuid value((const char*)dataAt); \ + dataAt += length; \ + processedBytes += length; \ + properties.O(value); \ + } + #define READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(P,O) \ if (propertyFlags.getHasProperty(P)) { \ xColor color; \ @@ -207,6 +237,15 @@ } \ } +#define COPY_PROPERTY_FROM_QSCRIPTVALUE_UUID(P, S) \ + QScriptValue P = object.property(#P); \ + if (P.isValid()) { \ + QUuid newValue = P.toVariant().toUuid(); \ + if (_defaultSettings || newValue != _##P) { \ + S(newValue); \ + } \ + } + #define COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(P, S) \ QScriptValue P = object.property(#P); \ if (P.isValid()) { \ diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index fa142d3abd..57752dff02 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -60,6 +60,19 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) { } + +void setSimId(EntityItemProperties& propertiesWithSimID) { + if (propertiesWithSimID.velocityChanged() || + propertiesWithSimID.rotationChanged() || + propertiesWithSimID.containsPositionChange()) { + auto nodeList = DependencyManager::get(); + const QUuid myNodeID = nodeList->getSessionUUID(); + propertiesWithSimID.setSimulatorID(myNodeID); + } +} + + + EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& properties) { // The application will keep track of creatorTokenID @@ -67,11 +80,7 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro // This Node is creating a new object. If it's in motion, set this Node as the simulator. EntityItemProperties propertiesWithSimID = properties; - if (properties.velocityChanged() || properties.rotationChanged()) { - auto nodeList = DependencyManager::get(); - const QString myNodeID = nodeList->getSessionUUID().toString(); - propertiesWithSimID.setSimulatorID(myNodeID); - } + setSimId(propertiesWithSimID); EntityItemID id(NEW_ENTITY, creatorTokenID, false ); @@ -146,14 +155,10 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E } } - // If this node is changing a physics-related property, claim simulation ownership + // if this Node is changing a physics-related property, claim simulation ownership. EntityItemProperties propertiesWithSimID = properties; - if (properties.velocityChanged() || properties.rotationChanged()) { - auto nodeList = DependencyManager::get(); - const QString myNodeID = nodeList->getSessionUUID().toString(); - propertiesWithSimID.setSimulatorID(myNodeID); - } - + setSimId(propertiesWithSimID); + // If we have a local entity tree set, then also update it. We can do this even if we don't know // the actual id, because we can edit out local entities just with creatorTokenID if (_entityTree) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 2227107537..07f61de8b4 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -131,7 +131,7 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro } } else { if (properties.simulatorIDChanged() && - !entity->getSimulatorID().isEmpty() && + !entity->getSimulatorID().isNull() && properties.getSimulatorID() != entity->getSimulatorID()) { // A Node is trying to take ownership of the simulation of this entity from another Node. Only allow this // if ownership hasn't recently changed. diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 3dcd2899d3..ad268edc6f 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -719,7 +719,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int if (bytesLeftToRead >= (int)(numberOfEntities * expectedBytesPerEntity)) { // look up the Id of this Node auto nodeList = DependencyManager::get(); - QString myNodeID = nodeList->getSessionUUID().toString(); + QUuid myNodeID = nodeList->getSessionUUID(); for (uint16_t i = 0; i < numberOfEntities; i++) { int bytesForThisEntity = 0; diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 0406aaa443..2c586ae0af 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -38,7 +38,7 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { itemItr = _hasSimulationOwnerEntities.begin(); while (itemItr != _hasSimulationOwnerEntities.end()) { EntityItem* entity = *itemItr; - if (!entity->getSimulatorID().isEmpty() && + if (!entity->getSimulatorID().isNull() && usecTimestampNow() - entity->getLastChangedOnServer() >= AUTO_REMOVE_SIMULATION_OWNER_USEC) { qCDebug(entities) << "auto-removing simulation owner" << entity->getSimulatorID(); entity->setSimulatorID(""); @@ -55,7 +55,7 @@ void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { } else if (entity->getCollisionsWillMove()) { _movableButStoppedEntities.insert(entity); } - if (!entity->getSimulatorID().isEmpty()) { + if (!entity->getSimulatorID().isNull()) { _hasSimulationOwnerEntities.insert(entity); } } @@ -79,7 +79,7 @@ void SimpleEntitySimulation::entityChangedInternal(EntityItem* entity) { _movingEntities.remove(entity); _movableButStoppedEntities.remove(entity); } - if (!entity->getSimulatorID().isEmpty()) { + if (!entity->getSimulatorID().isNull()) { _hasSimulationOwnerEntities.insert(entity); } } diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 674faa11c3..346d2f1a79 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -411,6 +411,17 @@ bool OctreePacketData::appendValue(const QString& string) { return success; } +bool OctreePacketData::appendValue(const QUuid& uuid) { + // TODO: this doesn't need a length + QByteArray bytes = uuid.toRfc4122(); + uint16_t length = bytes.size(); + bool success = appendValue(length); + if (success) { + success = appendRawData((const unsigned char*)bytes.constData(), bytes.size()); + } + return success; +} + bool OctreePacketData::appendValue(const QByteArray& bytes) { bool success = appendRawData((const unsigned char*)bytes.constData(), bytes.size()); return success; diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 1c1576f509..992eca99ae 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -166,6 +166,9 @@ public: /// appends a string value to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const QString& string); + /// appends a uuid value to the end of the stream, may fail if new data stream is too long to fit in packet + bool appendValue(const QUuid& uuid); + /// appends a QByteArray value to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const QByteArray& bytes); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 655db8fd2f..02d2ed896b 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -188,10 +188,10 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { } auto nodeList = DependencyManager::get(); - QString myNodeID = nodeList->getSessionUUID().toString(); - QString simulatorID = _entity->getSimulatorID(); + QUuid myNodeID = nodeList->getSessionUUID(); + QUuid simulatorID = _entity->getSimulatorID(); - if (!simulatorID.isEmpty() && simulatorID != myNodeID) { + if (!simulatorID.isNull() && simulatorID != myNodeID) { // some other Node is simulating this, so don't broadcast our computations. return false; } @@ -249,13 +249,13 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ auto nodeList = DependencyManager::get(); - QString myNodeID = nodeList->getSessionUUID().toString(); - QString simulatorID = _entity->getSimulatorID(); - if (simulatorID.isEmpty() && !(zeroSpeed && zeroSpin)) { + QUuid myNodeID = nodeList->getSessionUUID(); + QUuid simulatorID = _entity->getSimulatorID(); + if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); - } else if (simulatorID == myNodeID && _numNonMovingUpdates >= MAX_NUM_NON_MOVING_UPDATES - 1) { + } else if (simulatorID == myNodeID && _numNonMovingUpdates >= MAX_NUM_NON_MOVING_UPDATES - 2) { // we are the simulator and the object has stopped. give up "simulator" status _entity->setSimulatorID(""); properties.setSimulatorID(""); @@ -293,6 +293,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ #ifdef WANT_DEBUG qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; #endif + entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { #ifdef WANT_DEBUG From 23d56f5bd01c78bd8791052282cb199159ec84b2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 16 Apr 2015 14:51:55 -0700 Subject: [PATCH 110/401] Remove current DDE filtering --- interface/src/devices/DdeFaceTracker.cpp | 18 ++++++------------ interface/src/devices/DdeFaceTracker.h | 5 ----- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index a701160198..e596342473 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -156,12 +156,9 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui _browUpRightIndex(18), _mouthSmileLeftIndex(28), _mouthSmileRightIndex(29), - _jawOpenIndex(21), - _previousTranslation(glm::vec3()), - _previousRotation(glm::quat()) + _jawOpenIndex(21) { _coefficients.resize(NUM_FACESHIFT_BLENDSHAPES); - _previousCoefficients.resize(NUM_FACESHIFT_BLENDSHAPES); _blendshapeCoefficients.resize(NUM_FACESHIFT_BLENDSHAPES); @@ -290,13 +287,11 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { translation -= _referenceTranslation; translation /= LEAN_DAMPING_FACTOR; translation.x *= -1; - _headTranslation = (translation + _previousTranslation) / 2.0f; - _previousTranslation = translation; + _headTranslation = translation; // Compute relative rotation rotation = glm::inverse(_referenceRotation) * rotation; - _headRotation = (rotation + _previousRotation) / 2.0f; - _previousRotation = rotation; + _headRotation = rotation; // Translate DDE coefficients to Faceshift compatible coefficients for (int i = 0; i < NUM_EXPRESSIONS; i += 1) { @@ -305,8 +300,8 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { // Use EyeBlink values to control both EyeBlink and EyeOpen static const float RELAXED_EYE_VALUE = 0.1f; - float leftEye = (_coefficients[_leftBlinkIndex] + _previousCoefficients[_leftBlinkIndex]) / 2.0f; - float rightEye = (_coefficients[_rightBlinkIndex] + _previousCoefficients[_rightBlinkIndex]) / 2.0f; + float leftEye = _coefficients[_leftBlinkIndex]; + float rightEye = _coefficients[_rightBlinkIndex]; if (leftEye > RELAXED_EYE_VALUE) { _coefficients[_leftBlinkIndex] = leftEye - RELAXED_EYE_VALUE; _coefficients[_leftEyeOpenIndex] = 0.0f; @@ -341,8 +336,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { // Scale all coefficients for (int i = 0; i < NUM_EXPRESSIONS; i += 1) { _blendshapeCoefficients[i] - = glm::clamp(DDE_COEFFICIENT_SCALES[i] * (_coefficients[i] + _previousCoefficients[i]) / 2.0f, 0.0f, 1.0f); - _previousCoefficients[i] = _coefficients[i]; + = glm::clamp(DDE_COEFFICIENT_SCALES[i] * _coefficients[i], 0.0f, 1.0f); } } else { diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 490020e511..3cea667327 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -100,11 +100,6 @@ private: int _jawOpenIndex; QVector _coefficients; - - // Previous values for simple smoothing - glm::vec3 _previousTranslation; - glm::quat _previousRotation; - QVector _previousCoefficients; }; #endif // hifi_DdeFaceTracker_h \ No newline at end of file From 3e484ee2089b01e2608621b11ea01bf5330d4930 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 16 Apr 2015 15:04:25 -0700 Subject: [PATCH 111/401] Add menu item for enabling DDE filtering --- interface/src/Menu.cpp | 3 +++ interface/src/Menu.h | 1 + 2 files changed, 4 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d50cb48118..bb7d2b5382 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -386,6 +386,8 @@ Menu::Menu() { } #ifdef HAVE_DDE faceTrackingMenu->addSeparator(); + QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFiltering, 0, true); + ddeFiltering->setVisible(false); QAction* ddeFaceTrackerReset = addActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::ResetDDETracking, Qt::CTRL | Qt::Key_Apostrophe, DependencyManager::get().data(), SLOT(resetTracking())); @@ -991,6 +993,7 @@ void Menu::visibilityChanged(Discoverability::Mode discoverabilityMode) { void Menu::setActiveFaceTracker() { #ifdef HAVE_DDE bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression); + Menu::getInstance()->getActionForOption(MenuOption::DDEFiltering)->setVisible(isUsingDDE); Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE); #endif qApp->setActiveFaceTracker(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index f580b9204b..5798ca3a13 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -137,6 +137,7 @@ namespace MenuOption { const QString CopyAddress = "Copy Address to Clipboard"; const QString CopyPath = "Copy Path to Clipboard"; const QString DDEFaceRegression = "DDE Face Regression"; + const QString DDEFiltering = "DDE Filtering"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DeleteBookmark = "Delete Bookmark..."; const QString DisableActivityLogger = "Disable Activity Logger"; From d7881f18916e6375eef467d1264865aee18f2120 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 15:15:28 -0700 Subject: [PATCH 112/401] adjust logic for releasing ownership of simulation --- libraries/entities/src/EntityEditPacketSender.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index 6f58a5a626..5f77d1e782 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -41,7 +41,7 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityItemI auto nodeList = DependencyManager::get(); QUuid myNodeID = nodeList->getSessionUUID(); QString x = properties.getSimulatorID() == myNodeID ? "me" : properties.getSimulatorID().toString(); - qDebug() << "sending update:" << properties.simulatorIDChanged() << properties.getSimulatorID(); + qDebug() << "sending update:" << properties.simulatorIDChanged() << x; //// XXX diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 02d2ed896b..9af97d20ad 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -251,14 +251,20 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ auto nodeList = DependencyManager::get(); QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); + + // qDebug() << "XXX me =" << (simulatorID == myNodeID) + // << "_numNonMovingUpdates =" << _numNonMovingUpdates + // << "stopped =" << (zeroSpin && zeroSpeed) + // << "active =" << _body->isActive(); + if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); - } else if (simulatorID == myNodeID && _numNonMovingUpdates >= MAX_NUM_NON_MOVING_UPDATES - 2) { + } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the object has stopped. give up "simulator" status - _entity->setSimulatorID(""); - properties.setSimulatorID(""); + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. From ea8dcfa5b51207becb9a655ab487f043f83c2b30 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 15:33:43 -0700 Subject: [PATCH 113/401] read UUIDs as UUIDs rather than as strings. more debugging prints --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityItemPropertiesMacros.h | 3 ++- libraries/physics/src/EntityMotionState.cpp | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 94d4d7f8a7..5a37baf4a0 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -569,7 +569,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA, setUserData); if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) { - READ_ENTITY_PROPERTY_STRING(PROP_SIMULATOR_ID, setSimulatorID); + READ_ENTITY_PROPERTY_UUID(PROP_SIMULATOR_ID, setSimulatorID); } if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) { diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 8b9d9847bd..1611a542c9 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -96,7 +96,8 @@ dataAt += sizeof(length); \ bytesRead += sizeof(length); \ QByteArray ba((const char*)dataAt, length); \ - QUuid value = QUUid::fromRfc4122(ba); \ + QUuid value = QUuid::fromRfc4122(ba); \ + qDebug() << "UUID" << value; \ dataAt += length; \ bytesRead += length; \ if (overwriteLocalData) { \ diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 9af97d20ad..c3da5b35d1 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -191,8 +191,11 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); + qDebug() << "XXX" << simulatorID << myNodeID; + if (!simulatorID.isNull() && simulatorID != myNodeID) { // some other Node is simulating this, so don't broadcast our computations. + qDebug() << "NOT SENDING DUE TO NOT OWNER"; return false; } From c46f21152fa43dba02ee7d6c1d3fad9438e8d5ad Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 16 Apr 2015 15:47:02 -0700 Subject: [PATCH 114/401] Add velocity filtering to DDE head movement Based on filtering code in Faceshift.cpp. --- interface/src/devices/DdeFaceTracker.cpp | 44 ++++++++++++++++++++++-- interface/src/devices/DdeFaceTracker.h | 7 ++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index e596342473..4cbbe28ec2 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include "DdeFaceTracker.h" #include "FaceshiftConstants.h" #include "InterfaceLogging.h" @@ -267,6 +269,8 @@ float DdeFaceTracker::getBlendshapeCoefficient(int index) const { void DdeFaceTracker::decodePacket(const QByteArray& buffer) { if(buffer.size() > MIN_PACKET_SIZE) { + bool isFitering = Menu::getInstance()->isOptionChecked(MenuOption::DDEFiltering); + Packet packet; int bytesToCopy = glm::min((int)sizeof(packet), buffer.size()); memset(&packet.name, '\n', MAX_NAME_SIZE + 1); @@ -287,11 +291,36 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { translation -= _referenceTranslation; translation /= LEAN_DAMPING_FACTOR; translation.x *= -1; - _headTranslation = translation; + if (isFitering) { + glm::vec3 linearVelocity = (translation - _lastHeadTranslation) / _averageMessageTime; + const float LINEAR_VELOCITY_FILTER_STRENGTH = 0.3f; + float velocityFilter = glm::clamp(1.0f - glm::length(linearVelocity) * + LINEAR_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); + _filteredHeadTranslation = velocityFilter * _filteredHeadTranslation + (1.0f - velocityFilter) * translation; + _lastHeadTranslation = translation; + _headTranslation = _filteredHeadTranslation; + } else { + _headTranslation = translation; + } // Compute relative rotation rotation = glm::inverse(_referenceRotation) * rotation; - _headRotation = rotation; + if (isFitering) { + glm::quat r = rotation * glm::inverse(_headRotation); + float theta = 2 * acos(r.w); + glm::vec3 angularVelocity; + if (theta > EPSILON) { + float rMag = glm::length(glm::vec3(r.x, r.y, r.z)); + angularVelocity = theta / _averageMessageTime * glm::vec3(r.x, r.y, r.z) / rMag; + } else { + angularVelocity = glm::vec3(0, 0, 0); + } + const float ANGULAR_VELOCITY_FILTER_STRENGTH = 0.3f; + _headRotation = safeMix(_headRotation, rotation, glm::clamp(glm::length(angularVelocity) * + ANGULAR_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f)); + } else { + _headRotation = rotation; + } // Translate DDE coefficients to Faceshift compatible coefficients for (int i = 0; i < NUM_EXPRESSIONS; i += 1) { @@ -339,7 +368,16 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { = glm::clamp(DDE_COEFFICIENT_SCALES[i] * _coefficients[i], 0.0f, 1.0f); } - } else { + // Calculate average frame time + const float FRAME_AVERAGING_FACTOR = 0.99f; + quint64 usecsNow = usecTimestampNow(); + if (_lastMessageReceived != 0) { + _averageMessageTime = FRAME_AVERAGING_FACTOR * _averageMessageTime + + (1.0f - FRAME_AVERAGING_FACTOR) * (float)(usecsNow - _lastMessageReceived) / 1000000.0f; + } + _lastMessageReceived = usecsNow; + +} else { qCDebug(interfaceapp) << "[Error] DDE Face Tracker Decode Error"; } _lastReceiveTimestamp = usecTimestampNow(); diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 3cea667327..261b538d83 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -23,6 +23,8 @@ #include "FaceTracker.h" +const float STARTING_DDE_MESSAGE_TIME = 0.033f; + class DdeFaceTracker : public FaceTracker, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -100,6 +102,11 @@ private: int _jawOpenIndex; QVector _coefficients; + + quint64 _lastMessageReceived = 0; + float _averageMessageTime = STARTING_DDE_MESSAGE_TIME; + glm::vec3 _lastHeadTranslation = glm::vec3(0.0f); + glm::vec3 _filteredHeadTranslation = glm::vec3(0.0f); }; #endif // hifi_DdeFaceTracker_h \ No newline at end of file From 3b2a15f76a2488ef2641272b122b54defef3d5a2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 15:52:48 -0700 Subject: [PATCH 115/401] more debugging --- libraries/entities/src/EntityItemPropertiesMacros.h | 2 +- libraries/octree/src/OctreePacketData.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 1611a542c9..283d09b4be 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -97,7 +97,7 @@ bytesRead += sizeof(length); \ QByteArray ba((const char*)dataAt, length); \ QUuid value = QUuid::fromRfc4122(ba); \ - qDebug() << "UUID" << value; \ + qDebug() << "READING UUID" << (unsigned int)ba[0] << (unsigned int)ba[1] << value << length; \ dataAt += length; \ bytesRead += length; \ if (overwriteLocalData) { \ diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 346d2f1a79..3a12cc646e 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -418,6 +418,7 @@ bool OctreePacketData::appendValue(const QUuid& uuid) { bool success = appendValue(length); if (success) { success = appendRawData((const unsigned char*)bytes.constData(), bytes.size()); + qDebug() << "SENDING UUID" << (unsigned int)bytes[0] << (unsigned int)bytes[1] << uuid << length; } return success; } From 1484d6e37fd6796fd46fc004a01463351da3e9f3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 16:10:01 -0700 Subject: [PATCH 116/401] fix READ_ENTITY_PROPERTY_UUID_TO_PROPERTIES to use binary version --- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/EntityItemPropertiesMacros.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 2ea8e5f578..e75fa8104f 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -798,7 +798,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_USER_DATA, setUserData); - READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_SIMULATOR_ID, setSimulatorID); + READ_ENTITY_PROPERTY_UUID_TO_PROPERTIES(PROP_SIMULATOR_ID, setSimulatorID); if (properties.getType() == EntityTypes::Text) { READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_TEXT, setText); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 283d09b4be..ff66a16c6b 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -145,14 +145,15 @@ } -// TODO: make a version of this that does a binary unpacking of the uuid +// TODO: this doesn't need a length. See OctreePacketData::appendValue(const QUuid& uuid) #define READ_ENTITY_PROPERTY_UUID_TO_PROPERTIES(P,O) \ if (propertyFlags.getHasProperty(P)) { \ uint16_t length; \ memcpy(&length, dataAt, sizeof(length)); \ dataAt += sizeof(length); \ processedBytes += sizeof(length); \ - QUuid value((const char*)dataAt); \ + QByteArray ba((const char*)dataAt, length); \ + QUuid value = QUuid::fromRfc4122(ba); \ dataAt += length; \ processedBytes += length; \ properties.O(value); \ From f48f9caea48e01a72d86a0ce06caf744989da690 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 16:18:13 -0700 Subject: [PATCH 117/401] cut back on debuging prints --- libraries/entities/src/EntityItemPropertiesMacros.h | 1 - libraries/octree/src/OctreePacketData.cpp | 1 - libraries/physics/src/EntityMotionState.cpp | 8 -------- 3 files changed, 10 deletions(-) diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index ff66a16c6b..4a0b5c210d 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -97,7 +97,6 @@ bytesRead += sizeof(length); \ QByteArray ba((const char*)dataAt, length); \ QUuid value = QUuid::fromRfc4122(ba); \ - qDebug() << "READING UUID" << (unsigned int)ba[0] << (unsigned int)ba[1] << value << length; \ dataAt += length; \ bytesRead += length; \ if (overwriteLocalData) { \ diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 3a12cc646e..346d2f1a79 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -418,7 +418,6 @@ bool OctreePacketData::appendValue(const QUuid& uuid) { bool success = appendValue(length); if (success) { success = appendRawData((const unsigned char*)bytes.constData(), bytes.size()); - qDebug() << "SENDING UUID" << (unsigned int)bytes[0] << (unsigned int)bytes[1] << uuid << length; } return success; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c3da5b35d1..2d38667e6d 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -191,11 +191,8 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); - qDebug() << "XXX" << simulatorID << myNodeID; - if (!simulatorID.isNull() && simulatorID != myNodeID) { // some other Node is simulating this, so don't broadcast our computations. - qDebug() << "NOT SENDING DUE TO NOT OWNER"; return false; } @@ -255,11 +252,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); - // qDebug() << "XXX me =" << (simulatorID == myNodeID) - // << "_numNonMovingUpdates =" << _numNonMovingUpdates - // << "stopped =" << (zeroSpin && zeroSpeed) - // << "active =" << _body->isActive(); - if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator _entity->setSimulatorID(myNodeID); From ec26b4595ad0722ee276daf763a8e911045e2e83 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 16:27:30 -0700 Subject: [PATCH 118/401] adjust comment --- libraries/physics/src/EntityMotionState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 2d38667e6d..91776b211c 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -192,7 +192,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { QUuid simulatorID = _entity->getSimulatorID(); if (!simulatorID.isNull() && simulatorID != myNodeID) { - // some other Node is simulating this, so don't broadcast our computations. + // some other Node owns the simulating of this, so don't broadcast the results of local simulation. return false; } From d60ee3b6e24590d35c3233338261eec0b7954ac9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 16 Apr 2015 16:28:22 -0700 Subject: [PATCH 119/401] Add velocity filtering to DDE eyelids --- interface/src/devices/DdeFaceTracker.cpp | 21 ++++++++++++++++++--- interface/src/devices/DdeFaceTracker.h | 4 ++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 4cbbe28ec2..35bb7a2595 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -269,7 +269,7 @@ float DdeFaceTracker::getBlendshapeCoefficient(int index) const { void DdeFaceTracker::decodePacket(const QByteArray& buffer) { if(buffer.size() > MIN_PACKET_SIZE) { - bool isFitering = Menu::getInstance()->isOptionChecked(MenuOption::DDEFiltering); + bool isFiltering = Menu::getInstance()->isOptionChecked(MenuOption::DDEFiltering); Packet packet; int bytesToCopy = glm::min((int)sizeof(packet), buffer.size()); @@ -291,7 +291,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { translation -= _referenceTranslation; translation /= LEAN_DAMPING_FACTOR; translation.x *= -1; - if (isFitering) { + if (isFiltering) { glm::vec3 linearVelocity = (translation - _lastHeadTranslation) / _averageMessageTime; const float LINEAR_VELOCITY_FILTER_STRENGTH = 0.3f; float velocityFilter = glm::clamp(1.0f - glm::length(linearVelocity) * @@ -305,7 +305,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { // Compute relative rotation rotation = glm::inverse(_referenceRotation) * rotation; - if (isFitering) { + if (isFiltering) { glm::quat r = rotation * glm::inverse(_headRotation); float theta = 2 * acos(r.w); glm::vec3 angularVelocity; @@ -331,6 +331,21 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { static const float RELAXED_EYE_VALUE = 0.1f; float leftEye = _coefficients[_leftBlinkIndex]; float rightEye = _coefficients[_rightBlinkIndex]; + if (isFiltering) { + const float BLINK_VELOCITY_FILTER_STRENGTH = 0.3f; + + float velocity = fabs(leftEye - _lastLeftEyeBlink) / _averageMessageTime; + float velocityFilter = glm::clamp(velocity * BLINK_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); + _filteredLeftEyeBlink = velocityFilter * leftEye + (1.0f - velocityFilter) * _filteredLeftEyeBlink; + _lastLeftEyeBlink = leftEye; + leftEye = _filteredLeftEyeBlink; + + velocity = fabs(rightEye - _lastRightEyeBlink) / _averageMessageTime; + velocityFilter = glm::clamp(velocity * BLINK_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); + _filteredRightEyeBlink = velocityFilter * rightEye + (1.0f - velocityFilter) * _filteredRightEyeBlink; + _lastRightEyeBlink = rightEye; + rightEye = _filteredRightEyeBlink; + } if (leftEye > RELAXED_EYE_VALUE) { _coefficients[_leftBlinkIndex] = leftEye - RELAXED_EYE_VALUE; _coefficients[_leftEyeOpenIndex] = 0.0f; diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 261b538d83..50de9687d2 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -107,6 +107,10 @@ private: float _averageMessageTime = STARTING_DDE_MESSAGE_TIME; glm::vec3 _lastHeadTranslation = glm::vec3(0.0f); glm::vec3 _filteredHeadTranslation = glm::vec3(0.0f); + float _lastLeftEyeBlink = 0.0f; + float _filteredLeftEyeBlink = 0.0f; + float _lastRightEyeBlink = 0.0f; + float _filteredRightEyeBlink = 0.0f; }; #endif // hifi_DdeFaceTracker_h \ No newline at end of file From faf5e7415dabe002296655dfdfdba717e50880f8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 16:32:51 -0700 Subject: [PATCH 120/401] don't explicitly release simulator status --- libraries/physics/src/EntityMotionState.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 91776b211c..d54ee3571a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -258,8 +258,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setSimulatorID(myNodeID); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the object has stopped. give up "simulator" status - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); + + // XXX the entity server will clear the simulatorID after 2 seconds. if the interface clears + // it here, every node that sees the entity-stopped-moving packets will rebroadcast them. + + // _entity->setSimulatorID(QUuid()); + // properties.setSimulatorID(QUuid()); } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. @@ -270,7 +274,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } if (_numNonMovingUpdates <= 1) { // we only update lastEdited when we're sending new physics data - // (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data) + // (i.e. NOT when we just simulate the positions forward, nor when we resend non-moving data) // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly quint64 lastSimulated = _entity->getLastSimulated(); _entity->setLastEdited(lastSimulated); From 096f69961a695eb1dee16d82248fc1bb7055bc0a Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Thu, 16 Apr 2015 16:42:28 -0700 Subject: [PATCH 121/401] Filtering triggering of collisions with contact type of "continue" --- libraries/physics/src/PhysicsEngine.cpp | 44 ++++++++++--------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 50f52a7efc..68a71c59c3 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -395,24 +395,13 @@ void PhysicsEngine::computeCollisionEvents() { } } - // We harvest collision callbacks every few frames, which contributes the following effects: - // - // (1) There is a maximum collision callback rate per pair: substep_rate / SUBSTEPS_PER_COLLIION_FRAME - // (2) END/START cycles shorter than SUBSTEPS_PER_COLLIION_FRAME will be filtered out - // (3) There is variable lag between when the contact actually starts and when it is reported, - // up to SUBSTEPS_PER_COLLIION_FRAME * time_per_substep - // - const uint32_t SUBSTEPS_PER_COLLISION_FRAME = 2; - if (_numSubsteps - _numContactFrames * SUBSTEPS_PER_COLLISION_FRAME < SUBSTEPS_PER_COLLISION_FRAME) { - // we don't harvest collision callbacks every frame - // this sets a maximum callback-per-contact rate - // and also filters out END/START events that happen on shorter timescales - return; - } + const uint32_t CONTINUE_EVENT_FILTER_FREQUENCY = 10; - ++_numContactFrames; // scan known contacts and trigger events ContactMap::iterator contactItr = _contactMap.begin(); + + // TODO: enable scripts to filter based on contact event type + ContactEventType type = contactItr->second.computeType(_numContactFrames); while (contactItr != _contactMap.end()) { ObjectMotionState* A = static_cast(contactItr->first._a); ObjectMotionState* B = static_cast(contactItr->first._b); @@ -420,21 +409,21 @@ void PhysicsEngine::computeCollisionEvents() { // TODO: make triggering these events clean and efficient. The code at this context shouldn't // have to figure out what kind of object (entity, avatar, etc) these are in order to properly // emit a collision event. - if (A && A->getType() == MOTION_STATE_TYPE_ENTITY) { - EntityItemID idA = static_cast(A)->getEntity()->getEntityItemID(); - EntityItemID idB; - if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { - idB = static_cast(B)->getEntity()->getEntityItemID(); + if(type != CONTACT_EVENT_TYPE_CONTINUE || _numSubsteps % CONTINUE_EVENT_FILTER_FREQUENCY == 0){ + if (A && A->getType() == MOTION_STATE_TYPE_ENTITY) { + EntityItemID idA = static_cast(A)->getEntity()->getEntityItemID(); + EntityItemID idB; + if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { + idB = static_cast(B)->getEntity()->getEntityItemID(); + } + emit entityCollisionWithEntity(idA, idB, contactItr->second); + } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { + EntityItemID idA; + EntityItemID idB = static_cast(B)->getEntity()->getEntityItemID(); + emit entityCollisionWithEntity(idA, idB, contactItr->second); } - emit entityCollisionWithEntity(idA, idB, contactItr->second); - } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { - EntityItemID idA; - EntityItemID idB = static_cast(B)->getEntity()->getEntityItemID(); - emit entityCollisionWithEntity(idA, idB, contactItr->second); } - // TODO: enable scripts to filter based on contact event type - ContactEventType type = contactItr->second.computeType(_numContactFrames); if (type == CONTACT_EVENT_TYPE_END) { ContactMap::iterator iterToDelete = contactItr; ++contactItr; @@ -443,6 +432,7 @@ void PhysicsEngine::computeCollisionEvents() { ++contactItr; } } + ++_numContactFrames; } // Bullet collision flags are as follows: From 62a45ccebb6e3ea9804217f472e4e1db06a6ebb6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Apr 2015 17:00:36 -0700 Subject: [PATCH 122/401] re-enable code that gives up simulation ownership --- libraries/physics/src/EntityMotionState.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d54ee3571a..1324603bad 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -258,12 +258,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setSimulatorID(myNodeID); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the object has stopped. give up "simulator" status - - // XXX the entity server will clear the simulatorID after 2 seconds. if the interface clears - // it here, every node that sees the entity-stopped-moving packets will rebroadcast them. - - // _entity->setSimulatorID(QUuid()); - // properties.setSimulatorID(QUuid()); + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. From 41e7b75a8d01b3e64dc7362feb445a9829d30470 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 Apr 2015 17:14:18 -0700 Subject: [PATCH 123/401] revert mac version of HMD tools back to meta-H --- interface/src/Menu.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d50cb48118..bde0745c4d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -235,33 +235,33 @@ Menu::Menu() { QMenu* viewMenu = addMenu("View"); + addCheckableActionToQMenuAndActionHash(viewMenu, + MenuOption::Fullscreen, #ifdef Q_OS_MAC - addCheckableActionToQMenuAndActionHash(viewMenu, - MenuOption::Fullscreen, Qt::CTRL | Qt::META | Qt::Key_F, - false, - qApp, - SLOT(setFullscreen(bool))); #else - addCheckableActionToQMenuAndActionHash(viewMenu, - MenuOption::Fullscreen, Qt::CTRL | Qt::Key_F, +#endif false, qApp, SLOT(setFullscreen(bool))); -#endif + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true, qApp,SLOT(cameraMenuChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, qApp, SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::CTRL | Qt::Key_H, + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, +#ifdef Q_OS_MAC + Qt::META | Qt::Key_H, +#else + Qt::CTRL | Qt::Key_H, +#endif false, dialogsManager.data(), SLOT(hmdTools(bool))); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0, false, qApp, From b5b146b81b26ddcb3e73b18af6a3ecd795f5e0ac Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 16 Apr 2015 17:35:37 -0700 Subject: [PATCH 124/401] Training Team: improving the sun lighting interface to javascript to enable / disable the earthSkyModel, assign explicitely the SUnDirection and getter, and expose a AmbientINtensity to control the amount of the ambient lighting contribution Expose these to javascript --- examples/example/misc/sunLightExample.js | 6 +++ interface/src/Application.cpp | 2 +- libraries/model/src/model/Light.cpp | 4 ++ libraries/model/src/model/Light.h | 6 ++- libraries/model/src/model/Light.slh | 1 + libraries/model/src/model/Stage.cpp | 27 ++++++++--- libraries/model/src/model/Stage.h | 47 ++++++++++++------- .../render-utils/src/DeferredGlobalLight.slh | 6 +-- .../src/DeferredLightingEffect.cpp | 3 +- .../render-utils/src/DeferredLightingEffect.h | 2 +- .../src/SceneScriptingInterface.cpp | 24 ++++++++++ .../src/SceneScriptingInterface.h | 14 ++++++ 12 files changed, 111 insertions(+), 31 deletions(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index e6c06bb1ae..55c312881f 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -78,6 +78,12 @@ panel.newSlider("Light Intensity", 0.0, 5, function(value) { return (value).toFixed(2); } ); +panel.newSlider("Light Ambient Intensity", 0.0, 1.0, + function(value) { Scene.setSunAmbientIntensity(value); }, + function() { return Scene.getSunAmbientIntensity(); }, + function(value) { return (value).toFixed(2); } +); + Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); }); Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); }); Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc24127054..56b5d931e3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3045,7 +3045,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs { DependencyManager::get()->setAmbientLightMode(getRenderAmbientLight()); auto skyStage = DependencyManager::get()->getSkyStage(); - DependencyManager::get()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity()); + DependencyManager::get()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity(), skyStage->getSunLight()->getAmbientIntensity()); DependencyManager::get()->setGlobalAtmosphere(skyStage->getAtmosphere()); PROFILE_RANGE("DeferredLighting"); diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index ea77412140..e8c01c68aa 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -64,6 +64,10 @@ void Light::setIntensity(float intensity) { editSchema()._intensity = intensity; } +void Light::setAmbientIntensity(float intensity) { + editSchema()._ambientIntensity = intensity; +} + void Light::setMaximumRadius(float radius) { if (radius <= 0.f) { radius = 1.0f; diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 8f6c663668..6b9371a0ee 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -244,6 +244,10 @@ public: void setShowContour(float show); float getShowContour() const { return getSchema()._control.w; } + // If the light has an ambient (Indirect) component, then the Ambientintensity can be used to control its contribution to the lighting + void setAmbientIntensity(float intensity); + float getAmbientIntensity() const { return getSchema()._ambientIntensity; } + // Spherical Harmonics storing the Ambien lighting approximation used for the Sun typed light void setAmbientSphere(const SphericalHarmonics& sphere) { _ambientSphere = sphere; } const SphericalHarmonics& getAmbientSphere() const { return _ambientSphere; } @@ -254,7 +258,7 @@ public: public: Vec4 _position{0.0f, 0.0f, 0.0f, 1.0f}; Vec3 _direction{0.0f, 0.0f, -1.0f}; - float _spare0{0.0f}; + float _ambientIntensity{0.0f}; Color _color{1.0f}; float _intensity{1.0f}; Vec4 _attenuation{1.0f}; diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 41c6e075cf..1aaf0e8327 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -27,6 +27,7 @@ vec3 getLightDirection(Light l) { return l._direction.xyz; } // direction is -Z vec3 getLightColor(Light l) { return l._color.rgb; } float getLightIntensity(Light l) { return l._color.w; } +float getLightAmbientIntensity(Light l) { return l._direction.w; } float evalLightAttenuation(Light l, float r) { float d = max(r - l._attenuation.x, 0.0); diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index b72aa16497..68c13e5a7c 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -203,6 +203,7 @@ SunSkyStage::SunSkyStage() : _sunLight->setType(Light::SUN); setSunIntensity(1.0f); + setSunAmbientIntensity(0.5f); setSunColor(Vec3(1.0f, 1.0f, 1.0f)); // Default origin location is a special place in the world... @@ -249,12 +250,26 @@ void SunSkyStage::setOriginLocation(float longitude, float latitude, float altit invalidate(); } +void SunSkyStage::setEarthSunModelEnable(bool isEnabled) { + _earthSunModelEnable = isEnabled; + invalidate(); +} + void SunSkyStage::setSunColor(const Vec3& color) { _sunLight->setColor(color); } void SunSkyStage::setSunIntensity(float intensity) { _sunLight->setIntensity(intensity); } +void SunSkyStage::setSunAmbientIntensity(float intensity) { + _sunLight->setAmbientIntensity(intensity); +} + +void SunSkyStage::setSunDirection(const Vec3& direction) { + if (!isEarthSunModelEnabled()) { + _sunLight->setDirection(direction); + } +} // THe sun declinaison calculus is taken from https://en.wikipedia.org/wiki/Position_of_the_Sun double evalSunDeclinaison(double dayNumber) { @@ -271,19 +286,19 @@ void SunSkyStage::updateGraphicsObject() const { // And update the sunLAtitude as the declinaison depending of the time of the year _earthSunModel.setSunLatitude(evalSunDeclinaison(_yearTime)); - Vec3d sunLightDir = -_earthSunModel.getSurfaceSunDir(); - _sunLight->setDirection(Vec3(sunLightDir.x, sunLightDir.y, sunLightDir.z)); + if (isEarthSunModelEnabled()) { + Vec3d sunLightDir = -_earthSunModel.getSurfaceSunDir(); + _sunLight->setDirection(Vec3(sunLightDir.x, sunLightDir.y, sunLightDir.z)); - double originAlt = _earthSunModel.getAltitude(); - _sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f)); + double originAlt = _earthSunModel.getAltitude(); + _sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f)); + } static int firstTime = 0; if (firstTime == 0) { firstTime++; gpu::Shader::makeProgram(*(_skyPipeline->getProgram())); - } - } void SunSkyStage::setSkybox(const SkyboxPointer& skybox) { diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 30c96259ca..968d50587a 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -177,38 +177,49 @@ typedef QSharedPointer< Skybox > SkyboxPointer; // Sun sky stage generates the rendering primitives to display a scene realistically // at the specified location and time around earth -class SunSkyStage { +class SunSkyStage : public QObject { + Q_OBJECT public: SunSkyStage(); ~SunSkyStage(); // time of the day (local to the position) expressed in decimal hour in the range [0.0, 24.0] - void setDayTime(float hour); - float getDayTime() const { return _dayTime; } + Q_INVOKABLE void setDayTime(float hour); + Q_INVOKABLE float getDayTime() const { return _dayTime; } // time of the year expressed in day in the range [0, 365] - void setYearTime(unsigned int day); - unsigned int getYearTime() const { return _yearTime; } + Q_INVOKABLE void setYearTime(unsigned int day); + Q_INVOKABLE unsigned int getYearTime() const { return _yearTime; } // Origin orientation used to modify the cardinal axis alignement used. // THe default is north along +Z axis and west along +X axis. this orientation gets added // to the transform stack producing the sun light direction. - void setOriginOrientation(const Quat& orientation); - const Quat& getOriginOrientation() const { return _earthSunModel.getSurfaceOrientation(); } + Q_INVOKABLE void setOriginOrientation(const Quat& orientation); + Q_INVOKABLE const Quat& getOriginOrientation() const { return _earthSunModel.getSurfaceOrientation(); } // Location used to define the sun & sky is a longitude and latitude [rad] and a earth surface altitude [km] - void setOriginLocation(float longitude, float latitude, float surfaceAltitude); - float getOriginLatitude() const { return _earthSunModel.getLatitude(); } - float getOriginLongitude() const { return _earthSunModel.getLongitude(); } - float getOriginSurfaceAltitude() const { return _earthSunModel.getAltitude(); } + Q_INVOKABLE void setOriginLocation(float longitude, float latitude, float surfaceAltitude); + Q_INVOKABLE float getOriginLatitude() const { return _earthSunModel.getLatitude(); } + Q_INVOKABLE float getOriginLongitude() const { return _earthSunModel.getLongitude(); } + Q_INVOKABLE float getOriginSurfaceAltitude() const { return _earthSunModel.getAltitude(); } + + // Enable / disable the effect of the time and location on the sun direction and color + Q_INVOKABLE void setEarthSunModelEnable(bool isEnabled); + Q_INVOKABLE bool isEarthSunModelEnabled() const { return _earthSunModelEnable; } // Sun properties - void setSunColor(const Vec3& color); - const Vec3& getSunColor() const { return getSunLight()->getColor(); } - void setSunIntensity(float intensity); - float getSunIntensity() const { return getSunLight()->getIntensity(); } + Q_INVOKABLE void setSunColor(const Vec3& color); + Q_INVOKABLE const Vec3& getSunColor() const { return getSunLight()->getColor(); } + Q_INVOKABLE void setSunIntensity(float intensity); + Q_INVOKABLE float getSunIntensity() const { return getSunLight()->getIntensity(); } + Q_INVOKABLE void setSunAmbientIntensity(float intensity); + Q_INVOKABLE float getSunAmbientIntensity() const { return getSunLight()->getAmbientIntensity(); } + // The sun direction is expressed in the world space + Q_INVOKABLE void setSunDirection(const Vec3& direction); + Q_INVOKABLE const Vec3& getSunDirection() const { return getSunLight()->getDirection(); } + LightPointer getSunLight() const { valid(); return _sunLight; } AtmospherePointer getAtmosphere() const { valid(); return _atmosphere; } @@ -223,10 +234,10 @@ protected: gpu::PipelinePointer _skyPipeline; - float _dayTime; - int _yearTime; - + float _dayTime = 12.0f; + int _yearTime = 0; mutable EarthSunModel _earthSunModel; + bool _earthSunModelEnable = true; mutable bool _invalid = true; void invalidate() const { _invalid = true; } diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index ecb1f503c7..cbf7c31d1f 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -66,7 +66,7 @@ vec3 evalAmbienGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - vec3 color = diffuse.rgb * getLightColor(light) * 0.5; + vec3 color = diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); @@ -83,7 +83,7 @@ vec3 evalAmbienSphereGlobalColor(float shadowAttenuation, vec3 position, vec3 no vec3 fragEyeDir = normalize(fragEyeVector.xyz); vec3 ambientNormal = fragNormal.xyz; - vec3 color = diffuse.rgb * 0.5 * evalSphericalLight(ambientSphere, ambientNormal).xyz; + vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, ambientNormal).xyz * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); @@ -112,7 +112,7 @@ vec3 evalLightmappedColor(float shadowAttenuation, vec3 normal, vec3 diffuse, ve vec3 diffuseLight = lightAttenuation * lightmap; // ambient is a tiny percentage of the lightmap and only when in the shadow - vec3 ambientLight = (1 - lightAttenuation) * 0.5 * lightmap; + vec3 ambientLight = (1 - lightAttenuation) * lightmap * getLightAmbientIntensity(light); return diffuse * (ambientLight + diffuseLight); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 440f75e32e..bddb1815bf 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -554,11 +554,12 @@ void DeferredLightingEffect::setAmbientLightMode(int preset) { } } -void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity) { +void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity) { auto light = _allocatedLights.front(); light->setDirection(direction); light->setColor(diffuse); light->setIntensity(intensity); + light->setAmbientIntensity(ambientIntensity); } void DeferredLightingEffect::setGlobalSkybox(const model::SkyboxPointer& skybox) { diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 6d0d131029..0d3d370fd4 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -73,7 +73,7 @@ public: // update global lighting void setAmbientLightMode(int preset); - void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity); + void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity); void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; } void setGlobalSkybox(const model::SkyboxPointer& skybox); diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 5a8f591410..0f3818317e 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -62,6 +62,30 @@ float SceneScriptingInterface::getSunIntensity() const { return _skyStage->getSunIntensity(); } +void SceneScriptingInterface::setSunAmbientIntensity(float intensity) { + _skyStage->setSunAmbientIntensity(intensity); +} + +float SceneScriptingInterface::getSunAmbientIntensity() const { + return _skyStage->getSunAmbientIntensity(); +} + +void SceneScriptingInterface::setSunDirection(const glm::vec3& direction) { + _skyStage->setSunDirection(direction); +} + +const glm::vec3& SceneScriptingInterface::getSunDirection() const { + return _skyStage->getSunDirection(); +} + +void SceneScriptingInterface::setStageEarthSunModelEnable(bool isEnabled) { + _skyStage->setEarthSunModelEnable(isEnabled); +} + +bool SceneScriptingInterface::isStageEarthSunModelEnabled() const { + return _skyStage->isEarthSunModelEnabled(); +} + model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { return _skyStage; } diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 352bc1e78f..83f5a44bb7 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -38,10 +38,24 @@ public: Q_INVOKABLE void setStageYearTime(int day); Q_INVOKABLE int getStageYearTime() const; + Q_INVOKABLE void setStageEarthSunModelEnable(bool isEnabled); + Q_INVOKABLE bool isStageEarthSunModelEnabled() const; + + Q_INVOKABLE void setSunColor(const glm::vec3& color); Q_INVOKABLE const glm::vec3& getSunColor() const; Q_INVOKABLE void setSunIntensity(float intensity); Q_INVOKABLE float getSunIntensity() const; + Q_INVOKABLE void setSunAmbientIntensity(float intensity); + Q_INVOKABLE float getSunAmbientIntensity() const; + + // Only valid if stage Earth Sun model is disabled + Q_INVOKABLE void setSunDirection(const glm::vec3& direction); + + Q_INVOKABLE const glm::vec3& getSunDirection() const; + + + model::SunSkyStagePointer getSkyStage() const; From 1c5c7cc23997fa0bd4e5536fd636e71bedcf8c49 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 16 Apr 2015 17:55:55 -0700 Subject: [PATCH 125/401] faking a checkbox to do a boolean property control --- examples/example/misc/sunLightExample.js | 8 +- examples/utilities/tools/cookies.js | 122 +++++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index 55c312881f..2fe546cd0e 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -72,13 +72,19 @@ function runStageTime() { } Script.setInterval(runStageTime, tickTackPeriod); +panel.newCheckbox("Enable Earth Sun Model", + function(value) { Scene.setStageEarthSunModelEnable((value != 0)); }, + function() { return Scene.isStageEarthSunModelEnabled(); }, + function(value) { return (value); } +); + panel.newSlider("Light Intensity", 0.0, 5, function(value) { Scene.setSunIntensity(value); }, function() { return Scene.getSunIntensity(); }, function(value) { return (value).toFixed(2); } ); -panel.newSlider("Light Ambient Intensity", 0.0, 1.0, +panel.newSlider("Ambient Light Intensity", 0.0, 1.0, function(value) { Scene.setSunAmbientIntensity(value); }, function() { return Scene.getSunAmbientIntensity(); }, function(value) { return (value).toFixed(2); } diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 205b19c9f9..49446be234 100755 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -118,6 +118,113 @@ Slider = function(x,y,width,thumbSize) { }; } +// The Checkbox class +Checkbox = function(x,y,width,thumbSize) { + + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + this.background = Overlays.addOverlay("text", { + backgroundColor: { red: 125, green: 125, blue: 255 }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); + + this.thumbSize = thumbSize; + this.thumbHalfSize = 0.5 * thumbSize; + + this.minThumbX = x + this.thumbHalfSize; + this.maxThumbX = x + width - this.thumbHalfSize; + this.thumbX = this.minThumbX; + + this.minValue = 0.0; + this.maxValue = 1.0; + + this.clickOffsetX = 0; + this.isMoving = false; + + this.updateThumb = function() { + thumbTruePos = this.thumbX - 0.5 * this.thumbSize; + Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); + }; + + this.onMouseMoveEvent = function(event) { + if (this.isMoving) { + newThumbX = event.x - this.clickOffsetX; + if (newThumbX < this.minThumbX) { + newThumbX = this.minThumbX; + } + if (newThumbX > this.maxThumbX) { + newThumbX = this.maxThumbX; + } + this.thumbX = newThumbX; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + + this.onMousePressEvent = function(event) { + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + + }; + + this.onMouseReleaseEvent = function(event) { + this.isMoving = false; + }; + + // Public members: + + this.setNormalizedValue = function(value) { + if (value < 0.0) { + this.thumbX = this.minThumbX; + } else if (value > 1.0) { + this.thumbX = this.maxThumbX; + } else { + this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; + } + this.updateThumb(); + }; + this.getNormalizedValue = function() { + return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); + }; + + this.setValue = function(value) { + var normValue = (value - this.minValue) / (this.maxValue - this.minValue); + this.setNormalizedValue(normValue); + }; + + this.getValue = function() { + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; + + this.onValueChanged = function(value) {}; + + this.destroy = function() { + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + }; +} var textFontSize = 16; @@ -252,6 +359,21 @@ Panel = function(x, y) { // print("created Item... slider=" + name); }; + this.newCheckbox = function(name, setValue, getValue, displayValue) { + + var checkboxItem = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight); + checkbox.onValueChanged = function(value) { checkboxItem.setterFromWidget(value); }; + + + checkboxItem.widget = checkbox; + checkboxItem.setter(getValue()); + this.items[name] = checkboxItem; + this.nextY += rawYDelta; + // print("created Item... slider=" + name); + }; + this.destroy = function() { for (var i in this.items) { this.items[i].destroy(); From 759acfa17539865d6b34ebc517951637af39c7d7 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 16 Apr 2015 19:07:21 -0700 Subject: [PATCH 126/401] Working on getting the offscreen UI working on retina --- interface/src/Application.cpp | 12 +++++++++++- libraries/render-utils/src/OffscreenUi.cpp | 18 ++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 930e244136..d0ae13ce21 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -764,6 +764,16 @@ void Application::initializeUi() { return QPointF(p); }); offscreenUi->resume(); + connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect & r){ + static qreal oldDevicePixelRatio = 0; + qreal devicePixelRatio = _glWidget->devicePixelRatio(); + if (devicePixelRatio != oldDevicePixelRatio) { + oldDevicePixelRatio = devicePixelRatio; + qDebug() << "Device pixel ratio changed, triggering GL resize"; + resizeGL(_glWidget->width(), + _glWidget->height()); + } + }); } void Application::paintGL() { @@ -906,7 +916,7 @@ void Application::resizeGL(int width, int height) { glLoadIdentity(); auto offscreenUi = DependencyManager::get(); - offscreenUi->resize(QSize(width, height)); + offscreenUi->resize(_glWidget->size()); // update Stats width // let's set horizontal offset to give stats some margin to mirror diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index d0e54b08a9..d2d314bf96 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -79,7 +79,8 @@ void OffscreenUi::resize(const QSize & newSize) { makeCurrent(); // Clear out any fbos with the old size - _fboCache.setSize(newSize); + qreal pixelRatio = _renderControl->_renderWindow ? _renderControl->_renderWindow->devicePixelRatio() : 1.0; + _fboCache.setSize(newSize * pixelRatio); // Update our members if (_rootItem) { @@ -203,7 +204,7 @@ QPointF OffscreenUi::mapWindowToUi(const QPointF & p, QObject * dest) { } vec2 pos = toGlm(p); pos /= sourceSize; - pos *= vec2(toGlm(_quickWindow->renderTargetSize())); + pos *= vec2(toGlm(_quickWindow->size())); return QPointF(pos.x, pos.y); } @@ -300,11 +301,13 @@ void OffscreenUi::setProxyWindow(QWindow * window) { void OffscreenUi::show(const QUrl & url, const QString & name) { QQuickItem * item = _rootItem->findChild(name); + if (nullptr == item) { + load(url); + item = _rootItem->findChild(name); + } + if (nullptr != item) { item->setEnabled(true); - item->setVisible(true); - } else { - load(url); } } @@ -312,7 +315,7 @@ void OffscreenUi::toggle(const QUrl & url, const QString & name) { QQuickItem * item = _rootItem->findChild(name); // First load? if (nullptr == item) { - load(url); + show(url, name); return; } @@ -320,12 +323,11 @@ void OffscreenUi::toggle(const QUrl & url, const QString & name) { // dialogs can still swallow keyboard input) bool newFlag = !item->isEnabled(); item->setEnabled(newFlag); - // item->setVisible(newFlag); - } void OffscreenUi::load(const QUrl & url) { + qDebug() << "Loading from url: " << url; QVariant returnedValue; QVariant msg = url; QMetaObject::invokeMethod(_rootItem, "loadChild", From fd0c130dc2ea6d302d8eeea7c93f1ab9a6286f77 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 16 Apr 2015 22:20:49 -0700 Subject: [PATCH 127/401] Working on simplifying new dialog creation --- interface/resources/qml/AddressBarDialog.qml | 85 +++--- interface/resources/qml/CustomDialog.qml | 35 ++- interface/resources/qml/LoginDialog.qml | 286 +++++++++--------- interface/src/ui/AddressBarDialog.cpp | 6 +- interface/src/ui/AddressBarDialog.h | 8 +- interface/src/ui/LoginDialog.cpp | 5 +- interface/src/ui/LoginDialog.h | 8 +- .../render-utils/src/OffscreenQmlDialog.cpp | 18 ++ .../render-utils/src/OffscreenQmlDialog.h | 56 ++++ libraries/render-utils/src/OffscreenUi.h | 30 +- 10 files changed, 290 insertions(+), 247 deletions(-) create mode 100644 libraries/render-utils/src/OffscreenQmlDialog.cpp create mode 100644 libraries/render-utils/src/OffscreenQmlDialog.h diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index df06fabbe6..9508481309 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -4,8 +4,9 @@ import QtQuick.Controls 1.2 import QtQuick.Window 2.2 import QtQuick.Controls.Styles 1.3 -AddressBarDialog { - id: addressBarDialog +CustomDialog { + id: dialog + title: "Go to..." objectName: "AddressBarDialog" SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } height: 128 @@ -14,70 +15,56 @@ AddressBarDialog { onVisibleChanged: { if (!visible) { reset(); - } else { - addressLine.focus = true - addressLine.forceActiveFocus() } } - Component.onCompleted: { - addressLine.focus = true - addressLine.forceActiveFocus() - } - function reset() { addressLine.text = "" goButton.source = "../images/address-bar-submit.svg" } - CustomDialog { - id: dialog - anchors.fill: parent - title: "Go to..." + AddressBarDialog { + id: addressBarDialog // The client area - Item { - id: item1 - anchors.fill: parent - anchors.margins: parent.margins - anchors.topMargin: parent.topMargin + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin - CustomBorder { - height: 64 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.right: goButton.left - anchors.rightMargin: 8 - anchors.verticalCenter: parent.verticalCenter - CustomTextInput { - id: addressLine - anchors.fill: parent - helperText: "domain, location, @user, /x,y,z" - anchors.margins: 8 - onAccepted: { - addressBarDialog.loadAddress(addressLine.text) - } + CustomBorder { + height: 64 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: goButton.left + anchors.rightMargin: 8 + anchors.verticalCenter: parent.verticalCenter + CustomTextInput { + id: addressLine + anchors.fill: parent + helperText: "domain, location, @user, /x,y,z" + anchors.margins: 8 + onAccepted: { + addressBarDialog.loadAddress(addressLine.text) } } + } - Image { - id: goButton - width: 32 - height: 32 - anchors.right: parent.right - anchors.rightMargin: 8 - source: "../images/address-bar-submit.svg" - anchors.verticalCenter: parent.verticalCenter + Image { + id: goButton + width: 32 + height: 32 + anchors.right: parent.right + anchors.rightMargin: 8 + source: "../images/address-bar-submit.svg" + anchors.verticalCenter: parent.verticalCenter - MouseArea { - anchors.fill: parent - onClicked: { - parent.source = "../images/address-bar-submit-active.svg" - addressBarDialog.loadAddress(addressLine.text) - } + MouseArea { + anchors.fill: parent + onClicked: { + parent.source = "../images/address-bar-submit-active.svg" + addressBarDialog.loadAddress(addressLine.text) } } - } } } diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/CustomDialog.qml index 828cd80231..a681612f2c 100644 --- a/interface/resources/qml/CustomDialog.qml +++ b/interface/resources/qml/CustomDialog.qml @@ -7,10 +7,34 @@ import "hifiConstants.js" as HifiConstants Item { SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - id: dialog width: 256 height: 256 + scale: 0.0 + enabled: false + visible: false + + onEnabledChanged: { + scale = enabled ? 1.0 : 0.0 + } + + onScaleChanged: { + visible = (scale != 0.0); + } + + Component.onCompleted: { + scale = 1.0 + } + + Behavior on scale { + NumberAnimation { + //This specifies how long the animation takes + duration: 400 + //This selects an easing curve to interpolate with, the default is Easing.Linear + easing.type: Easing.InOutBounce + } + } + property int topMargin: dialog.height - clientBorder.height + 8 property int margins: 8 property string title @@ -54,11 +78,11 @@ Item { anchors.top: parent.top anchors.rightMargin: 4 drag { - target: dialog.parent + target: dialog minimumX: 0 minimumY: 0 - maximumX: dialog.parent.parent.width - dialog.parent.width - maximumY: dialog.parent.parent.height - dialog.parent.height + maximumX: dialog.parent.width - dialog.width + maximumY: dialog.parent.height - dialog.height } } Image { @@ -73,11 +97,10 @@ Item { MouseArea { anchors.fill: parent onClicked: { - dialog.parent.destroy() + dialog.destroy() } } } - } // header border CustomBorder { diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index c306f4ed7e..e96309f625 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -5,9 +5,9 @@ import QtQuick.Window 2.2 import QtQuick.Controls.Styles 1.3 import "hifiConstants.js" as HifiConstants -LoginDialog { +CustomDialog { + title: "Login" SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - id: loginDialog objectName: "LoginDialog" height: 512 width: 384 @@ -15,8 +15,6 @@ LoginDialog { onVisibleChanged: { if (!visible) { reset() - } else { - username.forceActiveFocus() } } @@ -26,163 +24,159 @@ LoginDialog { loginDialog.statusText = "" } - CustomDialog { + LoginDialog { + id: loginDialog anchors.fill: parent - title: "Login" - Item { - id: item1 - anchors.fill: parent - anchors.margins: parent.margins - anchors.topMargin: parent.topMargin - Column { - anchors.topMargin: 8 - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.top: parent.top - spacing: 8 + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + Column { + anchors.topMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.top: parent.top + spacing: 8 - Image { - height: 64 - anchors.horizontalCenter: parent.horizontalCenter - width: 64 - source: "../images/hifi-logo.svg" - } + Image { + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + width: 64 + source: "../images/hifi-logo.svg" + } - CustomBorder { - width: 304 - height: 64 - anchors.horizontalCenter: parent.horizontalCenter - CustomTextInput { - id: username - anchors.fill: parent - helperText: "Username or Email" - anchors.margins: 8 - KeyNavigation.tab: password - KeyNavigation.backtab: password - onAccepted: { - password.forceActiveFocus() - } + CustomBorder { + width: 304 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + CustomTextInput { + id: username + anchors.fill: parent + helperText: "Username or Email" + anchors.margins: 8 + KeyNavigation.tab: password + KeyNavigation.backtab: password + onAccepted: { + password.forceActiveFocus() } } - - CustomBorder { - width: 304 - height: 64 - anchors.horizontalCenter: parent.horizontalCenter - CustomTextInput { - id: password - anchors.fill: parent - echoMode: TextInput.Password - helperText: "Password" - anchors.margins: 8 - KeyNavigation.tab: username - KeyNavigation.backtab: username - onAccepted: { - if (username.text == "") { - username.forceActiveFocus() - } else { - loginDialog.login(username.text, password.text) - } - } - onFocusChanged: { - if (password.focus) { - password.selectAll() - } - } - } - } - - CustomText { - anchors.horizontalCenter: parent.horizontalCenter - textFormat: Text.StyledText - width: parent.width - height: 96 - wrapMode: Text.WordWrap - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - text: loginDialog.statusText - } } - Column { - anchors.bottomMargin: 5 - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.bottom: parent.bottom - - Rectangle { - width: 192 - height: 64 - anchors.horizontalCenter: parent.horizontalCenter - color: HifiConstants.color - border.width: 0 - radius: 10 - - MouseArea { - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: parent.top - anchors.right: parent.right - anchors.left: parent.left - onClicked: { + CustomBorder { + width: 304 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + CustomTextInput { + id: password + anchors.fill: parent + echoMode: TextInput.Password + helperText: "Password" + anchors.margins: 8 + KeyNavigation.tab: username + KeyNavigation.backtab: username + onAccepted: { + if (username.text == "") { + username.forceActiveFocus() + } else { loginDialog.login(username.text, password.text) } } - - Row { - anchors.centerIn: parent - anchors.verticalCenter: parent.verticalCenter - spacing: 8 - Image { - id: loginIcon - height: 32 - width: 32 - source: "../images/login.svg" - } - CustomText { - text: "Login" - color: "white" - width: 64 - height: parent.height - } - } - - } - - CustomText { - width: parent.width - height: 24 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - text:"Create Account" - font.pointSize: 12 - font.bold: true - color: HifiConstants.color - - MouseArea { - anchors.fill: parent - onClicked: { - loginDialog.openUrl(loginDialog.rootUrl + "/signup") + onFocusChanged: { + if (password.focus) { + password.selectAll() } } } + } - CustomText { - width: parent.width - height: 24 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.pointSize: 12 - text: "Recover Password" - color: HifiConstants.color + CustomText { + anchors.horizontalCenter: parent.horizontalCenter + textFormat: Text.StyledText + width: parent.width + height: 96 + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: loginDialog.statusText + } + } - MouseArea { - anchors.fill: parent - onClicked: { - loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new") - } + Column { + anchors.bottomMargin: 5 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.bottom: parent.bottom + + Rectangle { + width: 192 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + color: HifiConstants.color + border.width: 0 + radius: 10 + + MouseArea { + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + onClicked: { + loginDialog.login(username.text, password.text) + } + } + + Row { + anchors.centerIn: parent + anchors.verticalCenter: parent.verticalCenter + spacing: 8 + Image { + id: loginIcon + height: 32 + width: 32 + source: "../images/login.svg" + } + CustomText { + text: "Login" + color: "white" + width: 64 + height: parent.height + } + } + + } + + CustomText { + width: parent.width + height: 24 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text:"Create Account" + font.pointSize: 12 + font.bold: true + color: HifiConstants.color + + MouseArea { + anchors.fill: parent + onClicked: { + loginDialog.openUrl(loginDialog.rootUrl + "/signup") + } + } + } + + CustomText { + width: parent.width + height: 24 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.pointSize: 12 + text: "Recover Password" + color: HifiConstants.color + + MouseArea { + anchors.fill: parent + onClicked: { + loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new") } } } diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 49158265ba..befeb40cce 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -17,17 +17,15 @@ QML_DIALOG_DEF(AddressBarDialog) -AddressBarDialog::AddressBarDialog(QQuickItem *parent) : QQuickItem(parent) { +AddressBarDialog::AddressBarDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { auto addressManager = DependencyManager::get(); connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage); connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage); connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide); } - void AddressBarDialog::hide() { - setEnabled(false); - setVisible(false); + ((QQuickItem *)parent())->setEnabled(false); } void AddressBarDialog::loadAddress(const QString & address) { diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index 00e55ceb10..b4f4c44e0f 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -8,15 +8,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#pragma once #ifndef hifi_AddressBarDialog_h #define hifi_AddressBarDialog_h -#pragma once -#include +#include -#include "OffscreenUi.h" - -class AddressBarDialog : public QQuickItem +class AddressBarDialog : public OffscreenQmlDialog { Q_OBJECT QML_DIALOG_DECL diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 3b164041fa..3637d824fb 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -17,7 +17,7 @@ QML_DIALOG_DEF(LoginDialog) -LoginDialog::LoginDialog(QQuickItem *parent) : QQuickItem(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) { +LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) { connect(&AccountManager::getInstance(), &AccountManager::loginComplete, this, &LoginDialog::handleLoginCompleted); connect(&AccountManager::getInstance(), &AccountManager::loginFailed, @@ -42,8 +42,7 @@ void LoginDialog::toggleAction() { } void LoginDialog::handleLoginCompleted(const QUrl& authURL) { - setEnabled(false); - setVisible(false); + hide(); } void LoginDialog::handleLoginFailed() { diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index 3c9a98a9a4..d3f54981a5 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -8,15 +8,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#pragma once #ifndef hifi_LoginDialog_h #define hifi_LoginDialog_h -#pragma once -#include +#include -#include "OffscreenUi.h" - -class LoginDialog : public QQuickItem +class LoginDialog : public OffscreenQmlDialog { Q_OBJECT QML_DIALOG_DECL diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/render-utils/src/OffscreenQmlDialog.cpp new file mode 100644 index 0000000000..d6cfc9951b --- /dev/null +++ b/libraries/render-utils/src/OffscreenQmlDialog.cpp @@ -0,0 +1,18 @@ +// +// OffscreenQmlDialog.cpp +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 "OffscreenQmlDialog.h" + +OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem *parent) + : QQuickItem(parent) { } + +void OffscreenQmlDialog::hide() { + ((QQuickItem *)parent())->setEnabled(false); +} diff --git a/libraries/render-utils/src/OffscreenQmlDialog.h b/libraries/render-utils/src/OffscreenQmlDialog.h new file mode 100644 index 0000000000..6e94587fd2 --- /dev/null +++ b/libraries/render-utils/src/OffscreenQmlDialog.h @@ -0,0 +1,56 @@ +// +// OffscreenQmlDialog.h +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 +// + +#pragma once +#ifndef hifi_OffscreenQmlDialog_h +#define hifi_OffscreenQmlDialog_h + +#include +#include "OffscreenUi.h" + +#define QML_DIALOG_DECL \ +private: \ + static const QString NAME; \ + static const QUrl QML; \ +public: \ + static void registerType(); \ + static void show(); \ + static void toggle(); \ +private: + +#define QML_DIALOG_DEF(x) \ + const QUrl x::QML = QUrl(#x ".qml"); \ + const QString x::NAME = #x; \ + \ + void x::registerType() { \ + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ + } \ + \ + void x::show() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->show(QML, NAME); \ + } \ + \ + void x::toggle() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->toggle(QML, NAME); \ + } + +class OffscreenQmlDialog : public QQuickItem +{ + Q_OBJECT +public: + OffscreenQmlDialog(QQuickItem *parent = 0); + +protected: + void hide(); +}; + +#endif diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index 60302d9860..b9cf5d2226 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -33,34 +33,6 @@ #include "FboCache.h" #include "OffscreenGlCanvas.h" -#define QML_DIALOG_DECL \ -private: \ - static const QString NAME; \ - static const QUrl QML; \ -public: \ - static void registerType(); \ - static void show(); \ - static void toggle(); \ -private: - -#define QML_DIALOG_DEF(x) \ - const QUrl x::QML = QUrl(#x ".qml"); \ - const QString x::NAME = #x; \ - \ - void x::registerType() { \ - qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ - } \ - \ - void x::show() { \ - auto offscreenUi = DependencyManager::get(); \ - offscreenUi->show(QML, NAME); \ - } \ - \ - void x::toggle() { \ - auto offscreenUi = DependencyManager::get(); \ - offscreenUi->toggle(QML, NAME); \ - } - class OffscreenUi : public OffscreenGlCanvas, public Dependency { Q_OBJECT @@ -133,4 +105,4 @@ private: MouseTranslator _mouseTranslator{ [](const QPointF & p) { return p; } }; }; -#endif \ No newline at end of file +#endif From 2b4d894ab3b706d6ec7e07eebfede0c1038f3d88 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Fri, 17 Apr 2015 08:17:58 -0700 Subject: [PATCH 128/401] moved the type computation inside the while loop so it is correctly computed each iteration --- libraries/physics/src/PhysicsEngine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 68a71c59c3..e43fffb20a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -400,8 +400,7 @@ void PhysicsEngine::computeCollisionEvents() { // scan known contacts and trigger events ContactMap::iterator contactItr = _contactMap.begin(); - // TODO: enable scripts to filter based on contact event type - ContactEventType type = contactItr->second.computeType(_numContactFrames); + while (contactItr != _contactMap.end()) { ObjectMotionState* A = static_cast(contactItr->first._a); ObjectMotionState* B = static_cast(contactItr->first._b); @@ -409,6 +408,8 @@ void PhysicsEngine::computeCollisionEvents() { // TODO: make triggering these events clean and efficient. The code at this context shouldn't // have to figure out what kind of object (entity, avatar, etc) these are in order to properly // emit a collision event. + // TODO: enable scripts to filter based on contact event type + ContactEventType type = contactItr->second.computeType(_numContactFrames); if(type != CONTACT_EVENT_TYPE_CONTINUE || _numSubsteps % CONTINUE_EVENT_FILTER_FREQUENCY == 0){ if (A && A->getType() == MOTION_STATE_TYPE_ENTITY) { EntityItemID idA = static_cast(A)->getEntity()->getEntityItemID(); From f77038c52d6a75e7bccbe4f1b1aab520c21026c2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 09:37:48 -0700 Subject: [PATCH 129/401] when ignoring an incoming packet, still read it so the data-stream pointer doesn't get screwed up --- libraries/entities/src/EntityItem.cpp | 5 ++--- libraries/entities/src/EntityItem.h | 3 ++- libraries/entities/src/EntityTreeElement.cpp | 11 +++++------ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5a37baf4a0..3f342c4d86 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -312,7 +312,8 @@ int EntityItem::expectedBytes() { } -int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { +int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, + bool ignoreServerPacket) { if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { @@ -421,8 +422,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef qCDebug(entities) << " fromSameServerEdit:" << fromSameServerEdit; #endif - bool ignoreServerPacket = false; // assume we'll use this server packet - // If this packet is from the same server edit as the last packet we accepted from the server // we probably want to use it. if (fromSameServerEdit) { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 634b7e7d3d..b9def4f1db 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -113,7 +113,8 @@ public: static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); - virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); + virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, + bool ignoreServerPacket = false); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index ad268edc6f..a94891ea7e 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -696,7 +696,6 @@ bool EntityTreeElement::removeEntityItem(EntityItem* entity) { // and dirty path marking in one pass. int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { - // If we're the root, but this bitstream doesn't support root elements with data, then // return without reading any bytes if (this == _myTree->getRoot() && args.bitstreamVersion < VERSION_ROOT_ELEMENT_HAS_DATA) { @@ -735,20 +734,20 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int } // If the item already exists in our tree, we want do the following... - // 0) if this node is the simulator for the entity, ignore the update packet // 1) allow the existing item to read from the databuffer // 2) check to see if after reading the item, the containing element is still correct, fix it if needed // // TODO: Do we need to also do this? // 3) remember the old cube for the entity so we can mark it as dirty - if (entityItem && entityItem->getSimulatorID() == myNodeID) { - // do nothing, this was echoed back to us by the entity server - } else if (entityItem) { + if (entityItem) { QString entityScriptBefore = entityItem->getScript(); bool bestFitBefore = bestFitEntityBounds(entityItem); EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); - bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); + // this Node was the original source of this packet, so read it, but ignore it. + bool shouldIgnore = (entityItem && entityItem->getSimulatorID() == myNodeID); + + bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args, shouldIgnore); if (entityItem->getDirtyFlags()) { _myTree->entityChanged(entityItem); } From 781abdd0473048c007be81e6cab4c2c92e7eafab Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 17 Apr 2015 09:53:40 -0700 Subject: [PATCH 130/401] Tweaking test dialog and adding browser test --- interface/resources/qml/Browser.qml | 45 ++++++++++++++++++++++++++ interface/resources/qml/TestDialog.qml | 40 ++++++++--------------- 2 files changed, 59 insertions(+), 26 deletions(-) create mode 100644 interface/resources/qml/Browser.qml diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml new file mode 100644 index 0000000000..d7e08fbd97 --- /dev/null +++ b/interface/resources/qml/Browser.qml @@ -0,0 +1,45 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 +import QtWebKit 3.0 + +CustomDialog { + title: "Test Dlg" + id: testDialog + objectName: "Browser" + width: 1280 + height: 720 + + Item { + id: clientArea + // The client area + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + + + ScrollView { + anchors.fill: parent + WebView { + id: webview + url: "http://slashdot.org" + anchors.fill: parent + } + } + + } + + +} + + +/* + +// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property + +MouseArea { + anchors.fill: parent +} +*/ diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml index 9c8bcccd75..8ce68413b6 100644 --- a/interface/resources/qml/TestDialog.qml +++ b/interface/resources/qml/TestDialog.qml @@ -4,34 +4,20 @@ import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 import QtQuick.Controls.Styles 1.3 -Item { - objectName: "TestDialog" +CustomDialog { + title: "Test Dlg" id: testDialog - width: 384 - height: 384 + objectName: "TestDialog" + width: 512 + height: 512 scale: 0.0 - onEnabledChanged: { - scale = enabled ? 1.0 : 0.0 - } - onScaleChanged: { - visible = (scale != 0.0); - } - Component.onCompleted: { - scale = 1.0 - } - Behavior on scale { - NumberAnimation { - //This specifies how long the animation takes - duration: 400 - //This selects an easing curve to interpolate with, the default is Easing.Linear - easing.type: Easing.InOutBounce - } - } - - CustomDialog { - title: "Test Dlg" + Item { + id: clientArea + // The client area anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin Rectangle { property int d: 100 @@ -55,16 +41,18 @@ Item { anchors.top: parent.top anchors.topMargin: parent.titleSize + 12 } - + CustomButton { x: 128 y: 192 + text: "Test" anchors.bottom: parent.bottom anchors.bottomMargin: 12 anchors.right: parent.right anchors.rightMargin: 12 onClicked: { console.log("Click"); + if (square.visible) { square.visible = false } else { @@ -76,7 +64,7 @@ Item { CustomButton { id: customButton2 y: 192 - text: "Close" + text: "Move" anchors.left: parent.left anchors.leftMargin: 12 anchors.bottom: parent.bottom From c69aaa806b0d5f33ba17f969bee8d9ffe671beb7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 09:55:49 -0700 Subject: [PATCH 131/401] if a uuid is null, don't send a uuid of all zeros --- .../entities/src/EntityItemPropertiesMacros.h | 60 +++++++++++-------- libraries/octree/src/OctreePacketData.cpp | 15 +++-- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 4a0b5c210d..be6a221af4 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -88,20 +88,24 @@ } \ } -// TODO: this doesn't need a length. See OctreePacketData::appendValue(const QUuid& uuid) -#define READ_ENTITY_PROPERTY_UUID(P,O) \ - if (propertyFlags.getHasProperty(P)) { \ - uint16_t length; \ - memcpy(&length, dataAt, sizeof(length)); \ - dataAt += sizeof(length); \ - bytesRead += sizeof(length); \ - QByteArray ba((const char*)dataAt, length); \ - QUuid value = QUuid::fromRfc4122(ba); \ - dataAt += length; \ - bytesRead += length; \ - if (overwriteLocalData) { \ - O(value); \ - } \ +#define READ_ENTITY_PROPERTY_UUID(P,O) \ + if (propertyFlags.getHasProperty(P)) { \ + uint16_t length; \ + memcpy(&length, dataAt, sizeof(length)); \ + dataAt += sizeof(length); \ + bytesRead += sizeof(length); \ + QUuid value; \ + if (length == 0) { \ + value = QUuid(); \ + } else { \ + QByteArray ba((const char*)dataAt, length); \ + value = QUuid::fromRfc4122(ba); \ + dataAt += length; \ + bytesRead += length; \ + } \ + if (overwriteLocalData) { \ + O(value); \ + } \ } #define READ_ENTITY_PROPERTY_COLOR(P,M) \ @@ -144,18 +148,22 @@ } -// TODO: this doesn't need a length. See OctreePacketData::appendValue(const QUuid& uuid) -#define READ_ENTITY_PROPERTY_UUID_TO_PROPERTIES(P,O) \ - if (propertyFlags.getHasProperty(P)) { \ - uint16_t length; \ - memcpy(&length, dataAt, sizeof(length)); \ - dataAt += sizeof(length); \ - processedBytes += sizeof(length); \ - QByteArray ba((const char*)dataAt, length); \ - QUuid value = QUuid::fromRfc4122(ba); \ - dataAt += length; \ - processedBytes += length; \ - properties.O(value); \ +#define READ_ENTITY_PROPERTY_UUID_TO_PROPERTIES(P,O) \ + if (propertyFlags.getHasProperty(P)) { \ + uint16_t length; \ + memcpy(&length, dataAt, sizeof(length)); \ + dataAt += sizeof(length); \ + processedBytes += sizeof(length); \ + QUuid value; \ + if (length == 0) { \ + value = QUuid(); \ + } else { \ + QByteArray ba((const char*)dataAt, length); \ + value = QUuid::fromRfc4122(ba); \ + dataAt += length; \ + processedBytes += length; \ + } \ + properties.O(value); \ } #define READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(P,O) \ diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 346d2f1a79..64947010a0 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -412,14 +412,17 @@ bool OctreePacketData::appendValue(const QString& string) { } bool OctreePacketData::appendValue(const QUuid& uuid) { - // TODO: this doesn't need a length QByteArray bytes = uuid.toRfc4122(); - uint16_t length = bytes.size(); - bool success = appendValue(length); - if (success) { - success = appendRawData((const unsigned char*)bytes.constData(), bytes.size()); + if (uuid.isNull()) { + return appendValue((uint16_t)0); // zero length for null uuid + } else { + uint16_t length = bytes.size(); + bool success = appendValue(length); + if (success) { + success = appendRawData((const unsigned char*)bytes.constData(), bytes.size()); + } + return success; } - return success; } bool OctreePacketData::appendValue(const QByteArray& bytes) { From ad585f75595f323507d1314d4ea13dccf4f47d24 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 17 Apr 2015 10:05:54 -0700 Subject: [PATCH 132/401] Fixing NaN reference in test dialog --- interface/resources/qml/TestDialog.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml index 8ce68413b6..69aad4cdc8 100644 --- a/interface/resources/qml/TestDialog.qml +++ b/interface/resources/qml/TestDialog.qml @@ -10,7 +10,6 @@ CustomDialog { objectName: "TestDialog" width: 512 height: 512 - scale: 0.0 Item { id: clientArea @@ -39,7 +38,7 @@ CustomDialog { clip: true text: "test edit" anchors.top: parent.top - anchors.topMargin: parent.titleSize + 12 + anchors.topMargin: 12 } CustomButton { @@ -86,7 +85,6 @@ CustomDialog { } } - } From 4b73481604890e76f0df7ee57618839b995ed8c8 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Fri, 17 Apr 2015 10:19:31 -0700 Subject: [PATCH 133/401] Respond to changes in the device pixel ratio in the test window --- libraries/render-utils/src/OffscreenUi.cpp | 1 + tests/render-utils/src/main.cpp | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index d2d314bf96..68bb3eeacd 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -80,6 +80,7 @@ void OffscreenUi::resize(const QSize & newSize) { // Clear out any fbos with the old size qreal pixelRatio = _renderControl->_renderWindow ? _renderControl->_renderWindow->devicePixelRatio() : 1.0; + qDebug() << "Offscreen UI resizing to " << newSize.width() << "x" << newSize.height() << " with pixel ratio " << pixelRatio; _fboCache.setSize(newSize * pixelRatio); // Update our members diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 62c1fcf1c5..556fef0561 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -203,7 +203,16 @@ protected: } QWindow::keyPressEvent(event); } - + + void moveEvent(QMoveEvent *event) { + static qreal oldPixelRatio = 0.0; + if (devicePixelRatio() != oldPixelRatio) { + oldPixelRatio = devicePixelRatio(); + resizeWindow(size()); + } + + QWindow::moveEvent(event); + } }; #ifndef SERIF_FONT_FAMILY @@ -291,7 +300,7 @@ void QTestWindow::renderQml() { void QTestWindow::draw() { makeCurrent(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, _size.width(), _size.height()); + glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); //renderText(); renderQml(); From deec577db6695c1a25ef707392af37ae0ea9baaa Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 10:21:52 -0700 Subject: [PATCH 134/401] if nodes are fighting over phyics variables, squash physics-related properties in the updates from the loser of the race --- .../entities/src/EntityItemPropertiesMacros.h | 5 +++++ libraries/entities/src/EntityTree.cpp | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index be6a221af4..9cb3449d59 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -338,6 +338,7 @@ T get##N() const { return _##n; } \ void set##N(T value) { _##n = value; _##n##Changed = true; } \ bool n##Changed() const { return _##n##Changed; } \ + void set##N##Changed(bool value) { _##n##Changed = value; } \ private: \ T _##n; \ bool _##n##Changed; @@ -347,6 +348,7 @@ const T& get##N() const { return _##n; } \ void set##N(const T& value) { _##n = value; _##n##Changed = true; } \ bool n##Changed() const { return _##n##Changed; } \ + void set##N##Changed(bool value) { _##n##Changed = value; } \ private: \ T _##n; \ bool _##n##Changed; @@ -356,6 +358,7 @@ const T& get##N() const { return _##n; } \ void set##N(const T& value); \ bool n##Changed() const; \ + void set##N##Changed(bool value) { _##n##Changed = value; } \ private: \ T _##n; \ bool _##n##Changed; @@ -365,6 +368,7 @@ T get##N() const; \ void set##N(const T& value); \ bool n##Changed() const; \ + void set##N##Changed(bool value) { _##n##Changed = value; } \ private: \ T _##n; \ bool _##n##Changed; @@ -376,6 +380,7 @@ bool n##Changed() const { return _##n##Changed; } \ QString get##N##AsString() const; \ void set##N##FromString(const QString& name); \ + void set##N##Changed(bool value) { _##n##Changed = value; } \ private: \ T _##n; \ bool _##n##Changed; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 07f61de8b4..02568ef782 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -24,6 +24,10 @@ #include "EntitiesLogging.h" #include "RecurseOctreeToMapOperator.h" + +const quint64 SIMULATOR_CHANGE_LOCKOUT_PERIOD = 0.2 * USECS_PER_SECOND; + + EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage), _fbxService(NULL), @@ -108,9 +112,9 @@ bool EntityTree::updateEntity(EntityItem* entity, const EntityItemProperties& pr return updateEntityWithElement(entity, properties, containingElement, allowLockChange); } -bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemProperties& properties, +bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemProperties& origProperties, EntityTreeElement* containingElement, bool allowLockChange) { - + EntityItemProperties properties = origProperties; if (!allowLockChange && (entity->getLocked() != properties.getLocked())) { qCDebug(entities) << "Refusing disallowed lock adjustment."; return false; @@ -136,8 +140,13 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro // A Node is trying to take ownership of the simulation of this entity from another Node. Only allow this // if ownership hasn't recently changed. quint64 now = usecTimestampNow(); - if (now - entity->getSimulatorIDChangedTime() < 2 * USECS_PER_SECOND) { // XXX pick time and put in constant - qDebug() << "TOO SOON"; + if (now - entity->getSimulatorIDChangedTime() < SIMULATOR_CHANGE_LOCKOUT_PERIOD) { + qDebug() << "SIMULATOR_CHANGE_LOCKOUT_PERIOD"; + // squash the physics-related changes. + properties.setSimulatorIDChanged(false); + properties.setPositionChanged(false); + properties.setVelocityChanged(false); + properties.setAccelerationChanged(false); } } From c823fcd08381ce2cc5d344de4001e8bbf248fe5f Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 17 Apr 2015 10:35:48 -0700 Subject: [PATCH 135/401] Code tidying --- interface/src/devices/DdeFaceTracker.cpp | 14 ++++++++++++-- interface/src/devices/DdeFaceTracker.h | 18 ++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 35bb7a2595..743b3be780 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -134,6 +134,8 @@ struct Packet { char name[MAX_NAME_SIZE + 1]; }; +const float STARTING_DDE_MESSAGE_TIME = 0.033f; + DdeFaceTracker::DdeFaceTracker() : DdeFaceTracker(QHostAddress::Any, DDE_SERVER_PORT, DDE_CONTROL_PORT) { @@ -158,7 +160,15 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui _browUpRightIndex(18), _mouthSmileLeftIndex(28), _mouthSmileRightIndex(29), - _jawOpenIndex(21) + _jawOpenIndex(21), + _lastMessageReceived(0), + _averageMessageTime(STARTING_DDE_MESSAGE_TIME), + _lastHeadTranslation(glm::vec3(0.0f)), + _filteredHeadTranslation(glm::vec3(0.0f)), + _lastLeftEyeBlink(0.0f), + _filteredLeftEyeBlink(0.0f), + _lastRightEyeBlink(0.0f), + _filteredRightEyeBlink(0.0f) { _coefficients.resize(NUM_FACESHIFT_BLENDSHAPES); @@ -392,7 +402,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { } _lastMessageReceived = usecsNow; -} else { + } else { qCDebug(interfaceapp) << "[Error] DDE Face Tracker Decode Error"; } _lastReceiveTimestamp = usecTimestampNow(); diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 50de9687d2..aa3e9f3b81 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -23,8 +23,6 @@ #include "FaceTracker.h" -const float STARTING_DDE_MESSAGE_TIME = 0.033f; - class DdeFaceTracker : public FaceTracker, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -103,14 +101,14 @@ private: QVector _coefficients; - quint64 _lastMessageReceived = 0; - float _averageMessageTime = STARTING_DDE_MESSAGE_TIME; - glm::vec3 _lastHeadTranslation = glm::vec3(0.0f); - glm::vec3 _filteredHeadTranslation = glm::vec3(0.0f); - float _lastLeftEyeBlink = 0.0f; - float _filteredLeftEyeBlink = 0.0f; - float _lastRightEyeBlink = 0.0f; - float _filteredRightEyeBlink = 0.0f; + quint64 _lastMessageReceived; + float _averageMessageTime; + glm::vec3 _lastHeadTranslation; + glm::vec3 _filteredHeadTranslation; + float _lastLeftEyeBlink; + float _filteredLeftEyeBlink; + float _lastRightEyeBlink; + float _filteredRightEyeBlink; }; #endif // hifi_DdeFaceTracker_h \ No newline at end of file From 3da2d1680dc1441cac73d7c6e7f0947e1171ca5e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 10:41:11 -0700 Subject: [PATCH 136/401] fix code that causes scripted changes to physics-related entity properties to claim simulation ownership --- libraries/entities/src/EntityScriptingInterface.cpp | 12 ++++-------- libraries/entities/src/EntityTree.cpp | 6 +++--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 57752dff02..392cd92ab6 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -170,18 +170,14 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E // if at this point, we know the id, send the update to the entity server if (entityID.isKnownID) { // make sure the properties has a type, so that the encode can know which properties to include - if (properties.getType() == EntityTypes::Unknown) { + if (propertiesWithSimID.getType() == EntityTypes::Unknown) { EntityItem* entity = _entityTree->findEntityByEntityItemID(entityID); if (entity) { - EntityItemProperties tempProperties = properties; - tempProperties.setType(entity->getType()); - queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, tempProperties); - return entityID; + propertiesWithSimID.setType(entity->getType()); } } - - // if the properties already includes the type, then use it as is - queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties); + + queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, propertiesWithSimID); } return entityID; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 02568ef782..7c2f41ed2c 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -139,9 +139,9 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro properties.getSimulatorID() != entity->getSimulatorID()) { // A Node is trying to take ownership of the simulation of this entity from another Node. Only allow this // if ownership hasn't recently changed. - quint64 now = usecTimestampNow(); - if (now - entity->getSimulatorIDChangedTime() < SIMULATOR_CHANGE_LOCKOUT_PERIOD) { - qDebug() << "SIMULATOR_CHANGE_LOCKOUT_PERIOD"; + if (usecTimestampNow() - entity->getSimulatorIDChangedTime() < SIMULATOR_CHANGE_LOCKOUT_PERIOD) { + qCDebug(entities) << "simulator_change_lockout_period:" + << entity->getSimulatorID() << "to" << properties.getSimulatorID(); // squash the physics-related changes. properties.setSimulatorIDChanged(false); properties.setPositionChanged(false); From 64d17f101a2a73b7107a839a1aa98dd2e411adc3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 17 Apr 2015 10:44:01 -0700 Subject: [PATCH 137/401] obfuscate set access token from AM log --- libraries/networking/src/AccountManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 1f1ada5592..2830a13ca7 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -366,7 +366,7 @@ void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken) OAuthAccessToken newOAuthToken; newOAuthToken.token = accessToken; - qCDebug(networking) << "Setting new account manager access token to" << accessToken; + qCDebug(networking) << "Setting new account manager access token. F2C:" << accessToken.left(2) << "L2C:" << accessToken.right(2); _accountInfo.setAccessToken(newOAuthToken); } From f94fcdab7bdd4bbd2f4a640a0e6208c65be51ebf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 17 Apr 2015 10:44:18 -0700 Subject: [PATCH 138/401] print if DS is using an access token from env --- domain-server/src/DomainServer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 9ce15b7507..d7cd7ec47d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -302,6 +302,9 @@ bool DomainServer::didSetupAccountManagerWithAccessToken() { << "at keypath metaverse.access_token or in your ENV at key DOMAIN_SERVER_ACCESS_TOKEN"; return false; } + } else { + qDebug() << "Using access token from DOMAIN_SERVER_ACCESS_TOKEN in env. This overrides any access token present" + << " in the user or master config."; } // give this access token to the AccountManager From 6b085ca6684887511b447cd24b0dea059784aa3c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 17 Apr 2015 10:53:04 -0700 Subject: [PATCH 139/401] Move method out of Menu class --- interface/src/Application.cpp | 5 ++++- interface/src/Application.h | 3 ++- interface/src/Menu.cpp | 17 ++++------------- interface/src/Menu.h | 1 - 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc24127054..e3c101d280 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1748,7 +1748,10 @@ void Application::setActiveFaceTracker() { DependencyManager::get()->setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)); #endif #ifdef HAVE_DDE - DependencyManager::get()->setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression)); + bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression); + Menu::getInstance()->getActionForOption(MenuOption::DDEFiltering)->setVisible(isUsingDDE); + Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE); + DependencyManager::get()->setEnabled(isUsingDDE); #endif #ifdef HAVE_VISAGE DependencyManager::get()->updateEnabled(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 833d9a6799..b5b2921844 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -210,7 +210,6 @@ public: bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; } FaceTracker* getActiveFaceTracker(); - void setActiveFaceTracker(); QSystemTrayIcon* getTrayIcon() { return _trayIcon; } ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; } @@ -385,6 +384,8 @@ public slots: void setVSyncEnabled(); void resetSensors(); + void setActiveFaceTracker(); + void aboutApp(); void showEditEntitiesHelp(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index bb7d2b5382..74231b6fe3 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -362,25 +362,25 @@ Menu::Menu() { QAction* noFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::NoFaceTracking, 0, true, - this, SLOT(setActiveFaceTracker())); + qApp, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(noFaceTracker); #ifdef HAVE_FACESHIFT QAction* faceshiftFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Faceshift, 0, false, - this, SLOT(setActiveFaceTracker())); + qApp, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(faceshiftFaceTracker); #endif #ifdef HAVE_DDE QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFaceRegression, 0, false, - this, SLOT(setActiveFaceTracker())); + qApp, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(ddeFaceTracker); #endif #ifdef HAVE_VISAGE QAction* visageFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Visage, 0, false, - this, SLOT(setActiveFaceTracker())); + qApp, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(visageFaceTracker); #endif } @@ -989,12 +989,3 @@ void Menu::visibilityChanged(Discoverability::Mode discoverabilityMode) { qCDebug(interfaceapp) << "ERROR Menu::visibilityChanged() called with unrecognized value."; } } - -void Menu::setActiveFaceTracker() { -#ifdef HAVE_DDE - bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression); - Menu::getInstance()->getActionForOption(MenuOption::DDEFiltering)->setVisible(isUsingDDE); - Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE); -#endif - qApp->setActiveFaceTracker(); -} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 5798ca3a13..ea34664eaa 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -68,7 +68,6 @@ public slots: private slots: void setVisibility(); - void setActiveFaceTracker(); private: static Menu* _instance; From 32ced31f603ec805b25ef67636d6559a1853eef3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 10:57:00 -0700 Subject: [PATCH 140/401] adjust logic related to claiming and releasing simulation ownership during scripted changes to entities --- .../entities/src/EntityScriptingInterface.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 392cd92ab6..6bd988ec90 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -61,13 +61,18 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) { -void setSimId(EntityItemProperties& propertiesWithSimID) { +void setSimId(EntityItemProperties& propertiesWithSimID, EntityItem* entity) { + auto nodeList = DependencyManager::get(); + const QUuid myNodeID = nodeList->getSessionUUID(); + if (propertiesWithSimID.velocityChanged() || propertiesWithSimID.rotationChanged() || propertiesWithSimID.containsPositionChange()) { - auto nodeList = DependencyManager::get(); - const QUuid myNodeID = nodeList->getSessionUUID(); propertiesWithSimID.setSimulatorID(myNodeID); + entity->setSimulatorID(myNodeID); + } else if (entity->getSimulatorID() == myNodeID) { + propertiesWithSimID.setSimulatorID(QUuid()); // give up simulation ownership + entity->setSimulatorID(QUuid()); } } @@ -80,14 +85,14 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro // This Node is creating a new object. If it's in motion, set this Node as the simulator. EntityItemProperties propertiesWithSimID = properties; - setSimId(propertiesWithSimID); EntityItemID id(NEW_ENTITY, creatorTokenID, false ); // If we have a local entity tree set, then also update it. if (_entityTree) { _entityTree->lockForWrite(); - _entityTree->addEntity(id, propertiesWithSimID); + EntityItem* entity = _entityTree->addEntity(id, propertiesWithSimID); + setSimId(propertiesWithSimID, entity); _entityTree->unlock(); } @@ -157,7 +162,6 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E // if this Node is changing a physics-related property, claim simulation ownership. EntityItemProperties propertiesWithSimID = properties; - setSimId(propertiesWithSimID); // If we have a local entity tree set, then also update it. We can do this even if we don't know // the actual id, because we can edit out local entities just with creatorTokenID @@ -174,6 +178,7 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E EntityItem* entity = _entityTree->findEntityByEntityItemID(entityID); if (entity) { propertiesWithSimID.setType(entity->getType()); + setSimId(propertiesWithSimID, entity); } } From d90dec066c52a0d1d57f854f097e63c0514e0127 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 11:12:13 -0700 Subject: [PATCH 141/401] if an entity has no simulatorID, pull it out of list of entities with simulatorIDs --- libraries/entities/src/SimpleEntitySimulation.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 2c586ae0af..6343ed3e47 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -38,10 +38,11 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { itemItr = _hasSimulationOwnerEntities.begin(); while (itemItr != _hasSimulationOwnerEntities.end()) { EntityItem* entity = *itemItr; - if (!entity->getSimulatorID().isNull() && - usecTimestampNow() - entity->getLastChangedOnServer() >= AUTO_REMOVE_SIMULATION_OWNER_USEC) { + if (entity->getSimulatorID().isNull()) { + itemItr = _hasSimulationOwnerEntities.erase(itemItr); + } else if (usecTimestampNow() - entity->getLastChangedOnServer() >= AUTO_REMOVE_SIMULATION_OWNER_USEC) { qCDebug(entities) << "auto-removing simulation owner" << entity->getSimulatorID(); - entity->setSimulatorID(""); + entity->setSimulatorID(QUuid()); itemItr = _hasSimulationOwnerEntities.erase(itemItr); } else { ++itemItr; From 07b9d73edf341063b6894f59b8011bb6220c35aa Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 11:20:35 -0700 Subject: [PATCH 142/401] bump protocol version --- libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/networking/src/PacketHeaders.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 52153f9e83..4d7979bddf 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_HAVE_ACCELERATION; + return VERSION_ENTITIES_HAVE_UUIDS; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 9fb14854aa..979eb4d451 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -135,6 +135,7 @@ const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 12; const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED = 13; const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14; const PacketVersion VERSION_ENTITIES_HAVE_ACCELERATION = 15; +const PacketVersion VERSION_ENTITIES_HAVE_UUIDS = 16; const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; #endif // hifi_PacketHeaders_h From ee480248315e07c91db495674409313f6a446b94 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 17 Apr 2015 11:31:48 -0700 Subject: [PATCH 143/401] Remove uninitialized method reference --- interface/src/devices/DdeFaceTracker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 743b3be780..13b96dd18f 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -29,9 +29,9 @@ static const QHostAddress DDE_SERVER_ADDR("127.0.0.1"); static const quint16 DDE_SERVER_PORT = 64204; static const quint16 DDE_CONTROL_PORT = 64205; #if defined(Q_OS_WIN) -static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde.exe"; +static const QString DDE_PROGRAM_PATH = "/dde/dde.exe"; #elif defined(Q_OS_MAC) -static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde.app/Contents/MacOS/dde"; +static const QString DDE_PROGRAM_PATH = "/dde.app/Contents/MacOS/dde"; #endif static const QStringList DDE_ARGUMENTS = QStringList() << "--udp=" + DDE_SERVER_ADDR.toString() + ":" + QString::number(DDE_SERVER_PORT) From edb388ed834b2c6ab5b2c22f6fd6f5c5f3429959 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 17 Apr 2015 11:32:05 -0700 Subject: [PATCH 144/401] Fixing the function with no implementation --- libraries/render-utils/src/Model.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 9ca817a8e7..1559e73e61 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -496,9 +496,6 @@ private: class RenderBucketMap : public BaseRenderBucketMap { public: typedef RenderKey Key; - - - void addRenderBucket(Key key, RenderBucket& bucket); }; RenderBucketMap _renderBuckets; From 3055359d4ccad5a53645b30dafd5efdc18700050 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 17 Apr 2015 13:40:18 -0700 Subject: [PATCH 145/401] remove visage references from Application --- interface/src/Application.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0227003cb1..c3677696f5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -108,7 +108,6 @@ #include "devices/MIDIManager.h" #include "devices/OculusManager.h" #include "devices/TV3DManager.h" -#include "devices/Visage.h" #include "gpu/Batch.h" #include "gpu/GLBackend.h" @@ -242,7 +241,6 @@ bool setupEssentials(int& argc, char** argv) { auto ambientOcclusionEffect = DependencyManager::set(); auto textureCache = DependencyManager::set(); auto animationCache = DependencyManager::set(); - auto visage = DependencyManager::set(); auto ddeFaceTracker = DependencyManager::set(); auto modelBlender = DependencyManager::set(); auto audioToolBox = DependencyManager::set(); @@ -1735,12 +1733,10 @@ int Application::getMouseDragStartedY() const { FaceTracker* Application::getActiveFaceTracker() { auto faceshift = DependencyManager::get(); - auto visage = DependencyManager::get(); auto dde = DependencyManager::get(); return (dde->isActive() ? static_cast(dde.data()) : - (faceshift->isActive() ? static_cast(faceshift.data()) : - (visage->isActive() ? static_cast(visage.data()) : NULL))); + (faceshift->isActive() ? static_cast(faceshift.data()) : NULL)); } void Application::setActiveFaceTracker() { @@ -1753,9 +1749,6 @@ void Application::setActiveFaceTracker() { Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE); DependencyManager::get()->setEnabled(isUsingDDE); #endif -#ifdef HAVE_VISAGE - DependencyManager::get()->updateEnabled(); -#endif } bool Application::exportEntities(const QString& filename, const QVector& entityIDs) { @@ -1929,7 +1922,6 @@ void Application::init() { // initialize our face trackers after loading the menu settings DependencyManager::get()->init(); DependencyManager::get()->init(); - DependencyManager::get()->init(); Leapmotion::init(); RealSense::init(); @@ -3263,7 +3255,6 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { void Application::resetSensors() { DependencyManager::get()->reset(); - DependencyManager::get()->reset(); DependencyManager::get()->reset(); OculusManager::reset(); From 604bc2abe15b6572712ae82f711dcc38c8dae4bd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 17 Apr 2015 13:40:31 -0700 Subject: [PATCH 146/401] remove visage related files --- .gitignore | 4 - interface/external/visage/readme.txt | 14 -- interface/src/devices/Visage.cpp | 191 --------------------------- interface/src/devices/Visage.h | 63 --------- 4 files changed, 272 deletions(-) delete mode 100644 interface/external/visage/readme.txt delete mode 100644 interface/src/devices/Visage.cpp delete mode 100644 interface/src/devices/Visage.h diff --git a/.gitignore b/.gitignore index 44561daabc..b0c99080c7 100644 --- a/.gitignore +++ b/.gitignore @@ -32,10 +32,6 @@ DerivedData interface/external/*/* !interface/external/*/readme.txt -# ignore interface optional resources -interface/resources/visage/* -!interface/resources/visage/tracker.cfg - # Ignore interfaceCache for Linux users interface/interfaceCache/ diff --git a/interface/external/visage/readme.txt b/interface/external/visage/readme.txt deleted file mode 100644 index 3aff1039dc..0000000000 --- a/interface/external/visage/readme.txt +++ /dev/null @@ -1,14 +0,0 @@ - -Instructions for adding the Visage driver to Interface -Andrzej Kapolka, February 11, 2014 - -1. Copy the Visage sdk folders (lib, include, dependencies) into the interface/external/visage folder. - This readme.txt should be there as well. - -2. Copy the contents of the Visage configuration data folder (visageSDK-MacOS/Samples/MacOSX/data/) to - interface/resources/visage (i.e., so that interface/resources/visage/candide3.wfm is accessible) - -3. Copy the Visage license file to interface/resources/visage/license.vlc. - -4. Delete your build directory, run cmake and build, and you should be all set. - diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp deleted file mode 100644 index 010b872bc6..0000000000 --- a/interface/src/devices/Visage.cpp +++ /dev/null @@ -1,191 +0,0 @@ -// -// Visage.cpp -// interface/src/devices -// -// Created by Andrzej Kapolka on 2/11/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 "Faceshift.h" -#include "Visage.h" - -// this has to go after our normal includes, because its definition of HANDLE conflicts with Qt's -#ifdef HAVE_VISAGE -#include -#endif - -namespace VisageSDK { -#ifdef WIN32 - void __declspec(dllimport) initializeLicenseManager(char* licenseKeyFileName); -#else - void initializeLicenseManager(char* licenseKeyFileName); -#endif -} - -using namespace VisageSDK; - -const glm::vec3 DEFAULT_HEAD_ORIGIN(0.0f, 0.0f, 0.7f); - -Visage::Visage() : - _enabled(false), - _headOrigin(DEFAULT_HEAD_ORIGIN) { - -#ifdef HAVE_VISAGE -#ifdef WIN32 - QByteArray licensePath = PathUtils::resourcesPath().toLatin1() + "visage"; -#else - QByteArray licensePath = PathUtils::resourcesPath().toLatin1() + "visage/license.vlc"; -#endif - initializeLicenseManager(licensePath.data()); - _tracker = new VisageTracker2(PathUtils::resourcesPath().toLatin1() + "visage/tracker.cfg"); - _data = new FaceData(); -#endif -} - -Visage::~Visage() { -#ifdef HAVE_VISAGE - _tracker->stop(); - // deleting the tracker crashes windows; disable for now - //delete _tracker; - delete _data; -#endif -} - -#ifdef HAVE_VISAGE -static int leftEyeBlinkIndex = 0; -static int rightEyeBlinkIndex = 1; - -static QMultiHash > createActionUnitNameMap() { - QMultiHash > blendshapeMap; - blendshapeMap.insert("JawFwd", QPair("au_jaw_z_push", 1.0f)); - blendshapeMap.insert("JawLeft", QPair("au_jaw_x_push", 1.0f)); - blendshapeMap.insert("JawOpen", QPair("au_jaw_drop", 1.0f)); - blendshapeMap.insert("LipsLowerDown", QPair("au_lower_lip_drop", 1.0f)); - blendshapeMap.insert("LipsUpperOpen", QPair("au_upper_lip_raiser", 1.0f)); - blendshapeMap.insert("LipsStretch_R", QPair("au_lip_stretcher_left", 0.5f)); - blendshapeMap.insert("MouthSmile_L", QPair("au_lip_corner_depressor", -1.0f)); - blendshapeMap.insert("MouthSmile_R", QPair("au_lip_corner_depressor", -1.0f)); - blendshapeMap.insert("BrowsU_R", QPair("au_left_outer_brow_raiser", 1.0f)); - blendshapeMap.insert("BrowsU_C", QPair("au_left_inner_brow_raiser", 1.0f)); - blendshapeMap.insert("BrowsD_R", QPair("au_left_brow_lowerer", 1.0f)); - blendshapeMap.insert("EyeBlink_L", QPair("au_leye_closed", 1.0f)); - blendshapeMap.insert("EyeBlink_R", QPair("au_reye_closed", 1.0f)); - blendshapeMap.insert("EyeOpen_L", QPair("au_upper_lid_raiser", 1.0f)); - blendshapeMap.insert("EyeOpen_R", QPair("au_upper_lid_raiser", 1.0f)); - blendshapeMap.insert("LipLowerOpen", QPair("au_lower_lip_x_push", 1.0f)); - blendshapeMap.insert("LipsStretch_L", QPair("au_lip_stretcher_right", 0.5f)); - blendshapeMap.insert("BrowsU_L", QPair("au_right_outer_brow_raiser", 1.0f)); - blendshapeMap.insert("BrowsU_C", QPair("au_right_inner_brow_raiser", 1.0f)); - blendshapeMap.insert("BrowsD_L", QPair("au_right_brow_lowerer", 1.0f)); - - QMultiHash > actionUnitNameMap; - for (int i = 0;; i++) { - QByteArray blendshape = FACESHIFT_BLENDSHAPES[i]; - if (blendshape.isEmpty()) { - break; - } - if (blendshape == "EyeBlink_L") { - leftEyeBlinkIndex = i; - - } else if (blendshape == "EyeBlink_R") { - rightEyeBlinkIndex = i; - } - for (QMultiHash >::const_iterator it = blendshapeMap.constFind(blendshape); - it != blendshapeMap.constEnd() && it.key() == blendshape; it++) { - actionUnitNameMap.insert(it.value().first, QPair(i, it.value().second)); - } - } - - return actionUnitNameMap; -} - -static const QMultiHash >& getActionUnitNameMap() { - static QMultiHash > actionUnitNameMap = createActionUnitNameMap(); - return actionUnitNameMap; -} -#endif - - -#ifdef HAVE_VISAGE -const float TRANSLATION_SCALE = 20.0f; -void Visage::init() { - connect(DependencyManager::get().data(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled())); - updateEnabled(); -} - -void Visage::update(float deltaTime) { - if (!isActive()) { - return; - } - FaceTracker::update(deltaTime); - - _headRotation = glm::quat(glm::vec3(-_data->faceRotation[0], -_data->faceRotation[1], _data->faceRotation[2])); - _headTranslation = (glm::vec3(_data->faceTranslation[0], _data->faceTranslation[1], _data->faceTranslation[2]) - - _headOrigin) * TRANSLATION_SCALE; - _estimatedEyePitch = glm::degrees(-_data->gazeDirection[1]); - _estimatedEyeYaw = glm::degrees(-_data->gazeDirection[0]); - - if (_actionUnitIndexMap.isEmpty()) { - int maxIndex = -1; - for (int i = 0; i < _data->actionUnitCount; i++) { - QByteArray name = _data->actionUnitsNames[i]; - for (QMultiHash >::const_iterator it = getActionUnitNameMap().constFind(name); - it != getActionUnitNameMap().constEnd() && it.key() == name; it++) { - _actionUnitIndexMap.insert(i, it.value()); - maxIndex = qMax(maxIndex, it.value().first); - } - } - _blendshapeCoefficients.resize(maxIndex + 1); - } - - qFill(_blendshapeCoefficients.begin(), _blendshapeCoefficients.end(), 0.0f); - for (int i = 0; i < _data->actionUnitCount; i++) { - if (!_data->actionUnitsUsed[i]) { - continue; - } - for (QMultiHash >::const_iterator it = _actionUnitIndexMap.constFind(i); - it != _actionUnitIndexMap.constEnd() && it.key() == i; it++) { - _blendshapeCoefficients[it.value().first] += _data->actionUnits[i] * it.value().second; - } - } - _blendshapeCoefficients[leftEyeBlinkIndex] = 1.0f - _data->eyeClosure[1]; - _blendshapeCoefficients[rightEyeBlinkIndex] = 1.0f - _data->eyeClosure[0]; -} - -void Visage::reset() { - _headOrigin += _headTranslation / TRANSLATION_SCALE; -} -#endif - -void Visage::updateEnabled() { - setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) && - !(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) && - DependencyManager::get()->isConnectedOrConnecting()) && - !Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression)); -} - -void Visage::setEnabled(bool enabled) { -#ifdef HAVE_VISAGE - if (_enabled == enabled) { - return; - } - if ((_enabled = enabled)) { - _tracker->trackFromCam(); - } else { - _tracker->stop(); - } -#endif -} diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h deleted file mode 100644 index 3ff1ea8c27..0000000000 --- a/interface/src/devices/Visage.h +++ /dev/null @@ -1,63 +0,0 @@ -// -// Visage.h -// interface/src/devices -// -// Created by Andrzej Kapolka on 2/11/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_Visage_h -#define hifi_Visage_h - -#include -#include -#include - -#include - -#include "FaceTracker.h" - -namespace VisageSDK { - class VisageTracker2; - struct FaceData; -} - -/// Handles input from the Visage webcam feature tracking software. -class Visage : public FaceTracker, public Dependency { - Q_OBJECT - SINGLETON_DEPENDENCY - -public: -#ifdef HAVE_VISAGE - virtual void init(); - virtual void update(float deltaTime); - virtual void reset(); - - virtual bool isActive() const { return _tracker->getTrackingData(_data) == TRACK_STAT_OK; } - virtual bool isTracking() const { return isActive(); } -#endif - -public slots: - void updateEnabled(); - -private: - Visage(); - virtual ~Visage(); - -#ifdef HAVE_VISAGE - VisageSDK::VisageTracker2* _tracker; - VisageSDK::FaceData* _data; - QMultiHash > _actionUnitIndexMap; -#endif - - void setEnabled(bool enabled); - - bool _enabled; - - glm::vec3 _headOrigin; -}; - -#endif // hifi_Visage_h From 30e580e207581077a54c80c3e01d36c3e92aaa5f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 17 Apr 2015 13:42:30 -0700 Subject: [PATCH 147/401] remove visage from Menu --- interface/src/Menu.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8d6a1e3184..7789ddda4a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -30,7 +30,6 @@ #include "devices/Faceshift.h" #include "devices/RealSense.h" #include "devices/SixenseManager.h" -#include "devices/Visage.h" #include "MainWindow.h" #include "scripting/MenuScriptingInterface.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) @@ -376,12 +375,6 @@ Menu::Menu() { 0, false, qApp, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(ddeFaceTracker); -#endif -#ifdef HAVE_VISAGE - QAction* visageFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Visage, - 0, false, - qApp, SLOT(setActiveFaceTracker())); - faceTrackerGroup->addAction(visageFaceTracker); #endif } #ifdef HAVE_DDE From 931c46345ea8c7fda7f3d7d3cd37a5ae94ef6ced Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 17 Apr 2015 14:15:50 -0700 Subject: [PATCH 148/401] Move visibility methods into DiscoverabilityManager --- interface/src/DiscoverabilityManager.cpp | 31 ++++++++++++++++++++- interface/src/DiscoverabilityManager.h | 3 +++ interface/src/Menu.cpp | 34 +++--------------------- interface/src/Menu.h | 5 ---- 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 6622a27145..230f4202c8 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -18,6 +18,7 @@ #include #include "DiscoverabilityManager.h" +#include "Menu.h" const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::All; @@ -96,4 +97,32 @@ void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discov emit discoverabilityModeChanged(discoverabilityMode); } -} \ No newline at end of file +} + +void DiscoverabilityManager::setVisibility() { + Menu* menu = Menu::getInstance(); + + if (menu->isOptionChecked(MenuOption::VisibleToEveryone)) { + this->setDiscoverabilityMode(Discoverability::All); + } else if (menu->isOptionChecked(MenuOption::VisibleToFriends)) { + this->setDiscoverabilityMode(Discoverability::Friends); + } else if (menu->isOptionChecked(MenuOption::VisibleToNoOne)) { + this->setDiscoverabilityMode(Discoverability::None); + } else { + qDebug() << "ERROR DiscoverabilityManager::setVisibility() called with unrecognized value."; + } +} + +void DiscoverabilityManager::visibilityChanged(Discoverability::Mode discoverabilityMode) { + Menu* menu = Menu::getInstance(); + + if (discoverabilityMode == Discoverability::All) { + menu->setIsOptionChecked(MenuOption::VisibleToEveryone, true); + } else if (discoverabilityMode == Discoverability::Friends) { + menu->setIsOptionChecked(MenuOption::VisibleToFriends, true); + } else if (discoverabilityMode == Discoverability::None) { + menu->setIsOptionChecked(MenuOption::VisibleToNoOne, true); + } else { + qDebug() << "ERROR DiscoverabilityManager::visibilityChanged() called with unrecognized value."; + } +} diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h index 9daa9408f8..1b5adcdb5d 100644 --- a/interface/src/DiscoverabilityManager.h +++ b/interface/src/DiscoverabilityManager.h @@ -36,6 +36,9 @@ public slots: Discoverability::Mode getDiscoverabilityMode() { return static_cast(_mode.get()); } void setDiscoverabilityMode(Discoverability::Mode discoverabilityMode); + void setVisibility(); + void visibilityChanged(Discoverability::Mode discoverabilityMode); + signals: void discoverabilityModeChanged(Discoverability::Mode discoverabilityMode); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8d6a1e3184..b07d122aee 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -163,21 +163,21 @@ Menu::Menu() { QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone, 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, - this, SLOT(setVisibility())); + discoverabilityManager.data(), SLOT(setVisibility())); visibilityGroup->addAction(visibleToEveryone); QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends, 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, - this, SLOT(setVisibility())); + discoverabilityManager.data(), SLOT(setVisibility())); visibilityGroup->addAction(visibleToFriends); QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne, 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, - this, SLOT(setVisibility())); + discoverabilityManager.data(), SLOT(setVisibility())); visibilityGroup->addAction(visibleToNoOne); connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, - this, &Menu::visibilityChanged); + discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged); } addActionToQMenuAndActionHash(toolsMenu, @@ -963,29 +963,3 @@ bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { } return false; }; - -void Menu::setVisibility() { - auto discoverabilityManager = DependencyManager::get(); - - if (Menu::getInstance()->isOptionChecked(MenuOption::VisibleToEveryone)) { - discoverabilityManager->setDiscoverabilityMode(Discoverability::All); - } else if (Menu::getInstance()->isOptionChecked(MenuOption::VisibleToFriends)) { - discoverabilityManager->setDiscoverabilityMode(Discoverability::Friends); - } else if (Menu::getInstance()->isOptionChecked(MenuOption::VisibleToNoOne)) { - discoverabilityManager->setDiscoverabilityMode(Discoverability::None); - } else { - qCDebug(interfaceapp) << "ERROR Menu::setVisibility() called with unrecognized value."; - } -} - -void Menu::visibilityChanged(Discoverability::Mode discoverabilityMode) { - if (discoverabilityMode == Discoverability::All) { - setIsOptionChecked(MenuOption::VisibleToEveryone, true); - } else if (discoverabilityMode == Discoverability::Friends) { - setIsOptionChecked(MenuOption::VisibleToFriends, true); - } else if (discoverabilityMode == Discoverability::None) { - setIsOptionChecked(MenuOption::VisibleToNoOne, true); - } else { - qCDebug(interfaceapp) << "ERROR Menu::visibilityChanged() called with unrecognized value."; - } -} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index ea34664eaa..3d10d20f1b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -66,9 +66,6 @@ public slots: bool isOptionChecked(const QString& menuOption) const; void setIsOptionChecked(const QString& menuOption, bool isChecked); -private slots: - void setVisibility(); - private: static Menu* _instance; Menu(); @@ -99,8 +96,6 @@ private: int findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem); int positionBeforeSeparatorIfNeeded(QMenu* menu, int requestedPosition); - void visibilityChanged(Discoverability::Mode discoverabilityMode); - QHash _actionHash; }; From 63a81bdcb40260803662f3a296973220a6c803fd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 17 Apr 2015 14:27:58 -0700 Subject: [PATCH 149/401] remove VISAGE handling in interface CMakeLists --- interface/CMakeLists.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index f4f390607b..885e4ed4b5 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -170,15 +170,6 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) endif () endforeach() -# special APPLE modifications for Visage library -if (VISAGE_FOUND AND NOT DISABLE_VISAGE AND APPLE) - add_definitions(-DMAC_OS_X) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment") - find_library(AVFoundation AVFoundation) - find_library(CoreMedia CoreMedia) - target_link_libraries(${TARGET_NAME} ${AVFoundation} ${CoreMedia} ${NEW_STD_LIBRARY}) -endif () - # special OS X modifications for RtMidi library if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI AND APPLE) find_library(CoreMIDI CoreMIDI) From 6b615c1ba145665db75d14737341de99ff558f2a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 17 Apr 2015 14:28:20 -0700 Subject: [PATCH 150/401] remove Visage from menu header --- interface/src/Menu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index ea34664eaa..1db97c1250 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -251,7 +251,6 @@ namespace MenuOption { const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; const QString PackageModel = "Package Model..."; - const QString Visage = "Visage"; const QString VisibleToEveryone = "Everyone"; const QString VisibleToFriends = "Friends"; const QString VisibleToNoOne = "No one"; From cfac4fe9c16307559f23fd82a5695ab5fb996223 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 17 Apr 2015 14:28:41 -0700 Subject: [PATCH 151/401] remove the Visage find module --- cmake/modules/FindVisage.cmake | 68 ---------------------------------- 1 file changed, 68 deletions(-) delete mode 100644 cmake/modules/FindVisage.cmake diff --git a/cmake/modules/FindVisage.cmake b/cmake/modules/FindVisage.cmake deleted file mode 100644 index 2b288f4681..0000000000 --- a/cmake/modules/FindVisage.cmake +++ /dev/null @@ -1,68 +0,0 @@ -# -# FindVisage.cmake -# -# Try to find the Visage controller library -# -# You must provide a VISAGE_ROOT_DIR which contains lib and include directories -# -# Once done this will define -# -# VISAGE_FOUND - system found Visage -# VISAGE_INCLUDE_DIRS - the Visage include directory -# VISAGE_LIBRARIES - Link this to use Visage -# -# Created on 2/11/2014 by Andrzej Kapolka -# 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("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("visage") - -find_path(VISAGE_BASE_INCLUDE_DIR VisageTracker2.h PATH_SUFFIXES include HINTS ${VISAGE_SEARCH_DIRS}) - -if (APPLE) - find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h HINTS /usr/include/libxml2 ${VISAGE_SEARCH_DIRS}) - find_path(VISAGE_OPENCV_INCLUDE_DIR cv.h PATH_SUFFIXES dependencies/OpenCV_MacOSX/include HINTS ${VISAGE_SEARCH_DIRS}) - find_path(VISAGE_OPENCV2_INCLUDE_DIR opencv.hpp PATH_SUFFIXES dependencies/OpenCV_MacOSX/include/opencv2 HINTS ${VISAGE_SEARCH_DIRS}) - - find_library(VISAGE_CORE_LIBRARY NAME vscore PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS}) - find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS}) - find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib HINTS ${VISAGE_SEARCH_DIRS}) - - find_library(CoreVideo CoreVideo) - find_library(QTKit QTKit) - find_library(IOKit IOKit) - -elseif (WIN32) - find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS}) - find_path(VISAGE_OPENCV_INCLUDE_DIR opencv/cv.h PATH_SUFFIXES dependencies/OpenCV/include HINTS ${VISAGE_SEARCH_DIRS}) - find_path(VISAGE_OPENCV2_INCLUDE_DIR cv.h PATH_SUFFIXES dependencies/OpenCV/include/opencv HINTS ${VISAGE_SEARCH_DIRS}) - - find_library(VISAGE_CORE_LIBRARY NAME vscore PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS}) - find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS}) - find_library(VISAGE_OPENCV_LIBRARY NAME opencv_core243 PATH_SUFFIXES dependencies/OpenCV/lib HINTS ${VISAGE_SEARCH_DIRS}) -endif () - -include(FindPackageHandleStandardArgs) - -list(APPEND VISAGE_ARGS_LIST VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR - VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR - VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY) - -if (APPLE) - list(APPEND VISAGE_ARGS_LIST CoreVideo QTKit IOKit) -endif () - -find_package_handle_standard_args(Visage DEFAULT_MSG ${VISAGE_ARGS_LIST}) - -set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR}" "${VISAGE_OPENCV2_INCLUDE_DIR}" "${VISAGE_BASE_INCLUDE_DIR}") -set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}") - -if (APPLE) - list(APPEND VISAGE_LIBRARIES "${CoreVideo}" "${QTKit}" "${IOKit}") -endif () - -mark_as_advanced(VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES) From 511240da5ad37626b25c3ac3707c85a16cbe17b3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 17 Apr 2015 14:29:51 -0700 Subject: [PATCH 152/401] remove Visage from FaceTracker comment --- interface/src/devices/FaceTracker.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/FaceTracker.h b/interface/src/devices/FaceTracker.h index 362099aaf6..db6fdd74b9 100644 --- a/interface/src/devices/FaceTracker.h +++ b/interface/src/devices/FaceTracker.h @@ -18,7 +18,7 @@ #include #include -/// Base class for face trackers (Faceshift, Visage, DDE). +/// Base class for face trackers (Faceshift, DDE). class FaceTracker : public QObject { Q_OBJECT From dac57c44da697811fa6890a2c62b5b8c764c29b0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 15:05:47 -0700 Subject: [PATCH 153/401] if measured acceleration is close to zero, send zero to entity server, else send gravity --- .../entities/src/EntityEditPacketSender.cpp | 8 +++---- libraries/entities/src/EntityItem.cpp | 19 ++++----------- libraries/entities/src/EntityItem.h | 4 ++-- libraries/physics/src/EntityMotionState.cpp | 23 ++++++++++++------- libraries/physics/src/ObjectMotionState.cpp | 3 ++- libraries/physics/src/ObjectMotionState.h | 1 + 6 files changed, 28 insertions(+), 30 deletions(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index 5f77d1e782..478603dedf 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -38,10 +38,10 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityItemI //// XXX - auto nodeList = DependencyManager::get(); - QUuid myNodeID = nodeList->getSessionUUID(); - QString x = properties.getSimulatorID() == myNodeID ? "me" : properties.getSimulatorID().toString(); - qDebug() << "sending update:" << properties.simulatorIDChanged() << x; + // auto nodeList = DependencyManager::get(); + // QUuid myNodeID = nodeList->getSessionUUID(); + // QString x = properties.getSimulatorID() == myNodeID ? "me" : properties.getSimulatorID().toString(); + // qDebug() << "sending update:" << properties.simulatorIDChanged() << x; //// XXX diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3f342c4d86..b771279efa 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -699,6 +699,7 @@ void EntityItem::simulate(const quint64& now) { qCDebug(entities) << " MOVING...="; qCDebug(entities) << " hasVelocity=" << hasVelocity(); qCDebug(entities) << " hasGravity=" << hasGravity(); + qCDebug(entities) << " hasAcceleration=" << hasAcceleration(); qCDebug(entities) << " hasAngularVelocity=" << hasAngularVelocity(); qCDebug(entities) << " getAngularVelocity=" << getAngularVelocity(); } @@ -788,13 +789,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) { position = newPosition; - // apply gravity - if (hasGravity()) { - // handle resting on surface case, this is definitely a bit of a hack, and it only works on the - // "ground" plane of the domain, but for now it's what we've got - velocity += getGravity() * timeElapsed; - } - + // apply effective acceleration, which will be the same as gravity if the Entity isn't at rest. if (hasAcceleration()) { velocity += getAcceleration() * timeElapsed; } @@ -1151,14 +1146,8 @@ void EntityItem::updateGravity(const glm::vec3& value) { } void EntityItem::updateAcceleration(const glm::vec3& value) { - if (glm::distance(_acceleration, value) > MIN_ACCELERATION_DELTA) { - if (glm::length(value) < MIN_ACCELERATION_DELTA) { - _acceleration = ENTITY_ITEM_ZERO_VEC3; - } else { - _acceleration = value; - } - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; - } + _acceleration = value; + _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } void EntityItem::updateAngularVelocity(const glm::vec3& value) { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index b9def4f1db..96186b4c91 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -195,8 +195,8 @@ public: void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; } - const glm::vec3 getAcceleration() const { return _acceleration; } /// get acceleration in meters/second - void setAcceleration(const glm::vec3& value) { _acceleration = value; } /// acceleration in meters/second + const glm::vec3 getAcceleration() const { return _acceleration; } /// get acceleration in meters/second/second + void setAcceleration(const glm::vec3& value) { _acceleration = value; } /// acceleration in meters/second/second bool hasAcceleration() const { return _acceleration != ENTITY_ITEM_ZERO_VEC3; } float getDamping() const { return _damping; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f5468a0978..95a3dff6af 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -18,6 +18,7 @@ #include "PhysicsHelpers.h" #include "PhysicsLogging.h" +static const float MEASURED_ACCELERATION_CLOSE_TO_ZERO = 0.05; QSet* _outgoingEntityList; @@ -166,8 +167,8 @@ void EntityMotionState::updateObjectVelocities() { _sentAngularVelocity = _entity->getAngularVelocity(); setAngularVelocity(_sentAngularVelocity); - _sentAcceleration = _entity->getGravity(); - setGravity(_sentAcceleration); + _sentGravity = _entity->getGravity(); + setGravity(_sentGravity); _body->setActivationState(ACTIVE_TAG); } @@ -191,8 +192,8 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { } auto nodeList = DependencyManager::get(); - QUuid myNodeID = nodeList->getSessionUUID(); - QUuid simulatorID = _entity->getSimulatorID(); + const QUuid& myNodeID = nodeList->getSessionUUID(); + const QUuid& simulatorID = _entity->getSimulatorID(); if (!simulatorID.isNull() && simulatorID != myNodeID) { // some other Node owns the simulating of this, so don't broadcast the results of local simulation. @@ -203,13 +204,18 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { } void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step) { - if (!_entity->isKnownID()) { return; // never update entities that are unknown } if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); + if (glm::length(_measuredAcceleration) < MEASURED_ACCELERATION_CLOSE_TO_ZERO) { + _entity->setAcceleration(glm::vec3(0)); + } else { + _entity->setAcceleration(_entity->getGravity()); + } + if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); _sentPosition = bulletToGLM(worldTrans.getOrigin()); @@ -245,12 +251,13 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _sentMoving = false; } properties.setVelocity(_sentVelocity); - _sentAcceleration = bulletToGLM(_body->getGravity()); - properties.setGravity(_sentAcceleration); + _sentGravity = _entity->getGravity(); + properties.setGravity(_entity->getGravity()); + _sentAcceleration = _entity->getAcceleration(); + properties.setAcceleration(_sentAcceleration); properties.setAngularVelocity(_sentAngularVelocity); } - auto nodeList = DependencyManager::get(); QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 3d790ff7d4..852f2a96bd 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -57,6 +57,7 @@ ObjectMotionState::ObjectMotionState() : _sentRotation(), _sentVelocity(0.0f), _sentAngularVelocity(0.0f), + _sentGravity(0.0f), _sentAcceleration(0.0f), _lastSimulationStep(0), _lastVelocity(0.0f), @@ -174,7 +175,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) { // Else we measure the error between current and extrapolated transform (according to expected behavior // of remote EntitySimulation) and return true if the error is significant. - // NOTE: math in done the simulation-frame, which is NOT necessarily the same as the world-frame + // NOTE: math is done the simulation-frame, which is NOT necessarily the same as the world-frame // due to _worldOffset. // compute position error diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 9b5d6e7aa6..ad9ef861b9 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -138,6 +138,7 @@ protected: glm::quat _sentRotation;; glm::vec3 _sentVelocity; glm::vec3 _sentAngularVelocity; // radians per second + glm::vec3 _sentGravity; glm::vec3 _sentAcceleration; uint32_t _lastSimulationStep; From adfc82e1696305daf1b1fdffb532529c6041b94e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 15:10:34 -0700 Subject: [PATCH 154/401] remove commented-out code --- libraries/entities/src/EntityEditPacketSender.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index 478603dedf..e94725782d 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -36,15 +36,6 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityItemI unsigned char bufferOut[MAX_PACKET_SIZE]; int sizeOut = 0; - - //// XXX - // auto nodeList = DependencyManager::get(); - // QUuid myNodeID = nodeList->getSessionUUID(); - // QString x = properties.getSimulatorID() == myNodeID ? "me" : properties.getSimulatorID().toString(); - // qDebug() << "sending update:" << properties.simulatorIDChanged() << x; - //// XXX - - if (EntityItemProperties::encodeEntityEditPacket(type, modelID, properties, &bufferOut[0], _maxPacketSize, sizeOut)) { #ifdef WANT_DEBUG qCDebug(entities) << "calling queueOctreeEditMessage()..."; From e9d8c53f7544fabdd1ba062ee19bf1cc1099fab7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 15:18:05 -0700 Subject: [PATCH 155/401] undo dice testing hack --- examples/dice.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/dice.js b/examples/dice.js index 2b6d4d478e..b118a6b289 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -13,7 +13,7 @@ // var isDice = false; -var NUMBER_OF_DICE = 1; +var NUMBER_OF_DICE = 2; var dice = []; var DIE_SIZE = 0.20; From b3cb9fe9a402a777b5bda2557a15cf016829f242 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Apr 2015 15:33:41 -0700 Subject: [PATCH 156/401] fix comment some more --- libraries/physics/src/ObjectMotionState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 852f2a96bd..3d8e578056 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -175,7 +175,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) { // Else we measure the error between current and extrapolated transform (according to expected behavior // of remote EntitySimulation) and return true if the error is significant. - // NOTE: math is done the simulation-frame, which is NOT necessarily the same as the world-frame + // NOTE: math is done in the simulation-frame, which is NOT necessarily the same as the world-frame // due to _worldOffset. // compute position error From 16efa2a46fc850772b1723e502421afa1924954a Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 17 Apr 2015 16:58:29 -0700 Subject: [PATCH 157/401] Improving toggle visibility and loading behavior --- interface/resources/qml/AddressBarDialog.qml | 9 +- interface/resources/qml/CustomDialog.qml | 26 +++- interface/resources/qml/LoginDialog.qml | 6 + interface/resources/qml/Root.qml | 9 +- interface/resources/qml/TestDialog.qml | 10 +- interface/resources/qml/TestRoot.qml | 25 ++-- interface/resources/qml/componentCreation.js | 4 +- interface/src/Application.cpp | 4 +- interface/src/ui/AddressBarDialog.cpp | 7 +- libraries/render-utils/src/OffscreenUi.cpp | 133 +++++++++++++------ libraries/render-utils/src/OffscreenUi.h | 50 +++++-- tests/render-utils/src/main.cpp | 46 ++++--- 12 files changed, 231 insertions(+), 98 deletions(-) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 9508481309..ec1480928a 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -5,16 +5,21 @@ import QtQuick.Window 2.2 import QtQuick.Controls.Styles 1.3 CustomDialog { - id: dialog title: "Go to..." objectName: "AddressBarDialog" - SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } height: 128 width: 512 + destroyOnCloseButton: false onVisibleChanged: { if (!visible) { reset(); + } + } + + onEnabledChanged: { + if (enabled) { + addressLine.forceActiveFocus(); } } diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/CustomDialog.qml index a681612f2c..dd051566e3 100644 --- a/interface/resources/qml/CustomDialog.qml +++ b/interface/resources/qml/CustomDialog.qml @@ -12,7 +12,9 @@ Item { height: 256 scale: 0.0 enabled: false - visible: false + property int animationDuration: 400 + property bool destroyOnInvisible: false + property bool destroyOnCloseButton: true onEnabledChanged: { scale = enabled ? 1.0 : 0.0 @@ -22,14 +24,24 @@ Item { visible = (scale != 0.0); } - Component.onCompleted: { - scale = 1.0 + onVisibleChanged: { + if (!visible && destroyOnInvisible) { + console.log("Destroying closed component"); + destroy(); + } + } + + function close() { + if (destroyOnCloseButton) { + destroyOnInvisible = true + } + enabled = false; } Behavior on scale { NumberAnimation { //This specifies how long the animation takes - duration: 400 + duration: dialog.animationDuration //This selects an easing curve to interpolate with, the default is Easing.Linear easing.type: Easing.InOutBounce } @@ -81,8 +93,8 @@ Item { target: dialog minimumX: 0 minimumY: 0 - maximumX: dialog.parent.width - dialog.width - maximumY: dialog.parent.height - dialog.height + maximumX: dialog.parent ? dialog.parent.width - dialog.width : 0 + maximumY: dialog.parent ? dialog.parent.height - dialog.height : 0 } } Image { @@ -97,7 +109,7 @@ Item { MouseArea { anchors.fill: parent onClicked: { - dialog.destroy() + dialog.close(); } } } diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index e96309f625..be69b65ef7 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -18,6 +18,12 @@ CustomDialog { } } + onEnabledChanged: { + if (enabled) { + username.forceActiveFocus(); + } + } + function reset() { username.text = "" password.text = "" diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index f290a8b5ca..9422ef123d 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -1,14 +1,9 @@ +import Hifi 1.0 import QtQuick 2.3 -import "componentCreation.js" as Creator - -Item { +Root { id: root width: 1280 height: 720 - - function loadChild(url) { - Creator.createObject(root, url) - } } diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml index 69aad4cdc8..1fe8676bc6 100644 --- a/interface/resources/qml/TestDialog.qml +++ b/interface/resources/qml/TestDialog.qml @@ -5,12 +5,19 @@ import QtQuick.Dialogs 1.2 import QtQuick.Controls.Styles 1.3 CustomDialog { - title: "Test Dlg" + title: "Test Dialog" id: testDialog objectName: "TestDialog" width: 512 height: 512 + animationDuration: 200 + onEnabledChanged: { + if (enabled) { + edit.forceActiveFocus(); + } + } + Item { id: clientArea // The client area @@ -31,6 +38,7 @@ CustomDialog { CustomTextEdit { + id: edit anchors.left: parent.left anchors.leftMargin: 12 anchors.right: parent.right diff --git a/interface/resources/qml/TestRoot.qml b/interface/resources/qml/TestRoot.qml index a3ef5f8fe9..158c0b7a54 100644 --- a/interface/resources/qml/TestRoot.qml +++ b/interface/resources/qml/TestRoot.qml @@ -1,25 +1,34 @@ +import Hifi 1.0 import QtQuick 2.3 -import "componentCreation.js" as Creator - -Item { +Root { id: root width: 1280 height: 720 - function loadChild(url) { - Creator.createObject(root, url) + CustomButton { + id: messageBox + anchors.right: createDialog.left + anchors.rightMargin: 24 + anchors.bottom: parent.bottom + anchors.bottomMargin: 24 + text: "Message" + onClicked: { + console.log("Foo") + root.information("a") + console.log("Bar") + } } - CustomButton { + id: createDialog anchors.right: parent.right anchors.rightMargin: 24 anchors.bottom: parent.bottom anchors.bottomMargin: 24 - text: "Test" + text: "Create" onClicked: { - loadChild("TestDialog.qml"); + root.loadChild("TestDialog.qml"); } } } diff --git a/interface/resources/qml/componentCreation.js b/interface/resources/qml/componentCreation.js index 6e6469adfb..15a828d6f8 100644 --- a/interface/resources/qml/componentCreation.js +++ b/interface/resources/qml/componentCreation.js @@ -18,10 +18,12 @@ function finishCreation() { // Error Handling console.log("Error creating object"); } else { - instance.focus = true; + instance.enabled = true } } else if (component.status == Component.Error) { // Error Handling console.log("Error loading component:", component.errorString()); + } else { + console.log("Unknown component status: " + component.status); } } \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d0ae13ce21..18a325080c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -754,8 +754,8 @@ void Application::initializeUi() { offscreenUi->create(_glWidget->context()->contextHandle()); offscreenUi->resize(_glWidget->size()); offscreenUi->setProxyWindow(_window->windowHandle()); - auto rootQml = PathUtils::resourcesPath() + "qml/Root.qml"; - offscreenUi->loadQml(QUrl::fromLocalFile(rootQml)); + offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); + offscreenUi->load("Root.qml"); offscreenUi->setMouseTranslator([this](const QPointF& p){ if (OculusManager::isConnected()) { glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p)); diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index befeb40cce..5ef9b930ac 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -35,14 +35,13 @@ void AddressBarDialog::loadAddress(const QString & address) { } } -// TODO port to a QML based message box void AddressBarDialog::displayAddressOfflineMessage() { - QMessageBox::information(nullptr, "Address offline", + OffscreenUi::information("Address offline", "That user or place is currently offline."); } -// TODO port to a QML based message box void AddressBarDialog::displayAddressNotFoundMessage() { - QMessageBox::information(nullptr, "Address not found", + OffscreenUi::information("Address not found", "There is no address information for that user or place."); } + diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 68bb3eeacd..d9dd030758 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -12,8 +12,29 @@ #include #include #include +#include + +class OffscreenUiRoot : public QQuickItem { + Q_OBJECT +public: + + OffscreenUiRoot(QQuickItem *parent = 0); + Q_INVOKABLE void information(const QString & title, const QString & text); + Q_INVOKABLE void loadChild(const QUrl & url) { + DependencyManager::get()->load(url); + } +}; + + +OffscreenUiRoot::OffscreenUiRoot(QQuickItem *parent) : QQuickItem(parent) { +} + +void OffscreenUiRoot::information(const QString & title, const QString & text = "foo") { + OffscreenUi::information(title, text); +} OffscreenUi::OffscreenUi() { + ::qmlRegisterType("Hifi", 1, 0, "Root"); } OffscreenUi::~OffscreenUi() { @@ -62,19 +83,18 @@ void OffscreenUi::create(QOpenGLContext * shareContext) { // is needed too). connect(_renderControl, &QQuickRenderControl::renderRequested, this, &OffscreenUi::requestRender); connect(_renderControl, &QQuickRenderControl::sceneChanged, this, &OffscreenUi::requestUpdate); - connect(_quickWindow, &QQuickWindow::focusObjectChanged, this, [this](QObject *object){ - OffscreenUi * p = this; - qDebug() << "Focus changed to " << object; - }); _quickWindow->focusObject(); _qmlComponent = new QQmlComponent(_qmlEngine); - // Initialize the render control and our OpenGL resources. makeCurrent(); _renderControl->initialize(&_context); } +void OffscreenUi::addImportPath(const QString & path) { + _qmlEngine->addImportPath(path); +} + void OffscreenUi::resize(const QSize & newSize) { makeCurrent(); @@ -102,10 +122,15 @@ QQmlContext * OffscreenUi::qmlContext() { return QQmlEngine::contextForObject(_rootItem); } -void OffscreenUi::loadQml(const QUrl & qmlSource, std::function f) { +void OffscreenUi::setBaseUrl(const QUrl & baseUrl) { + _qmlEngine->setBaseUrl(baseUrl); +} + +void OffscreenUi::load(const QUrl & qmlSource, std::function f) { + qDebug() << "Loading QML from URL " << qmlSource; _qmlComponent->loadUrl(qmlSource); if (_qmlComponent->isLoading()) - connect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad); + connect(_qmlComponent, &QQmlComponent::statusChanged, this, [] {}); else finishQmlLoad(); } @@ -131,30 +156,43 @@ void OffscreenUi::finishQmlLoad() { return; } - QObject *rootObject = _qmlComponent->create(); + QObject *newObject = _qmlComponent->create(); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); foreach(const QQmlError &error, errorList) qWarning() << error.url() << error.line() << error; - qFatal("Unable to finish loading QML"); + if (!_rootItem) { + qFatal("Unable to finish loading QML root"); + } return; } - _rootItem = qobject_cast(rootObject); - if (!_rootItem) { + QQuickItem * newItem = qobject_cast(newObject); + if (!newItem) { qWarning("run: Not a QQuickItem"); - delete rootObject; - qFatal("Unable to find root QQuickItem"); + delete newObject; + if (!_rootItem) { + qFatal("Unable to find root QQuickItem"); + } return; } - // Make sure we can assign focus to the root item (critical for + // Make sure we make items focusable (critical for // supporting keyboard shortcuts) - _rootItem->setFlag(QQuickItem::ItemIsFocusScope, true); - // The root item is ready. Associate it with the window. - _rootItem->setParentItem(_quickWindow->contentItem()); - _rootItem->setSize(_quickWindow->renderTargetSize()); - qDebug() << "Finished setting up QML provider"; + newItem->setFlag(QQuickItem::ItemIsFocusScope, true); + + if (!_rootItem) { + // The root item is ready. Associate it with the window. + _rootItem = newItem; + _rootItem->setParentItem(_quickWindow->contentItem()); + _rootItem->setSize(_quickWindow->renderTargetSize()); + } else { + // Allow child windows to be destroyed from JS + QQmlEngine::setObjectOwnership(newItem, QQmlEngine::JavaScriptOwnership); + newItem->setParent(_rootItem); + newItem->setParentItem(_rootItem); + newItem->setEnabled(true); + } } @@ -240,7 +278,7 @@ bool OffscreenUi::eventFilter(QObject * dest, QEvent * e) { case QEvent::KeyRelease: { e->ignore(); - if (QApplication::sendEvent(_quickWindow, e)) { + if (QCoreApplication::sendEvent(_quickWindow, e)) { return e->isAccepted(); } } @@ -302,38 +340,55 @@ void OffscreenUi::setProxyWindow(QWindow * window) { void OffscreenUi::show(const QUrl & url, const QString & name) { QQuickItem * item = _rootItem->findChild(name); + // First load? if (nullptr == item) { load(url); - item = _rootItem->findChild(name); - } - - if (nullptr != item) { - item->setEnabled(true); + return; } + item->setEnabled(true); } void OffscreenUi::toggle(const QUrl & url, const QString & name) { QQuickItem * item = _rootItem->findChild(name); // First load? if (nullptr == item) { - show(url, name); + load(url); return; } + item->setEnabled(!item->isEnabled()); +} - // Toggle the visibity AND the enabled flag (otherwise invisible - // dialogs can still swallow keyboard input) - bool newFlag = !item->isEnabled(); - item->setEnabled(newFlag); +void OffscreenUi::messageBox(const QString &title, const QString &text, + QMessageBox::Icon icon, + QMessageBox::StandardButtons buttons, + ButtonCallback f) { +} + +void OffscreenUi::information(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons, + ButtonCallback callback) { + callback(QMessageBox::information(nullptr, title, text, buttons)); +} + +void OffscreenUi::question(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons, + ButtonCallback callback) { + callback(QMessageBox::question(nullptr, title, text, buttons)); +} + +void OffscreenUi::warning(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons, + ButtonCallback callback) { + callback(QMessageBox::warning(nullptr, title, text, buttons)); +} + +void OffscreenUi::critical(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons, + ButtonCallback callback) { + callback(QMessageBox::critical(nullptr, title, text, buttons)); } -void OffscreenUi::load(const QUrl & url) { - qDebug() << "Loading from url: " << url; - QVariant returnedValue; - QVariant msg = url; - QMetaObject::invokeMethod(_rootItem, "loadChild", - Q_RETURN_ARG(QVariant, returnedValue), - Q_ARG(QVariant, msg)); - qDebug() << "QML function returned:" << returnedValue.toString(); -} +OffscreenUi::ButtonCallback OffscreenUi::NO_OP_CALLBACK = [](QMessageBox::StandardButton) {}; +#include "OffscreenUi.moc" \ No newline at end of file diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index b9cf5d2226..73c022e4be 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -12,26 +12,25 @@ #ifndef hifi_OffscreenUi_h #define hifi_OffscreenUi_h - -#include -#include #include #include #include #include #include #include -#include -#include -#include #include -#include +#include + #include #include + +#include +#include #include -#include "FboCache.h" #include "OffscreenGlCanvas.h" +#include "FboCache.h" +#include class OffscreenUi : public OffscreenGlCanvas, public Dependency { @@ -60,11 +59,14 @@ public: virtual ~OffscreenUi(); void create(QOpenGLContext * context); void resize(const QSize & size); - void loadQml(const QUrl & qmlSource, std::function f = [](QQmlContext*) {}); - void load(const QUrl & url); + void load(const QUrl & qmlSource, std::function f = [](QQmlContext*) {}); + void load(const QString & qmlSourceFile, std::function f = [](QQmlContext*) {}) { + load(QUrl(qmlSourceFile), f); + } void show(const QUrl & url, const QString & name); void toggle(const QUrl & url, const QString & name); - + void setBaseUrl(const QUrl & baseUrl); + void addImportPath(const QString & path); QQmlContext * qmlContext(); void pause(); @@ -77,6 +79,32 @@ public: _mouseTranslator = mt; } + + // Messagebox replacement functions + using ButtonCallback = std::function < void(QMessageBox::StandardButton) >; + static ButtonCallback NO_OP_CALLBACK; + + static void messageBox(const QString &title, const QString &text, + QMessageBox::Icon icon, + QMessageBox::StandardButtons buttons, + ButtonCallback f); + + static void information(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + ButtonCallback callback = NO_OP_CALLBACK); + + static void question(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), + ButtonCallback callback = [](QMessageBox::StandardButton) {}); + + static void warning(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + ButtonCallback callback = [](QMessageBox::StandardButton) {}); + + static void critical(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + ButtonCallback callback = [](QMessageBox::StandardButton) {}); + protected: private slots: diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 556fef0561..eb61fd1f72 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -69,6 +69,17 @@ public: } }; + +const QString & getQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/qml/")) + "/"; + qDebug() << "Qml Path: " << dir; + } + return dir; +} // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { Q_OBJECT @@ -77,7 +88,6 @@ class QTestWindow : public QWindow { QSize _size; TextRenderer* _textRenderer[4]; RateCounter fps; - OffscreenUi _offscreenUi; int testQmlTexture{ 0 }; //ProgramPtr _planeProgam; //ShapeWrapperPtr _planeShape; @@ -90,11 +100,12 @@ protected: private: void resizeWindow(const QSize & size) { _size = size; - _offscreenUi.resize(_size); + DependencyManager::get()->resize(_size); } public: QTestWindow() { + DependencyManager::set(); setSurfaceType(QSurface::OpenGLSurface); QSurfaceFormat format; @@ -154,30 +165,30 @@ public: glClearColor(0.2f, 0.2f, 0.2f, 1); glDisable(GL_DEPTH_TEST); - _offscreenUi.create(_context); + auto offscreenUi = DependencyManager::get(); + offscreenUi->create(_context); // FIXME, need to switch to a QWindow for mouse and keyboard input to work - _offscreenUi.setProxyWindow(this); + offscreenUi->setProxyWindow(this); // "#0e7077" setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); - QApplication::applicationDirPath(); - QDir path(__FILE__); - path.cdUp(); - static const QString f(path.cleanPath(path.absoluteFilePath("../../../interface/resources/qml/TestRoot.qml"))); + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); + offscreenUi->load(QUrl("TestRoot.qml")); + offscreenUi->addImportPath(getQmlDir()); + offscreenUi->addImportPath("."); - _offscreenUi.loadQml(QUrl::fromLocalFile(f)); - connect(&_offscreenUi, &OffscreenUi::textureUpdated, this, [&](int textureId) { - _offscreenUi.lockTexture(textureId); + connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { + offscreenUi->lockTexture(textureId); assert(!glGetError()); GLuint oldTexture = testQmlTexture; testQmlTexture = textureId; if (oldTexture) { - _offscreenUi.releaseTexture(oldTexture); + offscreenUi->releaseTexture(oldTexture); } }); - installEventFilter(&_offscreenUi); - _offscreenUi.resume(); + installEventFilter(offscreenUi.data()); + offscreenUi->resume(); } virtual ~QTestWindow() { @@ -197,8 +208,10 @@ protected: void keyPressEvent(QKeyEvent *event) { switch (event->key()) { - case Qt::Key_Slash: - _offscreenUi.toggle(QString("TestDialog.qml"), "TestDialog"); + case Qt::Key_L: + if (event->modifiers() & Qt::CTRL) { + DependencyManager::get()->toggle(QString("TestDialog.qml"), "TestDialog"); + } break; } QWindow::keyPressEvent(event); @@ -319,6 +332,7 @@ int main(int argc, char** argv) { QApplication app(argc, argv); //QLoggingCategory::setFilterRules("qt.quick.mouse.debug = true"); QTestWindow window; + QTimer timer; timer.setInterval(1); app.connect(&timer, &QTimer::timeout, &app, [&] { From 8d23bf874f325cdcd375e5fe6e86d62a26f36858 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 17 Apr 2015 17:43:54 -0700 Subject: [PATCH 158/401] Enable resizable dialogs --- interface/resources/qml/CustomDialog.qml | 34 ++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/CustomDialog.qml index dd051566e3..1e0351af4f 100644 --- a/interface/resources/qml/CustomDialog.qml +++ b/interface/resources/qml/CustomDialog.qml @@ -15,6 +15,10 @@ Item { property int animationDuration: 400 property bool destroyOnInvisible: false property bool destroyOnCloseButton: true + property bool resizable: false + property int minX: 256 + property int minY: 256 + clip: true onEnabledChanged: { scale = enabled ? 1.0 : 0.0 @@ -37,6 +41,11 @@ Item { } enabled = false; } + + function deltaSize(dx, dy) { + width = Math.max(width + dx, minX) + height = Math.max(height + dy, minY) + } Behavior on scale { NumberAnimation { @@ -82,8 +91,6 @@ Item { MouseArea { id: titleDrag - property int startX - property int startY anchors.right: closeButton.left anchors.bottom: parent.bottom anchors.left: parent.left @@ -127,6 +134,29 @@ Item { anchors.rightMargin: 0 anchors.left: parent.left anchors.leftMargin: 0 + clip: true } // client border } // window border + + MouseArea { + id: sizeDrag + property int startX + property int startY + anchors.right: parent.right + anchors.bottom: parent.bottom + width: 16 + height: 16 + hoverEnabled: true + onPressed: { + startX = mouseX + startY = mouseY + } + onPositionChanged: { + if (pressed && dialog.resizable) { + dialog.deltaSize((mouseX - startX), (mouseY - startY)) + startX = mouseX + startY = mouseY + } + } + } } From 687ca7fee58bb4dfe780ed51698d132d63630efb Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 17 Apr 2015 19:00:40 -0700 Subject: [PATCH 159/401] Update the cookies.js to be able to edit and test direction and color, validate that the SunDirection and color and on/off is working --- examples/example/misc/sunLightExample.js | 15 +- examples/utilities/tools/cookies.js | 422 ++++++++++++++---- libraries/model/src/model/Light.h | 2 +- libraries/model/src/model/Stage.h | 43 +- .../src/SceneScriptingInterface.cpp | 4 +- .../src/SceneScriptingInterface.h | 4 +- 6 files changed, 364 insertions(+), 126 deletions(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index 2fe546cd0e..e4826dcfeb 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -41,7 +41,8 @@ panel.newSlider("Year Time", 0, 364, ); panel.newSlider("Day Time", 0, 24, - function(value) { Scene.setStageDayTime(value); }, + + function(value) { Scene.setStageDayTime(value); panel.update("Light Direction"); }, function() { return Scene.getStageDayTime(); }, function(value) { var hour = Math.floor(value); @@ -78,6 +79,12 @@ panel.newCheckbox("Enable Earth Sun Model", function(value) { return (value); } ); +panel.newDirectionBox("Light Direction", + function(value) { Scene.setSunDirection(value); }, + function() { return Scene.getSunDirection(); }, + function(value) { return value.x.toFixed(2) + "," + value.y.toFixed(2) + "," + value.z.toFixed(2); } +); + panel.newSlider("Light Intensity", 0.0, 5, function(value) { Scene.setSunIntensity(value); }, function() { return Scene.getSunIntensity(); }, @@ -90,6 +97,12 @@ panel.newSlider("Ambient Light Intensity", 0.0, 1.0, function(value) { return (value).toFixed(2); } ); +panel.newColorBox("Light Color", + function(value) { Scene.setSunColor(value); }, + function() { return Scene.getSunColor(); }, + function(value) { return (value); } // "(" + value.x + "," = value.y + "," + value.z + ")"; } +); + Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); }); Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); }); Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 49446be234..0182bf8db0 100755 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -12,6 +12,129 @@ // The Slider class Slider = function(x,y,width,thumbSize) { + this.background = Overlays.addOverlay("text", { + backgroundColor: { red: 125, green: 125, blue: 255 }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + + this.thumbSize = thumbSize; + this.thumbHalfSize = 0.5 * thumbSize; + + this.minThumbX = x + this.thumbHalfSize; + this.maxThumbX = x + width - this.thumbHalfSize; + this.thumbX = this.minThumbX; + + this.minValue = 0.0; + this.maxValue = 1.0; + + this.clickOffsetX = 0; + this.isMoving = false; + + this.updateThumb = function() { + thumbTruePos = this.thumbX - 0.5 * this.thumbSize; + Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); + }; + + this.isClickableOverlayItem = function(item) { + return (item == this.thumb) || (item == this.background); + }; + + this.onMouseMoveEvent = function(event) { + if (this.isMoving) { + newThumbX = event.x - this.clickOffsetX; + if (newThumbX < this.minThumbX) { + newThumbX = this.minThumbX; + } + if (newThumbX > this.maxThumbX) { + newThumbX = this.maxThumbX; + } + this.thumbX = newThumbX; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + + this.onMousePressEvent = function(event, clickedOverlay) { + if (!this.isClickableOverlayItem(clickedOverlay)) { + this.isMoving = false; + return; + } + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + + }; + + this.onMouseReleaseEvent = function(event) { + this.isMoving = false; + }; + + // Public members: + + this.setNormalizedValue = function(value) { + if (value < 0.0) { + this.thumbX = this.minThumbX; + } else if (value > 1.0) { + this.thumbX = this.maxThumbX; + } else { + this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; + } + this.updateThumb(); + }; + this.getNormalizedValue = function() { + return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); + }; + + this.setValue = function(value) { + var normValue = (value - this.minValue) / (this.maxValue - this.minValue); + this.setNormalizedValue(normValue); + }; + + this.getValue = function() { + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; + + this.onValueChanged = function(value) {}; + + this.destroy = function() { + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + }; + + this.setThumbColor = function(color) { + Overlays.editOverlay(this.thumb, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); + }; + this.setBackgroundColor = function(color) { + Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); + }; +} + +// The Checkbox class +Checkbox = function(x,y,width,thumbSize) { this.thumb = Overlays.addOverlay("text", { backgroundColor: { red: 255, green: 255, blue: 255 }, @@ -52,6 +175,10 @@ Slider = function(x,y,width,thumbSize) { Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); }; + this.isClickableOverlayItem = function(item) { + return item == this.background; + }; + this.onMouseMoveEvent = function(event) { if (this.isMoving) { newThumbX = event.x - this.clickOffsetX; @@ -67,7 +194,11 @@ Slider = function(x,y,width,thumbSize) { } }; - this.onMousePressEvent = function(event) { + this.onMousePressEvent = function(event, clickedOverlay) { + if (this.background != clickedOverlay) { + this.isMoving = false; + return; + } this.isMoving = true; var clickOffset = event.x - this.thumbX; if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { @@ -118,112 +249,166 @@ Slider = function(x,y,width,thumbSize) { }; } -// The Checkbox class -Checkbox = function(x,y,width,thumbSize) { +// The ColorBox class +ColorBox = function(x,y,width,thumbSize) { + var self = this; + + var slideHeight = thumbSize / 3; + var sliderWidth = width; + this.red = new Slider(x, y, width, slideHeight); + this.green = new Slider(x, y + slideHeight, width, slideHeight); + this.blue = new Slider(x, y + 2 * slideHeight, width, slideHeight); + this.red.setBackgroundColor({x: 1, y: 0, z: 0}); + this.green.setBackgroundColor({x: 0, y: 1, z: 0}); + this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 125, green: 125, blue: 255 }, - x: x, - y: y, - width: width, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); - - this.thumbSize = thumbSize; - this.thumbHalfSize = 0.5 * thumbSize; - - this.minThumbX = x + this.thumbHalfSize; - this.maxThumbX = x + width - this.thumbHalfSize; - this.thumbX = this.minThumbX; - - this.minValue = 0.0; - this.maxValue = 1.0; - - this.clickOffsetX = 0; - this.isMoving = false; - - this.updateThumb = function() { - thumbTruePos = this.thumbX - 0.5 * this.thumbSize; - Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); + this.isClickableOverlayItem = function(item) { + return this.red.isClickableOverlayItem(item) + || this.green.isClickableOverlayItem(item) + || this.blue.isClickableOverlayItem(item); }; this.onMouseMoveEvent = function(event) { - if (this.isMoving) { - newThumbX = event.x - this.clickOffsetX; - if (newThumbX < this.minThumbX) { - newThumbX = this.minThumbX; - } - if (newThumbX > this.maxThumbX) { - newThumbX = this.maxThumbX; - } - this.thumbX = newThumbX; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } + this.red.onMouseMoveEvent(event); + this.green.onMouseMoveEvent(event); + this.blue.onMouseMoveEvent(event); }; - this.onMousePressEvent = function(event) { - this.isMoving = true; - var clickOffset = event.x - this.thumbX; - if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { - this.clickOffsetX = clickOffset; - } else { - this.clickOffsetX = 0; - this.thumbX = event.x; - this.updateThumb(); - this.onValueChanged(this.getValue()); + this.onMousePressEvent = function(event, clickedOverlay) { + this.red.onMousePressEvent(event, clickedOverlay); + if (this.red.isMoving) { + return; } + this.green.onMousePressEvent(event, clickedOverlay); + if (this.green.isMoving) { + return; + } + + this.blue.onMousePressEvent(event, clickedOverlay); }; this.onMouseReleaseEvent = function(event) { - this.isMoving = false; + this.red.onMouseReleaseEvent(event); + this.green.onMouseReleaseEvent(event); + this.blue.onMouseReleaseEvent(event); + }; + + this.setterFromWidget = function(value) { + var color = self.getValue(); + self.onValueChanged(color); + self.updateRGBSliders(color); + }; + + this.red.onValueChanged = this.setterFromWidget; + this.green.onValueChanged = this.setterFromWidget; + this.blue.onValueChanged = this.setterFromWidget; + + this.updateRGBSliders = function(color) { + this.red.setThumbColor({x: color.x, y: 0, z: 0}); + this.green.setThumbColor({x: 0, y: color.y, z: 0}); + this.blue.setThumbColor({x: 0, y: 0, z: color.z}); }; // Public members: - - this.setNormalizedValue = function(value) { - if (value < 0.0) { - this.thumbX = this.minThumbX; - } else if (value > 1.0) { - this.thumbX = this.maxThumbX; - } else { - this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; - } - this.updateThumb(); - }; - this.getNormalizedValue = function() { - return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); - }; - this.setValue = function(value) { - var normValue = (value - this.minValue) / (this.maxValue - this.minValue); - this.setNormalizedValue(normValue); + this.red.setValue(value.x); + this.green.setValue(value.y); + this.blue.setValue(value.z); + this.updateRGBSliders(value); }; this.getValue = function() { - return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; + return value; + }; + + this.destroy = function() { + this.red.destroy(); + this.green.destroy(); + this.blue.destroy(); }; this.onValueChanged = function(value) {}; +} + +// The DirectionBox class +DirectionBox = function(x,y,width,thumbSize) { + var self = this; + + var slideHeight = thumbSize / 2; + var sliderWidth = width; + this.yaw = new Slider(x, y, width, slideHeight); + this.pitch = new Slider(x, y + slideHeight, width, slideHeight); + + this.yaw.setThumbColor({x: 1, y: 0, z: 0}); + this.yaw.minValue = -180; + this.yaw.maxValue = +180; + + this.pitch.setThumbColor({x: 0, y: 0, z: 1}); + this.pitch.minValue = -1; + this.pitch.maxValue = +1; + + this.isClickableOverlayItem = function(item) { + return this.yaw.isClickableOverlayItem(item) + || this.pitch.isClickableOverlayItem(item); + }; + + this.onMouseMoveEvent = function(event) { + this.yaw.onMouseMoveEvent(event); + this.pitch.onMouseMoveEvent(event); + }; + + this.onMousePressEvent = function(event, clickedOverlay) { + this.yaw.onMousePressEvent(event, clickedOverlay); + if (this.yaw.isMoving) { + return; + } + this.pitch.onMousePressEvent(event, clickedOverlay); + }; + + this.onMouseReleaseEvent = function(event) { + this.yaw.onMouseReleaseEvent(event); + this.pitch.onMouseReleaseEvent(event); + }; + + this.setterFromWidget = function(value) { + var yawPitch = self.getValue(); + self.onValueChanged(yawPitch); + }; + + this.yaw.onValueChanged = this.setterFromWidget; + this.pitch.onValueChanged = this.setterFromWidget; + + // Public members: + this.setValue = function(direction) { + var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); + if (flatXZ > 0.0) { + var flatX = direction.x / flatXZ; + var flatZ = direction.z / flatXZ; + var yaw = Math.acos(flatX) * 180 / Math.PI; + if (flatZ < 0) { + yaw = -yaw; + } + this.yaw.setValue(yaw); + } + this.pitch.setValue(direction.y); + }; + + this.getValue = function() { + var dirZ = this.pitch.getValue(); + var yaw = this.yaw.getValue() * Math.PI / 180; + var cosY = Math.sqrt(1 - dirZ*dirZ); + var value = {x:cosY * Math.cos(yaw), y:dirZ, z: cosY * Math.sin(yaw)}; + return value; + }; this.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); + this.yaw.destroy(); + this.pitch.destroy(); }; + + this.onValueChanged = function(value) {}; } var textFontSize = 16; @@ -274,7 +459,12 @@ function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, }; this.setterFromWidget = function(value) { setter(value); - Overlays.editOverlay(this.value, {text: this.displayer(getter())}); + // ANd loop back the value after the final setter has been called + var value = getter(); + if (this.widget) { + this.widget.setValue(value); + } + Overlays.editOverlay(this.value, {text: this.displayer(value)}); }; @@ -326,9 +516,9 @@ Panel = function(x, y) { for (var i in this.items) { var widget = this.items[i].widget; - if (clickedOverlay == widget.background) { + if (widget.isClickableOverlayItem(clickedOverlay)) { this.activeWidget = widget; - this.activeWidget.onMousePressEvent(event); + this.activeWidget.onMousePressEvent(event, clickedOverlay); // print("clicked... widget=" + i); break; } @@ -344,36 +534,63 @@ Panel = function(x, y) { this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { - var sliderItem = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); slider.minValue = minValue; slider.maxValue = maxValue; - slider.onValueChanged = function(value) { sliderItem.setterFromWidget(value); }; - sliderItem.widget = slider; - sliderItem.setter(getValue()); - this.items[name] = sliderItem; + item.widget = slider; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; this.nextY += rawYDelta; // print("created Item... slider=" + name); }; this.newCheckbox = function(name, setValue, getValue, displayValue) { - var checkboxItem = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight); - checkbox.onValueChanged = function(value) { checkboxItem.setterFromWidget(value); }; - - - checkboxItem.widget = checkbox; - checkboxItem.setter(getValue()); - this.items[name] = checkboxItem; + + item.widget = checkbox; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; this.nextY += rawYDelta; // print("created Item... slider=" + name); }; + this.newColorBox = function(name, setValue, getValue, displayValue) { + + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + + item.widget = colorBox; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; + this.nextY += rawYDelta; + // print("created Item... colorBox=" + name); + }; + + this.newDirectionBox= function(name, setValue, getValue, displayValue) { + + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var directionBox = new DirectionBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + + item.widget = directionBox; + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + item.setter(getValue()); + this.items[name] = item; + this.nextY += rawYDelta; + // print("created Item... directionBox=" + name); + }; + this.destroy = function() { for (var i in this.items) { this.items[i].destroy(); @@ -395,6 +612,15 @@ Panel = function(x, y) { } return null; } + + this.update = function(name) { + var item = this.items[name]; + if (item != null) { + return item.setter(item.getter()); + } + return null; + } + }; diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 6b9371a0ee..30e3a8edad 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -265,7 +265,7 @@ public: Vec4 _spot{0.0f, 0.0f, 0.0f, 3.0f}; Vec4 _shadow{0.0f}; - Vec4 _control{0.0f}; + Vec4 _control{0.0f, 0.0f, 0.0f, 0.0f}; Schema() {} }; diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 968d50587a..eca290b852 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -177,48 +177,47 @@ typedef QSharedPointer< Skybox > SkyboxPointer; // Sun sky stage generates the rendering primitives to display a scene realistically // at the specified location and time around earth -class SunSkyStage : public QObject { - Q_OBJECT +class SunSkyStage { public: SunSkyStage(); ~SunSkyStage(); // time of the day (local to the position) expressed in decimal hour in the range [0.0, 24.0] - Q_INVOKABLE void setDayTime(float hour); - Q_INVOKABLE float getDayTime() const { return _dayTime; } + void setDayTime(float hour); + float getDayTime() const { return _dayTime; } // time of the year expressed in day in the range [0, 365] - Q_INVOKABLE void setYearTime(unsigned int day); - Q_INVOKABLE unsigned int getYearTime() const { return _yearTime; } + void setYearTime(unsigned int day); + unsigned int getYearTime() const { return _yearTime; } // Origin orientation used to modify the cardinal axis alignement used. // THe default is north along +Z axis and west along +X axis. this orientation gets added // to the transform stack producing the sun light direction. - Q_INVOKABLE void setOriginOrientation(const Quat& orientation); - Q_INVOKABLE const Quat& getOriginOrientation() const { return _earthSunModel.getSurfaceOrientation(); } + void setOriginOrientation(const Quat& orientation); + const Quat& getOriginOrientation() const { return _earthSunModel.getSurfaceOrientation(); } // Location used to define the sun & sky is a longitude and latitude [rad] and a earth surface altitude [km] - Q_INVOKABLE void setOriginLocation(float longitude, float latitude, float surfaceAltitude); - Q_INVOKABLE float getOriginLatitude() const { return _earthSunModel.getLatitude(); } - Q_INVOKABLE float getOriginLongitude() const { return _earthSunModel.getLongitude(); } - Q_INVOKABLE float getOriginSurfaceAltitude() const { return _earthSunModel.getAltitude(); } + void setOriginLocation(float longitude, float latitude, float surfaceAltitude); + float getOriginLatitude() const { return _earthSunModel.getLatitude(); } + float getOriginLongitude() const { return _earthSunModel.getLongitude(); } + float getOriginSurfaceAltitude() const { return _earthSunModel.getAltitude(); } // Enable / disable the effect of the time and location on the sun direction and color - Q_INVOKABLE void setEarthSunModelEnable(bool isEnabled); - Q_INVOKABLE bool isEarthSunModelEnabled() const { return _earthSunModelEnable; } + void setEarthSunModelEnable(bool isEnabled); + bool isEarthSunModelEnabled() const { return _earthSunModelEnable; } // Sun properties - Q_INVOKABLE void setSunColor(const Vec3& color); - Q_INVOKABLE const Vec3& getSunColor() const { return getSunLight()->getColor(); } - Q_INVOKABLE void setSunIntensity(float intensity); - Q_INVOKABLE float getSunIntensity() const { return getSunLight()->getIntensity(); } - Q_INVOKABLE void setSunAmbientIntensity(float intensity); - Q_INVOKABLE float getSunAmbientIntensity() const { return getSunLight()->getAmbientIntensity(); } + void setSunColor(const Vec3& color); + const Vec3& getSunColor() const { return getSunLight()->getColor(); } + void setSunIntensity(float intensity); + float getSunIntensity() const { return getSunLight()->getIntensity(); } + void setSunAmbientIntensity(float intensity); + float getSunAmbientIntensity() const { return getSunLight()->getAmbientIntensity(); } // The sun direction is expressed in the world space - Q_INVOKABLE void setSunDirection(const Vec3& direction); - Q_INVOKABLE const Vec3& getSunDirection() const { return getSunLight()->getDirection(); } + void setSunDirection(const Vec3& direction); + const Vec3& getSunDirection() const { return getSunLight()->getDirection(); } LightPointer getSunLight() const { valid(); return _sunLight; } AtmospherePointer getAtmosphere() const { valid(); return _atmosphere; } diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 0f3818317e..557938c78a 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -50,7 +50,7 @@ void SceneScriptingInterface::setSunColor(const glm::vec3& color) { _skyStage->setSunColor(color); } -const glm::vec3& SceneScriptingInterface::getSunColor() const { +glm::vec3 SceneScriptingInterface::getSunColor() const { return _skyStage->getSunColor(); } @@ -74,7 +74,7 @@ void SceneScriptingInterface::setSunDirection(const glm::vec3& direction) { _skyStage->setSunDirection(direction); } -const glm::vec3& SceneScriptingInterface::getSunDirection() const { +glm::vec3 SceneScriptingInterface::getSunDirection() const { return _skyStage->getSunDirection(); } diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 83f5a44bb7..e847b7ff68 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -43,7 +43,7 @@ public: Q_INVOKABLE void setSunColor(const glm::vec3& color); - Q_INVOKABLE const glm::vec3& getSunColor() const; + Q_INVOKABLE glm::vec3 getSunColor() const; Q_INVOKABLE void setSunIntensity(float intensity); Q_INVOKABLE float getSunIntensity() const; Q_INVOKABLE void setSunAmbientIntensity(float intensity); @@ -52,7 +52,7 @@ public: // Only valid if stage Earth Sun model is disabled Q_INVOKABLE void setSunDirection(const glm::vec3& direction); - Q_INVOKABLE const glm::vec3& getSunDirection() const; + Q_INVOKABLE glm::vec3 getSunDirection() const; From 8268dc95ac58e1429167ef367232f02e20b71a0a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 20 Apr 2015 10:28:17 -0700 Subject: [PATCH 160/401] Include DDE reset in sensors reset --- interface/src/Application.cpp | 1 - interface/src/Menu.cpp | 5 ----- interface/src/Menu.h | 1 - interface/src/devices/DdeFaceTracker.cpp | 6 +++++- interface/src/devices/DdeFaceTracker.h | 3 +-- 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0227003cb1..7741faad68 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1750,7 +1750,6 @@ void Application::setActiveFaceTracker() { #ifdef HAVE_DDE bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression); Menu::getInstance()->getActionForOption(MenuOption::DDEFiltering)->setVisible(isUsingDDE); - Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE); DependencyManager::get()->setEnabled(isUsingDDE); #endif #ifdef HAVE_VISAGE diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b07d122aee..c6dceb2ee5 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -388,11 +388,6 @@ Menu::Menu() { faceTrackingMenu->addSeparator(); QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFiltering, 0, true); ddeFiltering->setVisible(false); - QAction* ddeFaceTrackerReset = addActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::ResetDDETracking, - Qt::CTRL | Qt::Key_Apostrophe, - DependencyManager::get().data(), SLOT(resetTracking())); - ddeFaceTrackerReset->setVisible(false); - faceTrackingMenu->addAction(ddeFaceTrackerReset); #endif addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3d10d20f1b..58efc1b4da 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -223,7 +223,6 @@ namespace MenuOption { const QString RenderAmbientLight8 = "CAMPUS_SUNSET"; const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET"; const QString ResetAvatarSize = "Reset Avatar Size"; - const QString ResetDDETracking = "Reset DDE Tracking"; const QString ResetSensors = "Reset Sensors"; const QString RunningScripts = "Running Scripts"; const QString RunTimingTests = "Run Timing Tests"; diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 50601421c2..c4f22a31a9 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -222,10 +222,14 @@ void DdeFaceTracker::processFinished(int exitCode, QProcess::ExitStatus exitStat } } -void DdeFaceTracker::resetTracking() { +void DdeFaceTracker::reset() { + _reset = true; + qDebug() << "[Info] Reset DDE Tracking"; const char* DDE_RESET_COMMAND = "reset"; _udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort); + + _reset = true; } bool DdeFaceTracker::isActive() const { diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index aa3e9f3b81..506e2974b6 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -28,7 +28,7 @@ class DdeFaceTracker : public FaceTracker, public Dependency { SINGLETON_DEPENDENCY public: - virtual void reset() { _reset = true; } + virtual void reset(); virtual bool isActive() const; virtual bool isTracking() const { return isActive(); } @@ -50,7 +50,6 @@ public: public slots: void setEnabled(bool enabled); - void resetTracking(); private slots: void processFinished(int exitCode, QProcess::ExitStatus exitStatus); From 766087c032e0e35287d6349109d391946e7f3700 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 20 Apr 2015 10:29:53 -0700 Subject: [PATCH 161/401] Run DDE "readonly" Try to fix some people having to run Interface in admin mode on Windows --- interface/src/devices/DdeFaceTracker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index c4f22a31a9..938cee729f 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -200,7 +200,7 @@ void DdeFaceTracker::setEnabled(bool enabled) { qDebug() << "[Info] DDE Face Tracker Starting"; _ddeProcess = new QProcess(qApp); connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus))); - _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS); + _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS, QIODevice::ReadOnly); } if (!enabled && _ddeProcess) { From fbff3627dcadc06532c91ee370d6d8ae34045498 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 20 Apr 2015 11:13:51 -0700 Subject: [PATCH 162/401] attempt to claim simulation ownership of entities the avatar crashes with --- libraries/physics/src/EntityMotionState.cpp | 2 ++ libraries/physics/src/PhysicsEngine.cpp | 37 ++++++++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 95a3dff6af..37472695c6 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -305,6 +305,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; #endif + qCDebug(physics) << "EntityMotionState::sendUpdate()"; + entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { #ifdef WANT_DEBUG diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index aa9921be64..af4349a66e 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -23,8 +23,9 @@ uint32_t PhysicsEngine::getNumSubsteps() { return _numSubsteps; } -PhysicsEngine::PhysicsEngine(const glm::vec3& offset) - : _originOffset(offset) { +PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : + _originOffset(offset), + _characterController(NULL) { } PhysicsEngine::~PhysicsEngine() { @@ -367,6 +368,12 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { void PhysicsEngine::computeCollisionEvents() { BT_PROFILE("computeCollisionEvents"); + + const btCollisionObject* characterCollisionObject = + _characterController ? _characterController->getCollisionObject() : NULL; + auto nodeList = DependencyManager::get(); + const QUuid& myNodeID = nodeList->getSessionUUID(); + // update all contacts every frame int numManifolds = _collisionDispatcher->getNumManifolds(); for (int i = 0; i < numManifolds; ++i) { @@ -382,12 +389,34 @@ void PhysicsEngine::computeCollisionEvents() { // which will eventually trigger a CONTACT_EVENT_TYPE_END continue; } - + void* a = objectA->getUserPointer(); void* b = objectB->getUserPointer(); if (a || b) { // the manifold has up to 4 distinct points, but only extract info from the first - _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); + const ContactKey& contactKey = ContactKey(a, b); + ContactInfo& contactInfo = _contactMap[contactKey]; + contactInfo.update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); + + // if our character capsule is colliding with something dynamic, claim simulation ownership. + // do this by setting the entity's simulator-id to NULL, thereby causing EntityMotionState::sendUpdate + // to set ownership to us. + if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) { + ObjectMotionState* B = static_cast(b); + EntityItem* entityB = static_cast(B)->getEntity(); + if (entityB->getSimulatorID() != myNodeID) { + qDebug() << "CLAIMING B"; + entityB->setSimulatorID(NULL); + } + } + if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) { + ObjectMotionState* A = static_cast(a); + EntityItem* entityA = static_cast(A)->getEntity(); + if (entityA->getSimulatorID() != myNodeID) { + qDebug() << "CLAIMING A"; + entityA->setSimulatorID(NULL); + } + } } } } From 88f289f3c1f475e3dd1aaa803f4f0d771606ab6e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 20 Apr 2015 11:19:48 -0700 Subject: [PATCH 163/401] small cleanup and some debugging prints --- libraries/physics/src/PhysicsEngine.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index af4349a66e..88b3a1362c 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -394,25 +394,21 @@ void PhysicsEngine::computeCollisionEvents() { void* b = objectB->getUserPointer(); if (a || b) { // the manifold has up to 4 distinct points, but only extract info from the first - const ContactKey& contactKey = ContactKey(a, b); - ContactInfo& contactInfo = _contactMap[contactKey]; - contactInfo.update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); + _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); // if our character capsule is colliding with something dynamic, claim simulation ownership. // do this by setting the entity's simulator-id to NULL, thereby causing EntityMotionState::sendUpdate // to set ownership to us. if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) { - ObjectMotionState* B = static_cast(b); - EntityItem* entityB = static_cast(B)->getEntity(); - if (entityB->getSimulatorID() != myNodeID) { + EntityItem* entityB = static_cast(b)->getEntity(); + if (!entityB->getSimulatorID().isNull() && entityB->getSimulatorID() != myNodeID) { qDebug() << "CLAIMING B"; entityB->setSimulatorID(NULL); } } if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) { - ObjectMotionState* A = static_cast(a); - EntityItem* entityA = static_cast(A)->getEntity(); - if (entityA->getSimulatorID() != myNodeID) { + EntityItem* entityA = static_cast(a)->getEntity(); + if (!entityA->getSimulatorID().isNull() && entityA->getSimulatorID() != myNodeID) { qDebug() << "CLAIMING A"; entityA->setSimulatorID(NULL); } From 08d300afcd6d80e6ac2cdfdb8653e707d2ce6173 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 20 Apr 2015 11:49:10 -0700 Subject: [PATCH 164/401] use a flag to indicate that simulation ownership should be grabbed --- libraries/entities/src/EntityItem.cpp | 1 + libraries/entities/src/EntityItem.h | 3 +++ libraries/entities/src/EntityTree.cpp | 2 ++ libraries/physics/src/EntityMotionState.cpp | 11 ++++++++++- libraries/physics/src/PhysicsEngine.cpp | 11 +++++------ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index b771279efa..512687d224 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -76,6 +76,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { _changedOnServer = 0; _element = NULL; _simulatorIDChangedTime = 0; + _shouldClaimSimulationOwnership = false; initFromEntityItemID(entityItemID); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 96186b4c91..3a6a00d2ba 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -259,6 +259,8 @@ public: QUuid getSimulatorID() const { return _simulatorID; } void setSimulatorID(const QUuid& value); quint64 getSimulatorIDChangedTime() const { return _simulatorIDChangedTime; } + void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } + bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } const QString& getMarketplaceID() const { return _marketplaceID; } void setMarketplaceID(const QString& value) { _marketplaceID = value; } @@ -355,6 +357,7 @@ protected: QString _userData; QUuid _simulatorID; // id of Node which is currently responsible for simulating this Entity quint64 _simulatorIDChangedTime; // when was _simulatorID last updated? + bool _shouldClaimSimulationOwnership; QString _marketplaceID; // NOTE: Damping is applied like this: v *= pow(1 - damping, dt) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 7c2f41ed2c..85caccbf34 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -147,6 +147,8 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro properties.setPositionChanged(false); properties.setVelocityChanged(false); properties.setAccelerationChanged(false); + } else { + qCDebug(entities) << "allowing simulatorID change"; } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 37472695c6..74a3d3220c 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -191,6 +191,10 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { return false; } + if (_entity->getShouldClaimSimulationOwnership()) { + return true; + } + auto nodeList = DependencyManager::get(); const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& simulatorID = _entity->getSimulatorID(); @@ -262,7 +266,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); - if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { + if (_entity->getShouldClaimSimulationOwnership()) { + _entity->setSimulatorID(myNodeID); + properties.setSimulatorID(myNodeID); + _entity->setShouldClaimSimulationOwnership(false); + } + else if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 88b3a1362c..c3ed870375 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -397,20 +397,19 @@ void PhysicsEngine::computeCollisionEvents() { _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); // if our character capsule is colliding with something dynamic, claim simulation ownership. - // do this by setting the entity's simulator-id to NULL, thereby causing EntityMotionState::sendUpdate - // to set ownership to us. + // see EntityMotionState::sendUpdate if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) { EntityItem* entityB = static_cast(b)->getEntity(); - if (!entityB->getSimulatorID().isNull() && entityB->getSimulatorID() != myNodeID) { + if (entityB->getSimulatorID() != myNodeID && !entityB->getShouldClaimSimulationOwnership()) { qDebug() << "CLAIMING B"; - entityB->setSimulatorID(NULL); + entityB->setShouldClaimSimulationOwnership(true); } } if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) { EntityItem* entityA = static_cast(a)->getEntity(); - if (!entityA->getSimulatorID().isNull() && entityA->getSimulatorID() != myNodeID) { + if (entityA->getSimulatorID() != myNodeID && !entityA->getShouldClaimSimulationOwnership()) { qDebug() << "CLAIMING A"; - entityA->setSimulatorID(NULL); + entityA->setShouldClaimSimulationOwnership(true); } } } From 56b005a872ea5ac2c0a0cbbc6b2711ff09092bda Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 20 Apr 2015 12:19:36 -0700 Subject: [PATCH 165/401] packets should be ignore if they contain local nodeID, not if local entity contains nodeID --- libraries/entities/src/EntityTreeElement.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index a94891ea7e..60b6c93483 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -745,7 +745,8 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); // this Node was the original source of this packet, so read it, but ignore it. - bool shouldIgnore = (entityItem && entityItem->getSimulatorID() == myNodeID); + // bool shouldIgnore = (entityItem && entityItem->getSimulatorID() == myNodeID); XXX + bool shouldIgnore = false; bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args, shouldIgnore); if (entityItem->getDirtyFlags()) { From 58c1827f69e395c79dddb1cbcb02624ab2572b16 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 20 Apr 2015 15:56:44 -0700 Subject: [PATCH 166/401] bring back the glPushPop in transform legacy mode --- libraries/render-utils/src/Model.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 2bbdf2a8f1..4bc69f1bea 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1754,6 +1754,12 @@ void Model::setupBatchTransform(gpu::Batch& batch, RenderArgs* args) { void Model::endScene(RenderMode mode, RenderArgs* args) { PROFILE_RANGE(__FUNCTION__); + +#if (GPU_TRANSFORM_PROFILE == GPU_LEGACY) + // with legacy transform profile, we still to protect that transform stack... + glPushMatrix(); +#endif + RenderArgs::RenderSide renderSide = RenderArgs::MONO; if (args) { renderSide = args->_renderSide; @@ -1921,6 +1927,12 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { backend.render(_sceneRenderBatch); } + +#if (GPU_TRANSFORM_PROFILE == GPU_LEGACY) + // with legacy transform profile, we still to protect that transform stack... + glPopMatrix(); +#endif + // restore all the default material settings _viewState->setupWorldLight(); From d6c8bd94cfbc15b63ca6ef3f05b09403e200a5f0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 20 Apr 2015 15:59:33 -0700 Subject: [PATCH 167/401] clean up some debugging prints --- libraries/entities/src/EntityTreeElement.cpp | 1 + libraries/physics/src/EntityMotionState.cpp | 6 +++--- libraries/physics/src/PhysicsEngine.cpp | 2 -- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 60b6c93483..9de7329594 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -745,6 +745,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); // this Node was the original source of this packet, so read it, but ignore it. + /// XXX what should be done here? Do we need to ignore packets which show us as simulator owner? XXX // bool shouldIgnore = (entityItem && entityItem->getSimulatorID() == myNodeID); XXX bool shouldIgnore = false; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 74a3d3220c..e188bad613 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -217,7 +217,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (glm::length(_measuredAcceleration) < MEASURED_ACCELERATION_CLOSE_TO_ZERO) { _entity->setAcceleration(glm::vec3(0)); } else { - _entity->setAcceleration(_entity->getGravity()); + // _entity->setAcceleration(_entity->getGravity()); + // XXX + _entity->setAcceleration(glm::vec3(0)); } if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { @@ -314,8 +316,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; #endif - qCDebug(physics) << "EntityMotionState::sendUpdate()"; - entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { #ifdef WANT_DEBUG diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index c3ed870375..a55da0fa8c 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -401,14 +401,12 @@ void PhysicsEngine::computeCollisionEvents() { if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) { EntityItem* entityB = static_cast(b)->getEntity(); if (entityB->getSimulatorID() != myNodeID && !entityB->getShouldClaimSimulationOwnership()) { - qDebug() << "CLAIMING B"; entityB->setShouldClaimSimulationOwnership(true); } } if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) { EntityItem* entityA = static_cast(a)->getEntity(); if (entityA->getSimulatorID() != myNodeID && !entityA->getShouldClaimSimulationOwnership()) { - qDebug() << "CLAIMING A"; entityA->setShouldClaimSimulationOwnership(true); } } From 23f1767634cf0c7a7fc5444ab3933c5ede22d58b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 20 Apr 2015 16:13:28 -0700 Subject: [PATCH 168/401] cleanup --- libraries/physics/src/PhysicsEngine.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index a55da0fa8c..fbfb7914f0 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -371,8 +371,6 @@ void PhysicsEngine::computeCollisionEvents() { const btCollisionObject* characterCollisionObject = _characterController ? _characterController->getCollisionObject() : NULL; - auto nodeList = DependencyManager::get(); - const QUuid& myNodeID = nodeList->getSessionUUID(); // update all contacts every frame int numManifolds = _collisionDispatcher->getNumManifolds(); @@ -400,15 +398,11 @@ void PhysicsEngine::computeCollisionEvents() { // see EntityMotionState::sendUpdate if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) { EntityItem* entityB = static_cast(b)->getEntity(); - if (entityB->getSimulatorID() != myNodeID && !entityB->getShouldClaimSimulationOwnership()) { - entityB->setShouldClaimSimulationOwnership(true); - } + entityB->setShouldClaimSimulationOwnership(true); } if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) { EntityItem* entityA = static_cast(a)->getEntity(); - if (entityA->getSimulatorID() != myNodeID && !entityA->getShouldClaimSimulationOwnership()) { - entityA->setShouldClaimSimulationOwnership(true); - } + entityA->setShouldClaimSimulationOwnership(true); } } } From 1af17fa9e7278f5f5502305393c16321556bae4d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 20 Apr 2015 16:14:36 -0700 Subject: [PATCH 169/401] Use voice to control DDE mouth Add voice blend coefficient values to DDE values. --- interface/src/Application.cpp | 1 + interface/src/Menu.cpp | 2 + interface/src/Menu.h | 3 +- interface/src/avatar/Head.cpp | 96 +++++++++++++++++++++-------------- interface/src/avatar/Head.h | 1 + 5 files changed, 64 insertions(+), 39 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9e00444fa5..a0f2b4cb05 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1745,6 +1745,7 @@ void Application::setActiveFaceTracker() { #endif #ifdef HAVE_DDE bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression); + Menu::getInstance()->getActionForOption(MenuOption::UseAudioForMouth)->setVisible(isUsingDDE); Menu::getInstance()->getActionForOption(MenuOption::DDEFiltering)->setVisible(isUsingDDE); Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE); DependencyManager::get()->setEnabled(isUsingDDE); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6b9075e917..df18e941fa 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -379,6 +379,8 @@ Menu::Menu() { } #ifdef HAVE_DDE faceTrackingMenu->addSeparator(); + QAction* useAudioForMouth = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseAudioForMouth, 0, true); + useAudioForMouth->setVisible(false); QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFiltering, 0, true); ddeFiltering->setVisible(false); QAction* ddeFaceTrackerReset = addActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::ResetDDETracking, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3c31db834a..0df1b5a83a 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -187,6 +187,7 @@ namespace MenuOption { const QString OctreeStats = "Entity Statistics"; const QString OffAxisProjection = "Off-Axis Projection"; const QString OnlyDisplayTopTen = "Only Display Top Ten"; + const QString PackageModel = "Package Model..."; const QString Pair = "Pair"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString Preferences = "Preferences..."; @@ -245,7 +246,7 @@ namespace MenuOption { const QString ToolWindow = "Tool Window"; const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; - const QString PackageModel = "Package Model..."; + const QString UseAudioForMouth = "Use Audio for Mouth"; const QString VisibleToEveryone = "Everyone"; const QString VisibleToFriends = "Friends"; const QString VisibleToNoOne = "No one"; diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index b90b693139..b84fd23614 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -76,12 +76,41 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { if (isMine) { MyAvatar* myAvatar = static_cast(_owningAvatar); + // Update audio trailing average for rendering facial animations + const float AUDIO_AVERAGING_SECS = 0.05f; + const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; + _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f)); + + if (_longTermAverageLoudness == -1.0) { + _longTermAverageLoudness = _averageLoudness; + } else { + _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f)); + } + // Only use face trackers when not playing back a recording. if (!myAvatar->isPlaying()) { FaceTracker* faceTracker = Application::getInstance()->getActiveFaceTracker(); _isFaceTrackerConnected = faceTracker != NULL; if (_isFaceTrackerConnected) { _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); + + if (typeid(*faceTracker) == typeid(DdeFaceTracker) + && Menu::getInstance()->isOptionChecked(MenuOption::UseAudioForMouth)) { + + calculateMouthShapes(); + + const int JAW_OPEN_BLENDSHAPE = 21; + const int MMMM_BLENDSHAPE = 34; + const int FUNNEL_BLENDSHAPE = 40; + const int SMILE_LEFT_BLENDSHAPE = 28; + const int SMILE_RIGHT_BLENDSHAPE = 29; + _blendshapeCoefficients[JAW_OPEN_BLENDSHAPE] += _audioJawOpen; + _blendshapeCoefficients[SMILE_LEFT_BLENDSHAPE] += _mouth4; + _blendshapeCoefficients[SMILE_RIGHT_BLENDSHAPE] += _mouth4; + _blendshapeCoefficients[MMMM_BLENDSHAPE] += _mouth2; + _blendshapeCoefficients[FUNNEL_BLENDSHAPE] += _mouth3; + + } } } // Twist the upper body to follow the rotation of the head, but only do this with my avatar, @@ -92,17 +121,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { setTorsoTwist(currentTwist + (getFinalYaw() * BODY_FOLLOW_HEAD_FACTOR - currentTwist) * BODY_FOLLOW_HEAD_YAW_RATE); } - // Update audio trailing average for rendering facial animations - const float AUDIO_AVERAGING_SECS = 0.05f; - const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; - _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f)); - - if (_longTermAverageLoudness == -1.0) { - _longTermAverageLoudness = _averageLoudness; - } else { - _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f)); - } - if (!(_isFaceTrackerConnected || billboard)) { // Update eye saccades const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f; @@ -177,33 +195,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } // use data to update fake Faceshift blendshape coefficients - - const float JAW_OPEN_SCALE = 0.015f; - const float JAW_OPEN_RATE = 0.9f; - const float JAW_CLOSE_RATE = 0.90f; - float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; - if (audioDelta > _audioJawOpen) { - _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; - } else { - _audioJawOpen *= JAW_CLOSE_RATE; - } - _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); - - // _mouth2 = "mmmm" shape - // _mouth3 = "funnel" shape - // _mouth4 = "smile" shape - const float FUNNEL_PERIOD = 0.985f; - const float FUNNEL_RANDOM_PERIOD = 0.01f; - const float MMMM_POWER = 0.25f; - const float MMMM_PERIOD = 0.91f; - const float MMMM_RANDOM_PERIOD = 0.15f; - const float SMILE_PERIOD = 0.925f; - const float SMILE_RANDOM_PERIOD = 0.05f; - - _mouth3 = glm::mix(_audioJawOpen, _mouth3, FUNNEL_PERIOD + randFloat() * FUNNEL_RANDOM_PERIOD); - _mouth2 = glm::mix(_audioJawOpen * MMMM_POWER, _mouth2, MMMM_PERIOD + randFloat() * MMMM_RANDOM_PERIOD); - _mouth4 = glm::mix(_audioJawOpen, _mouth4, SMILE_PERIOD + randFloat() * SMILE_RANDOM_PERIOD); - + calculateMouthShapes(); DependencyManager::get()->updateFakeCoefficients(_leftEyeBlink, _rightEyeBlink, _browAudioLift, @@ -230,6 +222,34 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } +void Head::calculateMouthShapes() { + const float JAW_OPEN_SCALE = 0.015f; + const float JAW_OPEN_RATE = 0.9f; + const float JAW_CLOSE_RATE = 0.90f; + float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; + if (audioDelta > _audioJawOpen) { + _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; + } else { + _audioJawOpen *= JAW_CLOSE_RATE; + } + _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); + + // _mouth2 = "mmmm" shape + // _mouth3 = "funnel" shape + // _mouth4 = "smile" shape + const float FUNNEL_PERIOD = 0.985f; + const float FUNNEL_RANDOM_PERIOD = 0.01f; + const float MMMM_POWER = 0.25f; + const float MMMM_PERIOD = 0.91f; + const float MMMM_RANDOM_PERIOD = 0.15f; + const float SMILE_PERIOD = 0.925f; + const float SMILE_RANDOM_PERIOD = 0.05f; + + _mouth3 = glm::mix(_audioJawOpen, _mouth3, FUNNEL_PERIOD + randFloat() * FUNNEL_RANDOM_PERIOD); + _mouth2 = glm::mix(_audioJawOpen * MMMM_POWER, _mouth2, MMMM_PERIOD + randFloat() * MMMM_RANDOM_PERIOD); + _mouth4 = glm::mix(_audioJawOpen, _mouth4, SMILE_PERIOD + randFloat() * SMILE_RANDOM_PERIOD); +} + void Head::relaxLean(float deltaTime) { // restore rotation, lean to neutral positions const float LEAN_RELAXATION_PERIOD = 0.25f; // seconds diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 5465d74172..d6d4cc1352 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -154,6 +154,7 @@ private: // private methods void renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition); + void calculateMouthShapes(); friend class FaceModel; }; From 61076826580d31fef97ad6240dc3e3154ed0bbbf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 20 Apr 2015 16:36:56 -0700 Subject: [PATCH 170/401] handle ignoring simulation data echoed back to us differently --- libraries/entities/src/EntityItem.cpp | 27 ++++++++++++++++++-- libraries/entities/src/EntityItem.h | 3 +-- libraries/entities/src/EntityTreeElement.cpp | 11 +------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 512687d224..d221c0bba4 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -313,8 +313,7 @@ int EntityItem::expectedBytes() { } -int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, - bool ignoreServerPacket) { +int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { @@ -325,6 +324,14 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef return 0; } + // if this bitstream indicates that this node is the simulation owner, ignore any physics-related updates. + glm::vec3 savePosition = _position; + glm::quat saveRotation = _rotation; + glm::vec3 saveVelocity = _velocity; + glm::vec3 saveGravity = _gravity; + glm::vec3 saveAcceleration = _acceleration; + + // Header bytes // object ID [16 bytes] // ByteCountCoded(type code) [~1 byte] @@ -398,6 +405,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef quint64 lastEditedFromBuffer = 0; quint64 lastEditedFromBufferAdjusted = 0; + bool ignoreServerPacket = false; + // TODO: we could make this encoded as a delta from _created // _lastEdited memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer)); @@ -608,6 +617,20 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef _lastSimulated = now; } } + + + auto nodeList = DependencyManager::get(); + const QUuid& myNodeID = nodeList->getSessionUUID(); + if (_simulatorID == myNodeID) { + // the packet that produced this bitstream originally came from physics simulations performed by + // this node, so our version has to be newer than what the packet contained. + _position = savePosition; + _rotation = saveRotation; + _velocity = saveVelocity; + _gravity = saveGravity; + _acceleration = saveAcceleration; + } + return bytesRead; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 3a6a00d2ba..ad856698a2 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -113,8 +113,7 @@ public: static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); - virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, - bool ignoreServerPacket = false); + virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 9de7329594..349bd51372 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -716,10 +716,6 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesRead += sizeof(numberOfEntities); if (bytesLeftToRead >= (int)(numberOfEntities * expectedBytesPerEntity)) { - // look up the Id of this Node - auto nodeList = DependencyManager::get(); - QUuid myNodeID = nodeList->getSessionUUID(); - for (uint16_t i = 0; i < numberOfEntities; i++) { int bytesForThisEntity = 0; EntityItemID entityItemID; @@ -744,12 +740,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int bool bestFitBefore = bestFitEntityBounds(entityItem); EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); - // this Node was the original source of this packet, so read it, but ignore it. - /// XXX what should be done here? Do we need to ignore packets which show us as simulator owner? XXX - // bool shouldIgnore = (entityItem && entityItem->getSimulatorID() == myNodeID); XXX - bool shouldIgnore = false; - - bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args, shouldIgnore); + bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); if (entityItem->getDirtyFlags()) { _myTree->entityChanged(entityItem); } From 4a5631fca6ad359c802d9df587dfd92f63a680f6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 20 Apr 2015 16:51:28 -0700 Subject: [PATCH 171/401] cleanups, diff minimization --- libraries/entities/src/EntityItem.cpp | 4 ++-- libraries/entities/src/EntityScriptingInterface.cpp | 4 ++-- libraries/physics/src/EntityMotionState.cpp | 4 +--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d221c0bba4..4875069aae 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -405,8 +405,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef quint64 lastEditedFromBuffer = 0; quint64 lastEditedFromBufferAdjusted = 0; - bool ignoreServerPacket = false; - // TODO: we could make this encoded as a delta from _created // _lastEdited memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer)); @@ -432,6 +430,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef qCDebug(entities) << " fromSameServerEdit:" << fromSameServerEdit; #endif + bool ignoreServerPacket = false; + // If this packet is from the same server edit as the last packet we accepted from the server // we probably want to use it. if (fromSameServerEdit) { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 6bd988ec90..53335beda0 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -65,6 +65,7 @@ void setSimId(EntityItemProperties& propertiesWithSimID, EntityItem* entity) { auto nodeList = DependencyManager::get(); const QUuid myNodeID = nodeList->getSessionUUID(); + // if this entity has non-zero physics/simulation related values, claim simulation ownership if (propertiesWithSimID.velocityChanged() || propertiesWithSimID.rotationChanged() || propertiesWithSimID.containsPositionChange()) { @@ -83,7 +84,6 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro // The application will keep track of creatorTokenID uint32_t creatorTokenID = EntityItemID::getNextCreatorTokenID(); - // This Node is creating a new object. If it's in motion, set this Node as the simulator. EntityItemProperties propertiesWithSimID = properties; EntityItemID id(NEW_ENTITY, creatorTokenID, false ); @@ -92,6 +92,7 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro if (_entityTree) { _entityTree->lockForWrite(); EntityItem* entity = _entityTree->addEntity(id, propertiesWithSimID); + // This Node is creating a new object. If it's in motion, set this Node as the simulator. setSimId(propertiesWithSimID, entity); _entityTree->unlock(); } @@ -160,7 +161,6 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E } } - // if this Node is changing a physics-related property, claim simulation ownership. EntityItemProperties propertiesWithSimID = properties; // If we have a local entity tree set, then also update it. We can do this even if we don't know diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index e188bad613..e689ac21bc 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -217,9 +217,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (glm::length(_measuredAcceleration) < MEASURED_ACCELERATION_CLOSE_TO_ZERO) { _entity->setAcceleration(glm::vec3(0)); } else { - // _entity->setAcceleration(_entity->getGravity()); - // XXX - _entity->setAcceleration(glm::vec3(0)); + _entity->setAcceleration(_entity->getGravity()); } if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { From c49e2c1804d5627d20c83e9bd752c92d7ba0b8b3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 20 Apr 2015 16:52:29 -0700 Subject: [PATCH 172/401] cleanups, diff minimization --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4875069aae..12fb1ba99d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -430,7 +430,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef qCDebug(entities) << " fromSameServerEdit:" << fromSameServerEdit; #endif - bool ignoreServerPacket = false; + bool ignoreServerPacket = false; // assume we'll use this server packet // If this packet is from the same server edit as the last packet we accepted from the server // we probably want to use it. From a9c2a6e0486c2dde52ec59ad42cce456c9f4bc28 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 20 Apr 2015 18:17:21 -0700 Subject: [PATCH 173/401] another attempt at zones starting from box --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 4 +++- libraries/entities/src/EntityItemProperties.h | 1 + libraries/entities/src/EntityTypes.cpp | 5 +++-- libraries/entities/src/EntityTypes.h | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index da972b3843..132feff7e3 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -30,9 +30,10 @@ #include "RenderableBoxEntityItem.h" #include "RenderableLightEntityItem.h" #include "RenderableModelEntityItem.h" +#include "RenderableParticleEffectEntityItem.h" #include "RenderableSphereEntityItem.h" #include "RenderableTextEntityItem.h" -#include "RenderableParticleEffectEntityItem.h" +#include "RenderableZoneEntityItem.h" #include "EntitiesRendererLogging.h" @@ -56,6 +57,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Text, RenderableTextEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory) + REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory) _currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID _currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 7de0fc0e8b..0bc0bcedc7 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -137,6 +137,7 @@ class EntityItemProperties { friend class LightEntityItem; // TODO: consider removing this friend relationship and use public methods friend class TextEntityItem; // TODO: consider removing this friend relationship and use public methods friend class ParticleEffectEntityItem; // TODO: consider removing this friend relationship and use public methods + friend class ZoneEntityItem; // TODO: consider removing this friend relationship and use public methods public: EntityItemProperties(); virtual ~EntityItemProperties(); diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 55e9512f53..f0baa3da93 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -21,9 +21,10 @@ #include "BoxEntityItem.h" #include "LightEntityItem.h" #include "ModelEntityItem.h" +#include "ParticleEffectEntityItem.h" #include "SphereEntityItem.h" #include "TextEntityItem.h" -#include "ParticleEffectEntityItem.h" +#include "ZoneEntityItem.h" QMap EntityTypes::_typeToNameMap; QMap EntityTypes::_nameToTypeMap; @@ -39,7 +40,7 @@ REGISTER_ENTITY_TYPE(Sphere) REGISTER_ENTITY_TYPE(Light) REGISTER_ENTITY_TYPE(Text) REGISTER_ENTITY_TYPE(ParticleEffect) - +REGISTER_ENTITY_TYPE(Zone) const QString& EntityTypes::getEntityTypeName(EntityType entityType) { QMap::iterator matchedTypeName = _typeToNameMap.find(entityType); diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index e1f8e876bb..28cfe2278b 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -36,7 +36,8 @@ public: Light, Text, ParticleEffect, - LAST = ParticleEffect + Zone, + LAST = Zone } EntityType; static const QString& getEntityTypeName(EntityType entityType); From 8ce4cb628a9c74015bc559e6915f1e966d1f5859 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 20 Apr 2015 18:18:01 -0700 Subject: [PATCH 174/401] another attempt at zones starting from box --- .../src/RenderableZoneEntityItem.cpp | 50 +++++++ .../src/RenderableZoneEntityItem.h | 29 +++++ libraries/entities/src/ZoneEntityItem.cpp | 122 ++++++++++++++++++ libraries/entities/src/ZoneEntityItem.h | 62 +++++++++ 4 files changed, 263 insertions(+) create mode 100644 libraries/entities-renderer/src/RenderableZoneEntityItem.cpp create mode 100644 libraries/entities-renderer/src/RenderableZoneEntityItem.h create mode 100644 libraries/entities/src/ZoneEntityItem.cpp create mode 100644 libraries/entities/src/ZoneEntityItem.h diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp new file mode 100644 index 0000000000..6a16404f89 --- /dev/null +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -0,0 +1,50 @@ +// +// RenderableZoneEntityItem.cpp +// interface/src +// +// Created by Brad Hefta-Gaub on 8/6/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 "RenderableZoneEntityItem.h" + +EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + return new RenderableZoneEntityItem(entityID, properties); +} + +void RenderableZoneEntityItem::render(RenderArgs* args) { + PerformanceTimer perfTimer("RenderableZoneEntityItem::render"); + assert(getType() == EntityTypes::Zone); + glm::vec3 position = getPosition(); + glm::vec3 center = getCenter(); + glm::vec3 dimensions = getDimensions(); + glm::quat rotation = getRotation(); + + const float MAX_COLOR = 255.0f; + + glm::vec4 cubeColor(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR, + getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha()); + + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + glPushMatrix(); + glm::vec3 positionToCenter = center - position; + glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + glScalef(dimensions.x, dimensions.y, dimensions.z); + DependencyManager::get()->renderWireCube(1.0f, cubeColor); + glPopMatrix(); + glPopMatrix(); + +}; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h new file mode 100644 index 0000000000..b05fd0e3f8 --- /dev/null +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -0,0 +1,29 @@ +// +// RenderableZoneEntityItem.h +// interface/src/entities +// +// Created by Brad Hefta-Gaub on 8/6/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_RenderableZoneEntityItem_h +#define hifi_RenderableZoneEntityItem_h + +#include + +class RenderableZoneEntityItem : public ZoneEntityItem { +public: + static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : + ZoneEntityItem(entityItemID, properties) + { } + + virtual void render(RenderArgs* args); +}; + + +#endif // hifi_RenderableZoneEntityItem_h diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp new file mode 100644 index 0000000000..a22c22ce5d --- /dev/null +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -0,0 +1,122 @@ +// +// ZoneEntityItem.cpp +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 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 "ZoneEntityItem.h" +#include "EntityTree.h" +#include "EntitiesLogging.h" +#include "EntityTreeElement.h" + +/* +bool ZoneEntityItem::_zonesArePickable = false; + +const xColor ZoneEntityItem::DEFAULT_SUN_sunColor = { 255, 255, 255 }; +const float ZoneEntityItem::DEFAULT_SUN_INTENSITY = 0.1f; +const float ZoneEntityItem::DEFAULT_SUN_AMBIENT_INTENSITY = 0.0f; +const bool ZoneEntityItem::DEFAULT_SUN_USE_EARTH_MODEL = true; +const float ZoneEntityItem::DEFAULT_SUN_APPARENT_LATITUDE = 37.777f; +const float ZoneEntityItem::DEFAULT_SUN_APPARENT_LONGITUDE = 122.407f; +const float ZoneEntityItem::DEFAULT_SUN_APPARENT_ALTITUDE = 0.03f; +const quint16 ZoneEntityItem::DEFAULT_SUN_APPARENT_DAY = 60; +const float ZoneEntityItem::DEFAULT_SUN_APPARENT_HOUR = 12.0f; +const glm::vec3 ZoneEntityItem::DEFAULT_SUN_DIRECTION = { 0.0f, -1.0f, 0.0f }; +*/ + +EntityItem* ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + EntityItem* result = new ZoneEntityItem(entityID, properties); + return result; +} + +ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : + EntityItem(entityItemID) +{ + _type = EntityTypes::Zone; + _created = properties.getCreated(); + setProperties(properties); +} + +EntityItemProperties ZoneEntityItem::getProperties() const { + EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class + + properties._color = getXColor(); + properties._colorChanged = false; + + properties._glowLevel = getGlowLevel(); + properties._glowLevelChanged = false; + + return properties; +} + +bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); + + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qCDebug(entities) << "ZoneEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties._lastEdited); + } + return somethingChanged; +} + +int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _sunColor); + + return bytesRead; +} + + +// TODO: eventually only include properties changed since the params.lastViewFrustumSent time +EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + requestedProperties += PROP_COLOR; + return requestedProperties; +} + +void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); +} + +void ZoneEntityItem::debugDump() const { + quint64 now = usecTimestampNow(); + qCDebug(entities) << " BOX EntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " color:" << _sunColor[0] << "," << _sunColor[1] << "," << _sunColor[2]; + qCDebug(entities) << " position:" << debugTreeVector(_position); + qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions); + qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); +} + diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h new file mode 100644 index 0000000000..4b0b960697 --- /dev/null +++ b/libraries/entities/src/ZoneEntityItem.h @@ -0,0 +1,62 @@ +// +// ZoneEntityItem.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 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_ZoneEntityItem_h +#define hifi_ZoneEntityItem_h + +#include "EntityItem.h" + +class ZoneEntityItem : public EntityItem { +public: + static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + ZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + + ALLOW_INSTANTIATION // This class can be instantiated + + // methods for getting/setting all properties of an entity + virtual EntityItemProperties getProperties() const; + virtual bool setProperties(const EntityItemProperties& properties); + + // TODO: eventually only include properties changed since the params.lastViewFrustumSent time + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const; + + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData); + + const rgbColor& getColor() const { return _sunColor; } + xColor getXColor() const { xColor color = { _sunColor[RED_INDEX], _sunColor[GREEN_INDEX], _sunColor[BLUE_INDEX] }; return color; } + + void setColor(const rgbColor& value) { memcpy(_sunColor, value, sizeof(_sunColor)); } + void setColor(const xColor& value) { + _sunColor[RED_INDEX] = value.red; + _sunColor[GREEN_INDEX] = value.green; + _sunColor[BLUE_INDEX] = value.blue; + } + + virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } + + virtual void debugDump() const; + +protected: + rgbColor _sunColor; +}; + +#endif // hifi_ZoneEntityItem_h From 85e9a794a34e06eb5d817a5e29c52521d903564b Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 21 Apr 2015 03:58:39 +0200 Subject: [PATCH 175/401] ability to run multiple interfaces on single Windows machine by switching user accounts (or using run as) --- interface/src/Application.h | 4 ++-- interface/src/main.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index b5b2921844..7417b821d4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -117,9 +117,9 @@ static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html"; #ifdef Q_OS_WIN static const UINT UWM_IDENTIFY_INSTANCES = - RegisterWindowMessage("UWM_IDENTIFY_INSTANCES_{8AB82783-B74A-4258-955B-8188C22AA0D6}"); + RegisterWindowMessage("UWM_IDENTIFY_INSTANCES_{8AB82783-B74A-4258-955B-8188C22AA0D6}_" + qgetenv("USERNAME")); static const UINT UWM_SHOW_APPLICATION = - RegisterWindowMessage("UWM_SHOW_APPLICATION_{71123FD6-3DA8-4DC1-9C27-8A12A6250CBA}"); + RegisterWindowMessage("UWM_SHOW_APPLICATION_{71123FD6-3DA8-4DC1-9C27-8A12A6250CBA}_" + qgetenv("USERNAME")); #endif class Application; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 7d80b077b8..7112944375 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -42,7 +42,7 @@ static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) { int main(int argc, const char* argv[]) { #ifdef Q_OS_WIN // Run only one instance of Interface at a time. - HANDLE mutex = CreateMutex(NULL, FALSE, "High Fidelity Interface"); + HANDLE mutex = CreateMutex(NULL, FALSE, "High Fidelity Interface - " + qgetenv("USERNAME")); DWORD result = GetLastError(); if (result == ERROR_ALREADY_EXISTS || result == ERROR_ACCESS_DENIED) { // Interface is already running. From 48364cb598731da936027c88b52f026b6d763aac Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 21 Apr 2015 11:04:14 -0700 Subject: [PATCH 176/401] refined the names of the key light porperties in Stage --- examples/example/misc/sunLightExample.js | 22 ++++++++--------- libraries/model/src/model/Stage.cpp | 8 +++---- libraries/model/src/model/Stage.h | 6 ++--- .../src/SceneScriptingInterface.cpp | 24 +++++++++---------- .../src/SceneScriptingInterface.h | 20 ++++++++-------- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index e4826dcfeb..45cf353620 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -73,33 +73,33 @@ function runStageTime() { } Script.setInterval(runStageTime, tickTackPeriod); -panel.newCheckbox("Enable Earth Sun Model", - function(value) { Scene.setStageEarthSunModelEnable((value != 0)); }, - function() { return Scene.isStageEarthSunModelEnabled(); }, +panel.newCheckbox("Enable Sun Model", + function(value) { Scene.setStageSunModelEnable((value != 0)); }, + function() { return Scene.isStageSunModelEnabled(); }, function(value) { return (value); } ); panel.newDirectionBox("Light Direction", - function(value) { Scene.setSunDirection(value); }, - function() { return Scene.getSunDirection(); }, + function(value) { Scene.setKeyLightDirection(value); }, + function() { return Scene.getKeyLightDirection(); }, function(value) { return value.x.toFixed(2) + "," + value.y.toFixed(2) + "," + value.z.toFixed(2); } ); panel.newSlider("Light Intensity", 0.0, 5, - function(value) { Scene.setSunIntensity(value); }, - function() { return Scene.getSunIntensity(); }, + function(value) { Scene.setKeyLightIntensity(value); }, + function() { return Scene.getKeyLightIntensity(); }, function(value) { return (value).toFixed(2); } ); panel.newSlider("Ambient Light Intensity", 0.0, 1.0, - function(value) { Scene.setSunAmbientIntensity(value); }, - function() { return Scene.getSunAmbientIntensity(); }, + function(value) { Scene.setKeyLightAmbientIntensity(value); }, + function() { return Scene.getKeyLightAmbientIntensity(); }, function(value) { return (value).toFixed(2); } ); panel.newColorBox("Light Color", - function(value) { Scene.setSunColor(value); }, - function() { return Scene.getSunColor(); }, + function(value) { Scene.setKeyLightColor(value); }, + function() { return Scene.getKeyLightColor(); }, function(value) { return (value); } // "(" + value.x + "," = value.y + "," + value.z + ")"; } ); diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 68c13e5a7c..77bc3f03f0 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -250,8 +250,8 @@ void SunSkyStage::setOriginLocation(float longitude, float latitude, float altit invalidate(); } -void SunSkyStage::setEarthSunModelEnable(bool isEnabled) { - _earthSunModelEnable = isEnabled; +void SunSkyStage::setSunModelEnable(bool isEnabled) { + _sunModelEnable = isEnabled; invalidate(); } @@ -266,7 +266,7 @@ void SunSkyStage::setSunAmbientIntensity(float intensity) { } void SunSkyStage::setSunDirection(const Vec3& direction) { - if (!isEarthSunModelEnabled()) { + if (!isSunModelEnabled()) { _sunLight->setDirection(direction); } } @@ -286,7 +286,7 @@ void SunSkyStage::updateGraphicsObject() const { // And update the sunLAtitude as the declinaison depending of the time of the year _earthSunModel.setSunLatitude(evalSunDeclinaison(_yearTime)); - if (isEarthSunModelEnabled()) { + if (isSunModelEnabled()) { Vec3d sunLightDir = -_earthSunModel.getSurfaceSunDir(); _sunLight->setDirection(Vec3(sunLightDir.x, sunLightDir.y, sunLightDir.z)); diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index eca290b852..237265ed12 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -204,8 +204,8 @@ public: float getOriginSurfaceAltitude() const { return _earthSunModel.getAltitude(); } // Enable / disable the effect of the time and location on the sun direction and color - void setEarthSunModelEnable(bool isEnabled); - bool isEarthSunModelEnabled() const { return _earthSunModelEnable; } + void setSunModelEnable(bool isEnabled); + bool isSunModelEnabled() const { return _sunModelEnable; } // Sun properties void setSunColor(const Vec3& color); @@ -236,7 +236,7 @@ protected: float _dayTime = 12.0f; int _yearTime = 0; mutable EarthSunModel _earthSunModel; - bool _earthSunModelEnable = true; + bool _sunModelEnable = true; mutable bool _invalid = true; void invalidate() const { _invalid = true; } diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 557938c78a..2461487414 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -46,44 +46,44 @@ int SceneScriptingInterface::getStageYearTime() const { return _skyStage->getYearTime(); } -void SceneScriptingInterface::setSunColor(const glm::vec3& color) { +void SceneScriptingInterface::setKeyLightColor(const glm::vec3& color) { _skyStage->setSunColor(color); } -glm::vec3 SceneScriptingInterface::getSunColor() const { +glm::vec3 SceneScriptingInterface::getKeyLightColor() const { return _skyStage->getSunColor(); } -void SceneScriptingInterface::setSunIntensity(float intensity) { +void SceneScriptingInterface::setKeyLightIntensity(float intensity) { _skyStage->setSunIntensity(intensity); } -float SceneScriptingInterface::getSunIntensity() const { +float SceneScriptingInterface::getKeyLightIntensity() const { return _skyStage->getSunIntensity(); } -void SceneScriptingInterface::setSunAmbientIntensity(float intensity) { +void SceneScriptingInterface::setKeyLightAmbientIntensity(float intensity) { _skyStage->setSunAmbientIntensity(intensity); } -float SceneScriptingInterface::getSunAmbientIntensity() const { +float SceneScriptingInterface::getKeyLightAmbientIntensity() const { return _skyStage->getSunAmbientIntensity(); } -void SceneScriptingInterface::setSunDirection(const glm::vec3& direction) { +void SceneScriptingInterface::setKeyLightDirection(const glm::vec3& direction) { _skyStage->setSunDirection(direction); } -glm::vec3 SceneScriptingInterface::getSunDirection() const { +glm::vec3 SceneScriptingInterface::getKeyLightDirection() const { return _skyStage->getSunDirection(); } -void SceneScriptingInterface::setStageEarthSunModelEnable(bool isEnabled) { - _skyStage->setEarthSunModelEnable(isEnabled); +void SceneScriptingInterface::setStageSunModelEnable(bool isEnabled) { + _skyStage->setSunModelEnable(isEnabled); } -bool SceneScriptingInterface::isStageEarthSunModelEnabled() const { - return _skyStage->isEarthSunModelEnabled(); +bool SceneScriptingInterface::isStageSunModelEnabled() const { + return _skyStage->isSunModelEnabled(); } model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index e847b7ff68..4c1a4e5da1 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -38,21 +38,21 @@ public: Q_INVOKABLE void setStageYearTime(int day); Q_INVOKABLE int getStageYearTime() const; - Q_INVOKABLE void setStageEarthSunModelEnable(bool isEnabled); - Q_INVOKABLE bool isStageEarthSunModelEnabled() const; + Q_INVOKABLE void setStageSunModelEnable(bool isEnabled); + Q_INVOKABLE bool isStageSunModelEnabled() const; - Q_INVOKABLE void setSunColor(const glm::vec3& color); - Q_INVOKABLE glm::vec3 getSunColor() const; - Q_INVOKABLE void setSunIntensity(float intensity); - Q_INVOKABLE float getSunIntensity() const; - Q_INVOKABLE void setSunAmbientIntensity(float intensity); - Q_INVOKABLE float getSunAmbientIntensity() const; + Q_INVOKABLE void setKeyLightColor(const glm::vec3& color); + Q_INVOKABLE glm::vec3 getKeyLightColor() const; + Q_INVOKABLE void setKeyLightIntensity(float intensity); + Q_INVOKABLE float getKeyLightIntensity() const; + Q_INVOKABLE void setKeyLightAmbientIntensity(float intensity); + Q_INVOKABLE float getKeyLightAmbientIntensity() const; // Only valid if stage Earth Sun model is disabled - Q_INVOKABLE void setSunDirection(const glm::vec3& direction); + Q_INVOKABLE void setKeyLightDirection(const glm::vec3& direction); - Q_INVOKABLE glm::vec3 getSunDirection() const; + Q_INVOKABLE glm::vec3 getKeyLightDirection() const; From f54821f9968913fc705c55f022dd43d9dba62fcc Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 21 Apr 2015 11:12:01 -0700 Subject: [PATCH 177/401] more details in the comments --- libraries/script-engine/src/SceneScriptingInterface.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 4c1a4e5da1..c384153a0f 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -38,6 +38,8 @@ public: Q_INVOKABLE void setStageYearTime(int day); Q_INVOKABLE int getStageYearTime() const; + // Enable/disable the stage sun model which uses the key light to simulate + // the sun light based on the location of the stage trelative to earth and the current time Q_INVOKABLE void setStageSunModelEnable(bool isEnabled); Q_INVOKABLE bool isStageSunModelEnabled() const; @@ -49,7 +51,7 @@ public: Q_INVOKABLE void setKeyLightAmbientIntensity(float intensity); Q_INVOKABLE float getKeyLightAmbientIntensity() const; - // Only valid if stage Earth Sun model is disabled + // setKeyLightDIrection is only effective if stage Sun model is disabled Q_INVOKABLE void setKeyLightDirection(const glm::vec3& direction); Q_INVOKABLE glm::vec3 getKeyLightDirection() const; From 4e2bcc069098704db2f424ace1c756557860db03 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Apr 2015 12:47:11 -0700 Subject: [PATCH 178/401] Add zone properties to entity property panel --- examples/html/entityProperties.html | 124 ++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index dd5bced393..649b9164ed 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -182,6 +182,23 @@ var elTextBackgroundColorGreen = document.getElementById("property-text-background-color-green"); var elTextBackgroundColorBlue = document.getElementById("property-text-background-color-blue"); + var elZoneSections = document.querySelectorAll(".zone-section"); + var elZoneStageSunModelEnabled = document.getElementById("property-zone-stage-sun-model-enabled"); + var elZoneKeyLightColorRed = document.getElementById("property-zone-key-light-color-red"); + var elZoneKeyLightColorGreen = document.getElementById("property-zone-key-light-color-green"); + var elZoneKeyLightColorBlue = document.getElementById("property-zone-key-light-color-blue"); + var elZoneKeyLightIntensity = document.getElementById("property-zone-key-color-intensity"); + var elZoneKeyLightAmbientIntensity = document.getElementById("property-zone-key-color-ambient-intensity"); + var elZoneKeyLightDirectionX = document.getElementById("property-zone-key-light-direction-x"); + var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y"); + var elZoneKeyLightDirectionZ = document.getElementById("property-zone-key-light-direction-z"); + + var elZoneStageLatitude = document.getElementById("property-zone-stage-latitude"); + var elZoneStageLongitude = document.getElementById("property-zone-stage-longitude"); + var elZoneStageAltitude = document.getElementById("property-zone-stage-altitude"); + var elZoneStageDay = document.getElementById("property-zone-stage-day"); + var elZoneStageHour = document.getElementById("property-zone-stage-hour"); + if (window.EventBridge !== undefined) { EventBridge.scriptEventReceived.connect(function(data) { data = JSON.parse(data); @@ -356,6 +373,32 @@ elLightCutoff.value = properties.cutoff; } + if (properties.type != "Zone") { + for (var i = 0; i < elZoneSections.length; i++) { + elZoneSections[i].style.display = 'none'; + } + } else { + for (var i = 0; i < elZoneSections.length; i++) { + elZoneSections[i].style.display = 'block'; + } + + elZoneStageSunModelEnabled.checked = properties.stageSunModelEnabled; + elZoneKeyLightColorRed.value = properties.keyLightColor.red; + elZoneKeyLightColorGreen.value = properties.keyLightColor.green; + elZoneKeyLightColorBlue.value = properties.keyLightColor.blue; + elZoneKeyLightIntensity.value = properties.keyLightIntensity; + elZoneKeyLightAmbientIntensity.value = properties.keyLightAmbientIntensity; + elZoneKeyLightDirectionX.value = properties.keyLightDirection.x.toFixed(2); + elZoneKeyLightDirectionY.value = properties.keyLightDirection.y.toFixed(2); + elZoneKeyLightDirectionZ.value = properties.keyLightDirection.z.toFixed(2); + + elZoneStageLatitude.value = properties.stageLatitude.toFixed(2); + elZoneStageLongitude.value = properties.stageLongitude.toFixed(2); + elZoneStageAltitude.value = properties.stageAltitude.toFixed(2); + elZoneStageDay.value = properties.stageDay; + elZoneStageHour.value = properties.stageHour; + } + if (selected) { activeElement.focus(); activeElement.select(); @@ -468,6 +511,26 @@ elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction); elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction); + elZoneStageSunModelEnabled.addEventListener('change', createEmitCheckedPropertyUpdateFunction('stageSunModelEnabled')); + var zoneKeyLightColorChangeFunction = createEmitColorPropertyUpdateFunction( + 'keyLightColor', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue); + elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction); + elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction); + elZoneKeyLightColorBlue.addEventListener('change', zoneKeyLightColorChangeFunction); + elZoneKeyLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('keyLightIntensity')); + elZoneKeyLightAmbientIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('keyLightAmbientIntensity')); + var zoneKeyLightDirectionChangeFunction = createEmitVec3PropertyUpdateFunction( + 'keyLightDirection', elZoneKeyLightDirectionX, elZoneKeyLightDirectionY, elZoneKeyLightDirectionZ); + elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction); + elZoneKeyLightDirectionY.addEventListener('change', zoneKeyLightDirectionChangeFunction); + elZoneKeyLightDirectionZ.addEventListener('change', zoneKeyLightDirectionChangeFunction); + + elZoneStageLatitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageLatitude')); + elZoneStageLongitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageLongitude')); + elZoneStageAltitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageAltitude')); + elZoneStageDay.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageDay')); + elZoneStageHour.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageHour')); + elMoveSelectionToGrid.addEventListener("click", function() { EventBridge.emitWebEvent(JSON.stringify({ type: "action", @@ -833,6 +896,67 @@ + +
+ Stage Sun Model Enabled + + + +
+ +
+
Key Color
+
+
R
+
G
+
B
+
+
+
+
Key Intensity
+
+ +
+
+
+
Key Direction
+
+
Pitch
+
Yaw
+
Roll
+
+
+ +
+
Stage Latitude
+
+ +
+
+
+
Stage Longitude
+
+ +
+
+
+
Stage Altitude
+
+ +
+
+
+
Stage Day
+
+ +
+
+
+
Stage Hour
+
+ +
+
From 3dfbd70d41e5e1ca9badbaa2e26e651590d0fe1f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Apr 2015 13:16:55 -0700 Subject: [PATCH 179/401] Add new zone button --- examples/edit.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/examples/edit.js b/examples/edit.js index 2b32769337..480b87d416 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -135,6 +135,7 @@ var toolBar = (function () { newSphereButton, newLightButton, newTextButton, + newZoneButton, browseMarketplaceButton; function initialize() { @@ -201,6 +202,14 @@ var toolBar = (function () { alpha: 0.9, visible: false }); + newZoneButton = toolBar.addTool({ + imageURL: toolIconUrl + "zonecube3.svg", + subImage: { x: 0, y: Tool.IMAGE_WIDTH + 208, width: 256, height: 256 }, + width: toolWidth, + height: toolHeight, + alpha: 0.9, + visible: false + }); that.setActive(false); } @@ -241,6 +250,7 @@ var toolBar = (function () { toolBar.showTool(newSphereButton, doShow); toolBar.showTool(newLightButton, doShow); toolBar.showTool(newTextButton, doShow); + toolBar.showTool(newZoneButton, doShow); }; var RESIZE_INTERVAL = 50; @@ -412,6 +422,21 @@ var toolBar = (function () { return true; } + if (newZoneButton === toolBar.clicked(clickedOverlay)) { + var position = getPositionToCreateEntity(); + + if (position.x > 0 && position.y > 0 && position.z > 0) { + placingEntityID = Entities.addEntity({ + type: "Zone", + position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS), + dimensions: { x: 10, y: 10, z: 10 }, + }); + } else { + print("Can't create box: Text would be out of bounds."); + } + return true; + } + return false; }; From e68f149aac64f4197ef891ced260e33af66e4d11 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 21 Apr 2015 13:18:53 -0700 Subject: [PATCH 180/401] Fixing bad merge --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 84c810ac0d..259b71afc2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -245,7 +245,7 @@ Menu::Menu() { false, qApp, SLOT(setFullscreen(bool))); -#endif + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, 0, // QML Qt::Key_P, true, qApp, SLOT(cameraMenuChanged())); From e436c9521206336b842152ce32783fbf913bff09 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 21 Apr 2015 14:36:13 -0700 Subject: [PATCH 181/401] first cut at reworking zones --- .../src/EntityTreeRenderer.cpp | 114 ++++++++++++++++- .../src/EntityTreeRenderer.h | 28 ++++- .../src/RenderableZoneEntityItem.cpp | 6 +- .../entities/src/EntityItemProperties.cpp | 85 ++++++++++++- libraries/entities/src/EntityItemProperties.h | 39 +++++- .../entities/src/EntityItemPropertiesMacros.h | 9 ++ libraries/entities/src/ZoneEntityItem.cpp | 117 ++++++++++++++---- libraries/entities/src/ZoneEntityItem.h | 69 +++++++++-- libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/networking/src/PacketHeaders.h | 3 +- 10 files changed, 421 insertions(+), 51 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 132feff7e3..adf7fb4e29 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "EntityTreeRenderer.h" @@ -35,7 +36,7 @@ #include "RenderableTextEntityItem.h" #include "RenderableZoneEntityItem.h" #include "EntitiesRendererLogging.h" - +#include "ZoneEntityItem.h" EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState, AbstractScriptingServicesInterface* scriptingServices) : @@ -395,10 +396,106 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R _tree->lockForRead(); - _tree->recurseTreeWithOperation(renderOperation, &args); -// Model::RenderMode modelRenderMode = renderMode == RenderArgs::SHADOW_RENDER_MODE - // ? RenderArgs::SHADOW_RENDER_MODE : RenderArgs::DEFAULT_RENDER_MODE; + // Implement some kind of a stack/union mechanism here... + // + // * As you enter a zone (A), you use it's properties + // * if already in a zone, and you enter the union of that zone and a new zone (A + B) + // you use the settings of the new zone (B) you entered.. but remember that you were previously + // in zone A + // * if you enter a new zone and are in the union of 3 zones (A+B+C) then use zone C and remember + // you were most recently in B + _lastZones = _currentZones; + _currentZones.clear(); + _tree->recurseTreeWithOperation(renderOperation, &args); + const ZoneEntityItem* bestZone = NULL; + + if (_currentZones.empty()) { + // if we're not in any current zone, then we can completely erase our zoneHistory + _zoneHistory.clear(); + } else { + // we're in some zone... check to see if we've changed zones.. + QSet newZones = _currentZones - _lastZones; + + if (!newZones.empty()) { + // we just entered a new zone, so we want to make a shift + EntityItemID theNewZone = *(newZones.begin()); // random we don't care, if it's one, then this works. + _zoneHistory << _currentZone; // remember the single zone we used to be in. + _currentZone = theNewZone; // change to our new zone + + // do something to remove any item of _zoneHistory that is not in _currentZones + QStack newHistory; + QStack::iterator i = _zoneHistory.begin(); + while(i != _zoneHistory.end()) { + EntityItemID zoneID = *i; + if (_currentZones.contains(zoneID)) { + newHistory << zoneID; + } + ++i; + } + + _zoneHistory = newHistory; + bestZone = dynamic_cast( + static_cast(_tree)->findEntityByEntityItemID(_currentZone)); + } else { + + if (_currentZones.contains(_currentZone)) { + // No change in zone, keep the current zone + bestZone = dynamic_cast( + static_cast(_tree)->findEntityByEntityItemID(_currentZone)); + } else { + if (!_zoneHistory.empty()) { + _currentZone = _zoneHistory.pop(); + bestZone = dynamic_cast( + static_cast(_tree)->findEntityByEntityItemID(_currentZone)); + } + + } + + } + } + + QSharedPointer scene = DependencyManager::get(); + + if (bestZone) { + if (!_hasPreviousZone) { + _previousKeyLightColor = scene->getKeyLightColor(); + _previousKeyLightIntensity = scene->getKeyLightIntensity(); + _previousKeyLightAmbientIntensity = scene->getKeyLightAmbientIntensity(); + _previousKeyLightDirection = scene->getKeyLightDirection(); + _previousUseEarthModel = scene->isStageEarthSunModelEnabled(); + _previousStageLongitude = scene->getStageLocationLongitude(); + _previousStageLatitude = scene->getStageLocationLatitude(); + _previousStageAltitude = scene->getStageLocationAltitude(); + _previousStageHour = scene->getStageDayTime(); + _previousStageDay = scene->getStageYearTime(); + _hasPreviousZone = true; + } + scene->setKeyLightColor(bestZone->getKeyLightColorVec3()); + scene->setKeyLightIntensity(bestZone->getKeyLightIntensity()); + scene->setKeyLightAmbientIntensity(bestZone->getKeyLightAmbientIntensity()); + scene->setKeyLightDirection(bestZone->getKeyLightDirection()); + scene->setStageEarthSunModelEnable(bestZone->getUseEarthModel()); + scene->setStageLocation(bestZone->getStageLongitude(), bestZone->getStageLatitude(), + bestZone->getStageAltitude()); + scene->setStageDayTime(bestZone->getStageHour()); + scene->setStageYearTime(bestZone->getStageDay()); + + } else { + _currentZone = EntityItemID(); // clear out current zone + if (_hasPreviousZone) { + scene->setKeyLightColor(_previousKeyLightColor); + scene->setKeyLightIntensity(_previousKeyLightIntensity); + scene->setKeyLightAmbientIntensity(_previousKeyLightAmbientIntensity); + scene->setKeyLightDirection(_previousKeyLightDirection); + scene->setStageEarthKeyLightModelEnable(_previousUseEarthModel); + scene->setStageLocation(_previousStageLongitude, _previousStageLatitude, + _previousStageAltitude); + scene->setStageDayTime(_previousStageHour); + scene->setStageYearTime(_previousStageDay); + _hasPreviousZone = false; + } + } // we must call endScene while we still have the tree locked so that no one deletes a model // on us while rendering the scene @@ -598,6 +695,15 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) EntityItem* entityItem = entityItems[i]; if (entityItem->isVisible()) { + + // Zone Entities are a special case we handle here... + if (entityItem->getType() == EntityTypes::Zone) { + if (entityItem->contains(args->_viewFrustum->getPosition())) { + _currentZones << entityItem->getEntityItemID(); + } + } + // NOTE: we might not want to render zones here... + // render entityItem AABox entityBox = entityItem->getAABox(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index e8d70c9df9..fd979fc9f9 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -12,18 +12,20 @@ #ifndef hifi_EntityTreeRenderer_h #define hifi_EntityTreeRenderer_h +#include +#include + #include #include // for RayToEntityIntersectionResult #include #include #include +class AbstractScriptingServicesInterface; +class AbstractViewStateInterface; class Model; class ScriptEngine; -class AbstractViewStateInterface; -class AbstractScriptingServicesInterface; - -class ScriptEngine; +class ZoneEntityItem; class EntityScriptDetails { public: @@ -164,6 +166,24 @@ private: bool _shuttingDown = false; QMultiMap _waitingOnPreload; + + QSet _lastZones; + QSet _currentZones; + QStack _zoneHistory; + EntityItemID _currentZone; + + bool _hasPreviousZone = false; + + glm::vec3 _previousKeyLightColor; + float _previousKeyLightIntensity; + float _previousKeyLightAmbientIntensity; + glm::vec3 _previousKeyLightDirection; + bool _previousStageSunModelEnabled; + float _previousStageLongitude; + float _previousStageLatitude; + float _previousStageAltitude; + float _previousStageHour; + int _previousStageDay; }; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 6a16404f89..d13fa37681 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -32,8 +32,8 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { const float MAX_COLOR = 255.0f; - glm::vec4 cubeColor(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR, - getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha()); + glm::vec4 cubeColor(_keyLightColor[RED_INDEX] / MAX_COLOR, _keyLightColor[GREEN_INDEX] / MAX_COLOR, + _keyLightColor[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha()); glPushMatrix(); glTranslatef(position.x, position.y, position.z); @@ -47,4 +47,6 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { glPopMatrix(); glPopMatrix(); + //debugDump(); + }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8a25d59f26..50856f53db 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -18,14 +18,14 @@ #include #include +#include "EntitiesLogging.h" #include "EntityItem.h" #include "EntityItemProperties.h" #include "EntityItemPropertiesDefaults.h" #include "ModelEntityItem.h" -#include "TextEntityItem.h" -#include "EntitiesLogging.h" #include "ParticleEffectEntityItem.h" - +#include "TextEntityItem.h" +#include "ZoneEntityItem.h" EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - 1); @@ -76,6 +76,16 @@ EntityItemProperties::EntityItemProperties() : CONSTRUCT_PROPERTY(localGravity, ParticleEffectEntityItem::DEFAULT_LOCAL_GRAVITY), CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS), CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), + CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR), + CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY), + CONSTRUCT_PROPERTY(keyLightAmbientIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY), + CONSTRUCT_PROPERTY(keyLightDirection, ZoneEntityItem::DEFAULT_KEYLIGHT_DIRECTION), + CONSTRUCT_PROPERTY(stageSunModelEnabled, ZoneEntityItem::DEFAULT_STAGE_SUN_MODEL_ENABLED), + CONSTRUCT_PROPERTY(stageLatitude, ZoneEntityItem::DEFAULT_STAGE_LATITUDE), + CONSTRUCT_PROPERTY(stageLongitude, ZoneEntityItem::DEFAULT_STAGE_LONGITUDE), + CONSTRUCT_PROPERTY(stageAltitude, ZoneEntityItem::DEFAULT_STAGE_ALTITUDE), + CONSTRUCT_PROPERTY(stageDay, ZoneEntityItem::DEFAULT_STAGE_DAY), + CONSTRUCT_PROPERTY(stageHour, ZoneEntityItem::DEFAULT_STAGE_HOUR), _id(UNKNOWN_ENTITY_ID), _idSet(false), @@ -268,6 +278,16 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_LOCAL_GRAVITY, localGravity); CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius); CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID); + CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, keyLightColor); + CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_INTENSITY, keyLightIntensity); + CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_AMBIENT_INTENSITY, keyLightAmbientIntensity); + CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_DIRECTION, keyLightDirection); + CHECK_PROPERTY_CHANGE(PROP_STAGE_SUN_MODEL_ENABLED, stageSunModelEnabled); + CHECK_PROPERTY_CHANGE(PROP_STAGE_LATITUDE, stageLatitude); + CHECK_PROPERTY_CHANGE(PROP_STAGE_LONGITUDE, stageLongitude); + CHECK_PROPERTY_CHANGE(PROP_STAGE_ALTITUDE, stageAltitude); + CHECK_PROPERTY_CHANGE(PROP_STAGE_DAY, stageDay); + CHECK_PROPERTY_CHANGE(PROP_STAGE_HOUR, stageHour); return changedProperties; } @@ -334,6 +354,17 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius); COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID); + COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(keyLightColor); + COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightIntensity); + COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightAmbientIntensity); + COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(keyLightDirection); + COPY_PROPERTY_TO_QSCRIPTVALUE(stageSunModelEnabled); + COPY_PROPERTY_TO_QSCRIPTVALUE(stageLatitude); + COPY_PROPERTY_TO_QSCRIPTVALUE(stageLongitude); + COPY_PROPERTY_TO_QSCRIPTVALUE(stageAltitude); + COPY_PROPERTY_TO_QSCRIPTVALUE(stageDay); + COPY_PROPERTY_TO_QSCRIPTVALUE(stageHour); + // Sitting properties support QScriptValue sittingPoints = engine->newObject(); for (int i = 0; i < _sittingPoints.size(); ++i) { @@ -418,6 +449,17 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(particleRadius, setParticleRadius); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(marketplaceID, setMarketplaceID); + COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(keyLightColor, setKeyLightColor); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(keyLightIntensity, setKeyLightIntensity); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(keyLightAmbientIntensity, setKeyLightAmbientIntensity); + COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(keyLightDirection, setKeyLightDirection); + COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(stageSunModelEnabled, setStageSunModelEnabled); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stageLatitude, setStageLatitude); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stageLongitude, setStageLongitude); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stageAltitude, setStageAltitude); + COPY_PROPERTY_FROM_QSCRIPTVALUE_INT(stageDay, setStageDay); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stageHour, setStageHour); + _lastEdited = usecTimestampNow(); } @@ -603,6 +645,19 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, appendValue, properties.getLocalGravity()); APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, properties.getParticleRadius()); } + + if (properties.getType() == EntityTypes::Zone) { + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, appendColor, properties.getKeyLightColor()); + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, appendValue, properties.getKeyLightIntensity()); + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, appendValue, properties.getKeyLightAmbientIntensity()); + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, appendValue, properties.getKeyLightDirection()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, appendValue, properties.getStageSunModelEnabled()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, appendValue, properties.getStageLatitude()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, appendValue, properties.getStageLongitude()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, properties.getStageAltitude()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, properties.getStageDay()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, properties.getStageHour()); + } APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, properties.getMarketplaceID()); } @@ -836,6 +891,19 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCAL_GRAVITY, float, setLocalGravity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius); } + + if (properties.getType() == EntityTypes::Zone) { + READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_KEYLIGHT_COLOR, setKeyLightColor); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_INTENSITY, float, setKeyLightIntensity); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_AMBIENT_INTENSITY, float, setKeyLightAmbientIntensity); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_DIRECTION, glm::vec3, setKeyLightDirection); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_SUN_MODEL_ENABLED, bool, setStageSunModelEnabled); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_LATITUDE, float, setStageLatitude); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_LONGITUDE, float, setStageLongitude); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_ALTITUDE, float, setStageAltitude); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_DAY, quint16, setStageDay); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_HOUR, float, setStageHour); + } READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MARKETPLACE_ID, setMarketplaceID); @@ -923,6 +991,17 @@ void EntityItemProperties::markAllChanged() { _particleRadiusChanged = true; _marketplaceIDChanged = true; + + _keyLightColorChanged = true; + _keyLightIntensityChanged = true; + _keyLightAmbientIntensityChanged = true; + _keyLightDirectionChanged = true; + _stageSunModelEnabledChanged = true; + _stageLatitudeChanged = true; + _stageLongitudeChanged = true; + _stageAltitudeChanged = true; + _stageDayChanged = true; + _stageHourChanged = true; } /// The maximum bounding cube for the entity, independent of it's rotation. diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 0bc0bcedc7..9a68abd73e 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -97,6 +97,17 @@ enum EntityPropertyList { PROP_MARKETPLACE_ID, PROP_ACCELERATION, PROP_SIMULATOR_ID, + + PROP_KEYLIGHT_COLOR, + PROP_KEYLIGHT_INTENSITY, + PROP_KEYLIGHT_AMBIENT_INTENSITY, + PROP_KEYLIGHT_DIRECTION, + PROP_STAGE_SUN_MODEL_ENABLED, + PROP_STAGE_LATITUDE, + PROP_STAGE_LONGITUDE, + PROP_STAGE_ALTITUDE, + PROP_STAGE_DAY, + PROP_STAGE_HOUR, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties ABOVE this line @@ -113,7 +124,22 @@ enum EntityPropertyList { PROP_TEXT = PROP_MODEL_URL, PROP_LINE_HEIGHT = PROP_ANIMATION_URL, PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS, - PROP_COLLISION_MODEL_URL_OLD_VERSION = PROP_ANIMATION_FPS + 1 + PROP_COLLISION_MODEL_URL_OLD_VERSION = PROP_ANIMATION_FPS + 1, + + // Aliases/Piggyback properties for Zones. These properties intentionally reuse the enum values for + // other properties + /* + PROP_KEYLIGHT_COLOR = PROP_COLOR, + PROP_KEYLIGHT_INTENSITY = PROP_INTENSITY, + PROP_KEYLIGHT_AMBIENT_INTENSITY = PROP_CUTOFF, + PROP_KEYLIGHT_DIRECTION = PROP_EXPONENT, + PROP_STAGE_SUN_MODEL_ENABLED = PROP_IS_SPOTLIGHT, + PROP_STAGE_LATITUDE = PROP_DIFFUSE_COLOR_UNUSED, + PROP_STAGE_LONGITUDE = PROP_AMBIENT_COLOR_UNUSED, + PROP_STAGE_ALTITUDE = PROP_SPECULAR_COLOR_UNUSED, + PROP_STAGE_DAY = PROP_LINEAR_ATTENUATION_UNUSED, + PROP_STAGE_HOUR = PROP_QUADRATIC_ATTENUATION_UNUSED, + */ // WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above }; @@ -215,6 +241,17 @@ public: DEFINE_PROPERTY(PROP_LOCAL_GRAVITY, LocalGravity, localGravity, float); DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float); DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString); + DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor); + DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float); + DEFINE_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float); + DEFINE_PROPERTY_REF(PROP_KEYLIGHT_DIRECTION, KeyLightDirection, keyLightDirection, glm::vec3); + DEFINE_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, StageSunModelEnabled, stageSunModelEnabled, bool); + DEFINE_PROPERTY(PROP_STAGE_LATITUDE, StageLatitude, stageLatitude, float); + DEFINE_PROPERTY(PROP_STAGE_LONGITUDE, StageLongitude, stageLongitude, float); + DEFINE_PROPERTY(PROP_STAGE_ALTITUDE, StageAltitude, stageAltitude, float); + DEFINE_PROPERTY(PROP_STAGE_DAY, StageDay, stageDay, quint16); + DEFINE_PROPERTY(PROP_STAGE_HOUR, StageHour, stageHour, float); + public: float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); } diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index e3e54f5bc8..753ac793ac 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -189,6 +189,15 @@ } \ } +#define COPY_PROPERTY_FROM_QSCRIPTVALUE_INT(P, S) \ + QScriptValue P = object.property(#P); \ + if (P.isValid()) { \ + int newValue = P.toVariant().toInt(); \ + if (_defaultSettings || newValue != _##P) { \ + S(newValue); \ + } \ + } + #define COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(P, S) \ QScriptValue P = object.property(#P); \ if (P.isValid()) { \ diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index a22c22ce5d..e0fe238c57 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -19,20 +19,18 @@ #include "EntitiesLogging.h" #include "EntityTreeElement.h" -/* bool ZoneEntityItem::_zonesArePickable = false; -const xColor ZoneEntityItem::DEFAULT_SUN_sunColor = { 255, 255, 255 }; -const float ZoneEntityItem::DEFAULT_SUN_INTENSITY = 0.1f; -const float ZoneEntityItem::DEFAULT_SUN_AMBIENT_INTENSITY = 0.0f; -const bool ZoneEntityItem::DEFAULT_SUN_USE_EARTH_MODEL = true; -const float ZoneEntityItem::DEFAULT_SUN_APPARENT_LATITUDE = 37.777f; -const float ZoneEntityItem::DEFAULT_SUN_APPARENT_LONGITUDE = 122.407f; -const float ZoneEntityItem::DEFAULT_SUN_APPARENT_ALTITUDE = 0.03f; -const quint16 ZoneEntityItem::DEFAULT_SUN_APPARENT_DAY = 60; -const float ZoneEntityItem::DEFAULT_SUN_APPARENT_HOUR = 12.0f; -const glm::vec3 ZoneEntityItem::DEFAULT_SUN_DIRECTION = { 0.0f, -1.0f, 0.0f }; -*/ +const xColor ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR = { 255, 255, 255 }; +const float ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY = 1.0f; +const float ZoneEntityItem::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY = 0.5f; +const glm::vec3 ZoneEntityItem::DEFAULT_KEYLIGHT_DIRECTION = { 0.0f, -1.0f, 0.0f }; +const bool ZoneEntityItem::DEFAULT_STAGE_SUN_MODEL_ENABLED = false; +const float ZoneEntityItem::DEFAULT_STAGE_LATITUDE = 37.777f; +const float ZoneEntityItem::DEFAULT_STAGE_LONGITUDE = 122.407f; +const float ZoneEntityItem::DEFAULT_STAGE_ALTITUDE = 0.03f; +const quint16 ZoneEntityItem::DEFAULT_STAGE_DAY = 60; +const float ZoneEntityItem::DEFAULT_STAGE_HOUR = 12.0f; EntityItem* ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItem* result = new ZoneEntityItem(entityID, properties); @@ -44,17 +42,37 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityIte { _type = EntityTypes::Zone; _created = properties.getCreated(); + + _keyLightColor[RED_INDEX] = DEFAULT_KEYLIGHT_COLOR.red; + _keyLightColor[GREEN_INDEX] = DEFAULT_KEYLIGHT_COLOR.green; + _keyLightColor[BLUE_INDEX] = DEFAULT_KEYLIGHT_COLOR.blue; + + _keyLightIntensity = DEFAULT_KEYLIGHT_INTENSITY; + _keyLightAmbientIntensity = DEFAULT_KEYLIGHT_AMBIENT_INTENSITY; + _keyLightDirection = DEFAULT_KEYLIGHT_DIRECTION; + _stageSunModelEnabled = DEFAULT_STAGE_SUN_MODEL_ENABLED; + _stageLatitude = DEFAULT_STAGE_LATITUDE; + _stageLongitude = DEFAULT_STAGE_LONGITUDE; + _stageAltitude = DEFAULT_STAGE_ALTITUDE; + _stageDay = DEFAULT_STAGE_DAY; + _stageHour = DEFAULT_STAGE_HOUR; + setProperties(properties); } EntityItemProperties ZoneEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class - properties._color = getXColor(); - properties._colorChanged = false; - - properties._glowLevel = getGlowLevel(); - properties._glowLevelChanged = false; + COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightColor, getKeyLightColor); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightIntensity, getKeyLightIntensity); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightAmbientIntensity, getKeyLightAmbientIntensity); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightDirection, getKeyLightDirection); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageSunModelEnabled, getStageSunModelEnabled); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageLatitude, getStageLatitude); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageLongitude, getStageLongitude); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageAltitude, getStageAltitude); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageDay, getStageDay); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageHour, getStageHour); return properties; } @@ -63,7 +81,16 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = false; somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightColor, setKeyLightColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightIntensity, setKeyLightIntensity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightAmbientIntensity, setKeyLightAmbientIntensity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightDirection, setKeyLightDirection); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageSunModelEnabled, setStageSunModelEnabled); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageLatitude, setStageLatitude); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageLongitude, setStageLongitude); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageAltitude, setStageAltitude); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageDay, setStageDay); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageHour, setStageHour); if (somethingChanged) { bool wantDebug = false; @@ -85,7 +112,16 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; - READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _sunColor); + READ_ENTITY_PROPERTY_COLOR(PROP_KEYLIGHT_COLOR, _keyLightColor); + READ_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, float, _keyLightIntensity); + READ_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, float, _keyLightAmbientIntensity); + READ_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, glm::vec3, _keyLightDirection); + READ_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, bool, _stageSunModelEnabled); + READ_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, float, _stageLatitude); + READ_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, float, _stageLongitude); + READ_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, float, _stageAltitude); + READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, _stageDay); + READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, _stageHour); return bytesRead; } @@ -94,7 +130,18 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, // TODO: eventually only include properties changed since the params.lastViewFrustumSent time EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_COLOR; + + requestedProperties += PROP_KEYLIGHT_COLOR; + requestedProperties += PROP_KEYLIGHT_INTENSITY; + requestedProperties += PROP_KEYLIGHT_AMBIENT_INTENSITY; + requestedProperties += PROP_KEYLIGHT_DIRECTION; + requestedProperties += PROP_STAGE_SUN_MODEL_ENABLED; + requestedProperties += PROP_STAGE_LATITUDE; + requestedProperties += PROP_STAGE_LONGITUDE; + requestedProperties += PROP_STAGE_ALTITUDE; + requestedProperties += PROP_STAGE_DAY; + requestedProperties += PROP_STAGE_HOUR; + return requestedProperties; } @@ -108,15 +155,33 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits bool successPropertyFits = true; - APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, appendColor, _keyLightColor); + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, appendValue, getKeyLightIntensity()); + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, appendValue, getKeyLightAmbientIntensity()); + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, appendValue, getKeyLightDirection()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, appendValue, getStageSunModelEnabled()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, appendValue, getStageLatitude()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, appendValue, getStageLongitude()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, getStageAltitude()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, getStageDay()); + APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, getStageHour()); } void ZoneEntityItem::debugDump() const { quint64 now = usecTimestampNow(); - qCDebug(entities) << " BOX EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " color:" << _sunColor[0] << "," << _sunColor[1] << "," << _sunColor[2]; - qCDebug(entities) << " position:" << debugTreeVector(_position); - qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); + qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " keyLightColor:" << _keyLightColor[0] << "," << _keyLightColor[1] << "," << _keyLightColor[2]; + qCDebug(entities) << " position:" << debugTreeVector(_position); + qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions); + qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); + qCDebug(entities) << " _keyLightIntensity:" << _keyLightIntensity; + qCDebug(entities) << " _keyLightAmbientIntensity:" << _keyLightAmbientIntensity; + qCDebug(entities) << " _keyLightDirection:" << _keyLightDirection; + qCDebug(entities) << " _stageSunModelEnabled:" << _stageSunModelEnabled; + qCDebug(entities) << " _stageLatitude:" << _stageLatitude; + qCDebug(entities) << " _stageLongitude:" << _stageLongitude; + qCDebug(entities) << " _stageAltitude:" << _stageAltitude; + qCDebug(entities) << " _stageDay:" << _stageDay; + qCDebug(entities) << " _stageHour:" << _stageHour; } diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 4b0b960697..5d22b2d8bd 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -41,22 +41,73 @@ public: ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); - const rgbColor& getColor() const { return _sunColor; } - xColor getXColor() const { xColor color = { _sunColor[RED_INDEX], _sunColor[GREEN_INDEX], _sunColor[BLUE_INDEX] }; return color; } + virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } - void setColor(const rgbColor& value) { memcpy(_sunColor, value, sizeof(_sunColor)); } - void setColor(const xColor& value) { - _sunColor[RED_INDEX] = value.red; - _sunColor[GREEN_INDEX] = value.green; - _sunColor[BLUE_INDEX] = value.blue; + xColor getKeyLightColor() const { xColor color = { _keyLightColor[RED_INDEX], _keyLightColor[GREEN_INDEX], _keyLightColor[BLUE_INDEX] }; return color; } + void setKeyLightColor(const xColor& value) { + _keyLightColor[RED_INDEX] = value.red; + _keyLightColor[GREEN_INDEX] = value.green; + _keyLightColor[BLUE_INDEX] = value.blue; } - virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } + float getKeyLightIntensity() const { return _keyLightIntensity; } + void setKeyLightIntensity(float value) { _keyLightIntensity = value; } + + float getKeyLightAmbientIntensity() const { return _keyLightAmbientIntensity; } + void setKeyLightAmbientIntensity(float value) { _keyLightAmbientIntensity = value; } + + const glm::vec3& getKeyLightDirection() const { return _keyLightDirection; } + void setKeyLightDirection(const glm::vec3& value) { _keyLightDirection = value; } + + bool getStageSunModelEnabled() const { return _stageSunModelEnabled; } + void setStageSunModelEnabled(bool value) { _stageSunModelEnabled = value; } + + float getStageLatitude() const { return _stageLatitude; } + void setStageLatitude(float value) { _stageLatitude = value; } + + float getStageLongitude() const { return _stageLongitude; } + void setStageLongitude(float value) { _stageLongitude = value; } + + float getStageAltitude() const { return _stageAltitude; } + void setStageAltitude(float value) { _stageAltitude = value; } + + uint16_t getStageDay() const { return _stageDay; } + void setStageDay(uint16_t value) { _stageDay = value; } + + float getStageHour() const { return _stageHour; } + void setStageHour(float value) { _stageHour = value; } + + static bool getZonesArePickable() { return _zonesArePickable; } + static void setZonesArePickable(bool value) { _zonesArePickable = value; } + virtual void debugDump() const; + static const xColor DEFAULT_KEYLIGHT_COLOR; + static const float DEFAULT_KEYLIGHT_INTENSITY; + static const float DEFAULT_KEYLIGHT_AMBIENT_INTENSITY; + static const glm::vec3 DEFAULT_KEYLIGHT_DIRECTION; + static const bool DEFAULT_STAGE_SUN_MODEL_ENABLED; + static const float DEFAULT_STAGE_LATITUDE; + static const float DEFAULT_STAGE_LONGITUDE; + static const float DEFAULT_STAGE_ALTITUDE; + static const quint16 DEFAULT_STAGE_DAY; + static const float DEFAULT_STAGE_HOUR; + protected: - rgbColor _sunColor; + // properties of the "sun" in the zone + rgbColor _keyLightColor; + float _keyLightIntensity; + float _keyLightAmbientIntensity; + glm::vec3 _keyLightDirection; + bool _stageSunModelEnabled; + float _stageLatitude; + float _stageLongitude; + float _stageAltitude; + uint16_t _stageDay; + float _stageHour; + + static bool _zonesArePickable; }; #endif // hifi_ZoneEntityItem_h diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 52153f9e83..8f0cee10cf 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_HAVE_ACCELERATION; + return VERSION_ENTITIES_ZONE_ENTITIES_EXIST; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 9fb14854aa..0f89aa9423 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -119,6 +119,7 @@ PacketType packetTypeForPacket(const char* packet); int arithmeticCodingValueFromBuffer(const char* checkValue); int numBytesArithmeticCodingFromBuffer(const char* checkValue); +const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; const PacketVersion VERSION_ENTITIES_HAVE_ANIMATION = 1; const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2; const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3; @@ -135,6 +136,6 @@ const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 12; const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED = 13; const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14; const PacketVersion VERSION_ENTITIES_HAVE_ACCELERATION = 15; -const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; +const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_EXIST = 16; #endif // hifi_PacketHeaders_h From 4ce451f9845856186f081773d355b6b61755e504 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 21 Apr 2015 14:55:45 -0700 Subject: [PATCH 182/401] wire up zone rendering again --- .../entities-renderer/src/EntityTreeRenderer.cpp | 6 +++--- libraries/entities/src/ZoneEntityItem.h | 14 +++++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index adf7fb4e29..59f7aa0f5c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -463,7 +463,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R _previousKeyLightIntensity = scene->getKeyLightIntensity(); _previousKeyLightAmbientIntensity = scene->getKeyLightAmbientIntensity(); _previousKeyLightDirection = scene->getKeyLightDirection(); - _previousUseEarthModel = scene->isStageEarthSunModelEnabled(); + _previousStageSunModelEnabled = scene->isStageSunModelEnabled(); _previousStageLongitude = scene->getStageLocationLongitude(); _previousStageLatitude = scene->getStageLocationLatitude(); _previousStageAltitude = scene->getStageLocationAltitude(); @@ -475,7 +475,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R scene->setKeyLightIntensity(bestZone->getKeyLightIntensity()); scene->setKeyLightAmbientIntensity(bestZone->getKeyLightAmbientIntensity()); scene->setKeyLightDirection(bestZone->getKeyLightDirection()); - scene->setStageEarthSunModelEnable(bestZone->getUseEarthModel()); + scene->setStageSunModelEnable(bestZone->getStageSunModelEnabled()); scene->setStageLocation(bestZone->getStageLongitude(), bestZone->getStageLatitude(), bestZone->getStageAltitude()); scene->setStageDayTime(bestZone->getStageHour()); @@ -488,7 +488,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R scene->setKeyLightIntensity(_previousKeyLightIntensity); scene->setKeyLightAmbientIntensity(_previousKeyLightAmbientIntensity); scene->setKeyLightDirection(_previousKeyLightDirection); - scene->setStageEarthKeyLightModelEnable(_previousUseEarthModel); + scene->setStageSunModelEnable(_previousStageSunModelEnabled); scene->setStageLocation(_previousStageLongitude, _previousStageLatitude, _previousStageAltitude); scene->setStageDayTime(_previousStageHour); diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 5d22b2d8bd..8f1b15d174 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -41,7 +41,10 @@ public: ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); - virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } + // NOTE: Apparently if you begin to return a shape type, then the physics system will prevent an avatar + // from penetrating the walls of the entity. This fact will likely be important to Clement as he works + // on better defining the shape/volume of a zone. + //virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } xColor getKeyLightColor() const { xColor color = { _keyLightColor[RED_INDEX], _keyLightColor[GREEN_INDEX], _keyLightColor[BLUE_INDEX] }; return color; } void setKeyLightColor(const xColor& value) { @@ -49,6 +52,15 @@ public: _keyLightColor[GREEN_INDEX] = value.green; _keyLightColor[BLUE_INDEX] = value.blue; } + + glm::vec3 getKeyLightColorVec3() const { + const quint8 MAX_COLOR = 255; + glm::vec3 color = { _keyLightColor[RED_INDEX] / MAX_COLOR, + _keyLightColor[GREEN_INDEX] / MAX_COLOR, + _keyLightColor[BLUE_INDEX] / MAX_COLOR }; + return color; + } + float getKeyLightIntensity() const { return _keyLightIntensity; } void setKeyLightIntensity(float value) { _keyLightIntensity = value; } From 8366dd02a0f1c0f3bdad779dae359c5a607c0645 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 21 Apr 2015 15:03:04 -0700 Subject: [PATCH 183/401] remove RenderableZoneEntityItem class since zones don't render like other entities --- .../src/EntityTreeRenderer.cpp | 52 +++++++++---------- .../src/RenderableZoneEntityItem.cpp | 52 ------------------- .../src/RenderableZoneEntityItem.h | 29 ----------- 3 files changed, 25 insertions(+), 108 deletions(-) delete mode 100644 libraries/entities-renderer/src/RenderableZoneEntityItem.cpp delete mode 100644 libraries/entities-renderer/src/RenderableZoneEntityItem.h diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 59f7aa0f5c..c14a821a38 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -34,7 +34,6 @@ #include "RenderableParticleEffectEntityItem.h" #include "RenderableSphereEntityItem.h" #include "RenderableTextEntityItem.h" -#include "RenderableZoneEntityItem.h" #include "EntitiesRendererLogging.h" #include "ZoneEntityItem.h" @@ -58,7 +57,6 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Text, RenderableTextEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory) - REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory) _currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID _currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID @@ -696,42 +694,42 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) if (entityItem->isVisible()) { - // Zone Entities are a special case we handle here... + // NOTE: Zone Entities are a special case we handle here... Zones don't render + // like other entity types. So we will skip the normal rendering tests if (entityItem->getType() == EntityTypes::Zone) { if (entityItem->contains(args->_viewFrustum->getPosition())) { _currentZones << entityItem->getEntityItemID(); } - } - // NOTE: we might not want to render zones here... - - // render entityItem - AABox entityBox = entityItem->getAABox(); + } else { + // render entityItem + AABox entityBox = entityItem->getAABox(); - // TODO: some entity types (like lights) might want to be rendered even - // when they are outside of the view frustum... - float distance = args->_viewFrustum->distanceToCamera(entityBox.calcCenter()); + // TODO: some entity types (like lights) might want to be rendered even + // when they are outside of the view frustum... + float distance = args->_viewFrustum->distanceToCamera(entityBox.calcCenter()); - bool outOfView = args->_viewFrustum->boxInFrustum(entityBox) == ViewFrustum::OUTSIDE; - if (!outOfView) { - bool bigEnoughToRender = _viewState->shouldRenderMesh(entityBox.getLargestDimension(), distance); + bool outOfView = args->_viewFrustum->boxInFrustum(entityBox) == ViewFrustum::OUTSIDE; + if (!outOfView) { + bool bigEnoughToRender = _viewState->shouldRenderMesh(entityBox.getLargestDimension(), distance); - if (bigEnoughToRender) { - renderProxies(entityItem, args); + if (bigEnoughToRender) { + renderProxies(entityItem, args); - Glower* glower = NULL; - if (entityItem->getGlowLevel() > 0.0f) { - glower = new Glower(entityItem->getGlowLevel()); - } - entityItem->render(args); - args->_itemsRendered++; - if (glower) { - delete glower; + Glower* glower = NULL; + if (entityItem->getGlowLevel() > 0.0f) { + glower = new Glower(entityItem->getGlowLevel()); + } + entityItem->render(args); + args->_itemsRendered++; + if (glower) { + delete glower; + } + } else { + args->_itemsTooSmall++; } } else { - args->_itemsTooSmall++; + args->_itemsOutOfView++; } - } else { - args->_itemsOutOfView++; } } } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp deleted file mode 100644 index d13fa37681..0000000000 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// -// RenderableZoneEntityItem.cpp -// interface/src -// -// Created by Brad Hefta-Gaub on 8/6/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 "RenderableZoneEntityItem.h" - -EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return new RenderableZoneEntityItem(entityID, properties); -} - -void RenderableZoneEntityItem::render(RenderArgs* args) { - PerformanceTimer perfTimer("RenderableZoneEntityItem::render"); - assert(getType() == EntityTypes::Zone); - glm::vec3 position = getPosition(); - glm::vec3 center = getCenter(); - glm::vec3 dimensions = getDimensions(); - glm::quat rotation = getRotation(); - - const float MAX_COLOR = 255.0f; - - glm::vec4 cubeColor(_keyLightColor[RED_INDEX] / MAX_COLOR, _keyLightColor[GREEN_INDEX] / MAX_COLOR, - _keyLightColor[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha()); - - glPushMatrix(); - glTranslatef(position.x, position.y, position.z); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - glPushMatrix(); - glm::vec3 positionToCenter = center - position; - glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); - glScalef(dimensions.x, dimensions.y, dimensions.z); - DependencyManager::get()->renderWireCube(1.0f, cubeColor); - glPopMatrix(); - glPopMatrix(); - - //debugDump(); - -}; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h deleted file mode 100644 index b05fd0e3f8..0000000000 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// RenderableZoneEntityItem.h -// interface/src/entities -// -// Created by Brad Hefta-Gaub on 8/6/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_RenderableZoneEntityItem_h -#define hifi_RenderableZoneEntityItem_h - -#include - -class RenderableZoneEntityItem : public ZoneEntityItem { -public: - static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - ZoneEntityItem(entityItemID, properties) - { } - - virtual void render(RenderArgs* args); -}; - - -#endif // hifi_RenderableZoneEntityItem_h From 486ab044a0b6065136b63d1509092e8ac8d99f4f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 21 Apr 2015 15:16:46 -0700 Subject: [PATCH 184/401] use piggyback properties to save on property bit space --- libraries/entities/src/EntityItemProperties.h | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 9a68abd73e..27b9adbc1b 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -98,23 +98,11 @@ enum EntityPropertyList { PROP_ACCELERATION, PROP_SIMULATOR_ID, - PROP_KEYLIGHT_COLOR, - PROP_KEYLIGHT_INTENSITY, - PROP_KEYLIGHT_AMBIENT_INTENSITY, - PROP_KEYLIGHT_DIRECTION, - PROP_STAGE_SUN_MODEL_ENABLED, - PROP_STAGE_LATITUDE, - PROP_STAGE_LONGITUDE, - PROP_STAGE_ALTITUDE, - PROP_STAGE_DAY, - PROP_STAGE_HOUR, - //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties ABOVE this line PROP_AFTER_LAST_ITEM, //////////////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////////////// // WARNING! Do not add props here unless you intentionally mean to reuse PROP_ indexes // @@ -127,8 +115,8 @@ enum EntityPropertyList { PROP_COLLISION_MODEL_URL_OLD_VERSION = PROP_ANIMATION_FPS + 1, // Aliases/Piggyback properties for Zones. These properties intentionally reuse the enum values for - // other properties - /* + // other properties which will never overlap with each other. We do this so that we don't have to expand + // the size of the properties bitflags mask PROP_KEYLIGHT_COLOR = PROP_COLOR, PROP_KEYLIGHT_INTENSITY = PROP_INTENSITY, PROP_KEYLIGHT_AMBIENT_INTENSITY = PROP_CUTOFF, @@ -139,7 +127,7 @@ enum EntityPropertyList { PROP_STAGE_ALTITUDE = PROP_SPECULAR_COLOR_UNUSED, PROP_STAGE_DAY = PROP_LINEAR_ATTENUATION_UNUSED, PROP_STAGE_HOUR = PROP_QUADRATIC_ATTENUATION_UNUSED, - */ + // WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above }; From cde64893afbdf95ea60d12b7b4c088f259d908fe Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 21 Apr 2015 18:36:06 -0700 Subject: [PATCH 185/401] coding standard --- libraries/entities/src/EntityTree.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 85caccbf34..5b15aa26b4 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -25,7 +25,7 @@ #include "RecurseOctreeToMapOperator.h" -const quint64 SIMULATOR_CHANGE_LOCKOUT_PERIOD = 0.2 * USECS_PER_SECOND; +const quint64 SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND); EntityTree::EntityTree(bool shouldReaverage) : diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index e689ac21bc..e5a12a2b66 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -18,7 +18,7 @@ #include "PhysicsHelpers.h" #include "PhysicsLogging.h" -static const float MEASURED_ACCELERATION_CLOSE_TO_ZERO = 0.05; +static const float MEASURED_ACCELERATION_CLOSE_TO_ZERO = 0.05f; QSet* _outgoingEntityList; @@ -215,7 +215,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ EntityItemProperties properties = _entity->getProperties(); if (glm::length(_measuredAcceleration) < MEASURED_ACCELERATION_CLOSE_TO_ZERO) { - _entity->setAcceleration(glm::vec3(0)); + _entity->setAcceleration(glm::vec3(0.0f)); } else { _entity->setAcceleration(_entity->getGravity()); } From e334c456ea0900c3432208ee34f9804fe6941a9a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 10:13:13 -0700 Subject: [PATCH 186/401] add a place to keep track of the number of simulation steps where acceleration was close to gravity for a given Entity --- libraries/entities/src/EntityItem.cpp | 1 + libraries/entities/src/EntityItem.h | 1 + 2 files changed, 2 insertions(+) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 12fb1ba99d..205b615642 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -74,6 +74,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { _created = UNKNOWN_CREATED_TIME; _dirtyFlags = 0; _changedOnServer = 0; + _accelerationNearlyGravityCount = 0; _element = NULL; _simulatorIDChangedTime = 0; _shouldClaimSimulationOwnership = false; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ad856698a2..ff4b975824 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -343,6 +343,7 @@ protected: glm::vec3 _velocity; glm::vec3 _gravity; glm::vec3 _acceleration; + quint8 _accelerationNearlyGravityCount; float _damping; float _lifetime; QString _script; From 3f705f3172f7cb599a4f50e8a2e6ffafdc23dcfc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 10:39:13 -0700 Subject: [PATCH 187/401] keep track of the number of simulation steps each entity has been accelerated at nearly its gravity. if we get 4 in a row, start sending acceleration equal to gravity to the entity server, so it will include gravity in its estimates --- libraries/entities/src/EntityItem.h | 4 ++++ libraries/physics/src/EntityMotionState.cpp | 23 ++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ff4b975824..a4903044d9 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -311,6 +311,10 @@ public: static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; } static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; } + void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } + void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } + quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } + protected: static bool _sendPhysicsUpdates; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index e5a12a2b66..86a60e5b99 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -18,7 +18,8 @@ #include "PhysicsHelpers.h" #include "PhysicsLogging.h" -static const float MEASURED_ACCELERATION_CLOSE_TO_ZERO = 0.05f; +static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; +static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4; QSet* _outgoingEntityList; @@ -214,10 +215,26 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); - if (glm::length(_measuredAcceleration) < MEASURED_ACCELERATION_CLOSE_TO_ZERO) { - _entity->setAcceleration(glm::vec3(0.0f)); + float gravityLength = glm::length(_entity->getGravity()); + float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); + if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { + // acceleration measured during the most recent simulation step was close to gravity. + if (_entity->getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { + // only increment this if we haven't reached the threshold yet. this is to avoid + // overflowing the counter. + _entity->incrementAccelerationNearlyGravityCount(); + } } else { + // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter + _entity->resetAccelerationNearlyGravityCount(); + } + + // if this entity has been accelerated at close to gravity for a certain number of frames, let + // the entity server's estimates include gravity. + if (_entity->getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { _entity->setAcceleration(_entity->getGravity()); + } else { + _entity->setAcceleration(glm::vec3(0.0f)); } if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { From 32673efc80ccc9e92a65cdadbac454e571fca41f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 10:51:45 -0700 Subject: [PATCH 188/401] compute collision events inside lock to avoid a rare crash --- libraries/physics/src/PhysicsEngine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 44bba990ac..d4963aaf81 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -348,10 +348,10 @@ void PhysicsEngine::stepSimulation() { _characterController->postSimulation(); } + computeCollisionEvents(); + unlock(); _entityTree->unlock(); - - computeCollisionEvents(); } } From 41166c1a42327d48c42bd164fa0e089668c12f4c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 11:18:18 -0700 Subject: [PATCH 189/401] allow entity server to time-out entity-simulation ownership rather than having interfaces give it up --- libraries/physics/src/EntityMotionState.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 86a60e5b99..c29abf9571 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -294,8 +294,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setSimulatorID(myNodeID); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the object has stopped. give up "simulator" status - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); + // _entity->setSimulatorID(QUuid()); + // properties.setSimulatorID(QUuid()); } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. From ac81e3e84781d5717ff983380f1f5136ed0f3a9a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 22 Apr 2015 11:27:35 -0700 Subject: [PATCH 190/401] added example script --- .../example/entities/zoneEntityExample.js | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/example/entities/zoneEntityExample.js diff --git a/examples/example/entities/zoneEntityExample.js b/examples/example/entities/zoneEntityExample.js new file mode 100644 index 0000000000..84d87d1370 --- /dev/null +++ b/examples/example/entities/zoneEntityExample.js @@ -0,0 +1,69 @@ +// +// zoneEntityExample.js +// examples +// +// Created by Brad Hefta-Gaub on 4/16/15. +// Copyright 2015 High Fidelity, Inc. +// +// This is an example script that demonstrates creating and editing a entity +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +var count = 0; +var stopAfter = 1000; + +var zoneEntityA = Entities.addEntity({ + type: "Zone", + position: { x: 5, y: 5, z: 5 }, + dimensions: { x: 10, y: 10, z: 10 }, + keyLightColor: { red: 255, green: 0, blue: 0 }, + stageSunModelEnabled: false, + keyLightDirection: { x: 0, y: -1.0, z: 0 } +}); + +print("zoneEntityA:" + zoneEntityA); + +var zoneEntityB = Entities.addEntity({ + type: "Zone", + position: { x: 1, y: 1, z: 21 }, + dimensions: { x: 2, y: 2, z: 2 }, + keyLightColor: { red: 0, green: 255, blue: 0 }, + keyLightIntensity: 0.9, + stageLatitude: 37.777, + stageLongitude: 122.407, + stageAltitude: 0.03, + stageDay: 60, + stageHour: 12, + stageSunModelEnabled: true +}); + +print("zoneEntityB:" + zoneEntityB); + + +var zoneEntityC = Entities.addEntity({ + type: "Zone", + position: { x: 5, y: 5, z: 15 }, + dimensions: { x: 10, y: 10, z: 10 }, + keyLightColor: { red: 0, green: 0, blue: 255 }, + keyLightIntensity: 0.75, + keyLightDirection: { x: 0, y: 0, z: -1 }, + stageSunModelEnabled: false +}); + +print("zoneEntityC:" + zoneEntityC); + + +// register the call back so it fires before each data send +Script.update.connect(function(deltaTime) { + // stop it... + if (count >= stopAfter) { + print("calling Script.stop()"); + Script.stop(); + } + count++; +}); + From dbf40afa4722689768cca3175e2a4b8e967bc0b6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 17 Apr 2015 18:25:20 +0200 Subject: [PATCH 191/401] Remove deprecated "*InDomainUnit" getter/setter --- libraries/entities/src/EntityItem.cpp | 6 ------ libraries/entities/src/EntityItem.h | 15 --------------- libraries/entities/src/TextEntityItem.cpp | 5 ----- libraries/entities/src/TextEntityItem.h | 1 - 4 files changed, 27 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 12fb1ba99d..0e6976c730 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1033,12 +1033,6 @@ AABox EntityItem::getAABox() const { return AABox(rotatedExtentsRelativeToRegistrationPoint); } -AABox EntityItem::getAABoxInDomainUnits() const { - AABox box = getAABox(); - box.scale(1.0f / (float)TREE_SCALE); - return box; -} - // NOTE: This should only be used in cases of old bitstreams which only contain radius data // 0,0,0 --> maxDimension,maxDimension,maxDimension // ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ad856698a2..4e1578510d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -145,25 +145,16 @@ public: // attributes applicable to all entity types EntityTypes::EntityType getType() const { return _type; } - glm::vec3 getPositionInDomainUnits() const { return _position / (float)TREE_SCALE; } /// get position in domain scale units (0.0 - 1.0) const glm::vec3& getPosition() const { return _position; } /// get position in meters - /// set position in domain scale units (0.0 - 1.0) - void setPositionInDomainUnits(const glm::vec3& value) - { setPosition(glm::clamp(value, 0.0f, 1.0f) * (float)TREE_SCALE); } void setPosition(const glm::vec3& value) { _position = value; } - glm::vec3 getCenterInDomainUnits() const { return getCenter() / (float) TREE_SCALE; } glm::vec3 getCenter() const; - glm::vec3 getDimensionsInDomainUnits() const { return _dimensions / (float)TREE_SCALE; } /// get dimensions in domain scale units (0.0 - 1.0) const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in meters - /// set dimensions in domain scale units (0.0 - 1.0) - virtual void setDimensionsInDomainUnits(const glm::vec3& value) { _dimensions = glm::abs(value) * (float)TREE_SCALE; } - /// set dimensions in meter units (0.0 - TREE_SCALE) virtual void setDimensions(const glm::vec3& value) { _dimensions = glm::abs(value); } @@ -182,15 +173,11 @@ public: float getDensity() const { return _density; } - glm::vec3 getVelocityInDomainUnits() const { return _velocity / (float)TREE_SCALE; } /// velocity in domain scale units (0.0-1.0) per second const glm::vec3 getVelocity() const { return _velocity; } /// get velocity in meters - void setVelocityInDomainUnits(const glm::vec3& value) { _velocity = value * (float)TREE_SCALE; } /// velocity in domain scale units (0.0-1.0) per second void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in meters bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; } - glm::vec3 getGravityInDomainUnits() const { return _gravity / (float)TREE_SCALE; } /// gravity in domain scale units (0.0-1.0) per second squared const glm::vec3& getGravity() const { return _gravity; } /// get gravity in meters - void setGravityInDomainUnits(const glm::vec3& value) { _gravity = value * (float)TREE_SCALE; } /// gravity in domain scale units (0.0-1.0) per second squared void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; } @@ -220,7 +207,6 @@ public: AACube getMaximumAACube() const; AACube getMinimumAACube() const; AABox getAABox() const; /// axis aligned bounding box in world-frame (meters) - AABox getAABoxInDomainUnits() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0) const QString& getScript() const { return _script; } void setScript(const QString& value) { _script = value; } @@ -268,7 +254,6 @@ public: float getRadius() const; virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); } - virtual bool containsInDomainUnits(const glm::vec3& point) const { return getAABoxInDomainUnits().contains(point); } virtual bool isReadyToComputeShape() { return true; } virtual void computeShapeInfo(ShapeInfo& info); diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 39a4d48d96..34d0ce051c 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -48,11 +48,6 @@ void TextEntityItem::setDimensions(const glm::vec3& value) { _dimensions = glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH); } -void TextEntityItem::setDimensionsInDomainUnits(const glm::vec3& value) { - // NOTE: Text Entities always have a "depth" of 1cm. - _dimensions = glm::vec3(value.x * (float)TREE_SCALE, value.y * (float)TREE_SCALE, TEXT_ENTITY_ITEM_FIXED_DEPTH); -} - EntityItemProperties TextEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 044975bdc8..d57b5442d6 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -24,7 +24,6 @@ public: /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately virtual void setDimensions(const glm::vec3& value); - virtual void setDimensionsInDomainUnits(const glm::vec3& value); virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity From 8db9f80779b73e5280548cfe1044327ee32ce5e9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Apr 2015 17:13:59 +0200 Subject: [PATCH 192/401] Reimplements "contains" for sphere and particles --- libraries/entities/src/ParticleEffectEntityItem.cpp | 8 ++++++++ libraries/entities/src/ParticleEffectEntityItem.h | 2 ++ libraries/entities/src/SphereEntityItem.cpp | 8 ++++++++ libraries/entities/src/SphereEntityItem.h | 3 +-- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 45312f465b..f12259d057 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -236,6 +236,14 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, getParticleRadius()); } +bool ParticleEffectEntityItem::contains(const glm::vec3& point) const { + // Transform point to be in a space where the elipsoide is a perfect sphere centered on the origin. + glm::vec3 transformedPoint = (point - getPosition()) / (getDimensions() / 2.0f); + + // Return whether said point is inside the sphere. + return glm::length(transformedPoint) <= 1.0f; +} + bool ParticleEffectEntityItem::isAnimatingSomething() const { return getAnimationIsPlaying() && getAnimationFPS() != 0.0f; diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index b00eb94685..b563274fa1 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -77,6 +77,8 @@ public: _color[GREEN_INDEX] = value.green; _color[BLUE_INDEX] = value.blue; } + + virtual bool contains(const glm::vec3& point) const; void updateShapeType(ShapeType type); virtual ShapeType getShapeType() const { return _shapeType; } diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 132ad43336..4a756be618 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -92,6 +92,14 @@ void SphereEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBi APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); } +bool SphereEntityItem::contains(const glm::vec3& point) const { + // Transform point to be in a space where the elipsoide is a perfect sphere centered on the origin. + glm::vec3 transformedPoint = (point - getPosition()) / (getDimensions() / 2.0f); + + // Return whether said point is inside the sphere. + return glm::length(transformedPoint) <= 1.0f; +} + bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index f79a2db7ff..98450121c5 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -50,8 +50,7 @@ public: _color[BLUE_INDEX] = value.blue; } - // TODO: implement proper contains for 3D ellipsoid - //virtual bool contains(const glm::vec3& point) const; + virtual bool contains(const glm::vec3& point) const; virtual ShapeType getShapeType() const { return SHAPE_TYPE_SPHERE; } From 955723acf10465d46991cce5d7fb141916b386bd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Apr 2015 17:21:27 +0200 Subject: [PATCH 193/401] RenderableEntityItem uses collision hull in contains --- .../src/RenderableModelEntityItem.cpp | 32 +++++++++++++++++++ .../src/RenderableModelEntityItem.h | 2 ++ libraries/shared/src/GLMHelpers.cpp | 7 ++++ libraries/shared/src/GLMHelpers.h | 2 ++ 4 files changed, 43 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 86b0be4dd8..ab823d090b 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -415,3 +415,35 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } +bool RenderableModelEntityItem::contains(const glm::vec3& point) const { + bool result = EntityItem::contains(point); + + if (result && _model && _model->getCollisionGeometry()) { + const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); + const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); + + auto checkEachPrimitive = [=](FBXMesh& mesh, QVector indices, int primitiveSize) -> bool { + for (unsigned int j = 0; j < indices.size(); j += primitiveSize) { + if (!isPointBehindTrianglesPlane(point, + mesh.vertices[indices[j]], + mesh.vertices[indices[j + 1]], + mesh.vertices[indices[j + 2]])) { + return false; + } + } + return true; + }; + + for (auto mesh : collisionGeometry.meshes) { + for (auto part : mesh.parts) { + // run through all the triangles and quads + if (!checkEachPrimitive(mesh, part.triangleIndices, 3) || + !checkEachPrimitive(mesh, part.quadIndices, 4)) { + return false; + } + } + } + } + + return result; +} diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index b632357942..ea153a2dd6 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -56,6 +56,8 @@ public: bool isReadyToComputeShape(); void computeShapeInfo(ShapeInfo& info); + + virtual bool contains(const glm::vec3& point) const; private: void remapTextures(); diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 4e8fb7d3cd..aed73c1989 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -203,6 +203,13 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { return glm::angleAxis(angle, axis); } +bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, glm::vec3 p2) { + glm::vec3 v1 = p0 - p1, v2 = p2 - p1; // Non-collinear vectors contained in the plane + glm::vec3 n = glm::cross(v1, v2); // Plane's normal vector, pointing out of the triangle + float d = -glm::dot(n, p0); // Compute plane's equation constant + return (glm::dot(n, point) + d) <= 0; +} + glm::vec3 extractTranslation(const glm::mat4& matrix) { return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]); } diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 50393b7f5f..e3a2c383e2 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -71,6 +71,8 @@ float angleBetween(const glm::vec3& v1, const glm::vec3& v2); glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); +bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, glm::vec3 p2); + glm::vec3 extractTranslation(const glm::mat4& matrix); void setTranslation(glm::mat4& matrix, const glm::vec3& translation); From f3fcb749df2787b2886db9a7e8875f0f20a3cffa Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Apr 2015 22:51:39 +0200 Subject: [PATCH 194/401] Fix algorithm + add comments --- .../src/RenderableModelEntityItem.cpp | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ab823d090b..e2c3de70af 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -416,34 +416,46 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } bool RenderableModelEntityItem::contains(const glm::vec3& point) const { - bool result = EntityItem::contains(point); - - if (result && _model && _model->getCollisionGeometry()) { + if (EntityItem::contains(point) && _model && _model->getCollisionGeometry()) { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); auto checkEachPrimitive = [=](FBXMesh& mesh, QVector indices, int primitiveSize) -> bool { + // Check whether the point is "behind" all the primitives. for (unsigned int j = 0; j < indices.size(); j += primitiveSize) { if (!isPointBehindTrianglesPlane(point, mesh.vertices[indices[j]], mesh.vertices[indices[j + 1]], mesh.vertices[indices[j + 2]])) { + // it's not behind at least one so we bail return false; } } return true; }; + // Check that the point is contained in at least one convex mesh. for (auto mesh : collisionGeometry.meshes) { + bool insideMesh = true; + + // To be considered inside a convex mesh, + // the point needs to be "behind" all the primitives respective planes. for (auto part : mesh.parts) { // run through all the triangles and quads if (!checkEachPrimitive(mesh, part.triangleIndices, 3) || !checkEachPrimitive(mesh, part.quadIndices, 4)) { - return false; + // If not, the point is outside, bail for this mesh + insideMesh = false; + continue; } } + if (insideMesh) { + // It's inside this mesh, return true. + return true; + } } } - return result; + // It wasn't in any mesh, return false. + return false; } From b446644549592ddb65e25e1bedd1682cb31da28c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Apr 2015 14:12:37 +0200 Subject: [PATCH 195/401] Rename CollisionModelURL handle --- libraries/entities/src/EntityItemProperties.cpp | 6 +++--- libraries/entities/src/EntityItemProperties.h | 4 ++-- libraries/entities/src/ModelEntityItem.cpp | 8 ++++---- tests/octree/src/OctreeTests.cpp | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 5c834f71bf..01fa90f905 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -245,7 +245,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); - CHECK_PROPERTY_CHANGE(PROP_COLLISION_MODEL_URL, collisionModelURL); + CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, collisionModelURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex); @@ -618,7 +618,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem if (properties.getType() == EntityTypes::Model) { APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL()); - APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, properties.getCollisionModelURL()); + APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, properties.getCollisionModelURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, properties.getAnimationURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, properties.getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex()); @@ -864,7 +864,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int if (properties.getType() == EntityTypes::Model) { READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL); - READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COLLISION_MODEL_URL, setCollisionModelURL); + READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCollisionModelURL); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 5172b3abba..6a5465cdc1 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -93,7 +93,7 @@ enum EntityPropertyList { PROP_LOCAL_GRAVITY, PROP_PARTICLE_RADIUS, - PROP_COLLISION_MODEL_URL, + PROP_COMPOUND_SHAPE_URL, PROP_MARKETPLACE_ID, PROP_ACCELERATION, PROP_SIMULATOR_ID, @@ -197,7 +197,7 @@ public: DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString); - DEFINE_PROPERTY_REF(PROP_COLLISION_MODEL_URL, CollisionModelURL, collisionModelURL, QString); + DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CollisionModelURL, collisionModelURL, QString); DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString); DEFINE_PROPERTY(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float); DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index f95eeea8e4..b8de15f99a 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -100,9 +100,9 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) { setCollisionModelURL(""); } else if (args.bitstreamVersion == VERSION_ENTITIES_HAS_COLLISION_MODEL) { - READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL_OLD_VERSION, setCollisionModelURL); + READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCollisionModelURL); } else { - READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL, setCollisionModelURL); + READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCollisionModelURL); } READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL); @@ -140,7 +140,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_MODEL_URL; - requestedProperties += PROP_COLLISION_MODEL_URL; + requestedProperties += PROP_COMPOUND_SHAPE_URL; requestedProperties += PROP_ANIMATION_URL; requestedProperties += PROP_ANIMATION_FPS; requestedProperties += PROP_ANIMATION_FRAME_INDEX; @@ -164,7 +164,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL()); - APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, getCollisionModelURL()); + APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCollisionModelURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, getAnimationURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex()); diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index 705a50aa10..4cfadbccfc 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -74,7 +74,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) { props.setHasProperty(PROP_POSITION); props.setHasProperty(PROP_RADIUS); props.setHasProperty(PROP_MODEL_URL); - props.setHasProperty(PROP_COLLISION_MODEL_URL); + props.setHasProperty(PROP_COMPOUND_SHAPE_URL); props.setHasProperty(PROP_ROTATION); QByteArray encoded = props.encode(); From 7f3be9c89b5b0ecf5decaad39e756aa288f253f7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Apr 2015 15:24:32 +0200 Subject: [PATCH 196/401] Add shapeType/compoundShapeURL to ZoneEntities --- .../entities/src/EntityItemProperties.cpp | 5 ++++ libraries/entities/src/EntityItemProperties.h | 1 + libraries/entities/src/ZoneEntityItem.cpp | 24 +++++++++++++++++++ libraries/entities/src/ZoneEntityItem.h | 13 +++++++++- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 01fa90f905..4ffc872a86 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -657,6 +657,9 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, properties.getStageAltitude()); APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, properties.getStageDay()); APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, properties.getStageHour()); + + APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)properties.getShapeType()); + APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, properties.getCompoundShapeURL()); } APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, properties.getMarketplaceID()); @@ -903,6 +906,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_ALTITUDE, float, setStageAltitude); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_DAY, quint16, setStageDay); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_HOUR, float, setStageHour); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); } READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MARKETPLACE_ID, setMarketplaceID); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 6a5465cdc1..8faa9db0e0 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -198,6 +198,7 @@ public: DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString); DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CollisionModelURL, collisionModelURL, QString); + DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString); DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString); DEFINE_PROPERTY(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float); DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float); diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index e0fe238c57..6439922a5d 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -31,6 +31,8 @@ const float ZoneEntityItem::DEFAULT_STAGE_LONGITUDE = 122.407f; const float ZoneEntityItem::DEFAULT_STAGE_ALTITUDE = 0.03f; const quint16 ZoneEntityItem::DEFAULT_STAGE_DAY = 60; const float ZoneEntityItem::DEFAULT_STAGE_HOUR = 12.0f; +const ShapeType ZoneEntityItem::DEFAULT_SHAPE_TYPE = SHAPE_TYPE_BOX; +const QString ZoneEntityItem::DEFAULT_COMPOUND_SHAPE_URL = ""; EntityItem* ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItem* result = new ZoneEntityItem(entityID, properties); @@ -73,6 +75,8 @@ EntityItemProperties ZoneEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageAltitude, getStageAltitude); COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageDay, getStageDay); COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageHour, getStageHour); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL); return properties; } @@ -91,6 +95,8 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageAltitude, setStageAltitude); SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageDay, setStageDay); SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageHour, setStageHour); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); if (somethingChanged) { bool wantDebug = false; @@ -122,6 +128,8 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, float, _stageAltitude); READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, _stageDay); READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, _stageHour); + READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, _shapeType); + READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, _compoundShapeURL); return bytesRead; } @@ -141,6 +149,8 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p requestedProperties += PROP_STAGE_ALTITUDE; requestedProperties += PROP_STAGE_DAY; requestedProperties += PROP_STAGE_HOUR; + requestedProperties += PROP_SHAPE_TYPE; + requestedProperties += PROP_COMPOUND_SHAPE_URL; return requestedProperties; } @@ -165,6 +175,8 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, getStageAltitude()); APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, getStageDay()); APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, getStageHour()); + APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)getShapeType()); + APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCompoundShapeURL()); } void ZoneEntityItem::debugDump() const { @@ -185,3 +197,15 @@ void ZoneEntityItem::debugDump() const { qCDebug(entities) << " _stageHour:" << _stageHour; } +ShapeType ZoneEntityItem::getShapeType() const { + if (_shapeType == SHAPE_TYPE_COMPOUND) { + return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; + } else { + return _shapeType; + } +} + +void ZoneEntityItem::setCompoundShapeURL(const QString& url) { + _compoundShapeURL = url; + _shapeType = _compoundShapeURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND; +} diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 8f1b15d174..bc44d70737 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -91,7 +91,13 @@ public: static bool getZonesArePickable() { return _zonesArePickable; } static void setZonesArePickable(bool value) { _zonesArePickable = value; } - + + void updateShapeType(ShapeType type) { _shapeType = type; } + virtual ShapeType getShapeType() const; + + virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); } + const QString getCompoundShapeURL() const { return _compoundShapeURL; } + virtual void setCompoundShapeURL(const QString& url); virtual void debugDump() const; @@ -105,6 +111,8 @@ public: static const float DEFAULT_STAGE_ALTITUDE; static const quint16 DEFAULT_STAGE_DAY; static const float DEFAULT_STAGE_HOUR; + static const ShapeType DEFAULT_SHAPE_TYPE; + static const QString DEFAULT_COMPOUND_SHAPE_URL; protected: // properties of the "sun" in the zone @@ -118,6 +126,9 @@ protected: float _stageAltitude; uint16_t _stageDay; float _stageHour; + + ShapeType _shapeType = SHAPE_TYPE_NONE; + QString _compoundShapeURL; static bool _zonesArePickable; }; From 8dc98d86b559c39dc34ef4a519b12e87a8c5ce29 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Apr 2015 15:46:54 +0200 Subject: [PATCH 197/401] Bump entities packet version --- libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/networking/src/PacketHeaders.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 8f0cee10cf..8fedc6b979 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_ZONE_ENTITIES_EXIST; + return VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index a05df968bd..01302f5568 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -138,5 +138,6 @@ const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14; const PacketVersion VERSION_ENTITIES_HAVE_ACCELERATION = 15; const PacketVersion VERSION_ENTITIES_HAVE_UUIDS = 16; const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_EXIST = 17; +const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE = 18; #endif // hifi_PacketHeaders_h From 9cec25614212ad0ff85f043c68a4f7f71e06cf8b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Apr 2015 15:51:46 +0200 Subject: [PATCH 198/401] Rename collisionModelURL members/methods --- .../src/EntityTreeRenderer.cpp | 2 +- .../src/RenderableModelEntityItem.cpp | 10 +++---- .../src/RenderableModelEntityItem.h | 2 +- .../entities/src/EntityItemProperties.cpp | 16 +++++------ libraries/entities/src/EntityItemProperties.h | 3 +- libraries/entities/src/ModelEntityItem.cpp | 28 +++++++++---------- libraries/entities/src/ModelEntityItem.h | 8 +++--- 7 files changed, 34 insertions(+), 35 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c14a821a38..d5d79f8bad 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -551,7 +551,7 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(const Entit if (entityItem->getType() == EntityTypes::Model) { const RenderableModelEntityItem* constModelEntityItem = dynamic_cast(entityItem); - if (constModelEntityItem->hasCollisionModel()) { + if (constModelEntityItem->hasCompoundShapeURL()) { RenderableModelEntityItem* modelEntityItem = const_cast(constModelEntityItem); Model* model = modelEntityItem->getModel(this); if (model) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e2c3de70af..b3ac6c2af3 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -224,10 +224,10 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { // if we have a previously allocated model, but its URL doesn't match // then we need to let our renderer update our model for us. if (_model && QUrl(getModelURL()) != _model->getURL()) { - result = _model = _myRenderer->updateModel(_model, getModelURL(), getCollisionModelURL()); + result = _model = _myRenderer->updateModel(_model, getModelURL(), getCompoundShapeURL()); _needsInitialSimulation = true; } else if (!_model) { // if we don't yet have a model, then we want our renderer to allocate one - result = _model = _myRenderer->allocateModel(getModelURL(), getCollisionModelURL()); + result = _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL()); _needsInitialSimulation = true; } else { // we already have the model we want... result = _model; @@ -267,8 +267,8 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking); } -void RenderableModelEntityItem::setCollisionModelURL(const QString& url) { - ModelEntityItem::setCollisionModelURL(url); +void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { + ModelEntityItem::setCompoundShapeURL(url); if (_model) { _model->setCollisionModelURL(QUrl(url)); } @@ -410,7 +410,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } glm::vec3 collisionModelDimensions = box.getDimensions(); - info.setParams(type, collisionModelDimensions, _collisionModelURL); + info.setParams(type, collisionModelDimensions, _compoundShapeURL); info.setConvexHulls(_points); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index ea153a2dd6..43f18af0db 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -52,7 +52,7 @@ public: bool needsToCallUpdate() const; - virtual void setCollisionModelURL(const QString& url); + virtual void setCompoundShapeURL(const QString& url); bool isReadyToComputeShape(); void computeShapeInfo(ShapeInfo& info); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 4ffc872a86..6ef6877bb1 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -44,7 +44,7 @@ EntityItemProperties::EntityItemProperties() : CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT), CONSTRUCT_PROPERTY(color, ), CONSTRUCT_PROPERTY(modelURL, ""), - CONSTRUCT_PROPERTY(collisionModelURL, ""), + CONSTRUCT_PROPERTY(compoundShapeURL, ""), CONSTRUCT_PROPERTY(animationURL, ""), CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS), CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX), @@ -175,7 +175,7 @@ void EntityItemProperties::debugDump() const { qCDebug(entities) << " _position=" << _position.x << "," << _position.y << "," << _position.z; qCDebug(entities) << " _dimensions=" << getDimensions(); qCDebug(entities) << " _modelURL=" << _modelURL; - qCDebug(entities) << " _collisionModelURL=" << _collisionModelURL; + qCDebug(entities) << " _compoundShapeURL=" << _compoundShapeURL; qCDebug(entities) << " changed properties..."; EntityPropertyFlags props = getChangedProperties(); props.debugDumpBits(); @@ -245,7 +245,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); - CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, collisionModelURL); + CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex); @@ -322,7 +322,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(visible); COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color); COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(collisionModelURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying); COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS); @@ -417,7 +417,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(visible, setVisible); COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(color, setColor); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(modelURL, setModelURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(collisionModelURL, setCollisionModelURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(compoundShapeURL, setCompoundShapeURL); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationURL, setAnimationURL); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS); @@ -618,7 +618,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem if (properties.getType() == EntityTypes::Model) { APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL()); - APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, properties.getCollisionModelURL()); + APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, properties.getCompoundShapeURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, properties.getAnimationURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, properties.getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex()); @@ -867,7 +867,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int if (properties.getType() == EntityTypes::Model) { READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL); - READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCollisionModelURL); + READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); @@ -963,7 +963,7 @@ void EntityItemProperties::markAllChanged() { _visibleChanged = true; _colorChanged = true; _modelURLChanged = true; - _collisionModelURLChanged = true; + _compoundShapeURLChanged = true; _animationURLChanged = true; _animationIsPlayingChanged = true; _animationFrameIndexChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 8faa9db0e0..faec9e1206 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -197,7 +197,6 @@ public: DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString); - DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CollisionModelURL, collisionModelURL, QString); DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString); DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString); DEFINE_PROPERTY(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float); @@ -341,7 +340,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionModelURL, collisionModelURL, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFPS, animationFPS, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFrameIndex, animationFrameIndex, ""); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index b8de15f99a..7616924f4a 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -47,7 +47,7 @@ EntityItemProperties ModelEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionModelURL, getCollisionModelURL); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationURL, getAnimationURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex); @@ -65,7 +65,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionModelURL, setCollisionModelURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationURL, setAnimationURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex); @@ -98,11 +98,11 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL); if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) { - setCollisionModelURL(""); + setCompoundShapeURL(""); } else if (args.bitstreamVersion == VERSION_ENTITIES_HAS_COLLISION_MODEL) { - READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCollisionModelURL); + READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL); } else { - READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCollisionModelURL); + READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL); } READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL); @@ -164,7 +164,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL()); - APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCollisionModelURL()); + APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCompoundShapeURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, getAnimationURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex()); @@ -272,7 +272,7 @@ void ModelEntityItem::debugDump() const { qCDebug(entities) << " position:" << getPosition(); qCDebug(entities) << " dimensions:" << getDimensions(); qCDebug(entities) << " model URL:" << getModelURL(); - qCDebug(entities) << " collision model URL:" << getCollisionModelURL(); + qCDebug(entities) << " collision model URL:" << getCompoundShapeURL(); } void ModelEntityItem::updateShapeType(ShapeType type) { @@ -280,8 +280,8 @@ void ModelEntityItem::updateShapeType(ShapeType type) { // we have allowed inconsistent ShapeType's to be stored in SVO files in the past (this was a bug) // but we are now enforcing the entity properties to be consistent. To make the possible we're // introducing a temporary workaround: we will ignore ShapeType updates that conflict with the - // _collisionModelURL. - if (hasCollisionModel()) { + // _compoundShapeURL. + if (hasCompoundShapeURL()) { type = SHAPE_TYPE_COMPOUND; } // END_TEMPORARY_WORKAROUND @@ -295,17 +295,17 @@ void ModelEntityItem::updateShapeType(ShapeType type) { // virtual ShapeType ModelEntityItem::getShapeType() const { if (_shapeType == SHAPE_TYPE_COMPOUND) { - return hasCollisionModel() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; + return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; } else { return _shapeType; } } -void ModelEntityItem::setCollisionModelURL(const QString& url) { - if (_collisionModelURL != url) { - _collisionModelURL = url; +void ModelEntityItem::setCompoundShapeURL(const QString& url) { + if (_compoundShapeURL != url) { + _compoundShapeURL = url; _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; - _shapeType = _collisionModelURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND; + _shapeType = _compoundShapeURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND; } } diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 057c5babaf..46fce6ff5f 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -57,13 +57,13 @@ public: const rgbColor& getColor() const { return _color; } xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } bool hasModel() const { return !_modelURL.isEmpty(); } - virtual bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); } + virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); } static const QString DEFAULT_MODEL_URL; const QString& getModelURL() const { return _modelURL; } static const QString DEFAULT_COLLISION_MODEL_URL; - const QString& getCollisionModelURL() const { return _collisionModelURL; } + const QString& getCompoundShapeURL() const { return _compoundShapeURL; } bool hasAnimation() const { return !_animationURL.isEmpty(); } static const QString DEFAULT_ANIMATION_URL; @@ -78,7 +78,7 @@ public: // model related properties void setModelURL(const QString& url) { _modelURL = url; } - virtual void setCollisionModelURL(const QString& url); + virtual void setCompoundShapeURL(const QString& url); void setAnimationURL(const QString& url); static const float DEFAULT_ANIMATION_FRAME_INDEX; void setAnimationFrameIndex(float value); @@ -126,7 +126,7 @@ protected: rgbColor _color; QString _modelURL; - QString _collisionModelURL; + QString _compoundShapeURL; quint64 _lastAnimated; QString _animationURL; From 99b3ef0d75fc0961e5c16b83e6364138d1b08a32 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Apr 2015 20:18:35 +0200 Subject: [PATCH 199/401] Move contain function to FBXGeometry --- .../src/RenderableModelEntityItem.cpp | 38 +--------------- libraries/fbx/src/FBXReader.cpp | 43 ++++++++++++++++++- libraries/fbx/src/FBXReader.h | 1 + 3 files changed, 44 insertions(+), 38 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index b3ac6c2af3..3f8899f6bd 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -420,42 +420,8 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); - auto checkEachPrimitive = [=](FBXMesh& mesh, QVector indices, int primitiveSize) -> bool { - // Check whether the point is "behind" all the primitives. - for (unsigned int j = 0; j < indices.size(); j += primitiveSize) { - if (!isPointBehindTrianglesPlane(point, - mesh.vertices[indices[j]], - mesh.vertices[indices[j + 1]], - mesh.vertices[indices[j + 2]])) { - // it's not behind at least one so we bail - return false; - } - } - return true; - }; - - // Check that the point is contained in at least one convex mesh. - for (auto mesh : collisionGeometry.meshes) { - bool insideMesh = true; - - // To be considered inside a convex mesh, - // the point needs to be "behind" all the primitives respective planes. - for (auto part : mesh.parts) { - // run through all the triangles and quads - if (!checkEachPrimitive(mesh, part.triangleIndices, 3) || - !checkEachPrimitive(mesh, part.quadIndices, 4)) { - // If not, the point is outside, bail for this mesh - insideMesh = false; - continue; - } - } - if (insideMesh) { - // It's inside this mesh, return true. - return true; - } - } + return collisionGeometry.convexHullContains(point); } - - // It wasn't in any mesh, return false. + return false; } diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 25ea9ef8e1..95cd99852f 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -125,6 +125,47 @@ Extents FBXGeometry::getUnscaledMeshExtents() const { return scaledExtents; } +// TODO: Move to model::Mesh when Sam's ready +bool FBXGeometry::convexHullContains(const glm::vec3& point) const { + auto checkEachPrimitive = [=](FBXMesh& mesh, QVector indices, int primitiveSize) -> bool { + // Check whether the point is "behind" all the primitives. + for (unsigned int j = 0; j < indices.size(); j += primitiveSize) { + if (!isPointBehindTrianglesPlane(point, + mesh.vertices[indices[j]], + mesh.vertices[indices[j + 1]], + mesh.vertices[indices[j + 2]])) { + // it's not behind at least one so we bail + return false; + } + } + return true; + }; + + // Check that the point is contained in at least one convex mesh. + for (auto mesh : meshes) { + bool insideMesh = true; + + // To be considered inside a convex mesh, + // the point needs to be "behind" all the primitives respective planes. + for (auto part : mesh.parts) { + // run through all the triangles and quads + if (!checkEachPrimitive(mesh, part.triangleIndices, 3) || + !checkEachPrimitive(mesh, part.quadIndices, 4)) { + // If not, the point is outside, bail for this mesh + insideMesh = false; + continue; + } + } + if (insideMesh) { + // It's inside this mesh, return true. + return true; + } + } + + // It wasn't in any mesh, return false. + return false; +} + QString FBXGeometry::getModelNameOfMesh(int meshIndex) const { if (meshIndicesToModelNames.contains(meshIndex)) { return meshIndicesToModelNames.value(meshIndex); @@ -132,8 +173,6 @@ QString FBXGeometry::getModelNameOfMesh(int meshIndex) const { return QString(); } - - static int fbxGeometryMetaTypeId = qRegisterMetaType(); static int fbxAnimationFrameMetaTypeId = qRegisterMetaType(); static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType >(); diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index d1576bc02a..871f3d0581 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -252,6 +252,7 @@ public: /// Returns the unscaled extents of the model's mesh Extents getUnscaledMeshExtents() const; + bool convexHullContains(const glm::vec3& point) const; QHash meshIndicesToModelNames; From 287d625c5221e205a068bdf4b02924946ff75451 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Apr 2015 20:19:45 +0200 Subject: [PATCH 200/401] Added RenderableZoneEntities class --- .../src/RenderableZoneEntityItem.cpp | 50 +++++++++++++++++++ .../src/RenderableZoneEntityItem.h | 39 +++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 libraries/entities-renderer/src/RenderableZoneEntityItem.cpp create mode 100644 libraries/entities-renderer/src/RenderableZoneEntityItem.h diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp new file mode 100644 index 0000000000..1c80b1f317 --- /dev/null +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -0,0 +1,50 @@ +// +// RenderableZoneEntityItem.cpp +// +// +// Created by Clement on 4/22/15. +// Copyright 2015 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 "RenderableZoneEntityItem.h" + +#include +#include + +EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + return new RenderableZoneEntityItem(entityID, properties); +} + +bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& properties) { + QString oldShapeURL = getCompoundShapeURL(); + bool somethingChanged = ZoneEntityItem::setProperties(properties); + if (somethingChanged && oldShapeURL != getCompoundShapeURL()) { + _compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); + } + return somethingChanged; +} + +int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { + QString oldShapeURL = getCompoundShapeURL(); + int bytesRead = ZoneEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead, + args, propertyFlags, overwriteLocalData); + if (oldShapeURL != getCompoundShapeURL()) { + _compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); + } + return bytesRead; +} + +bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { + if (EntityItem::contains(point) && _compoundShapeModel) { + const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry(); + + return geometry.convexHullContains(point); + } + + return false; +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h new file mode 100644 index 0000000000..8d8d8b4b3f --- /dev/null +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -0,0 +1,39 @@ +// +// RenderableZoneEntityItem.h +// +// +// Created by Clement on 4/22/15. +// Copyright 2015 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_RenderableZoneEntityItem_h +#define hifi_RenderableZoneEntityItem_h + +#include + +class NetworkGeometry; + +class RenderableZoneEntityItem : public ZoneEntityItem { +public: + static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : + ZoneEntityItem(entityItemID, properties) + { } + + virtual bool setProperties(const EntityItemProperties& properties); + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData); + + virtual bool contains(const glm::vec3& point) const; + +private: + + QSharedPointer _compoundShapeModel; +}; + +#endif // hifi_RenderableZoneEntityItem_h \ No newline at end of file From fb4e334c708e516759216d1ecc6be3a3cfd6efe2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 22 Apr 2015 12:38:34 -0700 Subject: [PATCH 201/401] implement volume priority for zones --- .../example/entities/zoneEntityExample.js | 4 +- .../src/EntityTreeRenderer.cpp | 99 ++++++------------- .../src/EntityTreeRenderer.h | 7 +- libraries/entities/src/EntityItem.h | 1 + 4 files changed, 35 insertions(+), 76 deletions(-) diff --git a/examples/example/entities/zoneEntityExample.js b/examples/example/entities/zoneEntityExample.js index 84d87d1370..052de06a1d 100644 --- a/examples/example/entities/zoneEntityExample.js +++ b/examples/example/entities/zoneEntityExample.js @@ -29,7 +29,7 @@ print("zoneEntityA:" + zoneEntityA); var zoneEntityB = Entities.addEntity({ type: "Zone", - position: { x: 1, y: 1, z: 21 }, + position: { x: 5, y: 5, z: 5 }, dimensions: { x: 2, y: 2, z: 2 }, keyLightColor: { red: 0, green: 255, blue: 0 }, keyLightIntensity: 0.9, @@ -46,7 +46,7 @@ print("zoneEntityB:" + zoneEntityB); var zoneEntityC = Entities.addEntity({ type: "Zone", - position: { x: 5, y: 5, z: 15 }, + position: { x: 5, y: 10, z: 5 }, dimensions: { x: 10, y: 10, z: 10 }, keyLightColor: { red: 0, green: 0, blue: 255 }, keyLightIntensity: 0.75, diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c14a821a38..f6557b5f9a 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -395,67 +395,14 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R _tree->lockForRead(); - // Implement some kind of a stack/union mechanism here... - // - // * As you enter a zone (A), you use it's properties - // * if already in a zone, and you enter the union of that zone and a new zone (A + B) - // you use the settings of the new zone (B) you entered.. but remember that you were previously - // in zone A - // * if you enter a new zone and are in the union of 3 zones (A+B+C) then use zone C and remember - // you were most recently in B - _lastZones = _currentZones; - _currentZones.clear(); + // Whenever you're in an intersection between zones, we will always choose the smallest zone. + _bestZone = NULL; + _bestZoneVolume = std::numeric_limits::max(); _tree->recurseTreeWithOperation(renderOperation, &args); - const ZoneEntityItem* bestZone = NULL; - - if (_currentZones.empty()) { - // if we're not in any current zone, then we can completely erase our zoneHistory - _zoneHistory.clear(); - } else { - // we're in some zone... check to see if we've changed zones.. - QSet newZones = _currentZones - _lastZones; - if (!newZones.empty()) { - // we just entered a new zone, so we want to make a shift - EntityItemID theNewZone = *(newZones.begin()); // random we don't care, if it's one, then this works. - _zoneHistory << _currentZone; // remember the single zone we used to be in. - _currentZone = theNewZone; // change to our new zone - - // do something to remove any item of _zoneHistory that is not in _currentZones - QStack newHistory; - QStack::iterator i = _zoneHistory.begin(); - while(i != _zoneHistory.end()) { - EntityItemID zoneID = *i; - if (_currentZones.contains(zoneID)) { - newHistory << zoneID; - } - ++i; - } - - _zoneHistory = newHistory; - bestZone = dynamic_cast( - static_cast(_tree)->findEntityByEntityItemID(_currentZone)); - } else { - - if (_currentZones.contains(_currentZone)) { - // No change in zone, keep the current zone - bestZone = dynamic_cast( - static_cast(_tree)->findEntityByEntityItemID(_currentZone)); - } else { - if (!_zoneHistory.empty()) { - _currentZone = _zoneHistory.pop(); - bestZone = dynamic_cast( - static_cast(_tree)->findEntityByEntityItemID(_currentZone)); - } - - } - - } - } - QSharedPointer scene = DependencyManager::get(); - if (bestZone) { + if (_bestZone) { if (!_hasPreviousZone) { _previousKeyLightColor = scene->getKeyLightColor(); _previousKeyLightIntensity = scene->getKeyLightIntensity(); @@ -469,18 +416,16 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R _previousStageDay = scene->getStageYearTime(); _hasPreviousZone = true; } - scene->setKeyLightColor(bestZone->getKeyLightColorVec3()); - scene->setKeyLightIntensity(bestZone->getKeyLightIntensity()); - scene->setKeyLightAmbientIntensity(bestZone->getKeyLightAmbientIntensity()); - scene->setKeyLightDirection(bestZone->getKeyLightDirection()); - scene->setStageSunModelEnable(bestZone->getStageSunModelEnabled()); - scene->setStageLocation(bestZone->getStageLongitude(), bestZone->getStageLatitude(), - bestZone->getStageAltitude()); - scene->setStageDayTime(bestZone->getStageHour()); - scene->setStageYearTime(bestZone->getStageDay()); - + scene->setKeyLightColor(_bestZone->getKeyLightColorVec3()); + scene->setKeyLightIntensity(_bestZone->getKeyLightIntensity()); + scene->setKeyLightAmbientIntensity(_bestZone->getKeyLightAmbientIntensity()); + scene->setKeyLightDirection(_bestZone->getKeyLightDirection()); + scene->setStageSunModelEnable(_bestZone->getStageSunModelEnabled()); + scene->setStageLocation(_bestZone->getStageLongitude(), _bestZone->getStageLatitude(), + _bestZone->getStageAltitude()); + scene->setStageDayTime(_bestZone->getStageHour()); + scene->setStageYearTime(_bestZone->getStageDay()); } else { - _currentZone = EntityItemID(); // clear out current zone if (_hasPreviousZone) { scene->setKeyLightColor(_previousKeyLightColor); scene->setKeyLightIntensity(_previousKeyLightIntensity); @@ -698,7 +643,23 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) // like other entity types. So we will skip the normal rendering tests if (entityItem->getType() == EntityTypes::Zone) { if (entityItem->contains(args->_viewFrustum->getPosition())) { - _currentZones << entityItem->getEntityItemID(); + float entityVolumeEstimate = entityItem->getVolumeEstimate(); + if (entityVolumeEstimate < _bestZoneVolume) { + _bestZoneVolume = entityVolumeEstimate; + _bestZone = dynamic_cast(entityItem); + } else if (entityVolumeEstimate == _bestZoneVolume) { + if (!_bestZone) { + _bestZoneVolume = entityVolumeEstimate; + _bestZone = dynamic_cast(entityItem); + } else { + // in the case of the volume being equal, we will use the + // EntityItemID to deterministically pick one entity over the other + if (entityItem->getEntityItemID() < _bestZone->getEntityItemID()) { + _bestZoneVolume = entityVolumeEstimate; + _bestZone = dynamic_cast(entityItem); + } + } + } } } else { // render entityItem diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index fd979fc9f9..8f720e5e48 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -167,12 +167,9 @@ private: QMultiMap _waitingOnPreload; - QSet _lastZones; - QSet _currentZones; - QStack _zoneHistory; - EntityItemID _currentZone; - bool _hasPreviousZone = false; + const ZoneEntityItem* _bestZone; + float _bestZoneVolume; glm::vec3 _previousKeyLightColor; float _previousKeyLightIntensity; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ad856698a2..28f1c7790b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -272,6 +272,7 @@ public: virtual bool isReadyToComputeShape() { return true; } virtual void computeShapeInfo(ShapeInfo& info); + virtual float getVolumeEstimate() const { return _dimensions.x * _dimensions.y * _dimensions.z; } /// return preferred shape type (actual physical shape may differ) virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } From dc30ca02104fa86661a57e4f2b40e4e5253e58bb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 12:51:29 -0700 Subject: [PATCH 202/401] experimenting --- libraries/physics/src/EntityMotionState.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c29abf9571..a8a4a31544 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -290,12 +290,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } else if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { // The object is moving and nobody thinks they own the motion. set this Node as the simulator - _entity->setSimulatorID(myNodeID); - properties.setSimulatorID(myNodeID); + // _entity->setSimulatorID(myNodeID); + // properties.setSimulatorID(myNodeID); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the object has stopped. give up "simulator" status - // _entity->setSimulatorID(QUuid()); - // properties.setSimulatorID(QUuid()); + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. From a6750eafd8b0a7e6f90c30305c0773fb2c2d5270 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 13:03:59 -0700 Subject: [PATCH 203/401] experimenting --- libraries/physics/src/EntityMotionState.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index a8a4a31544..90c7a56b16 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -284,8 +284,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ QUuid simulatorID = _entity->getSimulatorID(); if (_entity->getShouldClaimSimulationOwnership()) { - _entity->setSimulatorID(myNodeID); - properties.setSimulatorID(myNodeID); + // _entity->setSimulatorID(myNodeID); + // properties.setSimulatorID(myNodeID); _entity->setShouldClaimSimulationOwnership(false); } else if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { @@ -294,8 +294,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // properties.setSimulatorID(myNodeID); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the object has stopped. give up "simulator" status - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); + // _entity->setSimulatorID(QUuid()); + // properties.setSimulatorID(QUuid()); } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. From 35e2b87a70d43cef7447db218df548584528987a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 22 Apr 2015 13:15:57 -0700 Subject: [PATCH 204/401] Rename DDE menu items --- interface/src/Application.cpp | 4 ++-- interface/src/Menu.cpp | 4 ++-- interface/src/Menu.h | 4 ++-- interface/src/devices/DdeFaceTracker.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 92cb750d98..d6894a825a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1744,9 +1744,9 @@ void Application::setActiveFaceTracker() { DependencyManager::get()->setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)); #endif #ifdef HAVE_DDE - bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression); + bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::UseCamera); Menu::getInstance()->getActionForOption(MenuOption::UseAudioForMouth)->setVisible(isUsingDDE); - Menu::getInstance()->getActionForOption(MenuOption::DDEFiltering)->setVisible(isUsingDDE); + Menu::getInstance()->getActionForOption(MenuOption::VelocityFilter)->setVisible(isUsingDDE); DependencyManager::get()->setEnabled(isUsingDDE); #endif } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6bcc09f316..143c56c935 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -371,7 +371,7 @@ Menu::Menu() { faceTrackerGroup->addAction(faceshiftFaceTracker); #endif #ifdef HAVE_DDE - QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFaceRegression, + QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseCamera, 0, false, qApp, SLOT(setActiveFaceTracker())); faceTrackerGroup->addAction(ddeFaceTracker); @@ -381,7 +381,7 @@ Menu::Menu() { faceTrackingMenu->addSeparator(); QAction* useAudioForMouth = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseAudioForMouth, 0, true); useAudioForMouth->setVisible(false); - QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFiltering, 0, true); + QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true); ddeFiltering->setVisible(false); #endif diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 8f54d1a796..5a162d31bc 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -130,8 +130,6 @@ namespace MenuOption { const QString ControlWithSpeech = "Control With Speech"; const QString CopyAddress = "Copy Address to Clipboard"; const QString CopyPath = "Copy Path to Clipboard"; - const QString DDEFaceRegression = "DDE Face Regression"; - const QString DDEFiltering = "DDE Filtering"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DeleteBookmark = "Delete Bookmark..."; const QString DisableActivityLogger = "Disable Activity Logger"; @@ -246,6 +244,8 @@ namespace MenuOption { const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; const QString UseAudioForMouth = "Use Audio for Mouth"; + const QString UseCamera = "Use Camera"; + const QString VelocityFilter = "Velocity Filter"; const QString VisibleToEveryone = "Everyone"; const QString VisibleToFriends = "Friends"; const QString VisibleToNoOne = "No one"; diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 938cee729f..03989c6ffb 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -285,7 +285,7 @@ float DdeFaceTracker::getBlendshapeCoefficient(int index) const { void DdeFaceTracker::decodePacket(const QByteArray& buffer) { if(buffer.size() > MIN_PACKET_SIZE) { - bool isFiltering = Menu::getInstance()->isOptionChecked(MenuOption::DDEFiltering); + bool isFiltering = Menu::getInstance()->isOptionChecked(MenuOption::VelocityFilter); Packet packet; int bytesToCopy = glm::min((int)sizeof(packet), buffer.size()); From 7382b0b19f64b4315de07134859d2d94486f9bfe Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 13:17:20 -0700 Subject: [PATCH 205/401] experimenting --- libraries/physics/src/EntityMotionState.cpp | 24 ++++++++++----------- libraries/physics/src/PhysicsEngine.cpp | 13 +++++++++-- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 90c7a56b16..750e5ef64d 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -281,22 +281,22 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ auto nodeList = DependencyManager::get(); QUuid myNodeID = nodeList->getSessionUUID(); - QUuid simulatorID = _entity->getSimulatorID(); + // QUuid simulatorID = _entity->getSimulatorID(); if (_entity->getShouldClaimSimulationOwnership()) { - // _entity->setSimulatorID(myNodeID); - // properties.setSimulatorID(myNodeID); + _entity->setSimulatorID(myNodeID); + properties.setSimulatorID(myNodeID); _entity->setShouldClaimSimulationOwnership(false); } - else if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { - // The object is moving and nobody thinks they own the motion. set this Node as the simulator - // _entity->setSimulatorID(myNodeID); - // properties.setSimulatorID(myNodeID); - } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { - // we are the simulator and the object has stopped. give up "simulator" status - // _entity->setSimulatorID(QUuid()); - // properties.setSimulatorID(QUuid()); - } + // else if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { + // // The object is moving and nobody thinks they own the motion. set this Node as the simulator + // _entity->setSimulatorID(myNodeID); + // properties.setSimulatorID(myNodeID); + // } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { + // // we are the simulator and the object has stopped. give up "simulator" status + // _entity->setSimulatorID(QUuid()); + // properties.setSimulatorID(QUuid()); + // } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. if (_sentMoving) { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index d4963aaf81..3033ff5973 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -389,7 +389,9 @@ void PhysicsEngine::computeCollisionEvents() { } void* a = objectA->getUserPointer(); + EntityItem* entityA = a ? static_cast(a)->getEntity() : NULL; void* b = objectB->getUserPointer(); + EntityItem* entityB = b ? static_cast(b)->getEntity() : NULL; if (a || b) { // the manifold has up to 4 distinct points, but only extract info from the first _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); @@ -397,13 +399,20 @@ void PhysicsEngine::computeCollisionEvents() { // if our character capsule is colliding with something dynamic, claim simulation ownership. // see EntityMotionState::sendUpdate if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) { - EntityItem* entityB = static_cast(b)->getEntity(); entityB->setShouldClaimSimulationOwnership(true); } if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) { - EntityItem* entityA = static_cast(a)->getEntity(); entityA->setShouldClaimSimulationOwnership(true); } + + if (entityA && entityB) { + if (entityA->getShouldClaimSimulationOwnership()) { + entityB->setShouldClaimSimulationOwnership(true); + } + else if (entityB->getShouldClaimSimulationOwnership()) { + entityA->setShouldClaimSimulationOwnership(true); + } + } } } } From 27ed0c4a9866ab4ddcb67f3f1fd4e3164bbf869b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 13:21:06 -0700 Subject: [PATCH 206/401] experimenting --- libraries/physics/src/PhysicsEngine.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 3033ff5973..f33933fb3f 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -405,7 +405,9 @@ void PhysicsEngine::computeCollisionEvents() { entityA->setShouldClaimSimulationOwnership(true); } - if (entityA && entityB) { + if (entityA && entityB && + !objectA->isStaticOrKinematicObject() && + !objectB->isStaticOrKinematicObject()) { if (entityA->getShouldClaimSimulationOwnership()) { entityB->setShouldClaimSimulationOwnership(true); } From ee000f91aea414f3c19a98d5b75dd7cd57c73775 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 13:27:19 -0700 Subject: [PATCH 207/401] experimenting --- libraries/physics/src/PhysicsEngine.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index f33933fb3f..3cc8017722 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -369,6 +369,9 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { void PhysicsEngine::computeCollisionEvents() { BT_PROFILE("computeCollisionEvents"); + auto nodeList = DependencyManager::get(); + QUuid myNodeID = nodeList->getSessionUUID(); + const btCollisionObject* characterCollisionObject = _characterController ? _characterController->getCollisionObject() : NULL; @@ -398,20 +401,26 @@ void PhysicsEngine::computeCollisionEvents() { // if our character capsule is colliding with something dynamic, claim simulation ownership. // see EntityMotionState::sendUpdate - if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) { - entityB->setShouldClaimSimulationOwnership(true); - } - if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) { - entityA->setShouldClaimSimulationOwnership(true); - } + // if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) { + // entityB->setShouldClaimSimulationOwnership(true); + // } + // if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) { + // entityA->setShouldClaimSimulationOwnership(true); + // } + // collisions cause infections spread of simulation-ownership. we also attempt to take + // ownership of anything that collides with our avatar. if (entityA && entityB && !objectA->isStaticOrKinematicObject() && !objectB->isStaticOrKinematicObject()) { - if (entityA->getShouldClaimSimulationOwnership()) { + if (entityA->getSimulatorID() == myNodeID || + entityA->getShouldClaimSimulationOwnership() || + objectA == characterCollisionObject) { entityB->setShouldClaimSimulationOwnership(true); } - else if (entityB->getShouldClaimSimulationOwnership()) { + if (entityB->getSimulatorID() == myNodeID || + entityB->getShouldClaimSimulationOwnership() || + objectB == characterCollisionObject) { entityA->setShouldClaimSimulationOwnership(true); } } From 69ee33a3925362be30fa893dfcaa4dfa032b0a82 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 13:29:28 -0700 Subject: [PATCH 208/401] experimenting --- libraries/physics/src/EntityMotionState.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 750e5ef64d..643d152d27 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -331,6 +331,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; #endif + qDebug() << "sending"; + entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { #ifdef WANT_DEBUG From cd3ee39fcc3e46e5b21e5fb262dfdf17e4f7683c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 13:42:04 -0700 Subject: [PATCH 209/401] experimenting --- libraries/entities/src/EntityScriptingInterface.cpp | 2 ++ libraries/physics/src/PhysicsEngine.cpp | 11 ++--------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 53335beda0..8d73fd8e95 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -71,9 +71,11 @@ void setSimId(EntityItemProperties& propertiesWithSimID, EntityItem* entity) { propertiesWithSimID.containsPositionChange()) { propertiesWithSimID.setSimulatorID(myNodeID); entity->setSimulatorID(myNodeID); + qDebug() << "script claiming ownership"; } else if (entity->getSimulatorID() == myNodeID) { propertiesWithSimID.setSimulatorID(QUuid()); // give up simulation ownership entity->setSimulatorID(QUuid()); + qDebug() << "script releasing ownership"; } } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 3cc8017722..e4e9c547df 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -399,15 +399,6 @@ void PhysicsEngine::computeCollisionEvents() { // the manifold has up to 4 distinct points, but only extract info from the first _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); - // if our character capsule is colliding with something dynamic, claim simulation ownership. - // see EntityMotionState::sendUpdate - // if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) { - // entityB->setShouldClaimSimulationOwnership(true); - // } - // if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) { - // entityA->setShouldClaimSimulationOwnership(true); - // } - // collisions cause infections spread of simulation-ownership. we also attempt to take // ownership of anything that collides with our avatar. if (entityA && entityB && @@ -417,11 +408,13 @@ void PhysicsEngine::computeCollisionEvents() { entityA->getShouldClaimSimulationOwnership() || objectA == characterCollisionObject) { entityB->setShouldClaimSimulationOwnership(true); + qDebug() << "collision claiming ownership"; } if (entityB->getSimulatorID() == myNodeID || entityB->getShouldClaimSimulationOwnership() || objectB == characterCollisionObject) { entityA->setShouldClaimSimulationOwnership(true); + qDebug() << "collision claiming ownership"; } } } From 36dbbd0c9d00caf3f2323fa2f43fcf5c7a2db9a9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 14:14:12 -0700 Subject: [PATCH 210/401] experimenting --- libraries/physics/src/EntityMotionState.cpp | 3 ++- libraries/physics/src/PhysicsEngine.cpp | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 643d152d27..2a779d019a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -200,7 +200,8 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& simulatorID = _entity->getSimulatorID(); - if (!simulatorID.isNull() && simulatorID != myNodeID) { + // if (!simulatorID.isNull() && simulatorID != myNodeID) { + if (simulatorID != myNodeID) { // some other Node owns the simulating of this, so don't broadcast the results of local simulation. return false; } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index e4e9c547df..43a42e0bd4 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -407,14 +407,24 @@ void PhysicsEngine::computeCollisionEvents() { if (entityA->getSimulatorID() == myNodeID || entityA->getShouldClaimSimulationOwnership() || objectA == characterCollisionObject) { + + qDebug() << "collision claiming ownership" + << (entityA->getSimulatorID() == myNodeID) + << (entityA->getShouldClaimSimulationOwnership()) + << (objectA == characterCollisionObject); + entityB->setShouldClaimSimulationOwnership(true); - qDebug() << "collision claiming ownership"; } if (entityB->getSimulatorID() == myNodeID || entityB->getShouldClaimSimulationOwnership() || objectB == characterCollisionObject) { + + qDebug() << "collision claiming ownership" + << (entityB->getSimulatorID() == myNodeID) + << (entityB->getShouldClaimSimulationOwnership()) + << (objectB == characterCollisionObject); + entityA->setShouldClaimSimulationOwnership(true); - qDebug() << "collision claiming ownership"; } } } From c30d742f7d445adb950b2625a5d3fe5c634a2acb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 14:22:09 -0700 Subject: [PATCH 211/401] experimenting --- libraries/physics/src/PhysicsEngine.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 43a42e0bd4..8063f5cde7 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -408,10 +408,10 @@ void PhysicsEngine::computeCollisionEvents() { entityA->getShouldClaimSimulationOwnership() || objectA == characterCollisionObject) { - qDebug() << "collision claiming ownership" + qDebug() << "collision claiming ownership 0" << (entityA->getSimulatorID() == myNodeID) << (entityA->getShouldClaimSimulationOwnership()) - << (objectA == characterCollisionObject); + << (objectA == characterCollisionObject) << myNodeID; entityB->setShouldClaimSimulationOwnership(true); } @@ -419,10 +419,10 @@ void PhysicsEngine::computeCollisionEvents() { entityB->getShouldClaimSimulationOwnership() || objectB == characterCollisionObject) { - qDebug() << "collision claiming ownership" + qDebug() << "collision claiming ownership 1" << (entityB->getSimulatorID() == myNodeID) << (entityB->getShouldClaimSimulationOwnership()) - << (objectB == characterCollisionObject); + << (objectB == characterCollisionObject) << myNodeID; entityA->setShouldClaimSimulationOwnership(true); } From 92ceff1a0311f4af8ee8980e4b62a2189abe3b4f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 14:53:23 -0700 Subject: [PATCH 212/401] clean up EntityItem constructors --- libraries/entities/src/EntityItem.cpp | 110 +++++++++++--------------- libraries/entities/src/EntityItem.h | 3 - 2 files changed, 45 insertions(+), 68 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 205b615642..a5d87dee99 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -25,76 +25,56 @@ bool EntityItem::_sendPhysicsUpdates = true; -void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { - _id = entityItemID.id; - _creatorTokenID = entityItemID.creatorTokenID; - - // init values with defaults before calling setProperties +EntityItem::EntityItem(const EntityItemID& entityItemID) : + _type(EntityTypes::Unknown), + _id(entityItemID.id), + _creatorTokenID(entityItemID.creatorTokenID), + _newlyCreated(false), + _lastSimulated(0), + _lastUpdated(0), + _lastEdited(0), + _lastEditedFromRemote(0), + _lastEditedFromRemoteInRemoteTime(0), + _created(UNKNOWN_CREATED_TIME), + _changedOnServer(0), + _position(ENTITY_ITEM_ZERO_VEC3), + _dimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS), + _rotation(ENTITY_ITEM_DEFAULT_ROTATION), + _glowLevel(ENTITY_ITEM_DEFAULT_GLOW_LEVEL), + _localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA), + _density(ENTITY_ITEM_DEFAULT_DENSITY), + _volumeMultiplier(1.0f), + _velocity(ENTITY_ITEM_DEFAULT_VELOCITY), + _gravity(ENTITY_ITEM_DEFAULT_GRAVITY), + _acceleration(ENTITY_ITEM_DEFAULT_ACCELERATION), + _accelerationNearlyGravityCount(0), + _damping(ENTITY_ITEM_DEFAULT_DAMPING), + _lifetime(ENTITY_ITEM_DEFAULT_LIFETIME), + _script(ENTITY_ITEM_DEFAULT_SCRIPT), + _registrationPoint(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT), + _angularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY), + _angularDamping(ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING), + _visible(ENTITY_ITEM_DEFAULT_VISIBLE), + _ignoreForCollisions(ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS), + _collisionsWillMove(ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE), + _locked(ENTITY_ITEM_DEFAULT_LOCKED), + _userData(ENTITY_ITEM_DEFAULT_USER_DATA), + _simulatorID(ENTITY_ITEM_DEFAULT_SIMULATOR_ID), + _simulatorIDChangedTime(0), + _shouldClaimSimulationOwnership(false), + _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), + _physicsInfo(NULL), + _dirtyFlags(0), + _element(NULL) +{ quint64 now = usecTimestampNow(); _lastSimulated = now; _lastUpdated = now; - _lastEdited = 0; - _lastEditedFromRemote = 0; - _lastEditedFromRemoteInRemoteTime = 0; - _created = UNKNOWN_CREATED_TIME; - _changedOnServer = 0; - - _position = ENTITY_ITEM_ZERO_VEC3; - _dimensions = ENTITY_ITEM_DEFAULT_DIMENSIONS; - _density = ENTITY_ITEM_DEFAULT_DENSITY; - _rotation = ENTITY_ITEM_DEFAULT_ROTATION; - _glowLevel = ENTITY_ITEM_DEFAULT_GLOW_LEVEL; - _localRenderAlpha = ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA; - _velocity = ENTITY_ITEM_DEFAULT_VELOCITY; - _gravity = ENTITY_ITEM_DEFAULT_GRAVITY; - _acceleration = ENTITY_ITEM_DEFAULT_ACCELERATION; - _damping = ENTITY_ITEM_DEFAULT_DAMPING; - _lifetime = ENTITY_ITEM_DEFAULT_LIFETIME; - _script = ENTITY_ITEM_DEFAULT_SCRIPT; - _registrationPoint = ENTITY_ITEM_DEFAULT_REGISTRATION_POINT; - _angularVelocity = ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY; - _angularDamping = ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING; - _visible = ENTITY_ITEM_DEFAULT_VISIBLE; - _ignoreForCollisions = ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS; - _collisionsWillMove = ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE; - _locked = ENTITY_ITEM_DEFAULT_LOCKED; - _userData = ENTITY_ITEM_DEFAULT_USER_DATA; - _simulatorID = ENTITY_ITEM_DEFAULT_SIMULATOR_ID; - _marketplaceID = ENTITY_ITEM_DEFAULT_MARKETPLACE_ID; } -EntityItem::EntityItem(const EntityItemID& entityItemID) { - _type = EntityTypes::Unknown; - quint64 now = usecTimestampNow(); - _lastSimulated = now; - _lastUpdated = now; - _lastEdited = 0; - _lastEditedFromRemote = 0; - _lastEditedFromRemoteInRemoteTime = 0; - _created = UNKNOWN_CREATED_TIME; - _dirtyFlags = 0; - _changedOnServer = 0; - _accelerationNearlyGravityCount = 0; - _element = NULL; - _simulatorIDChangedTime = 0; - _shouldClaimSimulationOwnership = false; - initFromEntityItemID(entityItemID); -} - -EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) { - _type = EntityTypes::Unknown; - quint64 now = usecTimestampNow(); - _lastSimulated = now; - _lastUpdated = now; - _lastEdited = 0; - _lastEditedFromRemote = 0; - _lastEditedFromRemoteInRemoteTime = 0; - _created = UNKNOWN_CREATED_TIME; - _dirtyFlags = 0; - _changedOnServer = 0; - _element = NULL; - _simulatorIDChangedTime = 0; - initFromEntityItemID(entityItemID); +EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : + EntityItem(entityItemID) +{ setProperties(properties); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a4903044d9..5d19c11dc5 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -318,9 +318,6 @@ public: protected: static bool _sendPhysicsUpdates; - - virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init - EntityTypes::EntityType _type; QUuid _id; uint32_t _creatorTokenID; From 3450597d70dc360bce8c4dd6c40767b0e6a5b4ee Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 15:03:23 -0700 Subject: [PATCH 213/401] remove some debugging prints --- libraries/entities/src/EntityItem.cpp | 3 +-- libraries/physics/src/EntityMotionState.cpp | 16 ++-------------- libraries/physics/src/PhysicsEngine.cpp | 16 +--------------- 3 files changed, 4 insertions(+), 31 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a5d87dee99..5a141af581 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -72,8 +72,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _lastUpdated = now; } -EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) +EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : EntityItem(entityItemID) { setProperties(properties); } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 2a779d019a..e77271710f 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -200,7 +200,6 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& simulatorID = _entity->getSimulatorID(); - // if (!simulatorID.isNull() && simulatorID != myNodeID) { if (simulatorID != myNodeID) { // some other Node owns the simulating of this, so don't broadcast the results of local simulation. return false; @@ -280,24 +279,13 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setAngularVelocity(_sentAngularVelocity); } - auto nodeList = DependencyManager::get(); - QUuid myNodeID = nodeList->getSessionUUID(); - // QUuid simulatorID = _entity->getSimulatorID(); - if (_entity->getShouldClaimSimulationOwnership()) { + auto nodeList = DependencyManager::get(); + QUuid myNodeID = nodeList->getSessionUUID(); _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); _entity->setShouldClaimSimulationOwnership(false); } - // else if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { - // // The object is moving and nobody thinks they own the motion. set this Node as the simulator - // _entity->setSimulatorID(myNodeID); - // properties.setSimulatorID(myNodeID); - // } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { - // // we are the simulator and the object has stopped. give up "simulator" status - // _entity->setSimulatorID(QUuid()); - // properties.setSimulatorID(QUuid()); - // } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. if (_sentMoving) { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 8063f5cde7..ae76e1c785 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -401,29 +401,15 @@ void PhysicsEngine::computeCollisionEvents() { // collisions cause infections spread of simulation-ownership. we also attempt to take // ownership of anything that collides with our avatar. - if (entityA && entityB && - !objectA->isStaticOrKinematicObject() && - !objectB->isStaticOrKinematicObject()) { + if (entityA && entityB && !objectA->isStaticOrKinematicObject() && !objectB->isStaticOrKinematicObject()) { if (entityA->getSimulatorID() == myNodeID || entityA->getShouldClaimSimulationOwnership() || objectA == characterCollisionObject) { - - qDebug() << "collision claiming ownership 0" - << (entityA->getSimulatorID() == myNodeID) - << (entityA->getShouldClaimSimulationOwnership()) - << (objectA == characterCollisionObject) << myNodeID; - entityB->setShouldClaimSimulationOwnership(true); } if (entityB->getSimulatorID() == myNodeID || entityB->getShouldClaimSimulationOwnership() || objectB == characterCollisionObject) { - - qDebug() << "collision claiming ownership 1" - << (entityB->getSimulatorID() == myNodeID) - << (entityB->getShouldClaimSimulationOwnership()) - << (objectB == characterCollisionObject) << myNodeID; - entityA->setShouldClaimSimulationOwnership(true); } } From 6678922f5ccdcb4a287cca10c745516d2a8ce4cd Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 15:09:56 -0700 Subject: [PATCH 214/401] put back code for interface giving up simulator status when something stops --- libraries/physics/src/EntityMotionState.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index e77271710f..bf59998637 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -279,14 +279,22 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setAngularVelocity(_sentAngularVelocity); } + auto nodeList = DependencyManager::get(); + QUuid myNodeID = nodeList->getSessionUUID(); + QUuid simulatorID = _entity->getSimulatorID(); + if (_entity->getShouldClaimSimulationOwnership()) { - auto nodeList = DependencyManager::get(); - QUuid myNodeID = nodeList->getSessionUUID(); _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); _entity->setShouldClaimSimulationOwnership(false); } + if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { + // we are the simulator and the object has stopped. give up "simulator" status + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); + } + // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. if (_sentMoving) { _numNonMovingUpdates = 0; From 7781808beadb56ab6a4adb427cd05a68f1bff826 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 15:25:09 -0700 Subject: [PATCH 215/401] remove debug prints, fix a comment --- libraries/entities/src/EntityScriptingInterface.cpp | 2 -- libraries/physics/src/EntityMotionState.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 8d73fd8e95..53335beda0 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -71,11 +71,9 @@ void setSimId(EntityItemProperties& propertiesWithSimID, EntityItem* entity) { propertiesWithSimID.containsPositionChange()) { propertiesWithSimID.setSimulatorID(myNodeID); entity->setSimulatorID(myNodeID); - qDebug() << "script claiming ownership"; } else if (entity->getSimulatorID() == myNodeID) { propertiesWithSimID.setSimulatorID(QUuid()); // give up simulation ownership entity->setSimulatorID(QUuid()); - qDebug() << "script releasing ownership"; } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index bf59998637..20472b625c 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -229,7 +229,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _entity->resetAccelerationNearlyGravityCount(); } - // if this entity has been accelerated at close to gravity for a certain number of frames, let + // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let // the entity server's estimates include gravity. if (_entity->getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { _entity->setAcceleration(_entity->getGravity()); From 07a848c9ce44f5231a4550e0728aed901e6935ac Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 15:50:39 -0700 Subject: [PATCH 216/401] added bump call in physics engine for when an entity is deleted and may have something resting on top of it --- libraries/entities/src/EntitySimulation.h | 2 ++ libraries/entities/src/EntityTree.cpp | 3 ++ libraries/physics/src/PhysicsEngine.cpp | 34 ++++++++++++++++++++++- libraries/physics/src/PhysicsEngine.h | 1 + 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 1eb4fdc951..913f431186 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -61,6 +61,8 @@ public: void clearEntities(); + virtual void bump(EntityItem* bumpEntity) {} + EntityTree* getEntityTree() { return _entityTree; } signals: diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 5b15aa26b4..a41deb174f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -269,6 +269,9 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign return; } + // in case something is resting on top of this, give it a bump in the simulation. + _simulation->bump(existingEntity); + if (existingEntity->getLocked() && !force) { if (!ignoreWarnings) { qCDebug(entities) << "ERROR! EntityTree::deleteEntity() trying to delete locked entity. entityID=" << entityID; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index ae76e1c785..074500f719 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -366,6 +366,39 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { } } + +void PhysicsEngine::bump(EntityItem* bumpEntity) { + // If this node is doing something like deleting an entity, scan for contacts involving the + // entity. For each found, flag the other entity involved as being simulated by this node. + lock(); + int numManifolds = _collisionDispatcher->getNumManifolds(); + for (int i = 0; i < numManifolds; ++i) { + btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); + if (contactManifold->getNumContacts() > 0) { + const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); + const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); + if (objectA && objectB) { + void* a = objectA->getUserPointer(); + void* b = objectB->getUserPointer(); + if (a && b) { + EntityItem* entityA = a ? static_cast(a)->getEntity() : NULL; + EntityItem* entityB = b ? static_cast(b)->getEntity() : NULL; + if (entityA && entityB) { + if (entityA == bumpEntity) { + entityB->setShouldClaimSimulationOwnership(true); + } + if (entityB == bumpEntity) { + entityA->setShouldClaimSimulationOwnership(true); + } + } + } + } + } + } + unlock(); +} + + void PhysicsEngine::computeCollisionEvents() { BT_PROFILE("computeCollisionEvents"); @@ -422,7 +455,6 @@ void PhysicsEngine::computeCollisionEvents() { // scan known contacts and trigger events ContactMap::iterator contactItr = _contactMap.begin(); - while (contactItr != _contactMap.end()) { ObjectMotionState* A = static_cast(contactItr->first._a); ObjectMotionState* B = static_cast(contactItr->first._b); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 6e1f430237..63ec96d04e 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -68,6 +68,7 @@ public: void stepSimulation(); void stepNonPhysicalKinematics(const quint64& now); + virtual void bump(EntityItem* bumpEntity); void computeCollisionEvents(); void dumpStatsIfNecessary(); From 96b4517e6ede70d4f02f55c5a552560780898af7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 16:05:31 -0700 Subject: [PATCH 217/401] when removing something from bullet, attempt to wake up anything that was touching it --- libraries/entities/src/EntitySimulation.h | 2 -- libraries/entities/src/EntityTree.cpp | 3 --- libraries/physics/src/EntityMotionState.cpp | 2 -- libraries/physics/src/PhysicsEngine.cpp | 8 ++++++++ libraries/physics/src/PhysicsEngine.h | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 913f431186..1eb4fdc951 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -61,8 +61,6 @@ public: void clearEntities(); - virtual void bump(EntityItem* bumpEntity) {} - EntityTree* getEntityTree() { return _entityTree; } signals: diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a41deb174f..5b15aa26b4 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -269,9 +269,6 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign return; } - // in case something is resting on top of this, give it a bump in the simulation. - _simulation->bump(existingEntity); - if (existingEntity->getLocked() && !force) { if (!ignoreWarnings) { qCDebug(entities) << "ERROR! EntityTree::deleteEntity() trying to delete locked entity. entityID=" << entityID; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 20472b625c..382cc5a734 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -328,8 +328,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; #endif - qDebug() << "sending"; - entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { #ifdef WANT_DEBUG diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 074500f719..88d6112772 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -386,9 +386,15 @@ void PhysicsEngine::bump(EntityItem* bumpEntity) { if (entityA && entityB) { if (entityA == bumpEntity) { entityB->setShouldClaimSimulationOwnership(true); + if (!objectB->isActive()) { + objectB->setActivationState(ACTIVE_TAG); + } } if (entityB == bumpEntity) { entityA->setShouldClaimSimulationOwnership(true); + if (!objectA->isActive()) { + objectA->setActivationState(ACTIVE_TAG); + } } } } @@ -564,6 +570,8 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { assert(motionState); + EntityItem* entity = static_cast(motionState)->getEntity(); + bump(entity); btRigidBody* body = motionState->getRigidBody(); if (body) { const btCollisionShape* shape = body->getCollisionShape(); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 63ec96d04e..148261c6d2 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -68,7 +68,6 @@ public: void stepSimulation(); void stepNonPhysicalKinematics(const quint64& now); - virtual void bump(EntityItem* bumpEntity); void computeCollisionEvents(); void dumpStatsIfNecessary(); @@ -99,6 +98,7 @@ private: // return 'true' of update was successful bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); + void bump(EntityItem* bumpEntity); btClock _clock; btDefaultCollisionConfiguration* _collisionConfig = NULL; From 864f8cb3b3e051f12c28efc57d2d76f14d0588f1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 16:10:25 -0700 Subject: [PATCH 218/401] fix comment --- libraries/physics/src/PhysicsEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 88d6112772..50990d708c 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -438,7 +438,7 @@ void PhysicsEngine::computeCollisionEvents() { // the manifold has up to 4 distinct points, but only extract info from the first _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); - // collisions cause infections spread of simulation-ownership. we also attempt to take + // collisions cause infectious spread of simulation-ownership. we also attempt to take // ownership of anything that collides with our avatar. if (entityA && entityB && !objectA->isStaticOrKinematicObject() && !objectB->isStaticOrKinematicObject()) { if (entityA->getSimulatorID() == myNodeID || From 5a7f8a2f5a03428152ce0bea3e359708a4c3feb3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 17:06:21 -0700 Subject: [PATCH 219/401] git rid of unneeded bump code. re-indent billiards.js and rez in balls with some y velocity so they fall to the table --- examples/example/games/billiards.js | 254 +++++++++--------- .../entities/src/EntityScriptingInterface.cpp | 23 +- libraries/physics/src/PhysicsEngine.cpp | 44 +-- libraries/physics/src/PhysicsEngine.h | 1 - 4 files changed, 145 insertions(+), 177 deletions(-) diff --git a/examples/example/games/billiards.js b/examples/example/games/billiards.js index d4bc71ba37..8e890515c0 100644 --- a/examples/example/games/billiards.js +++ b/examples/example/games/billiards.js @@ -39,126 +39,130 @@ hitSounds.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "Collisions-ballhitsandc HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var screenSize = Controller.getViewportDimensions(); var reticle = Overlays.addOverlay("image", { - x: screenSize.x / 2 - 16, - y: screenSize.y / 2 - 16, - width: 32, - height: 32, - imageURL: HIFI_PUBLIC_BUCKET + "images/billiardsReticle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); + x: screenSize.x / 2 - 16, + y: screenSize.y / 2 - 16, + width: 32, + height: 32, + imageURL: HIFI_PUBLIC_BUCKET + "images/billiardsReticle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 +}); function makeTable(pos) { - // Top - tableParts.push(Entities.addEntity( + // Top + tableParts.push(Entities.addEntity( { type: "Box", - position: pos, - dimensions: { x: LENGTH * SCALE, y: HEIGHT, z: WIDTH * SCALE }, - color: { red: 0, green: 255, blue: 0 } })); - // Long Bumpers - tableParts.push(Entities.addEntity( + position: pos, + dimensions: { x: LENGTH * SCALE, y: HEIGHT, z: WIDTH * SCALE }, + color: { red: 0, green: 255, blue: 0 } })); + // Long Bumpers + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x - LENGTH / 2.0, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, - dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); - tableParts.push(Entities.addEntity( + position: { x: pos.x - LENGTH / 2.0, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, + dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x + LENGTH / 2.0, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, - dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); + position: { x: pos.x + LENGTH / 2.0, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, + dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); - tableParts.push(Entities.addEntity( + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x - LENGTH / 2.0, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, - dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); - tableParts.push(Entities.addEntity( + position: { x: pos.x - LENGTH / 2.0, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, + dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x + LENGTH / 2.0, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, - dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); - // End bumpers - tableParts.push(Entities.addEntity( + position: { x: pos.x + LENGTH / 2.0, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, + dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); + // End bumpers + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x + (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z }, - dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); + position: { x: pos.x + (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z }, + dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); - tableParts.push(Entities.addEntity( + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x - (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z }, - dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); + position: { x: pos.x - (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z }, + dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); } function makeBalls(pos) { - // Object balls + // Object balls var whichBall = [ 1, 14, 15, 4, 8, 7, 12, 9, 3, 13, 10, 5, 6, 11, 2 ]; var ballNumber = 0; - var ballPosition = { x: pos.x + (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z }; - for (var row = 1; row <= 5; row++) { - ballPosition.z = pos.z - ((row - 1.0) / 2.0 * (BALL_SIZE + BALL_GAP) * SCALE); - for (var spot = 0; spot < row; spot++) { - balls.push(Entities.addEntity( + var ballPosition = { x: pos.x + (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z }; + for (var row = 1; row <= 5; row++) { + ballPosition.z = pos.z - ((row - 1.0) / 2.0 * (BALL_SIZE + BALL_GAP) * SCALE); + for (var spot = 0; spot < row; spot++) { + balls.push(Entities.addEntity( { type: "Model", - modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/ball_" + whichBall[ballNumber].toString() + ".fbx", - position: ballPosition, - dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE }, - rotation: Quat.fromPitchYawRollDegrees((Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20), - color: { red: 255, green: 255, blue: 255 }, - gravity: { x: 0, y: GRAVITY, z: 0 }, - ignoreCollisions: false, - damping: 0.50, - shapeType: "sphere", - collisionsWillMove: true })); - ballPosition.z += (BALL_SIZE + BALL_GAP) * SCALE; + modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/ball_" + + whichBall[ballNumber].toString() + ".fbx", + position: ballPosition, + dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE }, + rotation: Quat.fromPitchYawRollDegrees((Math.random() - 0.5) * 20, + (Math.random() - 0.5) * 20, + (Math.random() - 0.5) * 20), + color: { red: 255, green: 255, blue: 255 }, + gravity: { x: 0, y: GRAVITY, z: 0 }, + velocity: {x: 0, y: -0.2, z: 0 }, + ignoreCollisions: false, + damping: 0.50, + shapeType: "sphere", + collisionsWillMove: true })); + ballPosition.z += (BALL_SIZE + BALL_GAP) * SCALE; ballNumber++; - } - ballPosition.x += (BALL_GAP + Math.sqrt(3.0) / 2.0 * BALL_SIZE) * SCALE; } + ballPosition.x += (BALL_GAP + Math.sqrt(3.0) / 2.0 * BALL_SIZE) * SCALE; + } // Cue Ball cuePosition = { x: pos.x - (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z }; cueBall = Entities.addEntity( - { type: "Model", - modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/cue_ball.fbx", - position: cuePosition, - dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE }, - color: { red: 255, green: 255, blue: 255 }, - gravity: { x: 0, y: GRAVITY, z: 0 }, - angularVelocity: { x: 0, y: 0, z: 0 }, - velocity: {x: 0, y: 0, z: 0 }, - ignoreCollisions: false, - damping: 0.50, - shapeType: "sphere", - collisionsWillMove: true }); - + { type: "Model", + modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/cue_ball.fbx", + position: cuePosition, + dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE }, + color: { red: 255, green: 255, blue: 255 }, + gravity: { x: 0, y: GRAVITY, z: 0 }, + angularVelocity: { x: 0, y: 0, z: 0 }, + velocity: {x: 0, y: -0.2, z: 0 }, + ignoreCollisions: false, + damping: 0.50, + shapeType: "sphere", + collisionsWillMove: true }); + } function isObjectBall(id) { - for (var i; i < balls.length; i++) { - if (balls[i].id == id) { - return true; - } - } - return false; + for (var i; i < balls.length; i++) { + if (balls[i].id == id) { + return true; + } + } + return false; } function shootCue(velocity) { - var DISTANCE_FROM_CAMERA = BALL_SIZE * 5.0 * SCALE; + var DISTANCE_FROM_CAMERA = BALL_SIZE * 5.0 * SCALE; var camera = Camera.getPosition(); var forwardVector = Quat.getFront(Camera.getOrientation()); var cuePosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA)); @@ -180,14 +184,14 @@ function shootCue(velocity) { density: 8000, ignoreCollisions: false, collisionsWillMove: true - }); + }); print("Shot, velocity = " + velocity); } function keyReleaseEvent(event) { - if ((startStroke > 0) && event.text == "SPACE") { - var endTime = new Date().getTime(); - var delta = endTime - startStroke; + if ((startStroke > 0) && event.text == "SPACE") { + var endTime = new Date().getTime(); + var delta = endTime - startStroke; shootCue(delta / 100.0); startStroke = 0; } @@ -201,49 +205,49 @@ function keyPressEvent(event) { } function cleanup() { - for (var i = 0; i < tableParts.length; i++) { - if (!tableParts[i].isKnownID) { - tableParts[i] = Entities.identifyEntity(tableParts[i]); - } - Entities.deleteEntity(tableParts[i]); + for (var i = 0; i < tableParts.length; i++) { + if (!tableParts[i].isKnownID) { + tableParts[i] = Entities.identifyEntity(tableParts[i]); } - for (var i = 0; i < balls.length; i++) { - if (!balls[i].isKnownID) { - balls[i] = Entities.identifyEntity(balls[i]); - } - Entities.deleteEntity(balls[i]); + Entities.deleteEntity(tableParts[i]); + } + for (var i = 0; i < balls.length; i++) { + if (!balls[i].isKnownID) { + balls[i] = Entities.identifyEntity(balls[i]); } - Overlays.deleteOverlay(reticle); - Entities.deleteEntity(cueBall); + Entities.deleteEntity(balls[i]); + } + Overlays.deleteOverlay(reticle); + Entities.deleteEntity(cueBall); } function update(deltaTime) { - if (!cueBall.isKnownID) { - cueBall = Entities.identifyEntity(cueBall); - } else { - // Check if cue ball has fallen off table, re-drop if so - var cueProperties = Entities.getEntityProperties(cueBall); - if (cueProperties.position.y < tableCenter.y) { - // Replace the cueball - Entities.editEntity(cueBall, { position: cuePosition } ); + if (!cueBall.isKnownID) { + cueBall = Entities.identifyEntity(cueBall); + } else { + // Check if cue ball has fallen off table, re-drop if so + var cueProperties = Entities.getEntityProperties(cueBall); + if (cueProperties.position.y < tableCenter.y) { + // Replace the cueball + Entities.editEntity(cueBall, { position: cuePosition } ); - } } + } } function entityCollisionWithEntity(entity1, entity2, collision) { - /* - NOT WORKING YET - if ((entity1.id == cueBall.id) || (entity2.id == cueBall.id)) { - print("Cue ball collision!"); - //audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); - //Audio.playSound(hitSounds[0], { position: Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())) }); - } + /* + NOT WORKING YET + if ((entity1.id == cueBall.id) || (entity2.id == cueBall.id)) { + print("Cue ball collision!"); + //audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); + //Audio.playSound(hitSounds[0], { position: Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())) }); + } - else if (isObjectBall(entity1.id) || isObjectBall(entity2.id)) { - print("Object ball collision"); - } */ + else if (isObjectBall(entity1.id) || isObjectBall(entity2.id)) { + print("Object ball collision"); + } */ } tableCenter = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation()))); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 53335beda0..fa726ee7db 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -65,16 +65,19 @@ void setSimId(EntityItemProperties& propertiesWithSimID, EntityItem* entity) { auto nodeList = DependencyManager::get(); const QUuid myNodeID = nodeList->getSessionUUID(); - // if this entity has non-zero physics/simulation related values, claim simulation ownership - if (propertiesWithSimID.velocityChanged() || - propertiesWithSimID.rotationChanged() || - propertiesWithSimID.containsPositionChange()) { - propertiesWithSimID.setSimulatorID(myNodeID); - entity->setSimulatorID(myNodeID); - } else if (entity->getSimulatorID() == myNodeID) { - propertiesWithSimID.setSimulatorID(QUuid()); // give up simulation ownership - entity->setSimulatorID(QUuid()); - } + // // if this entity has non-zero physics/simulation related values, claim simulation ownership + // if (propertiesWithSimID.velocityChanged() || + // propertiesWithSimID.rotationChanged() || + // propertiesWithSimID.containsPositionChange()) { + // propertiesWithSimID.setSimulatorID(myNodeID); + // entity->setSimulatorID(myNodeID); + // } else if (entity->getSimulatorID() == myNodeID) { + // propertiesWithSimID.setSimulatorID(QUuid()); // give up simulation ownership + // entity->setSimulatorID(QUuid()); + // } + + propertiesWithSimID.setSimulatorID(myNodeID); + entity->setSimulatorID(myNodeID); } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 50990d708c..7a569a4987 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -366,45 +366,6 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { } } - -void PhysicsEngine::bump(EntityItem* bumpEntity) { - // If this node is doing something like deleting an entity, scan for contacts involving the - // entity. For each found, flag the other entity involved as being simulated by this node. - lock(); - int numManifolds = _collisionDispatcher->getNumManifolds(); - for (int i = 0; i < numManifolds; ++i) { - btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); - if (contactManifold->getNumContacts() > 0) { - const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); - const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); - if (objectA && objectB) { - void* a = objectA->getUserPointer(); - void* b = objectB->getUserPointer(); - if (a && b) { - EntityItem* entityA = a ? static_cast(a)->getEntity() : NULL; - EntityItem* entityB = b ? static_cast(b)->getEntity() : NULL; - if (entityA && entityB) { - if (entityA == bumpEntity) { - entityB->setShouldClaimSimulationOwnership(true); - if (!objectB->isActive()) { - objectB->setActivationState(ACTIVE_TAG); - } - } - if (entityB == bumpEntity) { - entityA->setShouldClaimSimulationOwnership(true); - if (!objectA->isActive()) { - objectA->setActivationState(ACTIVE_TAG); - } - } - } - } - } - } - } - unlock(); -} - - void PhysicsEngine::computeCollisionEvents() { BT_PROFILE("computeCollisionEvents"); @@ -570,9 +531,10 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { assert(motionState); - EntityItem* entity = static_cast(motionState)->getEntity(); - bump(entity); btRigidBody* body = motionState->getRigidBody(); + // set the about-to-be-deleted entity active in order to wake up the island it's part of. this is done + // so that anything resting on top of it will fall. + body->setActivationState(ACTIVE_TAG); if (body) { const btCollisionShape* shape = body->getCollisionShape(); _dynamicsWorld->removeRigidBody(body); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 148261c6d2..6e1f430237 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -98,7 +98,6 @@ private: // return 'true' of update was successful bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); - void bump(EntityItem* bumpEntity); btClock _clock; btDefaultCollisionConfiguration* _collisionConfig = NULL; From d51f5a0ae85b5ca923dd6e36621e61e3cd2ad1d1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 17:22:37 -0700 Subject: [PATCH 220/401] remove commented out code --- libraries/entities/src/EntityScriptingInterface.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index fa726ee7db..32589c711b 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -64,18 +64,6 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) { void setSimId(EntityItemProperties& propertiesWithSimID, EntityItem* entity) { auto nodeList = DependencyManager::get(); const QUuid myNodeID = nodeList->getSessionUUID(); - - // // if this entity has non-zero physics/simulation related values, claim simulation ownership - // if (propertiesWithSimID.velocityChanged() || - // propertiesWithSimID.rotationChanged() || - // propertiesWithSimID.containsPositionChange()) { - // propertiesWithSimID.setSimulatorID(myNodeID); - // entity->setSimulatorID(myNodeID); - // } else if (entity->getSimulatorID() == myNodeID) { - // propertiesWithSimID.setSimulatorID(QUuid()); // give up simulation ownership - // entity->setSimulatorID(QUuid()); - // } - propertiesWithSimID.setSimulatorID(myNodeID); entity->setSimulatorID(myNodeID); } From 4ca076ed940dea8429d1965a692f8c5f8ac59515 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 18:53:49 -0700 Subject: [PATCH 221/401] put PhysicsEngine::bump back in. some things get missed if we just set the one thing active --- libraries/physics/src/PhysicsEngine.cpp | 43 ++++++++++++++++++++++++- libraries/physics/src/PhysicsEngine.h | 1 + 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 7a569a4987..e1551a0488 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -529,12 +529,53 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap motionState->resetMeasuredAcceleration(); } +void PhysicsEngine::bump(EntityItem* bumpEntity) { + // If this node is doing something like deleting an entity, scan for contacts involving the + // entity. For each found, flag the other entity involved as being simulated by this node. + lock(); + int numManifolds = _collisionDispatcher->getNumManifolds(); + for (int i = 0; i < numManifolds; ++i) { + btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); + if (contactManifold->getNumContacts() > 0) { + const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); + const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); + if (objectA && objectB) { + void* a = objectA->getUserPointer(); + void* b = objectB->getUserPointer(); + if (a && b) { + EntityItem* entityA = a ? static_cast(a)->getEntity() : NULL; + EntityItem* entityB = b ? static_cast(b)->getEntity() : NULL; + if (entityA && entityB) { + if (entityA == bumpEntity) { + entityB->setShouldClaimSimulationOwnership(true); + if (!objectB->isActive()) { + objectB->setActivationState(ACTIVE_TAG); + } + } + if (entityB == bumpEntity) { + entityA->setShouldClaimSimulationOwnership(true); + if (!objectA->isActive()) { + objectA->setActivationState(ACTIVE_TAG); + } + } + } + } + } + } + } + unlock(); +} + void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { assert(motionState); btRigidBody* body = motionState->getRigidBody(); + // set the about-to-be-deleted entity active in order to wake up the island it's part of. this is done // so that anything resting on top of it will fall. - body->setActivationState(ACTIVE_TAG); + // body->setActivationState(ACTIVE_TAG); + EntityItem* entity = static_cast(motionState)->getEntity(); + bump(entity); + if (body) { const btCollisionShape* shape = body->getCollisionShape(); _dynamicsWorld->removeRigidBody(body); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 6e1f430237..148261c6d2 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -98,6 +98,7 @@ private: // return 'true' of update was successful bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); + void bump(EntityItem* bumpEntity); btClock _clock; btDefaultCollisionConfiguration* _collisionConfig = NULL; From 8d8c4babba722957683f9bca92f79d01ddb17369 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 19:05:57 -0700 Subject: [PATCH 222/401] Coding standard fixes --- interface/src/Application.cpp | 3 +- interface/src/ui/ApplicationOverlay.cpp | 10 +- interface/src/ui/LoginDialog.h | 6 +- .../render-utils/src/OffscreenGlCanvas.cpp | 2 +- .../render-utils/src/OffscreenGlCanvas.h | 2 +- .../render-utils/src/OffscreenQmlDialog.cpp | 2 +- .../render-utils/src/OffscreenQmlDialog.h | 2 +- libraries/render-utils/src/OffscreenUi.cpp | 139 +++++++++--------- libraries/render-utils/src/OffscreenUi.h | 50 +++---- 9 files changed, 107 insertions(+), 109 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e7f8096e33..5adc408d8c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -569,8 +569,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : this->installEventFilter(this); // The offscreen UI needs to intercept the mouse and keyboard // events coming from the onscreen window - _glWidget->installEventFilter( - DependencyManager::get().data()); + _glWidget->installEventFilter(DependencyManager::get().data()); } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 5583790b13..2a8f01aafc 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -237,15 +237,15 @@ void ApplicationOverlay::renderOverlay() { // A quick and dirty solution for compositing the old overlay // texture with the new one template -void with_each_texture(GLuint a, GLuint b, F f) { +void with_each_texture(GLuint firstPassTexture, GLuint secondPassTexture, F f) { glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); - if (a) { - glBindTexture(GL_TEXTURE_2D, a); + if (firstPassTexture) { + glBindTexture(GL_TEXTURE_2D, firstPassTexture); f(); } - if (b) { - glBindTexture(GL_TEXTURE_2D, b); + if (secondPassTexture) { + glBindTexture(GL_TEXTURE_2D, secondPassTexture); f(); } glBindTexture(GL_TEXTURE_2D, 0); diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index d3f54981a5..7fe44bf543 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -25,7 +25,7 @@ class LoginDialog : public OffscreenQmlDialog public: static void toggleAction(); - LoginDialog(QQuickItem *parent = 0); + LoginDialog(QQuickItem* parent = 0); void setStatusText(const QString & a); QString statusText() const; @@ -39,8 +39,8 @@ protected: void handleLoginCompleted(const QUrl& authURL); void handleLoginFailed(); - Q_INVOKABLE void login(const QString & username, const QString & password); - Q_INVOKABLE void openUrl(const QString & url); + Q_INVOKABLE void login(const QString& username, const QString& password); + Q_INVOKABLE void openUrl(const QString& url); private: QString _statusText; const QString _rootUrl; diff --git a/libraries/render-utils/src/OffscreenGlCanvas.cpp b/libraries/render-utils/src/OffscreenGlCanvas.cpp index d6b268d4e9..0e5d4928d8 100644 --- a/libraries/render-utils/src/OffscreenGlCanvas.cpp +++ b/libraries/render-utils/src/OffscreenGlCanvas.cpp @@ -15,7 +15,7 @@ OffscreenGlCanvas::OffscreenGlCanvas() { } -void OffscreenGlCanvas::create(QOpenGLContext * sharedContext) { +void OffscreenGlCanvas::create(QOpenGLContext* sharedContext) { if (nullptr != sharedContext) { sharedContext->doneCurrent(); _context.setFormat(sharedContext->format()); diff --git a/libraries/render-utils/src/OffscreenGlCanvas.h b/libraries/render-utils/src/OffscreenGlCanvas.h index 1b2f15f690..5a64a4cf10 100644 --- a/libraries/render-utils/src/OffscreenGlCanvas.h +++ b/libraries/render-utils/src/OffscreenGlCanvas.h @@ -18,7 +18,7 @@ class OffscreenGlCanvas : public QObject { public: OffscreenGlCanvas(); - void create(QOpenGLContext * sharedContext = nullptr); + void create(QOpenGLContext* sharedContext = nullptr); bool makeCurrent(); void doneCurrent(); diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/render-utils/src/OffscreenQmlDialog.cpp index d6cfc9951b..ae0525e17d 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.cpp +++ b/libraries/render-utils/src/OffscreenQmlDialog.cpp @@ -10,7 +10,7 @@ #include "OffscreenQmlDialog.h" -OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem *parent) +OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem* parent) : QQuickItem(parent) { } void OffscreenQmlDialog::hide() { diff --git a/libraries/render-utils/src/OffscreenQmlDialog.h b/libraries/render-utils/src/OffscreenQmlDialog.h index 6e94587fd2..bb69b4b63f 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.h +++ b/libraries/render-utils/src/OffscreenQmlDialog.h @@ -47,7 +47,7 @@ class OffscreenQmlDialog : public QQuickItem { Q_OBJECT public: - OffscreenQmlDialog(QQuickItem *parent = 0); + OffscreenQmlDialog(QQuickItem* parent = 0); protected: void hide(); diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index d9dd030758..6849837da3 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -18,18 +18,18 @@ class OffscreenUiRoot : public QQuickItem { Q_OBJECT public: - OffscreenUiRoot(QQuickItem *parent = 0); - Q_INVOKABLE void information(const QString & title, const QString & text); - Q_INVOKABLE void loadChild(const QUrl & url) { + OffscreenUiRoot(QQuickItem* parent = 0); + Q_INVOKABLE void information(const QString& title, const QString& text); + Q_INVOKABLE void loadChild(const QUrl& url) { DependencyManager::get()->load(url); } }; -OffscreenUiRoot::OffscreenUiRoot(QQuickItem *parent) : QQuickItem(parent) { +OffscreenUiRoot::OffscreenUiRoot(QQuickItem* parent) : QQuickItem(parent) { } -void OffscreenUiRoot::information(const QString & title, const QString & text = "foo") { +void OffscreenUiRoot::information(const QString& title, const QString& text) { OffscreenUi::information(title, text); } @@ -55,7 +55,7 @@ OffscreenUi::~OffscreenUi() { doneCurrent(); } -void OffscreenUi::create(QOpenGLContext * shareContext) { +void OffscreenUi::create(QOpenGLContext* shareContext) { OffscreenGlCanvas::create(shareContext); makeCurrent(); @@ -69,8 +69,9 @@ void OffscreenUi::create(QOpenGLContext * shareContext) { _quickWindow->setFlags(_quickWindow->flags() | static_cast(Qt::WA_TranslucentBackground)); // Create a QML engine. _qmlEngine = new QQmlEngine; - if (!_qmlEngine->incubationController()) + if (!_qmlEngine->incubationController()) { _qmlEngine->setIncubationController(_quickWindow->incubationController()); + } // When Quick says there is a need to render, we will not render immediately. Instead, // a timer with a small interval is used to get better performance. @@ -91,11 +92,11 @@ void OffscreenUi::create(QOpenGLContext * shareContext) { _renderControl->initialize(&_context); } -void OffscreenUi::addImportPath(const QString & path) { +void OffscreenUi::addImportPath(const QString& path) { _qmlEngine->addImportPath(path); } -void OffscreenUi::resize(const QSize & newSize) { +void OffscreenUi::resize(const QSize& newSize) { makeCurrent(); // Clear out any fbos with the old size @@ -115,24 +116,25 @@ void OffscreenUi::resize(const QSize & newSize) { doneCurrent(); } -QQmlContext * OffscreenUi::qmlContext() { +QQmlContext* OffscreenUi::qmlContext() { if (nullptr == _rootItem) { return _qmlComponent->creationContext(); } return QQmlEngine::contextForObject(_rootItem); } -void OffscreenUi::setBaseUrl(const QUrl & baseUrl) { +void OffscreenUi::setBaseUrl(const QUrl& baseUrl) { _qmlEngine->setBaseUrl(baseUrl); } -void OffscreenUi::load(const QUrl & qmlSource, std::function f) { +void OffscreenUi::load(const QUrl& qmlSource, std::function f) { qDebug() << "Loading QML from URL " << qmlSource; _qmlComponent->loadUrl(qmlSource); - if (_qmlComponent->isLoading()) - connect(_qmlComponent, &QQmlComponent::statusChanged, this, [] {}); - else + if (_qmlComponent->isLoading()) { + connect(_qmlComponent, &QQmlComponent::statusChanged, this, []{}); + } else { finishQmlLoad(); + } } void OffscreenUi::requestUpdate() { @@ -156,7 +158,7 @@ void OffscreenUi::finishQmlLoad() { return; } - QObject *newObject = _qmlComponent->create(); + QObject* newObject = _qmlComponent->create(); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); foreach(const QQmlError &error, errorList) @@ -167,7 +169,7 @@ void OffscreenUi::finishQmlLoad() { return; } - QQuickItem * newItem = qobject_cast(newObject); + QQuickItem* newItem = qobject_cast(newObject); if (!newItem) { qWarning("run: Not a QQuickItem"); delete newObject; @@ -200,8 +202,9 @@ void OffscreenUi::updateQuick() { if (_paused) { return; } - if (!makeCurrent()) + if (!makeCurrent()) { return; + } // Polish, synchronize and render the next frame (into our fbo). In this example // everything happens on the same thread and therefore all three steps are performed @@ -234,7 +237,7 @@ void OffscreenUi::updateQuick() { emit textureUpdated(fbo->texture()); } -QPointF OffscreenUi::mapWindowToUi(const QPointF & p, QObject * dest) { +QPointF OffscreenUi::mapWindowToUi(const QPointF& p, QObject* dest) { vec2 sourceSize; if (dynamic_cast(dest)) { sourceSize = toGlm(((QWidget*)dest)->size()); @@ -252,7 +255,7 @@ QPointF OffscreenUi::mapWindowToUi(const QPointF & p, QObject * dest) { // Event handling customization // -bool OffscreenUi::eventFilter(QObject * dest, QEvent * e) { +bool OffscreenUi::eventFilter(QObject* dest, QEvent* e) { // Only intercept events while we're in an active state if (_paused) { return false; @@ -264,50 +267,46 @@ bool OffscreenUi::eventFilter(QObject * dest, QEvent * e) { } switch (e->type()) { - case QEvent::Resize: - { - QResizeEvent * re = (QResizeEvent *)e; - QGLWidget * widget = dynamic_cast(dest); - if (widget) { - this->resize(re->size()); + case QEvent::Resize: { + QResizeEvent* re = (QResizeEvent*)e; + QGLWidget* widget = dynamic_cast(dest); + if (widget) { + this->resize(re->size()); + } + return false; } - return false; - } - case QEvent::KeyPress: - case QEvent::KeyRelease: - { - e->ignore(); - if (QCoreApplication::sendEvent(_quickWindow, e)) { - return e->isAccepted(); + case QEvent::KeyPress: + case QEvent::KeyRelease: { + e->ignore(); + if (QCoreApplication::sendEvent(_quickWindow, e)) { + return e->isAccepted(); + } + break; } - } - break; - case QEvent::Wheel: - { - QWheelEvent * we = (QWheelEvent*)e; - QWheelEvent mappedEvent(mapWindowToUi(we->pos(), dest), we->delta(), we->buttons(), we->modifiers(), we->orientation()); - QCoreApplication::sendEvent(_quickWindow, &mappedEvent); - return true; - } - break; + case QEvent::Wheel: { + QWheelEvent* we = (QWheelEvent*)e; + QWheelEvent mappedEvent(mapWindowToUi(we->pos(), dest), we->delta(), we->buttons(), we->modifiers(), we->orientation()); + QCoreApplication::sendEvent(_quickWindow, &mappedEvent); + return true; + } - // Fall through - case QEvent::MouseButtonDblClick: - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseMove: - { - QMouseEvent * me = (QMouseEvent *)e; - QPointF originalPos = me->localPos(); - QPointF transformedPos = _mouseTranslator(originalPos); - QMouseEvent mappedEvent(e->type(), mapWindowToUi(transformedPos, dest), me->screenPos(), me->button(), me->buttons(), me->modifiers()); - QCoreApplication::sendEvent(_quickWindow, &mappedEvent); - return QObject::event(e); - } + // Fall through + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: { + QMouseEvent* me = (QMouseEvent *)e; + QPointF originalPos = me->localPos(); + QPointF transformedPos = _mouseTranslator(originalPos); + QMouseEvent mappedEvent(e->type(), mapWindowToUi(transformedPos, dest), me->screenPos(), me->button(), me->buttons(), me->modifiers()); + QCoreApplication::sendEvent(_quickWindow, &mappedEvent); + return QObject::event(e); + } - default: break; + default: + break; } return false; @@ -334,22 +333,22 @@ bool OffscreenUi::isPaused() const { return _paused; } -void OffscreenUi::setProxyWindow(QWindow * window) { +void OffscreenUi::setProxyWindow(QWindow* window) { _renderControl->_renderWindow = window; } -void OffscreenUi::show(const QUrl & url, const QString & name) { - QQuickItem * item = _rootItem->findChild(name); +void OffscreenUi::show(const QUrl& url, const QString& name) { + QQuickItem* item = _rootItem->findChild(name); // First load? - if (nullptr == item) { + if (!item) { load(url); return; } item->setEnabled(true); } -void OffscreenUi::toggle(const QUrl & url, const QString & name) { - QQuickItem * item = _rootItem->findChild(name); +void OffscreenUi::toggle(const QUrl& url, const QString& name) { + QQuickItem* item = _rootItem->findChild(name); // First load? if (nullptr == item) { load(url); @@ -358,31 +357,31 @@ void OffscreenUi::toggle(const QUrl & url, const QString & name) { item->setEnabled(!item->isEnabled()); } -void OffscreenUi::messageBox(const QString &title, const QString &text, +void OffscreenUi::messageBox(const QString& title, const QString& text, QMessageBox::Icon icon, QMessageBox::StandardButtons buttons, ButtonCallback f) { } -void OffscreenUi::information(const QString &title, const QString &text, +void OffscreenUi::information(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, ButtonCallback callback) { callback(QMessageBox::information(nullptr, title, text, buttons)); } -void OffscreenUi::question(const QString &title, const QString &text, +void OffscreenUi::question(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, ButtonCallback callback) { callback(QMessageBox::question(nullptr, title, text, buttons)); } -void OffscreenUi::warning(const QString &title, const QString &text, +void OffscreenUi::warning(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, ButtonCallback callback) { callback(QMessageBox::warning(nullptr, title, text, buttons)); } -void OffscreenUi::critical(const QString &title, const QString &text, +void OffscreenUi::critical(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, ButtonCallback callback) { callback(QMessageBox::critical(nullptr, title, text, buttons)); @@ -391,4 +390,4 @@ void OffscreenUi::critical(const QString &title, const QString &text, OffscreenUi::ButtonCallback OffscreenUi::NO_OP_CALLBACK = [](QMessageBox::StandardButton) {}; -#include "OffscreenUi.moc" \ No newline at end of file +#include "OffscreenUi.moc" diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index 73c022e4be..16db24e5ae 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -38,7 +38,7 @@ class OffscreenUi : public OffscreenGlCanvas, public Dependency { class QMyQuickRenderControl : public QQuickRenderControl { protected: - QWindow * renderWindow(QPoint * offset) Q_DECL_OVERRIDE{ + QWindow* renderWindow(QPoint* offset) Q_DECL_OVERRIDE{ if (nullptr == _renderWindow) { return QQuickRenderControl::renderWindow(offset); } @@ -49,59 +49,59 @@ class OffscreenUi : public OffscreenGlCanvas, public Dependency { } private: - QWindow * _renderWindow{ nullptr }; + QWindow* _renderWindow{ nullptr }; friend class OffscreenUi; }; public: - using MouseTranslator = std::function < QPointF(const QPointF &) > ; + using MouseTranslator = std::function; OffscreenUi(); virtual ~OffscreenUi(); - void create(QOpenGLContext * context); - void resize(const QSize & size); - void load(const QUrl & qmlSource, std::function f = [](QQmlContext*) {}); - void load(const QString & qmlSourceFile, std::function f = [](QQmlContext*) {}) { + void create(QOpenGLContext* context); + void resize(const QSize& size); + void load(const QUrl& qmlSource, std::function f = [](QQmlContext*) {}); + void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*) {}) { load(QUrl(qmlSourceFile), f); } - void show(const QUrl & url, const QString & name); - void toggle(const QUrl & url, const QString & name); - void setBaseUrl(const QUrl & baseUrl); - void addImportPath(const QString & path); + void show(const QUrl& url, const QString& name); + void toggle(const QUrl& url, const QString& name); + void setBaseUrl(const QUrl& baseUrl); + void addImportPath(const QString& path); QQmlContext * qmlContext(); void pause(); void resume(); bool isPaused() const; - void setProxyWindow(QWindow * window); - QPointF mapWindowToUi(const QPointF & p, QObject * dest); - virtual bool eventFilter(QObject * dest, QEvent * e); + void setProxyWindow(QWindow* window); + QPointF mapWindowToUi(const QPointF& p, QObject* dest); + virtual bool eventFilter(QObject* dest, QEvent* e); void setMouseTranslator(MouseTranslator mt) { _mouseTranslator = mt; } // Messagebox replacement functions - using ButtonCallback = std::function < void(QMessageBox::StandardButton) >; + using ButtonCallback = std::function; static ButtonCallback NO_OP_CALLBACK; - static void messageBox(const QString &title, const QString &text, + static void messageBox(const QString& title, const QString& text, QMessageBox::Icon icon, QMessageBox::StandardButtons buttons, ButtonCallback f); - static void information(const QString &title, const QString &text, + static void information(const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, ButtonCallback callback = NO_OP_CALLBACK); - static void question(const QString &title, const QString &text, + static void question(const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), ButtonCallback callback = [](QMessageBox::StandardButton) {}); - static void warning(const QString &title, const QString &text, + static void warning(const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, ButtonCallback callback = [](QMessageBox::StandardButton) {}); - static void critical(const QString &title, const QString &text, + static void critical(const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, ButtonCallback callback = [](QMessageBox::StandardButton) {}); @@ -121,11 +121,11 @@ signals: void textureUpdated(GLuint texture); private: - QMyQuickRenderControl *_renderControl{ new QMyQuickRenderControl }; - QQuickWindow *_quickWindow{ nullptr }; - QQmlEngine *_qmlEngine{ nullptr }; - QQmlComponent *_qmlComponent{ nullptr }; - QQuickItem * _rootItem{ nullptr }; + QMyQuickRenderControl* _renderControl{ new QMyQuickRenderControl }; + QQuickWindow* _quickWindow{ nullptr }; + QQmlEngine* _qmlEngine{ nullptr }; + QQmlComponent* _qmlComponent{ nullptr }; + QQuickItem* _rootItem{ nullptr }; QTimer _updateTimer; FboCache _fboCache; bool _polish{ true }; From c4d2bd2cdaac29a237fa84398e923db9bb633115 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 19:18:09 -0700 Subject: [PATCH 223/401] More coding standard fixes --- interface/src/Application.h | 4 ++-- interface/src/GLCanvas.cpp | 2 +- interface/src/ui/AddressBarDialog.cpp | 6 +++--- interface/src/ui/AddressBarDialog.h | 4 ++-- interface/src/ui/LoginDialog.cpp | 10 +++++----- interface/src/ui/LoginDialog.h | 2 +- libraries/render-utils/src/FboCache.cpp | 2 +- libraries/render-utils/src/FboCache.h | 2 +- .../render-utils/src/OffscreenQmlDialog.cpp | 2 +- libraries/render-utils/src/OffscreenUi.cpp | 6 ++++-- libraries/shared/src/ThreadHelpers.h | 4 ++-- tests/render-utils/src/main.cpp | 18 ++++++++---------- 12 files changed, 31 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index cb54f7dc79..89de18dde5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -171,8 +171,8 @@ public: void touchUpdateEvent(QTouchEvent* event); void wheelEvent(QWheelEvent* event); - void dropEvent(QDropEvent *event); - void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent* event); + void dragEnterEvent(QDragEnterEvent* event); bool event(QEvent* event); bool eventFilter(QObject* object, QEvent* event); diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index d0c0cb6713..0e25f0f596 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -127,7 +127,7 @@ void GLCanvas::throttleRender() { int updateTime = 0; bool GLCanvas::event(QEvent* event) { switch (event->type()) { - case QEvent::MouseMove: + case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::KeyPress: diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 5ef9b930ac..6b5c92c194 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -17,7 +17,7 @@ QML_DIALOG_DEF(AddressBarDialog) -AddressBarDialog::AddressBarDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { +AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) { auto addressManager = DependencyManager::get(); connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage); connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage); @@ -25,10 +25,10 @@ AddressBarDialog::AddressBarDialog(QQuickItem *parent) : OffscreenQmlDialog(pare } void AddressBarDialog::hide() { - ((QQuickItem *)parent())->setEnabled(false); + ((QQuickItem*)parent())->setEnabled(false); } -void AddressBarDialog::loadAddress(const QString & address) { +void AddressBarDialog::loadAddress(const QString& address) { qDebug() << "Called LoadAddress with address " << address; if (!address.isEmpty()) { DependencyManager::get()->handleLookupString(address); diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index b4f4c44e0f..a9035cc915 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -20,14 +20,14 @@ class AddressBarDialog : public OffscreenQmlDialog QML_DIALOG_DECL public: - AddressBarDialog(QQuickItem *parent = 0); + AddressBarDialog(QQuickItem* parent = 0); protected: void displayAddressOfflineMessage(); void displayAddressNotFoundMessage(); void hide(); - Q_INVOKABLE void loadAddress(const QString & address); + Q_INVOKABLE void loadAddress(const QString& address); }; #endif diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 3637d824fb..10541415bf 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -41,7 +41,7 @@ void LoginDialog::toggleAction() { } } -void LoginDialog::handleLoginCompleted(const QUrl& authURL) { +void LoginDialog::handleLoginCompleted(const QUrl&) { hide(); } @@ -49,9 +49,9 @@ void LoginDialog::handleLoginFailed() { setStatusText("Invalid username or password.< / font>"); } -void LoginDialog::setStatusText(const QString &a) { +void LoginDialog::setStatusText(const QString& statusText) { if (a != _statusText) { - _statusText = a; + _statusText = statusText; emit statusTextChanged(); } } @@ -64,12 +64,12 @@ QString LoginDialog::rootUrl() const { return _rootUrl; } -void LoginDialog::login(const QString & username, const QString & password) { +void LoginDialog::login(const QString& username, const QString& password) { qDebug() << "Attempting to login " << username; setStatusText("Authenticating..."); AccountManager::getInstance().requestAccessToken(username, password); } -void LoginDialog::openUrl(const QString & url) { +void LoginDialog::openUrl(const QString& url) { qDebug() << url; } diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index 7fe44bf543..b4f83bb9ad 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -27,7 +27,7 @@ public: LoginDialog(QQuickItem* parent = 0); - void setStatusText(const QString & a); + void setStatusText(const QString& a); QString statusText() const; QString rootUrl() const; diff --git a/libraries/render-utils/src/FboCache.cpp b/libraries/render-utils/src/FboCache.cpp index fdd29d20d8..2ca3d47bdf 100644 --- a/libraries/render-utils/src/FboCache.cpp +++ b/libraries/render-utils/src/FboCache.cpp @@ -72,7 +72,7 @@ QOpenGLFramebufferObject* FboCache::getReadyFbo() { return result; } -void FboCache::setSize(const QSize & newSize) { +void FboCache::setSize(const QSize& newSize) { if (_size == newSize) { return; } diff --git a/libraries/render-utils/src/FboCache.h b/libraries/render-utils/src/FboCache.h index 975d602278..30278470fd 100644 --- a/libraries/render-utils/src/FboCache.h +++ b/libraries/render-utils/src/FboCache.h @@ -30,7 +30,7 @@ public: // the appropriate OpenGL context is active when doing so. // Important.... textures are sharable resources, but FBOs ARE NOT. - void setSize(const QSize & newSize); + void setSize(const QSize& newSize); QOpenGLFramebufferObject* getReadyFbo(); // These operations are thread safe and require no OpenGL context. They manipulate the diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/render-utils/src/OffscreenQmlDialog.cpp index ae0525e17d..98dc68f94b 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.cpp +++ b/libraries/render-utils/src/OffscreenQmlDialog.cpp @@ -14,5 +14,5 @@ OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem* parent) : QQuickItem(parent) { } void OffscreenQmlDialog::hide() { - ((QQuickItem *)parent())->setEnabled(false); + ((QQuickItem*)parent())->setEnabled(false); } diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 6849837da3..5fb2773d31 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -139,13 +139,15 @@ void OffscreenUi::load(const QUrl& qmlSource, std::function void OffscreenUi::requestUpdate() { _polish = true; - if (!_updateTimer.isActive()) + if (!_updateTimer.isActive()) { _updateTimer.start(); + } } void OffscreenUi::requestRender() { - if (!_updateTimer.isActive()) + if (!_updateTimer.isActive()) { _updateTimer.start(); + } } void OffscreenUi::finishQmlLoad() { diff --git a/libraries/shared/src/ThreadHelpers.h b/libraries/shared/src/ThreadHelpers.h index 8a64691da7..cc0e1ee666 100644 --- a/libraries/shared/src/ThreadHelpers.h +++ b/libraries/shared/src/ThreadHelpers.h @@ -21,9 +21,9 @@ void withLock(L lock, F function) { } template -void withLock(QMutex & lock, F function) { +void withLock(QMutex& lock, F function) { QMutexLocker locker(&lock); function(); } -#endif \ No newline at end of file +#endif diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index eb61fd1f72..7adad34879 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -70,7 +70,7 @@ public: }; -const QString & getQmlDir() { +const QString& getQmlDir() { static QString dir; if (dir.isEmpty()) { QDir path(__FILE__); @@ -98,7 +98,7 @@ protected: void renderQml(); private: - void resizeWindow(const QSize & size) { + void resizeWindow(const QSize& size) { _size = size; DependencyManager::get()->resize(_size); } @@ -126,7 +126,7 @@ public: makeCurrent(); { - QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); logger->initialize(); // initializes in the current context, i.e. ctx logger->enableMessages(); connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { @@ -201,12 +201,12 @@ public: protected: - void resizeEvent(QResizeEvent * ev) override { + void resizeEvent(QResizeEvent* ev) override { resizeWindow(ev->size()); } - void keyPressEvent(QKeyEvent *event) { + void keyPressEvent(QKeyEvent* event) { switch (event->key()) { case Qt::Key_L: if (event->modifiers() & Qt::CTRL) { @@ -217,7 +217,7 @@ protected: QWindow::keyPressEvent(event); } - void moveEvent(QMoveEvent *event) { + void moveEvent(QMoveEvent* event) { static qreal oldPixelRatio = 0.0; if (devicePixelRatio() != oldPixelRatio) { oldPixelRatio = devicePixelRatio(); @@ -232,8 +232,8 @@ protected: #define SERIF_FONT_FAMILY "Times New Roman" #endif -static const wchar_t * EXAMPLE_TEXT = L"Hello"; -//static const wchar_t * EXAMPLE_TEXT = L"\xC1y Hello 1.0\ny\xC1 line 2\n\xC1y"; +static const wchar_t* EXAMPLE_TEXT = L"Hello"; +//static const wchar_t* EXAMPLE_TEXT = L"\xC1y Hello 1.0\ny\xC1 line 2\n\xC1y"; static const glm::uvec2 QUAD_OFFSET(10, 10); static const glm::vec3 COLORS[4] = { { 1.0, 1.0, 1.0 }, { 0.5, 1.0, 0.5 }, { @@ -283,7 +283,6 @@ void QTestWindow::renderText() { } void QTestWindow::renderQml() { - glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); @@ -297,7 +296,6 @@ void QTestWindow::renderQml() { } glBegin(GL_QUADS); { - glTexCoord2f(0, 0); glVertex2f(-1, -1); glTexCoord2f(0, 1); From 930ec7a6d8ecb8d61566d85d91a7afd3295bb252 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 19:22:10 -0700 Subject: [PATCH 224/401] One more --- tests/render-utils/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 7adad34879..9d7363c241 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -84,7 +84,7 @@ const QString& getQmlDir() { class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext * _context{ nullptr }; + QOpenGLContext* _context{ nullptr }; QSize _size; TextRenderer* _textRenderer[4]; RateCounter fps; From 732e9723cd0294880776dfd74b371c9db824eecc Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 19:24:43 -0700 Subject: [PATCH 225/401] Messed up rename --- interface/src/ui/LoginDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 10541415bf..4df42c0f15 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -50,7 +50,7 @@ void LoginDialog::handleLoginFailed() { } void LoginDialog::setStatusText(const QString& statusText) { - if (a != _statusText) { + if (statusText != _statusText) { _statusText = statusText; emit statusTextChanged(); } From 44efcdf82ad48ee56a72674a377543699bc7b24d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 20:08:49 -0700 Subject: [PATCH 226/401] More coding standard --- libraries/render-utils/src/OffscreenUi.cpp | 56 ++++++++++++---------- libraries/render-utils/src/OffscreenUi.h | 12 ++--- libraries/render-utils/src/RenderUtil.h | 4 +- 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 5fb2773d31..d63f3330e9 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -239,17 +239,17 @@ void OffscreenUi::updateQuick() { emit textureUpdated(fbo->texture()); } -QPointF OffscreenUi::mapWindowToUi(const QPointF& p, QObject* dest) { +QPointF OffscreenUi::mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject) { vec2 sourceSize; - if (dynamic_cast(dest)) { - sourceSize = toGlm(((QWidget*)dest)->size()); - } else if (dynamic_cast(dest)) { - sourceSize = toGlm(((QWindow*)dest)->size()); + if (dynamic_cast(sourceObject)) { + sourceSize = toGlm(((QWidget*)sourceObject)->size()); + } else if (dynamic_cast(sourceObject)) { + sourceSize = toGlm(((QWindow*)sourceObject)->size()); } - vec2 pos = toGlm(p); - pos /= sourceSize; - pos *= vec2(toGlm(_quickWindow->size())); - return QPointF(pos.x, pos.y); + vec2 offscreenPosition = toGlm(sourcePosition); + offscreenPosition /= sourceSize; + offscreenPosition *= vec2(toGlm(_quickWindow->size())); + return QPointF(offscreenPosition.x, offscreenPosition.y); } /////////////////////////////////////////////////////// @@ -257,39 +257,42 @@ QPointF OffscreenUi::mapWindowToUi(const QPointF& p, QObject* dest) { // Event handling customization // -bool OffscreenUi::eventFilter(QObject* dest, QEvent* e) { +bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { // Only intercept events while we're in an active state if (_paused) { return false; } // Don't intercept our own events, or we enter an infinite recursion - if (dest == _quickWindow) { + if (originalDestination == _quickWindow) { return false; } - switch (e->type()) { + switch (event->type()) { case QEvent::Resize: { - QResizeEvent* re = (QResizeEvent*)e; - QGLWidget* widget = dynamic_cast(dest); + QResizeEvent* resizeEvent = (QResizeEvent*)event; + QGLWidget* widget = dynamic_cast(originalDestination); if (widget) { - this->resize(re->size()); + this->resize(resizeEvent->size()); } return false; } case QEvent::KeyPress: case QEvent::KeyRelease: { - e->ignore(); - if (QCoreApplication::sendEvent(_quickWindow, e)) { - return e->isAccepted(); + event->ignore(); + if (QCoreApplication::sendEvent(_quickWindow, event)) { + return event->isAccepted(); } break; } case QEvent::Wheel: { - QWheelEvent* we = (QWheelEvent*)e; - QWheelEvent mappedEvent(mapWindowToUi(we->pos(), dest), we->delta(), we->buttons(), we->modifiers(), we->orientation()); + QWheelEvent* wheelEvent = (QWheelEvent*)event; + QWheelEvent mappedEvent( + mapWindowToUi(wheelEvent->pos(), originalDestination), + wheelEvent->delta(), wheelEvent->buttons(), + wheelEvent->modifiers(), wheelEvent->orientation()); QCoreApplication::sendEvent(_quickWindow, &mappedEvent); return true; } @@ -299,12 +302,15 @@ bool OffscreenUi::eventFilter(QObject* dest, QEvent* e) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { - QMouseEvent* me = (QMouseEvent *)e; - QPointF originalPos = me->localPos(); + QMouseEvent* mouseEvent = (QMouseEvent *)event; + QPointF originalPos = mouseEvent->localPos(); QPointF transformedPos = _mouseTranslator(originalPos); - QMouseEvent mappedEvent(e->type(), mapWindowToUi(transformedPos, dest), me->screenPos(), me->button(), me->buttons(), me->modifiers()); + QMouseEvent mappedEvent(mouseEvent->type(), + mapWindowToUi(transformedPos, originalDestination), + mouseEvent->screenPos(), mouseEvent->button(), + mouseEvent->buttons(), mouseEvent->modifiers()); QCoreApplication::sendEvent(_quickWindow, &mappedEvent); - return QObject::event(e); + return QObject::event(event); } default: @@ -352,7 +358,7 @@ void OffscreenUi::show(const QUrl& url, const QString& name) { void OffscreenUi::toggle(const QUrl& url, const QString& name) { QQuickItem* item = _rootItem->findChild(name); // First load? - if (nullptr == item) { + if (!item) { load(url); return; } diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index 16db24e5ae..d86f99554e 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -67,16 +67,16 @@ public: void toggle(const QUrl& url, const QString& name); void setBaseUrl(const QUrl& baseUrl); void addImportPath(const QString& path); - QQmlContext * qmlContext(); + QQmlContext* qmlContext(); void pause(); void resume(); bool isPaused() const; void setProxyWindow(QWindow* window); - QPointF mapWindowToUi(const QPointF& p, QObject* dest); - virtual bool eventFilter(QObject* dest, QEvent* e); - void setMouseTranslator(MouseTranslator mt) { - _mouseTranslator = mt; + QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); + virtual bool eventFilter(QObject* originalDestination, QEvent* event); + void setMouseTranslator(MouseTranslator mouseTranslator) { + _mouseTranslator = mouseTranslator; } @@ -130,7 +130,7 @@ private: FboCache _fboCache; bool _polish{ true }; bool _paused{ true }; - MouseTranslator _mouseTranslator{ [](const QPointF & p) { return p; } }; + MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p; } }; }; #endif diff --git a/libraries/render-utils/src/RenderUtil.h b/libraries/render-utils/src/RenderUtil.h index 74d6c23791..8c1b1e12e7 100644 --- a/libraries/render-utils/src/RenderUtil.h +++ b/libraries/render-utils/src/RenderUtil.h @@ -37,7 +37,7 @@ void withProjectionIdentity(F f) { } template -void withProjectionMatrix(GLfloat * matrix, F f) { +void withProjectionMatrix(GLfloat* matrix, F f) { withProjectionPush([&] { glLoadMatrixf(matrix); f(); @@ -58,7 +58,7 @@ void withModelviewIdentity(F f) { } template -void withModelviewMatrix(GLfloat * matrix, F f) { +void withModelviewMatrix(GLfloat* matrix, F f) { withModelviewPush([&] { glLoadMatrixf(matrix); f(); From eab4ad9ea98343afeb4bd8a7a171a8aa2957ae91 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 20:16:41 -0700 Subject: [PATCH 227/401] More coding standard stuff --- interface/src/ui/AddressBarDialog.h | 2 +- interface/src/ui/LoginDialog.h | 4 ++-- libraries/render-utils/src/OffscreenQmlDialog.cpp | 2 +- libraries/render-utils/src/OffscreenQmlDialog.h | 2 +- libraries/render-utils/src/OffscreenUi.cpp | 7 ++++++- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index a9035cc915..28056edd30 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -20,7 +20,7 @@ class AddressBarDialog : public OffscreenQmlDialog QML_DIALOG_DECL public: - AddressBarDialog(QQuickItem* parent = 0); + AddressBarDialog(QQuickItem* parent = nullptr); protected: void displayAddressOfflineMessage(); diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index b4f83bb9ad..b6d505943e 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -25,9 +25,9 @@ class LoginDialog : public OffscreenQmlDialog public: static void toggleAction(); - LoginDialog(QQuickItem* parent = 0); + LoginDialog(QQuickItem* parent = nullptr); - void setStatusText(const QString& a); + void setStatusText(const QString& statusText); QString statusText() const; QString rootUrl() const; diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/render-utils/src/OffscreenQmlDialog.cpp index 98dc68f94b..d1e060245d 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.cpp +++ b/libraries/render-utils/src/OffscreenQmlDialog.cpp @@ -14,5 +14,5 @@ OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem* parent) : QQuickItem(parent) { } void OffscreenQmlDialog::hide() { - ((QQuickItem*)parent())->setEnabled(false); + static_cast(parent())->setEnabled(false); } diff --git a/libraries/render-utils/src/OffscreenQmlDialog.h b/libraries/render-utils/src/OffscreenQmlDialog.h index bb69b4b63f..eca82261c0 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.h +++ b/libraries/render-utils/src/OffscreenQmlDialog.h @@ -47,7 +47,7 @@ class OffscreenQmlDialog : public QQuickItem { Q_OBJECT public: - OffscreenQmlDialog(QQuickItem* parent = 0); + OffscreenQmlDialog(QQuickItem* parent = nullptr); protected: void hide(); diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index d63f3330e9..d4e1f15b22 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -14,6 +14,11 @@ #include #include +// Time between receiving a request to render the offscreen UI actually triggering +// the render. Could possibly be increased depending on the framerate we expect to +// achieve. +static const int SMALL_INTERVAL = 5; + class OffscreenUiRoot : public QQuickItem { Q_OBJECT public: @@ -76,7 +81,7 @@ void OffscreenUi::create(QOpenGLContext* shareContext) { // When Quick says there is a need to render, we will not render immediately. Instead, // a timer with a small interval is used to get better performance. _updateTimer.setSingleShot(true); - _updateTimer.setInterval(5); + _updateTimer.setInterval(SMALL_INTERVAL); connect(&_updateTimer, &QTimer::timeout, this, &OffscreenUi::updateQuick); // Now hook up the signals. For simplicy we don't differentiate between From de179256d3a15aad8a78b391047b47e52e0e2efa Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 20:19:19 -0700 Subject: [PATCH 228/401] Kill all the whitespace --- libraries/render-utils/src/OffscreenUi.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index d4e1f15b22..db93a14b0d 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -275,7 +275,7 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { switch (event->type()) { case QEvent::Resize: { - QResizeEvent* resizeEvent = (QResizeEvent*)event; + QResizeEvent* resizeEvent = static_cast(event); QGLWidget* widget = dynamic_cast(originalDestination); if (widget) { this->resize(resizeEvent->size()); @@ -293,7 +293,7 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { } case QEvent::Wheel: { - QWheelEvent* wheelEvent = (QWheelEvent*)event; + QWheelEvent* wheelEvent = static_cast(event); QWheelEvent mappedEvent( mapWindowToUi(wheelEvent->pos(), originalDestination), wheelEvent->delta(), wheelEvent->buttons(), @@ -307,7 +307,7 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { - QMouseEvent* mouseEvent = (QMouseEvent *)event; + QMouseEvent* mouseEvent = static_cast(event); QPointF originalPos = mouseEvent->localPos(); QPointF transformedPos = _mouseTranslator(originalPos); QMouseEvent mappedEvent(mouseEvent->type(), From 9e96026c5276ff673904e8437310a79cebb57439 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Apr 2015 21:36:36 -0700 Subject: [PATCH 229/401] move _accelerationNearlyGravityCount and _shouldClaimSimulationOwnership from EntityItem to EntityMotionState --- libraries/entities/src/EntityItem.cpp | 2 -- libraries/entities/src/EntityItem.h | 8 ------- libraries/physics/src/EntityMotionState.cpp | 21 ++++++++++-------- libraries/physics/src/EntityMotionState.h | 9 ++++++++ libraries/physics/src/PhysicsEngine.cpp | 24 ++++++++++++--------- 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5a141af581..1a52db6c67 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -47,7 +47,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _velocity(ENTITY_ITEM_DEFAULT_VELOCITY), _gravity(ENTITY_ITEM_DEFAULT_GRAVITY), _acceleration(ENTITY_ITEM_DEFAULT_ACCELERATION), - _accelerationNearlyGravityCount(0), _damping(ENTITY_ITEM_DEFAULT_DAMPING), _lifetime(ENTITY_ITEM_DEFAULT_LIFETIME), _script(ENTITY_ITEM_DEFAULT_SCRIPT), @@ -61,7 +60,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _userData(ENTITY_ITEM_DEFAULT_USER_DATA), _simulatorID(ENTITY_ITEM_DEFAULT_SIMULATOR_ID), _simulatorIDChangedTime(0), - _shouldClaimSimulationOwnership(false), _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), _physicsInfo(NULL), _dirtyFlags(0), diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5d19c11dc5..6fd17cc7d5 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -258,8 +258,6 @@ public: QUuid getSimulatorID() const { return _simulatorID; } void setSimulatorID(const QUuid& value); quint64 getSimulatorIDChangedTime() const { return _simulatorIDChangedTime; } - void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } - bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } const QString& getMarketplaceID() const { return _marketplaceID; } void setMarketplaceID(const QString& value) { _marketplaceID = value; } @@ -311,10 +309,6 @@ public: static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; } static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; } - void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } - void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } - quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } - protected: static bool _sendPhysicsUpdates; @@ -344,7 +338,6 @@ protected: glm::vec3 _velocity; glm::vec3 _gravity; glm::vec3 _acceleration; - quint8 _accelerationNearlyGravityCount; float _damping; float _lifetime; QString _script; @@ -358,7 +351,6 @@ protected: QString _userData; QUuid _simulatorID; // id of Node which is currently responsible for simulating this Entity quint64 _simulatorIDChangedTime; // when was _simulatorID last updated? - bool _shouldClaimSimulationOwnership; QString _marketplaceID; // NOTE: Damping is applied like this: v *= pow(1 - damping, dt) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 382cc5a734..d1571fbcc5 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -35,8 +35,11 @@ void EntityMotionState::enqueueOutgoingEntity(EntityItem* entity) { _outgoingEntityList->insert(entity); } -EntityMotionState::EntityMotionState(EntityItem* entity) - : _entity(entity) { +EntityMotionState::EntityMotionState(EntityItem* entity) : + _entity(entity), + _accelerationNearlyGravityCount(0), + _shouldClaimSimulationOwnership(false) +{ _type = MOTION_STATE_TYPE_ENTITY; assert(entity != NULL); } @@ -192,7 +195,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { return false; } - if (_entity->getShouldClaimSimulationOwnership()) { + if (getShouldClaimSimulationOwnership()) { return true; } @@ -219,19 +222,19 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { // acceleration measured during the most recent simulation step was close to gravity. - if (_entity->getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { + if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { // only increment this if we haven't reached the threshold yet. this is to avoid // overflowing the counter. - _entity->incrementAccelerationNearlyGravityCount(); + incrementAccelerationNearlyGravityCount(); } } else { // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter - _entity->resetAccelerationNearlyGravityCount(); + resetAccelerationNearlyGravityCount(); } // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let // the entity server's estimates include gravity. - if (_entity->getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { + if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { _entity->setAcceleration(_entity->getGravity()); } else { _entity->setAcceleration(glm::vec3(0.0f)); @@ -283,10 +286,10 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); - if (_entity->getShouldClaimSimulationOwnership()) { + if (getShouldClaimSimulationOwnership()) { _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); - _entity->setShouldClaimSimulationOwnership(false); + setShouldClaimSimulationOwnership(false); } if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 2b965a39d3..d3678a81fe 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -64,8 +64,17 @@ public: EntityItem* getEntity() const { return _entity; } + void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } + void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } + quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } + + void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } + bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } + protected: EntityItem* _entity; + quint8 _accelerationNearlyGravityCount; + bool _shouldClaimSimulationOwnership; }; #endif // hifi_EntityMotionState_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index e1551a0488..0a122c5fd6 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -392,9 +392,11 @@ void PhysicsEngine::computeCollisionEvents() { } void* a = objectA->getUserPointer(); - EntityItem* entityA = a ? static_cast(a)->getEntity() : NULL; + EntityMotionState* entityMotionStateA = static_cast(a); + EntityItem* entityA = entityMotionStateA ? entityMotionStateA->getEntity() : NULL; void* b = objectB->getUserPointer(); - EntityItem* entityB = b ? static_cast(b)->getEntity() : NULL; + EntityMotionState* entityMotionStateB = static_cast(b); + EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : NULL; if (a || b) { // the manifold has up to 4 distinct points, but only extract info from the first _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); @@ -403,14 +405,14 @@ void PhysicsEngine::computeCollisionEvents() { // ownership of anything that collides with our avatar. if (entityA && entityB && !objectA->isStaticOrKinematicObject() && !objectB->isStaticOrKinematicObject()) { if (entityA->getSimulatorID() == myNodeID || - entityA->getShouldClaimSimulationOwnership() || + entityMotionStateA->getShouldClaimSimulationOwnership() || objectA == characterCollisionObject) { - entityB->setShouldClaimSimulationOwnership(true); + entityMotionStateB->setShouldClaimSimulationOwnership(true); } if (entityB->getSimulatorID() == myNodeID || - entityB->getShouldClaimSimulationOwnership() || + entityMotionStateA->getShouldClaimSimulationOwnership() || objectB == characterCollisionObject) { - entityA->setShouldClaimSimulationOwnership(true); + entityMotionStateB->setShouldClaimSimulationOwnership(true); } } } @@ -543,17 +545,19 @@ void PhysicsEngine::bump(EntityItem* bumpEntity) { void* a = objectA->getUserPointer(); void* b = objectB->getUserPointer(); if (a && b) { - EntityItem* entityA = a ? static_cast(a)->getEntity() : NULL; - EntityItem* entityB = b ? static_cast(b)->getEntity() : NULL; + EntityMotionState* entityMotionStateA = static_cast(a); + EntityMotionState* entityMotionStateB = static_cast(b); + EntityItem* entityA = entityMotionStateA ? entityMotionStateA->getEntity() : NULL; + EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : NULL; if (entityA && entityB) { if (entityA == bumpEntity) { - entityB->setShouldClaimSimulationOwnership(true); + entityMotionStateB->setShouldClaimSimulationOwnership(true); if (!objectB->isActive()) { objectB->setActivationState(ACTIVE_TAG); } } if (entityB == bumpEntity) { - entityA->setShouldClaimSimulationOwnership(true); + entityMotionStateA->setShouldClaimSimulationOwnership(true); if (!objectA->isActive()) { objectA->setActivationState(ACTIVE_TAG); } From 3ebe72f02576bd513406fab5960184d572178f24 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 12:12:42 +0200 Subject: [PATCH 230/401] Fix read macro --- libraries/entities/src/ZoneEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 6439922a5d..82c59d2e71 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -129,7 +129,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, _stageDay); READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, _stageHour); READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, _shapeType); - READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, _compoundShapeURL); + READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL); return bytesRead; } From 837a0d3ba84e3c8e2b503c84fc5931e73a0fcaca Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 12:13:52 +0200 Subject: [PATCH 231/401] rename collision model in edit.js --- examples/html/entityProperties.html | 10 +++++----- examples/libraries/ToolTip.js | 2 +- examples/libraries/entityPropertyDialogBox.js | 4 ++-- libraries/entities/src/ModelEntityItem.cpp | 4 ++-- libraries/entities/src/ModelEntityItem.h | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index dd5bced393..c11f6d94d5 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -162,7 +162,7 @@ var elModelSections = document.querySelectorAll(".model-section"); var elModelURL = document.getElementById("property-model-url"); - var elCollisionModelURL = document.getElementById("property-collision-model-url"); + var elCompoundShapeURL = document.getElementById("property-compound-shape-url"); var elModelAnimationURL = document.getElementById("property-model-animation-url"); var elModelAnimationPlaying = document.getElementById("property-model-animation-playing"); var elModelAnimationFPS = document.getElementById("property-model-animation-fps"); @@ -306,7 +306,7 @@ } elModelURL.value = properties.modelURL; - elCollisionModelURL.value = properties.collisionModelURL; + elCompoundShapeURL.value = properties.compoundShapeURL; elModelAnimationURL.value = properties.animationURL; elModelAnimationPlaying.checked = properties.animationIsPlaying; elModelAnimationFPS.value = properties.animationFPS; @@ -444,7 +444,7 @@ elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff')); elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL')); - elCollisionModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionModelURL')); + elCompoundShapeURL.addEventListener('change', createEmitTextPropertyUpdateFunction('compoundShapeURL')); elModelAnimationURL.addEventListener('change', createEmitTextPropertyUpdateFunction('animationURL')); elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying')); elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS')); @@ -712,9 +712,9 @@
-
Collision Model URL
+
Compound Shape URL
- +
diff --git a/examples/libraries/ToolTip.js b/examples/libraries/ToolTip.js index 680f617436..2b0e125d4b 100644 --- a/examples/libraries/ToolTip.js +++ b/examples/libraries/ToolTip.js @@ -53,7 +53,7 @@ function Tooltip() { text += "ID: " + properties.id + "\n" if (properties.type == "Model") { text += "Model URL: " + properties.modelURL + "\n" - text += "Collision Model URL: " + properties.collisionModelURL + "\n" + text += "Compound Shape URL: " + properties.compoundShapeURL + "\n" text += "Animation URL: " + properties.animationURL + "\n" text += "Animation is playing: " + properties.animationIsPlaying + "\n" if (properties.sittingPoints && properties.sittingPoints.length > 0) { diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index d8a91da8f9..255cec4265 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -52,7 +52,7 @@ EntityPropertyDialogBox = (function () { if (properties.type == "Model") { array.push({ label: "Model URL:", value: properties.modelURL }); index++; - array.push({ label: "Collision Model URL:", value: properties.collisionModelURL }); + array.push({ label: "Compound Shape URL:", value: properties.compoundShapeURL }); index++; array.push({ label: "Animation URL:", value: properties.animationURL }); index++; @@ -284,7 +284,7 @@ EntityPropertyDialogBox = (function () { properties.locked = array[index++].value; if (properties.type == "Model") { properties.modelURL = array[index++].value; - properties.collisionModelURL = array[index++].value; + properties.compoundShapeURL = array[index++].value; properties.animationURL = array[index++].value; var newAnimationIsPlaying = array[index++].value; diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 7616924f4a..1abb48abcd 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -21,7 +21,7 @@ #include "ModelEntityItem.h" const QString ModelEntityItem::DEFAULT_MODEL_URL = QString(""); -const QString ModelEntityItem::DEFAULT_COLLISION_MODEL_URL = QString(""); +const QString ModelEntityItem::DEFAULT_COMPOUND_SHAPE_URL = QString(""); const QString ModelEntityItem::DEFAULT_ANIMATION_URL = QString(""); const float ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f; const bool ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false; @@ -272,7 +272,7 @@ void ModelEntityItem::debugDump() const { qCDebug(entities) << " position:" << getPosition(); qCDebug(entities) << " dimensions:" << getDimensions(); qCDebug(entities) << " model URL:" << getModelURL(); - qCDebug(entities) << " collision model URL:" << getCompoundShapeURL(); + qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL(); } void ModelEntityItem::updateShapeType(ShapeType type) { diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 46fce6ff5f..6fe2adc928 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -62,7 +62,7 @@ public: static const QString DEFAULT_MODEL_URL; const QString& getModelURL() const { return _modelURL; } - static const QString DEFAULT_COLLISION_MODEL_URL; + static const QString DEFAULT_COMPOUND_SHAPE_URL; const QString& getCompoundShapeURL() const { return _compoundShapeURL; } bool hasAnimation() const { return !_animationURL.isEmpty(); } From 01f4f349114756ded818c95a91b4a30ebfd22270 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 13:04:59 +0200 Subject: [PATCH 232/401] Centralize contains standard cases --- libraries/entities/src/EntityItem.cpp | 19 +++++++++++++++++++ libraries/entities/src/EntityItem.h | 2 +- .../entities/src/ParticleEffectEntityItem.cpp | 8 -------- .../entities/src/ParticleEffectEntityItem.h | 2 -- libraries/entities/src/SphereEntityItem.cpp | 8 -------- libraries/entities/src/SphereEntityItem.h | 2 -- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 0e6976c730..ea012922b8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1060,6 +1060,25 @@ float EntityItem::getRadius() const { return 0.5f * glm::length(_dimensions); } +bool EntityItem::contains(const glm::vec3 &point) const { + switch (getShapeType()) { + case SHAPE_TYPE_BOX: { + // Transform point to be in a space where the box is a 1m cube centered on the origin. + glm::vec3 transformedPoint = (glm::inverse(getRotation()) * (point - getPosition())) / (getDimensions() / 2.0f); + return AABox(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f).contains(transformedPoint); + } + case SHAPE_TYPE_SPHERE: + case SHAPE_TYPE_ELLIPSOID: { + // Transform point to be in a space where the elipsoide is a perfect sphere centered on the origin. + glm::vec3 transformedPoint = (glm::inverse(getRotation()) * (point - getPosition())) / (getDimensions() / 2.0f); + // Return whether said point is inside the sphere. + return glm::length(transformedPoint) <= 1.0f; + } + default: + return getAABox().contains(point); + } +} + void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 4e1578510d..49b853d8dd 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -253,7 +253,7 @@ public: // TODO: get rid of users of getRadius()... float getRadius() const; - virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); } + virtual bool contains(const glm::vec3& point) const; virtual bool isReadyToComputeShape() { return true; } virtual void computeShapeInfo(ShapeInfo& info); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index f12259d057..45312f465b 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -236,14 +236,6 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, getParticleRadius()); } -bool ParticleEffectEntityItem::contains(const glm::vec3& point) const { - // Transform point to be in a space where the elipsoide is a perfect sphere centered on the origin. - glm::vec3 transformedPoint = (point - getPosition()) / (getDimensions() / 2.0f); - - // Return whether said point is inside the sphere. - return glm::length(transformedPoint) <= 1.0f; -} - bool ParticleEffectEntityItem::isAnimatingSomething() const { return getAnimationIsPlaying() && getAnimationFPS() != 0.0f; diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index b563274fa1..b00eb94685 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -77,8 +77,6 @@ public: _color[GREEN_INDEX] = value.green; _color[BLUE_INDEX] = value.blue; } - - virtual bool contains(const glm::vec3& point) const; void updateShapeType(ShapeType type); virtual ShapeType getShapeType() const { return _shapeType; } diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 4a756be618..132ad43336 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -92,14 +92,6 @@ void SphereEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBi APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); } -bool SphereEntityItem::contains(const glm::vec3& point) const { - // Transform point to be in a space where the elipsoide is a perfect sphere centered on the origin. - glm::vec3 transformedPoint = (point - getPosition()) / (getDimensions() / 2.0f); - - // Return whether said point is inside the sphere. - return glm::length(transformedPoint) <= 1.0f; -} - bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index 98450121c5..b6516b714f 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -50,8 +50,6 @@ public: _color[BLUE_INDEX] = value.blue; } - virtual bool contains(const glm::vec3& point) const; - virtual ShapeType getShapeType() const { return SHAPE_TYPE_SPHERE; } virtual bool supportsDetailedRayIntersection() const { return true; } From f117941c8d6042ed7f77d61ddb8ed8c109113edc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 13:25:14 +0200 Subject: [PATCH 233/401] Macro fixing --- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 6ef6877bb1..7d5a40f6fd 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -907,7 +907,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_DAY, quint16, setStageDay); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_HOUR, float, setStageHour); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); + READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL); } READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MARKETPLACE_ID, setMarketplaceID); diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 82c59d2e71..5447c24baf 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -128,7 +128,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, float, _stageAltitude); READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, _stageDay); READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, _stageHour); - READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, _shapeType); + READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType); READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL); return bytesRead; From fb4d1d35574ce085e989f80ef18f051cebdc3c30 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 14:01:22 +0200 Subject: [PATCH 234/401] Fix compoundShapeURL reseting shapeType --- libraries/entities/src/ZoneEntityItem.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 5447c24baf..64d0b2fe31 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -58,6 +58,8 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityIte _stageAltitude = DEFAULT_STAGE_ALTITUDE; _stageDay = DEFAULT_STAGE_DAY; _stageHour = DEFAULT_STAGE_HOUR; + _shapeType = DEFAULT_SHAPE_TYPE; + _compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL; setProperties(properties); } @@ -207,5 +209,9 @@ ShapeType ZoneEntityItem::getShapeType() const { void ZoneEntityItem::setCompoundShapeURL(const QString& url) { _compoundShapeURL = url; - _shapeType = _compoundShapeURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND; + if (!_compoundShapeURL.isEmpty()) { + updateShapeType(SHAPE_TYPE_COMPOUND); + } else if (_shapeType == SHAPE_TYPE_COMPOUND) { + _shapeType = DEFAULT_SHAPE_TYPE; + } } From 15482d6a573011f0bd6192b92710a21132d143b8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 15:21:51 +0200 Subject: [PATCH 235/401] Don't compute shape for zones --- libraries/entities/src/ZoneEntityItem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index bc44d70737..ad64557103 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -92,6 +92,7 @@ public: static bool getZonesArePickable() { return _zonesArePickable; } static void setZonesArePickable(bool value) { _zonesArePickable = value; } + virtual bool isReadyToComputeShape() { return false; } void updateShapeType(ShapeType type) { _shapeType = type; } virtual ShapeType getShapeType() const; From c91ca146d5f191c99d896ef5ed6c198432f8fe36 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 15:22:58 +0200 Subject: [PATCH 236/401] Add different shapes to zone example --- examples/example/entities/zoneEntityExample.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/example/entities/zoneEntityExample.js b/examples/example/entities/zoneEntityExample.js index 84d87d1370..660ff2945d 100644 --- a/examples/example/entities/zoneEntityExample.js +++ b/examples/example/entities/zoneEntityExample.js @@ -22,7 +22,8 @@ var zoneEntityA = Entities.addEntity({ dimensions: { x: 10, y: 10, z: 10 }, keyLightColor: { red: 255, green: 0, blue: 0 }, stageSunModelEnabled: false, - keyLightDirection: { x: 0, y: -1.0, z: 0 } + keyLightDirection: { x: 0, y: -1.0, z: 0 }, + shapeType: "sphere" }); print("zoneEntityA:" + zoneEntityA); @@ -51,7 +52,9 @@ var zoneEntityC = Entities.addEntity({ keyLightColor: { red: 0, green: 0, blue: 255 }, keyLightIntensity: 0.75, keyLightDirection: { x: 0, y: 0, z: -1 }, - stageSunModelEnabled: false + stageSunModelEnabled: false, + shapeType: "compound", + compoundShapeURL: "http://headache.hungry.com/~seth/hifi/cube.fbx" }); print("zoneEntityC:" + zoneEntityC); From 3a0b5f9d22d2fe060e1185a6ced6bb89b8f830a8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 15:34:03 +0200 Subject: [PATCH 237/401] Register RenderableZoneEntityItem in EntityTreeRenderer --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 3 ++- libraries/entities-renderer/src/RenderableZoneEntityItem.cpp | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index d5d79f8bad..751fda2abe 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -34,8 +34,8 @@ #include "RenderableParticleEffectEntityItem.h" #include "RenderableSphereEntityItem.h" #include "RenderableTextEntityItem.h" +#include "RenderableZoneEntityItem.h" #include "EntitiesRendererLogging.h" -#include "ZoneEntityItem.h" EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState, AbstractScriptingServicesInterface* scriptingServices) : @@ -57,6 +57,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Text, RenderableTextEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory) + REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory) _currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID _currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 1c80b1f317..27232d7dda 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -40,6 +40,10 @@ int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch } bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { + if (getShapeType() != SHAPE_TYPE_COMPOUND) { + return EntityItem::contains(point); + } + if (EntityItem::contains(point) && _compoundShapeModel) { const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry(); From 6be09109661830e2594794ae280f6237c1e7d580 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 15:58:18 +0200 Subject: [PATCH 238/401] Fix contain for collision hulls --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 3 ++- libraries/entities-renderer/src/RenderableZoneEntityItem.cpp | 5 +++-- libraries/shared/src/GLMHelpers.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 3f8899f6bd..8acd3b796b 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -419,8 +419,9 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { if (EntityItem::contains(point) && _model && _model->getCollisionGeometry()) { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); + glm::vec3 transformedPoint = (glm::inverse(getRotation()) * (point - getPosition())) / (getDimensions() / 2.0f); - return collisionGeometry.convexHullContains(point); + return collisionGeometry.convexHullContains(transformedPoint); } return false; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 27232d7dda..472d14093e 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -44,10 +44,11 @@ bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { return EntityItem::contains(point); } - if (EntityItem::contains(point) && _compoundShapeModel) { + if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) { const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry(); + glm::vec3 transformedPoint = (glm::inverse(getRotation()) * (point - getPosition())) / (getDimensions() / 2.0f); - return geometry.convexHullContains(point); + return geometry.convexHullContains(transformedPoint); } return false; diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index aed73c1989..5d1b70275c 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -207,7 +207,7 @@ bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, gl glm::vec3 v1 = p0 - p1, v2 = p2 - p1; // Non-collinear vectors contained in the plane glm::vec3 n = glm::cross(v1, v2); // Plane's normal vector, pointing out of the triangle float d = -glm::dot(n, p0); // Compute plane's equation constant - return (glm::dot(n, point) + d) <= 0; + return (glm::dot(n, point) + d) >= 0; } glm::vec3 extractTranslation(const glm::mat4& matrix) { From 99fd590a909e1fa3e93abcbf70105f3b22d2d438 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 16:05:06 +0200 Subject: [PATCH 239/401] Update compound shape geometry when async get --- libraries/entities-renderer/src/RenderableZoneEntityItem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 472d14093e..905ac5cfde 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -43,6 +43,9 @@ bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { if (getShapeType() != SHAPE_TYPE_COMPOUND) { return EntityItem::contains(point); } + if (!_compoundShapeModel && hasCompoundShapeURL()) { + const_cast(this)->_compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); + } if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) { const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry(); From bda72025af1ea7dd49a5bfe71a8894f3a5e1662e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 16:40:40 +0200 Subject: [PATCH 240/401] Check mesh extend before going through triangles --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/fbx/src/FBXReader.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ea012922b8..7c47dadd2f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1060,7 +1060,7 @@ float EntityItem::getRadius() const { return 0.5f * glm::length(_dimensions); } -bool EntityItem::contains(const glm::vec3 &point) const { +bool EntityItem::contains(const glm::vec3& point) const { switch (getShapeType()) { case SHAPE_TYPE_BOX: { // Transform point to be in a space where the box is a 1m cube centered on the origin. diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 95cd99852f..1c89ee4067 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -127,6 +127,10 @@ Extents FBXGeometry::getUnscaledMeshExtents() const { // TODO: Move to model::Mesh when Sam's ready bool FBXGeometry::convexHullContains(const glm::vec3& point) const { + if (!getUnscaledMeshExtents().containsPoint(point)) { + return false; + } + auto checkEachPrimitive = [=](FBXMesh& mesh, QVector indices, int primitiveSize) -> bool { // Check whether the point is "behind" all the primitives. for (unsigned int j = 0; j < indices.size(); j += primitiveSize) { From f494f86ee5aaece234e3cde75017038bc077c2d1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 17:48:29 +0200 Subject: [PATCH 241/401] Handle registration point in transforms --- .../src/RenderableModelEntityItem.cpp | 4 +- .../src/RenderableZoneEntityItem.cpp | 5 +-- libraries/entities/src/EntityItem.cpp | 39 +++++++++++++------ libraries/entities/src/EntityItem.h | 5 +++ libraries/entities/src/SphereEntityItem.cpp | 8 +--- 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 8acd3b796b..8ca6562505 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -419,9 +419,7 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { if (EntityItem::contains(point) && _model && _model->getCollisionGeometry()) { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); - glm::vec3 transformedPoint = (glm::inverse(getRotation()) * (point - getPosition())) / (getDimensions() / 2.0f); - - return collisionGeometry.convexHullContains(transformedPoint); + return collisionGeometry.convexHullContains(worldToEntity(point)); } return false; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 905ac5cfde..e4c56dc419 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -49,9 +49,8 @@ bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) { const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry(); - glm::vec3 transformedPoint = (glm::inverse(getRotation()) * (point - getPosition())) / (getDimensions() / 2.0f); - - return geometry.convexHullContains(transformedPoint); + glm::vec3 meshDimensions = geometry.getUnscaledMeshExtents().maximum - geometry.getUnscaledMeshExtents().minimum; + return geometry.convexHullContains(worldToEntity(point) * meshDimensions); } return false; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7c47dadd2f..2f4e8c87d7 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -11,6 +11,8 @@ #include +#include + #include #include #include @@ -843,7 +845,27 @@ bool EntityItem::isMoving() const { return hasVelocity() || hasAngularVelocity(); } -bool EntityItem::lifetimeHasExpired() const { +glm::mat4 EntityItem::getEntityToWorldMatrix() const { + glm::mat4 translation = glm::translate(getPosition()); + glm::mat4 rotation = glm::mat4_cast(getRotation()); + glm::mat4 scale = glm::scale(getDimensions()); + glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()); + return translation * rotation * scale * registration; +} + +glm::mat4 EntityItem::getWorldToEntityMatrix() const { + return glm::inverse(getEntityToWorldMatrix()); +} + +glm::vec3 EntityItem::entityToWorld(const glm::vec3 point) const { + return glm::vec3(getEntityToWorldMatrix() * glm::vec4(point, 1.0f)); +} + +glm::vec3 EntityItem::worldToEntity(const glm::vec3 point) const { + return glm::vec3(getWorldToEntityMatrix() * glm::vec4(point, 1.0f)); +} + +bool EntityItem::lifetimeHasExpired() const { return isMortal() && (getAge() > getLifetime()); } @@ -1062,18 +1084,11 @@ float EntityItem::getRadius() const { bool EntityItem::contains(const glm::vec3& point) const { switch (getShapeType()) { - case SHAPE_TYPE_BOX: { - // Transform point to be in a space where the box is a 1m cube centered on the origin. - glm::vec3 transformedPoint = (glm::inverse(getRotation()) * (point - getPosition())) / (getDimensions() / 2.0f); - return AABox(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f).contains(transformedPoint); - } + case SHAPE_TYPE_BOX: + return AABox(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f).contains(worldToEntity(point)); case SHAPE_TYPE_SPHERE: - case SHAPE_TYPE_ELLIPSOID: { - // Transform point to be in a space where the elipsoide is a perfect sphere centered on the origin. - glm::vec3 transformedPoint = (glm::inverse(getRotation()) * (point - getPosition())) / (getDimensions() / 2.0f); - // Return whether said point is inside the sphere. - return glm::length(transformedPoint) <= 1.0f; - } + case SHAPE_TYPE_ELLIPSOID: + return glm::length(worldToEntity(point)) <= 0.5f; default: return getAABox().contains(point); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index facc5c333f..0ebcd06a77 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -297,6 +297,11 @@ public: static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; } static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; } + glm::mat4 getEntityToWorldMatrix() const; + glm::mat4 getWorldToEntityMatrix() const; + glm::vec3 worldToEntity(const glm::vec3 point) const; + glm::vec3 entityToWorld(const glm::vec3 point) const; + protected: static bool _sendPhysicsUpdates; diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 132ad43336..d17e49cb59 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -96,11 +96,7 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { // determine the ray in the frame of the entity transformed from a unit sphere - glm::mat4 translation = glm::translate(getPosition()); - glm::mat4 rotation = glm::mat4_cast(getRotation()); - glm::mat4 scale = glm::scale(getDimensions()); - glm::mat4 registration = glm::translate(glm::vec3(0.5f, 0.5f, 0.5f) - getRegistrationPoint()); - glm::mat4 entityToWorldMatrix = translation * rotation * scale * registration; + glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix(); glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f)); glm::vec3 entityFrameDirection = glm::normalize(glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f))); @@ -112,7 +108,7 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons glm::vec3 entityFrameHitAt = entityFrameOrigin + (entityFrameDirection * localDistance); // then translate back to work coordinates glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f)); - distance = glm::distance(origin,hitAt); + distance = glm::distance(origin, hitAt); return true; } return false; From 51d99da29f2524b4a8c94a8a648c3ee549f431ba Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 17:50:26 +0200 Subject: [PATCH 242/401] Magic number --- libraries/entities/src/EntityItem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 2f4e8c87d7..445158af35 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1088,7 +1088,8 @@ bool EntityItem::contains(const glm::vec3& point) const { return AABox(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f).contains(worldToEntity(point)); case SHAPE_TYPE_SPHERE: case SHAPE_TYPE_ELLIPSOID: - return glm::length(worldToEntity(point)) <= 0.5f; + static const float UNIT_SPHERE_RADIUS = 1.0f / 2.0f; + return glm::length(worldToEntity(point)) <= UNIT_SPHERE_RADIUS; default: return getAABox().contains(point); } From 10e53783964feed07b76272d32da43eca8ee0dc8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Apr 2015 09:13:18 -0700 Subject: [PATCH 243/401] fix mangled if --- libraries/physics/src/PhysicsEngine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 0a122c5fd6..f187f5727d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -410,9 +410,9 @@ void PhysicsEngine::computeCollisionEvents() { entityMotionStateB->setShouldClaimSimulationOwnership(true); } if (entityB->getSimulatorID() == myNodeID || - entityMotionStateA->getShouldClaimSimulationOwnership() || + entityMotionStateB->getShouldClaimSimulationOwnership() || objectB == characterCollisionObject) { - entityMotionStateB->setShouldClaimSimulationOwnership(true); + entityMotionStateA->setShouldClaimSimulationOwnership(true); } } } From 5654e3abed40e3e6839c33eb444ed10b244411e6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Apr 2015 13:23:00 -0700 Subject: [PATCH 244/401] Add zone overlay manager --- examples/edit.js | 6 ++++++ examples/libraries/lightOverlayManager.js | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/edit.js b/examples/edit.js index 480b87d416..091de29374 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -13,6 +13,8 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +Script.include(["libraries/overlays.js"]); + Script.include([ "libraries/stringHelpers.js", "libraries/dataviewHelpers.js", @@ -28,6 +30,7 @@ Script.include([ "libraries/gridTool.js", "libraries/entityList.js", "libraries/lightOverlayManager.js", + "libraries/zoneOverlayManager.js", ]); var selectionDisplay = SelectionDisplay; @@ -35,6 +38,8 @@ var selectionManager = SelectionManager; var entityPropertyDialogBox = EntityPropertyDialogBox; var lightOverlayManager = new LightOverlayManager(); +var zoneOverlayManager = new ZoneOverlayManager(); +zoneOverlayManager.setVisible(true); var cameraManager = new CameraManager(); @@ -47,6 +52,7 @@ var entityListTool = EntityListTool(); selectionManager.addEventListener(function() { selectionDisplay.updateHandles(); lightOverlayManager.updatePositions(); + zoneOverlayManager.updatePositions(); }); var windowDimensions = Controller.getViewportDimensions(); diff --git a/examples/libraries/lightOverlayManager.js b/examples/libraries/lightOverlayManager.js index 8032d77c49..a140461a27 100644 --- a/examples/libraries/lightOverlayManager.js +++ b/examples/libraries/lightOverlayManager.js @@ -122,7 +122,7 @@ LightOverlayManager = function() { Entities.clearingEntities.connect(clearEntities); // Add existing entities - var ids = Entities.findEntities(MyAvatar.position, 100); + var ids = Entities.findEntities(MyAvatar.position, 64000); for (var i = 0; i < ids.length; i++) { addEntity(ids[i]); } From af46ece9af95a238171662a47da3e16f4a2aa99d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 09:33:10 -0700 Subject: [PATCH 245/401] Remove overlays.js include --- examples/edit.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 091de29374..a15870f84e 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -13,8 +13,6 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; -Script.include(["libraries/overlays.js"]); - Script.include([ "libraries/stringHelpers.js", "libraries/dataviewHelpers.js", From ab261f44439651bee510c5ffc9baa7a3cf955e02 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 09:33:33 -0700 Subject: [PATCH 246/401] Update zone overlay to only be visible when edit is on --- examples/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/edit.js b/examples/edit.js index a15870f84e..d745b95f33 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -37,7 +37,6 @@ var entityPropertyDialogBox = EntityPropertyDialogBox; var lightOverlayManager = new LightOverlayManager(); var zoneOverlayManager = new ZoneOverlayManager(); -zoneOverlayManager.setVisible(true); var cameraManager = new CameraManager(); @@ -245,6 +244,7 @@ var toolBar = (function () { } toolBar.selectTool(activeButton, isActive); lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE)); + zoneOverlayManager.setVisible(isActive); }; // Sets visibility of tool buttons, excluding the power button From 6612f9cb61b0c3eb48e3ac357ed36629d5b905f0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 09:33:58 -0700 Subject: [PATCH 247/401] Fix key light properties in proeprties window --- examples/html/entityProperties.html | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 649b9164ed..348dc00df4 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -187,8 +187,8 @@ var elZoneKeyLightColorRed = document.getElementById("property-zone-key-light-color-red"); var elZoneKeyLightColorGreen = document.getElementById("property-zone-key-light-color-green"); var elZoneKeyLightColorBlue = document.getElementById("property-zone-key-light-color-blue"); - var elZoneKeyLightIntensity = document.getElementById("property-zone-key-color-intensity"); - var elZoneKeyLightAmbientIntensity = document.getElementById("property-zone-key-color-ambient-intensity"); + var elZoneKeyLightIntensity = document.getElementById("property-zone-key-intensity"); + var elZoneKeyLightAmbientIntensity = document.getElementById("property-zone-key-ambient-intensity"); var elZoneKeyLightDirectionX = document.getElementById("property-zone-key-light-direction-x"); var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y"); var elZoneKeyLightDirectionZ = document.getElementById("property-zone-key-light-direction-z"); @@ -905,7 +905,7 @@
-
Key Color
+
Key Light Color
R
G
@@ -913,13 +913,19 @@
-
Key Intensity
+
Key Light Intensity
- +
-
Key Direction
+
Key Light Ambient Intensity
+
+ +
+
+
+
Key Light Direction
Pitch
Yaw
From b31f95a002cc52a58b4b1e75440c180df43e1857 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 09:34:23 -0700 Subject: [PATCH 248/401] Fix cube rendering not working with transparency --- interface/src/ui/overlays/Cube3DOverlay.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index a9bfbae8dd..60f985b083 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -77,7 +77,7 @@ void Cube3DOverlay::render(RenderArgs* args) { if (_drawOnHUD) { DependencyManager::get()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha)); } else { - DependencyManager::get()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha)); + DependencyManager::get()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha)); } glPopMatrix(); @@ -89,7 +89,7 @@ void Cube3DOverlay::render(RenderArgs* args) { if (_drawOnHUD) { DependencyManager::get()->renderSolidCube(1.0f, cubeColor); } else { - DependencyManager::get()->renderSolidCube(1.0f, cubeColor); + DependencyManager::get()->renderSolidCube(1.0f, cubeColor); } glPopMatrix(); } else { From e0d4a0b1e15d0ba572fdad15eadc3ea19e040c26 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 09:36:41 -0700 Subject: [PATCH 249/401] Add functionality to turn zone picking off --- libraries/entities/src/EntityScriptingInterface.cpp | 9 +++++++++ libraries/entities/src/EntityScriptingInterface.h | 3 +++ libraries/entities/src/ZoneEntityItem.cpp | 6 ++++++ libraries/entities/src/ZoneEntityItem.h | 6 +++++- 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 53335beda0..13e6b83393 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -15,6 +15,7 @@ #include "EntityTree.h" #include "LightEntityItem.h" #include "ModelEntityItem.h" +#include "ZoneEntityItem.h" EntityScriptingInterface::EntityScriptingInterface() : @@ -315,6 +316,14 @@ bool EntityScriptingInterface::getLightsArePickable() const { return LightEntityItem::getLightsArePickable(); } +void EntityScriptingInterface::setZonesArePickable(bool value) { + ZoneEntityItem::setZonesArePickable(value); +} + +bool EntityScriptingInterface::getZonesArePickable() const { + return ZoneEntityItem::getZonesArePickable(); +} + void EntityScriptingInterface::setSendPhysicsUpdates(bool value) { EntityItem::setSendPhysicsUpdates(value); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 075f5a712b..151036e926 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -111,6 +111,9 @@ public slots: Q_INVOKABLE void setLightsArePickable(bool value); Q_INVOKABLE bool getLightsArePickable() const; + Q_INVOKABLE void setZonesArePickable(bool value); + Q_INVOKABLE bool getZonesArePickable() const; + Q_INVOKABLE void setSendPhysicsUpdates(bool value); Q_INVOKABLE bool getSendPhysicsUpdates() const; diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index e0fe238c57..60a61e4e89 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -185,3 +185,9 @@ void ZoneEntityItem::debugDump() const { qCDebug(entities) << " _stageHour:" << _stageHour; } +bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject, bool precisionPicking) const { + + return _zonesArePickable; +} diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 8f1b15d174..bc1d77ab65 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -91,7 +91,11 @@ public: static bool getZonesArePickable() { return _zonesArePickable; } static void setZonesArePickable(bool value) { _zonesArePickable = value; } - + + virtual bool supportsDetailedRayIntersection() const { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject, bool precisionPicking) const; virtual void debugDump() const; From 4a99c21e7bf5d6a2ed563590cedf035411fd8542 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 09:36:53 -0700 Subject: [PATCH 250/401] Add zoneOverlayManager.js --- examples/libraries/zoneOverlayManager.js | 169 +++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 examples/libraries/zoneOverlayManager.js diff --git a/examples/libraries/zoneOverlayManager.js b/examples/libraries/zoneOverlayManager.js new file mode 100644 index 0000000000..603caf44c7 --- /dev/null +++ b/examples/libraries/zoneOverlayManager.js @@ -0,0 +1,169 @@ +ZoneOverlayManager = function(isEntityFunc, entityAddedFunc, entityRemovedFunc, entityMovedFunc) { + var self = this; + + var visible = false; + + // List of all created overlays + var allOverlays = []; + + // List of overlays not currently being used + var unusedOverlays = []; + + // Map from EntityItemID.id to overlay id + var entityOverlays = {}; + + // Map from EntityItemID.id to EntityItemID object + var entityIDs = {}; + + this.updatePositions = function(ids) { + for (var id in entityIDs) { + var entityID = entityIDs[id]; + var properties = Entities.getEntityProperties(entityID); + Overlays.editOverlay(entityOverlays[entityID.id].solid, { + position: properties.position, + rotation: properties.rotation, + dimensions: properties.dimensions, + }); + Overlays.editOverlay(entityOverlays[entityID.id].outline, { + position: properties.position, + rotation: properties.rotation, + dimensions: properties.dimensions, + visible: true, + }); + } + }; + + this.findRayIntersection = function(pickRay) { + return false; + + var result = Overlays.findRayIntersection(pickRay); + var found = false; + + if (result.intersects) { + for (var id in entityOverlays) { + if (result.overlayID == entityOverlays[id]) { + result.entityID = entityIDs[id]; + found = true; + break; + } + } + + if (!found) { + result.intersects = false; + } + } + + return result; + }; + + this.setVisible = function(isVisible) { + if (visible != isVisible) { + visible = isVisible; + for (var id in entityOverlays) { + Overlays.editOverlay(entityOverlays[id].solid, { visible: visible }); + Overlays.editOverlay(entityOverlays[id].outline, { visible: visible }); + } + } + }; + + // Allocate or get an unused overlay + function getOverlay() { + if (unusedOverlays.length == 0) { + var overlay = Overlays.addOverlay("cube", { + }); + allOverlays.push(overlay); + } else { + var overlay = unusedOverlays.pop(); + }; + return overlay; + } + + function releaseOverlay(overlay) { + unusedOverlays.push(overlay); + Overlays.editOverlay(overlay, { visible: false }); + } + + function addEntity(entityID) { + var properties = Entities.getEntityProperties(entityID); + if (properties.type == "Zone" && !(entityID.id in entityOverlays)) { + var overlaySolid = getOverlay(); + var overlayOutline = getOverlay(); + + entityOverlays[entityID.id] = { + solid: overlaySolid, + outline: overlayOutline, + } + entityIDs[entityID.id] = entityID; + + var color = { + red: Math.round(Math.random() * 255), + green: Math.round(Math.random() * 255), + blue: Math.round(Math.random() * 255) + }; + Overlays.editOverlay(overlaySolid, { + position: properties.position, + rotation: properties.rotation, + dimensions: properties.dimensions, + visible: visible, + solid: true, + alpha: 0.1, + color: color, + ignoreRayIntersection: true, + }); + Overlays.editOverlay(overlayOutline, { + position: properties.position, + rotation: properties.rotation, + dimensions: properties.dimensions, + visible: visible, + solid: false, + dashed: false, + lineWidth: 2.0, + alpha: 1.0, + color: color, + ignoreRayIntersection: true, + }); + } + } + + function deleteEntity(entityID) { + if (entityID.id in entityOverlays) { + releaseOverlay(entityOverlays[entityID.id].outline); + releaseOverlay(entityOverlays[entityID.id].solid); + delete entityOverlays[entityID.id]; + } + } + + function changeEntityID(oldEntityID, newEntityID) { + entityOverlays[newEntityID.id] = entityOverlays[oldEntityID.id]; + entityIDs[newEntityID.id] = newEntityID; + + delete entityOverlays[oldEntityID.id]; + delete entityIDs[oldEntityID.id]; + } + + function clearEntities() { + for (var id in entityOverlays) { + releaseOverlay(entityOverlays[id].outline); + releaseOverlay(entityOverlays[id].solid); + } + entityOverlays = {}; + entityIDs = {}; + } + + Entities.addingEntity.connect(addEntity); + Entities.changingEntityID.connect(changeEntityID); + Entities.deletingEntity.connect(deleteEntity); + Entities.clearingEntities.connect(clearEntities); + + // Add existing entities + var ids = Entities.findEntities(MyAvatar.position, 64000); + for (var i = 0; i < ids.length; i++) { + addEntity(ids[i]); + } + + Script.scriptEnding.connect(function() { + for (var i = 0; i < allOverlays.length; i++) { + Overlays.deleteOverlay(allOverlays[i]); + } + }); +}; From d45e935b93a7c254da94ed9da995a85e89d676d0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 09:52:01 -0700 Subject: [PATCH 251/401] Add show zone overlay option to menu --- examples/edit.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/edit.js b/examples/edit.js index d745b95f33..8e7ccbc3c8 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -80,11 +80,13 @@ var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS); var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select"; var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus"; var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode"; +var MENU_SHOW_ZONES_IN_EDIT_MODE = "Show Zones in Edit Mode"; var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled"; var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect"; var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus"; var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode"; +var SETTING_SHOW_ZONES_IN_EDIT_MODE = "showZonesInEditMode"; var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain." var INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG = "You do not have the necessary permissions to place items on this domain." @@ -244,7 +246,7 @@ var toolBar = (function () { } toolBar.selectTool(activeButton, isActive); lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE)); - zoneOverlayManager.setVisible(isActive); + zoneOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); }; // Sets visibility of tool buttons, excluding the power button @@ -805,6 +807,8 @@ function setupModelMenus() { isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" }); Menu.addMenuItem({ menuName: "View", menuItemName: MENU_SHOW_LIGHTS_IN_EDIT_MODE, afterItem: MENU_EASE_ON_FOCUS, isCheckable: true, isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE) == "true" }); + Menu.addMenuItem({ menuName: "View", menuItemName: MENU_SHOW_ZONES_IN_EDIT_MODE, afterItem: MENU_SHOW_LIGHTS_IN_EDIT_MODE, + isCheckable: true, isChecked: Settings.getValue(SETTING_SHOW_ZONES_IN_EDIT_MODE) == "true" }); Entities.setLightsArePickable(false); } @@ -833,12 +837,14 @@ function cleanupModelMenus() { Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT); Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS); Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE); + Menu.removeMenuItem("View", MENU_SHOW_ZONES_IN_EDIT_MODE); } Script.scriptEnding.connect(function() { Settings.setValue(SETTING_AUTO_FOCUS_ON_SELECT, Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)); Settings.setValue(SETTING_EASE_ON_FOCUS, Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); Settings.setValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE)); + Settings.setValue(SETTING_SHOW_ZONES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); progressDialog.cleanup(); toolBar.cleanup(); @@ -971,6 +977,8 @@ function handeMenuEvent(menuItem) { selectAllEtitiesInCurrentSelectionBox(true); } else if (menuItem == MENU_SHOW_LIGHTS_IN_EDIT_MODE) { lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE)); + } else if (menuItem == MENU_SHOW_ZONES_IN_EDIT_MODE) { + zoneOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); } tooltip.show(false); } From 30b9e16c1a0b1cba9d7618e2297243fc041c9625 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 09:52:21 -0700 Subject: [PATCH 252/401] Remove unused findRayIntersection from zoneOverlayManager --- examples/libraries/zoneOverlayManager.js | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/examples/libraries/zoneOverlayManager.js b/examples/libraries/zoneOverlayManager.js index 603caf44c7..9898b888fa 100644 --- a/examples/libraries/zoneOverlayManager.js +++ b/examples/libraries/zoneOverlayManager.js @@ -28,34 +28,10 @@ ZoneOverlayManager = function(isEntityFunc, entityAddedFunc, entityRemovedFunc, position: properties.position, rotation: properties.rotation, dimensions: properties.dimensions, - visible: true, }); } }; - this.findRayIntersection = function(pickRay) { - return false; - - var result = Overlays.findRayIntersection(pickRay); - var found = false; - - if (result.intersects) { - for (var id in entityOverlays) { - if (result.overlayID == entityOverlays[id]) { - result.entityID = entityIDs[id]; - found = true; - break; - } - } - - if (!found) { - result.intersects = false; - } - } - - return result; - }; - this.setVisible = function(isVisible) { if (visible != isVisible) { visible = isVisible; From 83490051d9f47315e32d0768956ad43850a0d922 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 18:55:20 +0200 Subject: [PATCH 253/401] Move shape related contains() to ShapeInfo --- .../src/EntityTreeRenderer.cpp | 2 +- .../src/RenderableModelEntityItem.cpp | 2 +- .../src/RenderableModelEntityItem.h | 2 +- .../src/RenderableZoneEntityItem.cpp | 4 +- .../src/RenderableZoneEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 17 +++---- libraries/entities/src/EntityItem.h | 2 +- libraries/shared/src/ShapeInfo.cpp | 48 +++++++++++++++++++ libraries/shared/src/ShapeInfo.h | 4 ++ 9 files changed, 66 insertions(+), 17 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index dde13552f3..af3e71ae58 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -324,7 +324,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { // create a list of entities that actually contain the avatar's position foreach(const EntityItem* entity, foundEntities) { - if (entity->contains(avatarPosition)) { + if (const_cast(entity)->contains(avatarPosition)) { entitiesContainingAvatar << entity->getEntityItemID(); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 8ca6562505..40053cae48 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -415,7 +415,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } -bool RenderableModelEntityItem::contains(const glm::vec3& point) const { +bool RenderableModelEntityItem::contains(const glm::vec3& point) { if (EntityItem::contains(point) && _model && _model->getCollisionGeometry()) { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 43f18af0db..f718c82936 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -57,7 +57,7 @@ public: bool isReadyToComputeShape(); void computeShapeInfo(ShapeInfo& info); - virtual bool contains(const glm::vec3& point) const; + virtual bool contains(const glm::vec3& point); private: void remapTextures(); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index e4c56dc419..4f198cff2e 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -39,12 +39,12 @@ int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch return bytesRead; } -bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { +bool RenderableZoneEntityItem::contains(const glm::vec3& point) { if (getShapeType() != SHAPE_TYPE_COMPOUND) { return EntityItem::contains(point); } if (!_compoundShapeModel && hasCompoundShapeURL()) { - const_cast(this)->_compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); + _compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); } if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) { diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 8d8d8b4b3f..0b49b39055 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -29,7 +29,7 @@ public: ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); - virtual bool contains(const glm::vec3& point) const; + virtual bool contains(const glm::vec3& point); private: diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 445158af35..1dbd9fe91f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1082,16 +1082,13 @@ float EntityItem::getRadius() const { return 0.5f * glm::length(_dimensions); } -bool EntityItem::contains(const glm::vec3& point) const { - switch (getShapeType()) { - case SHAPE_TYPE_BOX: - return AABox(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f).contains(worldToEntity(point)); - case SHAPE_TYPE_SPHERE: - case SHAPE_TYPE_ELLIPSOID: - static const float UNIT_SPHERE_RADIUS = 1.0f / 2.0f; - return glm::length(worldToEntity(point)) <= UNIT_SPHERE_RADIUS; - default: - return getAABox().contains(point); +bool EntityItem::contains(const glm::vec3& point) { + if (getShapeType() == SHAPE_TYPE_COMPOUND) { + return getAABox().contains(point); + } else { + ShapeInfo info; + info.setParams(getShapeType(), glm::vec3(0.5f)); + return info.contains(worldToEntity(point)); } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0ebcd06a77..1150e11a8a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -253,7 +253,7 @@ public: // TODO: get rid of users of getRadius()... float getRadius() const; - virtual bool contains(const glm::vec3& point) const; + virtual bool contains(const glm::vec3& point); virtual bool isReadyToComputeShape() { return true; } virtual void computeShapeInfo(ShapeInfo& info); diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 544df35b86..2c88685a90 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -124,6 +124,54 @@ float ShapeInfo::computeVolume() const { return volume; } +bool ShapeInfo::contains(const glm::vec3& point) const { + switch(_type) { + case SHAPE_TYPE_SPHERE: + return glm::length(point) <= _halfExtents.x; + case SHAPE_TYPE_ELLIPSOID: { + glm::vec3 scaledPoint = glm::abs(point) / _halfExtents; + return glm::length(scaledPoint) <= 1.0f; + } + case SHAPE_TYPE_CYLINDER_X: + return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z; + case SHAPE_TYPE_CYLINDER_Y: + return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.x; + case SHAPE_TYPE_CYLINDER_Z: + return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y; + case SHAPE_TYPE_CAPSULE_X: { + if (glm::abs(point.x) <= _halfExtents.x) { + return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z; + } else { + glm::vec3 absPoint = glm::abs(point) - _halfExtents.x; + return glm::length(absPoint) <= _halfExtents.z; + } + } + case SHAPE_TYPE_CAPSULE_Y: { + if (glm::abs(point.y) <= _halfExtents.y) { + return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.x; + } else { + glm::vec3 absPoint = glm::abs(point) - _halfExtents.y; + return glm::length(absPoint) <= _halfExtents.x; + } + } + case SHAPE_TYPE_CAPSULE_Z: { + if (glm::abs(point.z) <= _halfExtents.z) { + return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y; + } else { + glm::vec3 absPoint = glm::abs(point) - _halfExtents.z; + return glm::length(absPoint) <= _halfExtents.y; + } + } + case SHAPE_TYPE_BOX: + default: { + glm::vec3 absPoint = glm::abs(point); + return absPoint.x <= _halfExtents.x + && absPoint.y <= _halfExtents.y + && absPoint.z <= _halfExtents.z; + } + } +} + const DoubleHashKey& ShapeInfo::getHash() const { // NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance. if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) { diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index 8770ef62c7..114d209788 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -57,6 +57,10 @@ public: void appendToPoints (const QVector& newPoints) { _points << newPoints; } float computeVolume() const; + + /// Returns whether point is inside the shape + /// For compound shapes it will only return whether it is inside the bounding box + bool contains(const glm::vec3& point) const; const DoubleHashKey& getHash() const; From 78207f0d519a112fa1ac1d1ace2f7ae51136c0dc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 10:00:05 -0700 Subject: [PATCH 254/401] Make zones pickable in edit.js while control is down --- examples/edit.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/examples/edit.js b/examples/edit.js index 8e7ccbc3c8..55c85b3b2f 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -517,12 +517,23 @@ function rayPlaneIntersection(pickRay, point, normal) { } function findClickedEntity(event) { + var pickZones = event.isControl; + + if (pickZones) { + print("Picking zones"); + Entities.setZonesArePickable(true); + } + var pickRay = Camera.computePickRay(event.x, event.y); var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking var lightResult = lightOverlayManager.findRayIntersection(pickRay); lightResult.accurate = true; + if (pickZones) { + Entities.setZonesArePickable(false); + } + var result; if (!entityResult.intersects && !lightResult.intersects) { From 2ca592de8b63080ac9d329db1ba3d57f472d7428 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Apr 2015 10:02:29 -0700 Subject: [PATCH 255/401] fix logic with infectious simulation ownership --- libraries/physics/src/EntityMotionState.h | 7 ++-- libraries/physics/src/ObjectMotionState.h | 6 ++++ libraries/physics/src/PhysicsEngine.cpp | 42 ++++++++++++----------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index d3678a81fe..07f82aaa42 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -62,14 +62,13 @@ public: virtual uint32_t getIncomingDirtyFlags() const; virtual void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } - EntityItem* getEntity() const { return _entity; } - void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } - void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } - bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } + virtual EntityItem* getEntity() const { return _entity; } + virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } + virtual bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } protected: EntityItem* _entity; diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index ad9ef861b9..9e0917a3ab 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -111,6 +111,12 @@ public: virtual bool isMoving() const = 0; friend class PhysicsEngine; + + // these are here so we can call into EntityMotionObject with a base-class pointer + virtual EntityItem* getEntity() const { return NULL; } + virtual void setShouldClaimSimulationOwnership(bool value) { } + virtual bool getShouldClaimSimulationOwnership() { return false; } + protected: void setRigidBody(btRigidBody* body); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index f187f5727d..45f3c97e30 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -391,29 +391,31 @@ void PhysicsEngine::computeCollisionEvents() { continue; } - void* a = objectA->getUserPointer(); - EntityMotionState* entityMotionStateA = static_cast(a); - EntityItem* entityA = entityMotionStateA ? entityMotionStateA->getEntity() : NULL; - void* b = objectB->getUserPointer(); - EntityMotionState* entityMotionStateB = static_cast(b); - EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : NULL; + ObjectMotionState* a = static_cast(objectA->getUserPointer()); + ObjectMotionState* b = static_cast(objectB->getUserPointer()); + EntityItem* entityA = a ? a->getEntity() : NULL; + EntityItem* entityB = b ? b->getEntity() : NULL; + bool aIsDynamic = entityA && !objectA->isStaticOrKinematicObject(); + bool bIsDynamic = entityB && !objectB->isStaticOrKinematicObject(); + if (a || b) { // the manifold has up to 4 distinct points, but only extract info from the first _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); - - // collisions cause infectious spread of simulation-ownership. we also attempt to take - // ownership of anything that collides with our avatar. - if (entityA && entityB && !objectA->isStaticOrKinematicObject() && !objectB->isStaticOrKinematicObject()) { - if (entityA->getSimulatorID() == myNodeID || - entityMotionStateA->getShouldClaimSimulationOwnership() || - objectA == characterCollisionObject) { - entityMotionStateB->setShouldClaimSimulationOwnership(true); - } - if (entityB->getSimulatorID() == myNodeID || - entityMotionStateB->getShouldClaimSimulationOwnership() || - objectB == characterCollisionObject) { - entityMotionStateA->setShouldClaimSimulationOwnership(true); - } + } + // collisions cause infectious spread of simulation-ownership. we also attempt to take + // ownership of anything that collides with our avatar. + if ((aIsDynamic && entityA->getSimulatorID() == myNodeID) || + (a && a->getShouldClaimSimulationOwnership()) || + (objectA == characterCollisionObject)) { + if (bIsDynamic) { + b->setShouldClaimSimulationOwnership(true); + } + } + if ((bIsDynamic && entityB->getSimulatorID() == myNodeID) || + (b && b->getShouldClaimSimulationOwnership()) || + (objectB == characterCollisionObject)) { + if (aIsDynamic) { + a->setShouldClaimSimulationOwnership(true); } } } From c21e06e7a757de1c77df87027667f0d911323342 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Apr 2015 10:08:59 -0700 Subject: [PATCH 256/401] don't pile things up at the origin during a load --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 12fb1ba99d..9a4471cce6 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -621,7 +621,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto nodeList = DependencyManager::get(); const QUuid& myNodeID = nodeList->getSessionUUID(); - if (_simulatorID == myNodeID) { + if (_simulatorID == myNodeID && !_simulatorID.isNull()) { // the packet that produced this bitstream originally came from physics simulations performed by // this node, so our version has to be newer than what the packet contained. _position = savePosition; From b340cd06bfc619f8f28f456722c03ff87aa050e8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 19:14:07 +0200 Subject: [PATCH 257/401] Fix volume formula for capsules --- libraries/shared/src/ShapeInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 2c88685a90..1c86f109c5 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -114,7 +114,7 @@ float ShapeInfo::computeVolume() const { } case SHAPE_TYPE_CAPSULE_Y: { float radius = _halfExtents.x; - volume = PI * radius * radius * (2.0f * _halfExtents.y + 4.0f * radius / 3.0f); + volume = PI * radius * radius * (2.0f * (_halfExtents.y - _halfExtents.x) + 4.0f * radius / 3.0f); break; } default: From b776ea811065de9e5ff330ab639796cda570d822 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Apr 2015 19:15:06 +0200 Subject: [PATCH 258/401] Make ::contains() back into a const --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 +- libraries/entities-renderer/src/RenderableModelEntityItem.h | 2 +- libraries/entities-renderer/src/RenderableZoneEntityItem.cpp | 4 ++-- libraries/entities-renderer/src/RenderableZoneEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityItem.h | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index af3e71ae58..dde13552f3 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -324,7 +324,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { // create a list of entities that actually contain the avatar's position foreach(const EntityItem* entity, foundEntities) { - if (const_cast(entity)->contains(avatarPosition)) { + if (entity->contains(avatarPosition)) { entitiesContainingAvatar << entity->getEntityItemID(); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 40053cae48..8ca6562505 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -415,7 +415,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } -bool RenderableModelEntityItem::contains(const glm::vec3& point) { +bool RenderableModelEntityItem::contains(const glm::vec3& point) const { if (EntityItem::contains(point) && _model && _model->getCollisionGeometry()) { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index f718c82936..43f18af0db 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -57,7 +57,7 @@ public: bool isReadyToComputeShape(); void computeShapeInfo(ShapeInfo& info); - virtual bool contains(const glm::vec3& point); + virtual bool contains(const glm::vec3& point) const; private: void remapTextures(); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 4f198cff2e..e4c56dc419 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -39,12 +39,12 @@ int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch return bytesRead; } -bool RenderableZoneEntityItem::contains(const glm::vec3& point) { +bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { if (getShapeType() != SHAPE_TYPE_COMPOUND) { return EntityItem::contains(point); } if (!_compoundShapeModel && hasCompoundShapeURL()) { - _compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); + const_cast(this)->_compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); } if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) { diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 0b49b39055..8d8d8b4b3f 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -29,7 +29,7 @@ public: ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); - virtual bool contains(const glm::vec3& point); + virtual bool contains(const glm::vec3& point) const; private: diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1dbd9fe91f..65fe72fc1a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1082,7 +1082,7 @@ float EntityItem::getRadius() const { return 0.5f * glm::length(_dimensions); } -bool EntityItem::contains(const glm::vec3& point) { +bool EntityItem::contains(const glm::vec3& point) const { if (getShapeType() == SHAPE_TYPE_COMPOUND) { return getAABox().contains(point); } else { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 1150e11a8a..0ebcd06a77 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -253,7 +253,7 @@ public: // TODO: get rid of users of getRadius()... float getRadius() const; - virtual bool contains(const glm::vec3& point); + virtual bool contains(const glm::vec3& point) const; virtual bool isReadyToComputeShape() { return true; } virtual void computeShapeInfo(ShapeInfo& info); From 361bf7e4413ba0c2e72326b408fb7a7194be70df Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 10:15:18 -0700 Subject: [PATCH 259/401] Remove unnecessary print --- examples/edit.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/edit.js b/examples/edit.js index 55c85b3b2f..59dcbaad19 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -520,7 +520,6 @@ function findClickedEntity(event) { var pickZones = event.isControl; if (pickZones) { - print("Picking zones"); Entities.setZonesArePickable(true); } From ac7b37323157b02d8e69b388128f92571ac92cee Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 23 Apr 2015 10:27:28 -0700 Subject: [PATCH 260/401] Throttle rendering needs to ensure it's active context --- interface/src/GLCanvas.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 0e25f0f596..9a9512a0b0 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -115,6 +115,7 @@ void GLCanvas::throttleRender() { OculusManager::beginFrameTiming(); } + makeCurrent(); Application::getInstance()->paintGL(); swapBuffers(); From d0af5580c8ff28bdff91337530deb4b6c989c0db Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 23 Apr 2015 10:28:03 -0700 Subject: [PATCH 261/401] Fix mouse wheel and clickthrough bugs in offscreen UI --- libraries/render-utils/src/OffscreenUi.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index db93a14b0d..969d3052cd 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -298,8 +298,11 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { mapWindowToUi(wheelEvent->pos(), originalDestination), wheelEvent->delta(), wheelEvent->buttons(), wheelEvent->modifiers(), wheelEvent->orientation()); - QCoreApplication::sendEvent(_quickWindow, &mappedEvent); - return true; + mappedEvent.ignore(); + if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) { + return mappedEvent.isAccepted(); + } + break; } // Fall through @@ -314,8 +317,11 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { mapWindowToUi(transformedPos, originalDestination), mouseEvent->screenPos(), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); - QCoreApplication::sendEvent(_quickWindow, &mappedEvent); - return QObject::event(event); + mappedEvent.ignore(); + if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) { + return mappedEvent.isAccepted(); + } + break; } default: From 1657c5092031a43d698368d9110083955de69f2d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Apr 2015 12:00:13 -0700 Subject: [PATCH 262/401] Add limits to zone fields in entity properties window --- examples/html/entityProperties.html | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 348dc00df4..46afe5abf9 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -386,8 +386,8 @@ elZoneKeyLightColorRed.value = properties.keyLightColor.red; elZoneKeyLightColorGreen.value = properties.keyLightColor.green; elZoneKeyLightColorBlue.value = properties.keyLightColor.blue; - elZoneKeyLightIntensity.value = properties.keyLightIntensity; - elZoneKeyLightAmbientIntensity.value = properties.keyLightAmbientIntensity; + elZoneKeyLightIntensity.value = properties.keyLightIntensity.toFixed(2); + elZoneKeyLightAmbientIntensity.value = properties.keyLightAmbientIntensity.toFixed(2); elZoneKeyLightDirectionX.value = properties.keyLightDirection.x.toFixed(2); elZoneKeyLightDirectionY.value = properties.keyLightDirection.y.toFixed(2); elZoneKeyLightDirectionZ.value = properties.keyLightDirection.z.toFixed(2); @@ -907,21 +907,21 @@
Key Light Color
-
R
-
G
-
B
+
R
+
G
+
B
Key Light Intensity
- +
Key Light Ambient Intensity
- +
@@ -936,31 +936,31 @@
Stage Latitude
- +
Stage Longitude
- +
Stage Altitude
- +
Stage Day
- +
Stage Hour
- +
From 5dddca37ca2bf80888fcebaae18a8ef24e590f9c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 23 Apr 2015 13:44:39 -0700 Subject: [PATCH 263/401] fix default shape of zones --- libraries/entities/src/ZoneEntityItem.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index b1d440e5e5..9ccb2697a0 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -200,10 +200,11 @@ void ZoneEntityItem::debugDump() const { } ShapeType ZoneEntityItem::getShapeType() const { + // Zones are not allowed to have a SHAPE_TYPE_NONE... they are always at least a SHAPE_TYPE_BOX if (_shapeType == SHAPE_TYPE_COMPOUND) { - return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; + return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_BOX; } else { - return _shapeType; + return _shapeType == SHAPE_TYPE_NONE ? SHAPE_TYPE_BOX : _shapeType; } } From aac5675579ec893fd92ee643ef7296d444511d2f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 23 Apr 2015 13:45:00 -0700 Subject: [PATCH 264/401] add full domain example --- .../entities/fullDomainZoneEntityExample.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 examples/example/entities/fullDomainZoneEntityExample.js diff --git a/examples/example/entities/fullDomainZoneEntityExample.js b/examples/example/entities/fullDomainZoneEntityExample.js new file mode 100644 index 0000000000..e422cfd398 --- /dev/null +++ b/examples/example/entities/fullDomainZoneEntityExample.js @@ -0,0 +1,23 @@ +// +// fullDomainZoneEntityExample.js +// examples +// +// Created by Brad Hefta-Gaub on 4/16/15. +// Copyright 2015 High Fidelity, Inc. +// +// This is an example script that demonstrates creating a Zone which is as large as the entire domain +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Entities.addEntity({ + type: "Zone", + position: { x: -10000, y: -10000, z: -10000 }, + dimensions: { x: 30000, y: 30000, z: 30000 }, + keyLightColor: { red: 255, green: 255, blue: 0 }, + keyLightDirection: { x: 0, y: -1.0, z: 0 }, + keyLightIntensity: 1.0, + keyLightAmbientIntensity: 0.5 +}); + From ae804357d884835946b37ee1a980c54ff929618c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 23 Apr 2015 14:10:54 -0700 Subject: [PATCH 265/401] Attempting to fix backspace issue in new UI --- interface/src/Application.cpp | 5 +++ libraries/render-utils/src/OffscreenUi.cpp | 44 +++++++++++++++++++--- libraries/render-utils/src/OffscreenUi.h | 1 + 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1df771f127..9ae54ac83e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1028,6 +1028,11 @@ bool Application::event(QEvent* event) { bool Application::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::ShortcutOverride) { + if (DependencyManager::get()->shouldSwallowShortcut(event)) { + event->accept(); + return true; + } + // Filter out captured keys before they're used for shortcut actions. if (_controllerScriptingInterface.isKeyCaptured(static_cast(event))) { event->accept(); diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 969d3052cd..837affab59 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -89,7 +89,15 @@ void OffscreenUi::create(QOpenGLContext* shareContext) { // is needed too). connect(_renderControl, &QQuickRenderControl::renderRequested, this, &OffscreenUi::requestRender); connect(_renderControl, &QQuickRenderControl::sceneChanged, this, &OffscreenUi::requestUpdate); - _quickWindow->focusObject(); + +#ifdef DEBUG + connect(_quickWindow, &QQuickWindow::focusObjectChanged, [this]{ + qDebug() << "New focus item " << _quickWindow->focusObject(); + }); + connect(_quickWindow, &QQuickWindow::activeFocusItemChanged, [this] { + qDebug() << "New active focus item " << _quickWindow->activeFocusItem(); + }); +#endif _qmlComponent = new QQmlComponent(_qmlEngine); // Initialize the render control and our OpenGL resources. @@ -257,6 +265,24 @@ QPointF OffscreenUi::mapWindowToUi(const QPointF& sourcePosition, QObject* sourc return QPointF(offscreenPosition.x, offscreenPosition.y); } +// This hack allows the QML UI to work with keys that are also bound as +// shortcuts at the application level. However, it seems as though the +// bound actions are still getting triggered. At least for backspace. +// Not sure why. +// +// However, the problem may go away once we switch to the new menu system, +// so I think it's OK for the time being. +bool OffscreenUi::shouldSwallowShortcut(QEvent * event) { + Q_ASSERT(event->type() == QEvent::ShortcutOverride); + QObject * focusObject = _quickWindow->focusObject(); + if (focusObject != _quickWindow && focusObject != _rootItem) { + //qDebug() << "Swallowed shortcut " << static_cast(event)->key(); + event->accept(); + return true; + } + return false; +} + /////////////////////////////////////////////////////// // // Event handling customization @@ -268,11 +294,17 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { return false; } + +#ifdef DEBUG // Don't intercept our own events, or we enter an infinite recursion - if (originalDestination == _quickWindow) { - return false; + QObject * recurseTest = originalDestination; + while (recurseTest) { + Q_ASSERT(recurseTest != _rootItem && recurseTest != _quickWindow); + recurseTest = recurseTest->parent(); } - +#endif + + switch (event->type()) { case QEvent::Resize: { QResizeEvent* resizeEvent = static_cast(event); @@ -280,12 +312,14 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { if (widget) { this->resize(resizeEvent->size()); } - return false; + break; } case QEvent::KeyPress: case QEvent::KeyRelease: { event->ignore(); + //if (_quickWindow->activeFocusItem()) { + // _quickWindow->sendEvent(_quickWindow->activeFocusItem(), event); if (QCoreApplication::sendEvent(_quickWindow, event)) { return event->isAccepted(); } diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index d86f99554e..c64d0d833c 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -73,6 +73,7 @@ public: void resume(); bool isPaused() const; void setProxyWindow(QWindow* window); + bool shouldSwallowShortcut(QEvent* event); QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); virtual bool eventFilter(QObject* originalDestination, QEvent* event); void setMouseTranslator(MouseTranslator mouseTranslator) { From d10621f3291c20fef7b5c7580cb0e117df7ed8b1 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 23 Apr 2015 14:16:59 -0700 Subject: [PATCH 266/401] Revert DDE start-up permission change --- interface/src/devices/DdeFaceTracker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 03989c6ffb..8afa61c6c2 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -200,7 +200,7 @@ void DdeFaceTracker::setEnabled(bool enabled) { qDebug() << "[Info] DDE Face Tracker Starting"; _ddeProcess = new QProcess(qApp); connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus))); - _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS, QIODevice::ReadOnly); + _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS); } if (!enabled && _ddeProcess) { From a9d65f168b2251f30a92b0ac9fe54be7ca4312ee Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 18 Apr 2015 23:50:56 -0700 Subject: [PATCH 267/401] Working on marketplace dialog --- interface/resources/qml/MarketplaceDialog.qml | 51 +++++++++++++++++++ interface/resources/qml/componentCreation.js | 29 ----------- interface/src/Application.cpp | 22 +++++++- .../scripting/WindowScriptingInterface.cpp | 2 +- interface/src/ui/MarketplaceDialog.cpp | 49 ++++++++++++++++++ interface/src/ui/MarketplaceDialog.h | 29 +++++++++++ tests/render-utils/src/main.cpp | 17 +++++++ 7 files changed, 168 insertions(+), 31 deletions(-) create mode 100644 interface/resources/qml/MarketplaceDialog.qml delete mode 100644 interface/resources/qml/componentCreation.js create mode 100644 interface/src/ui/MarketplaceDialog.cpp create mode 100644 interface/src/ui/MarketplaceDialog.h diff --git a/interface/resources/qml/MarketplaceDialog.qml b/interface/resources/qml/MarketplaceDialog.qml new file mode 100644 index 0000000000..3fdd9b2b4d --- /dev/null +++ b/interface/resources/qml/MarketplaceDialog.qml @@ -0,0 +1,51 @@ +import Hifi 1.0 +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 +import QtWebKit 3.0 + +CustomDialog { + title: "Test Dlg" + id: testDialog + objectName: "Browser" + width: 720 + height: 720 + resizable: true + + MarketplaceDialog { + id: marketplaceDialog + } + + Item { + id: clientArea + // The client area + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + + + ScrollView { + anchors.fill: parent + WebView { + objectName: "WebView" + id: webview + url: "https://metaverse.highfidelity.com/marketplace" + anchors.fill: parent + onNavigationRequested: { + console.log(request.url) + if (!marketplaceDialog.navigationRequested(request.url)) { + console.log("Application absorbed the request") + request.action = WebView.IgnoreRequest; + return; + } + console.log("Application passed on the request") + request.action = WebView.AcceptRequest; + return; + } + } + } + + } +} diff --git a/interface/resources/qml/componentCreation.js b/interface/resources/qml/componentCreation.js deleted file mode 100644 index 15a828d6f8..0000000000 --- a/interface/resources/qml/componentCreation.js +++ /dev/null @@ -1,29 +0,0 @@ -var component; -var instance; -var parent; - -function createObject(parentObject, url) { - parent = parentObject; - component = Qt.createComponent(url); - if (component.status == Component.Ready) - finishCreation(); - else - component.statusChanged.connect(finishCreation); -} - -function finishCreation() { - if (component.status == Component.Ready) { - instance = component.createObject(parent, {"x": 100, "y": 100}); - if (instance == null) { - // Error Handling - console.log("Error creating object"); - } else { - instance.enabled = true - } - } else if (component.status == Component.Error) { - // Error Handling - console.log("Error loading component:", component.errorString()); - } else { - console.log("Unknown component status: " + component.status); - } -} \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9ae54ac83e..8c93418153 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -52,6 +52,8 @@ #include #include #include +#include +#include #include #include @@ -82,6 +84,7 @@ #include #include #include +#include #include @@ -132,6 +135,7 @@ #include "ui/DialogsManager.h" #include "ui/InfoView.h" #include "ui/LoginDialog.h" +#include "ui/MarketplaceDialog.h" #include "ui/Snapshot.h" #include "ui/StandAloneJSConsole.h" #include "ui/Stats.h" @@ -743,12 +747,26 @@ void Application::initializeGL() { InfoView::showFirstTime(INFO_HELP_PATH); } +class OAuthFactory : public QQmlNetworkAccessManagerFactory { + QThreadStorage oauthNetworkAccessManagers; +public: + virtual QNetworkAccessManager * create(QObject * parent) { + if (!oauthNetworkAccessManagers.hasLocalData()) { + oauthNetworkAccessManagers.setLocalData(OAuthNetworkAccessManager::getInstance()); + } + return oauthNetworkAccessManagers.localData(); + } +}; + void Application::initializeUi() { AddressBarDialog::registerType(); LoginDialog::registerType(); + MarketplaceDialog::registerType(); auto offscreenUi = DependencyManager::get(); offscreenUi->create(_glWidget->context()->contextHandle()); + offscreenUi->qmlEngine()->setNetworkAccessManagerFactory(new OAuthFactory()); + offscreenUi->qmlEngine()->networkAccessManager(); offscreenUi->resize(_glWidget->size()); offscreenUi->setProxyWindow(_window->windowHandle()); offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); @@ -1129,7 +1147,9 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_Backslash: - Menu::getInstance()->triggerOption(MenuOption::Chat); + MarketplaceDialog::show(); + + //Menu::getInstance()->triggerOption(MenuOption::Chat); break; case Qt::Key_Up: diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 6ed3e48274..46ca0c160f 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -51,7 +51,7 @@ void WindowScriptingInterface::setFocus() { } void WindowScriptingInterface::raiseMainWindow() { - Application::getInstance()->getWindow()->raise(); +// Application::getInstance()->getWindow()->raise(); } void WindowScriptingInterface::setCursorVisible(bool visible) { diff --git a/interface/src/ui/MarketplaceDialog.cpp b/interface/src/ui/MarketplaceDialog.cpp new file mode 100644 index 0000000000..34d3414ef4 --- /dev/null +++ b/interface/src/ui/MarketplaceDialog.cpp @@ -0,0 +1,49 @@ +// +// AddressBarDialog.cpp +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 "Application.h" +#include "MarketplaceDialog.h" + + +#include + +#include "DependencyManager.h" + +QML_DIALOG_DEF(MarketplaceDialog) + + +MarketplaceDialog::MarketplaceDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { + this-> +} + +bool MarketplaceDialog::navigationRequested(const QString & url) { + qDebug() << url; + if (Application::getInstance()->canAcceptURL(url)) { + qDebug() << "Trying to send url to the app"; + if (Application::getInstance()->acceptURL(url)) { + qDebug() << "Sent url to the app"; + return false; // we handled it, so QWebPage doesn't need to handle it + } + } + return true; +} + +//https://metaverse.highfidelity.com/marketplace + +// +//bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) { +// QString urlString = request.url().toString(); +// if (Application::getInstance()->canAcceptURL(urlString)) { +// if (Application::getInstance()->acceptURL(urlString)) { +// return false; // we handled it, so QWebPage doesn't need to handle it +// } +// } +// return true; +//} \ No newline at end of file diff --git a/interface/src/ui/MarketplaceDialog.h b/interface/src/ui/MarketplaceDialog.h new file mode 100644 index 0000000000..137bb0bea7 --- /dev/null +++ b/interface/src/ui/MarketplaceDialog.h @@ -0,0 +1,29 @@ +// +// AddressBarDialog.h +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 +// + +#pragma once +#ifndef hifi_MarketplaceDialog_h +#define hifi_MarketplaceDialog_h + +#include + +class MarketplaceDialog : public OffscreenQmlDialog +{ + Q_OBJECT + QML_DIALOG_DECL + +public: + MarketplaceDialog(QQuickItem *parent = 0); + + Q_INVOKABLE bool navigationRequested(const QString & url); + +}; + +#endif diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 9d7363c241..28d542e51a 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -27,6 +27,8 @@ #include #include #include +#include + #include #include #include @@ -189,6 +191,8 @@ public: }); installEventFilter(offscreenUi.data()); offscreenUi->resume(); + QWebEnginePage *page = new QWebEnginePage; + page->runJavaScript("'Java''' 'Script'", [](const QVariant &result) { qDebug() << result; }); } virtual ~QTestWindow() { @@ -210,9 +214,22 @@ protected: switch (event->key()) { case Qt::Key_L: if (event->modifiers() & Qt::CTRL) { + auto offscreenUi = DependencyManager::get(); + offscreenUi->qmlEngine()->clearComponentCache(); DependencyManager::get()->toggle(QString("TestDialog.qml"), "TestDialog"); } break; + case Qt::Key_K: + if (event->modifiers() & Qt::CTRL) { + DependencyManager::get()->toggle(QString("Browser.qml"), "Browser"); + } + break; + case Qt::Key_J: + if (event->modifiers() & Qt::CTRL) { + QObject * obj = DependencyManager::get()->findObject("WebView"); + qDebug() << obj; + } + break; } QWindow::keyPressEvent(event); } From 8269b9925b372a09fb24bf1ec7b2e67c1a1e0310 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 20 Apr 2015 17:18:16 -0700 Subject: [PATCH 268/401] Adding first pass at message box --- interface/resources/qml/CustomButton.qml | 8 +- interface/resources/qml/MessageDialog.qml | 359 ++++++++++++++++++ interface/resources/qml/images/critical.png | Bin 0 -> 253 bytes .../resources/qml/images/information.png | Bin 0 -> 254 bytes interface/resources/qml/images/question.png | Bin 0 -> 257 bytes interface/resources/qml/images/warning.png | Bin 0 -> 224 bytes interface/src/Application.cpp | 4 +- interface/src/ui/LoginDialog.cpp | 4 +- interface/src/ui/MarketplaceDialog.cpp | 20 - libraries/render-utils/src/MessageDialog.cpp | 142 +++++++ libraries/render-utils/src/MessageDialog.h | 98 +++++ .../render-utils/src/OffscreenQmlDialog.cpp | 24 ++ .../render-utils/src/OffscreenQmlDialog.h | 60 ++- libraries/render-utils/src/OffscreenUi.cpp | 61 +-- libraries/render-utils/src/OffscreenUi.h | 31 +- 15 files changed, 740 insertions(+), 71 deletions(-) create mode 100644 interface/resources/qml/MessageDialog.qml create mode 100644 interface/resources/qml/images/critical.png create mode 100644 interface/resources/qml/images/information.png create mode 100644 interface/resources/qml/images/question.png create mode 100644 interface/resources/qml/images/warning.png create mode 100644 libraries/render-utils/src/MessageDialog.cpp create mode 100644 libraries/render-utils/src/MessageDialog.h diff --git a/interface/resources/qml/CustomButton.qml b/interface/resources/qml/CustomButton.qml index ce57d7ce5e..fb1b544207 100644 --- a/interface/resources/qml/CustomButton.qml +++ b/interface/resources/qml/CustomButton.qml @@ -6,9 +6,13 @@ import QtQuick.Controls.Styles 1.3 Button { SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } text: "Text" - width: 128 - height: 64 style: ButtonStyle { + padding { + top: 8 + left: 12 + right: 12 + bottom: 8 + } background: CustomBorder { anchors.fill: parent } diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml new file mode 100644 index 0000000000..f4a360baed --- /dev/null +++ b/interface/resources/qml/MessageDialog.qml @@ -0,0 +1,359 @@ +/***************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick.Dialogs module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +*****************************************************************************/ + +import Hifi 1.0 as Hifi +import QtQuick 2.2 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.1 +import QtQuick.Dialogs 1.2 + +CustomDialog { + id: root + property real spacing: 8 + property real outerSpacing: 16 + + destroyOnCloseButton: true + destroyOnInvisible: true + implicitHeight: content.implicitHeight + outerSpacing * 2 + 48 + implicitWidth: Math.min(200, Math.max(mainText.implicitWidth, content.buttonsRowImplicitWidth) + outerSpacing * 2); + + onImplicitHeightChanged: root.height = implicitHeight + onImplicitWidthChanged: root.width = implicitWidth + + SystemPalette { id: palette } + + function calculateImplicitWidth() { + if (buttons.visibleChildren.length < 2) + return; + var calcWidth = 0; + for (var i = 0; i < buttons.visibleChildren.length; ++i) { + calcWidth += Math.max(100, buttons.visibleChildren[i].implicitWidth) + root.spacing + } + content.buttonsRowImplicitWidth = outerSpacing + calcWidth + 48 + } + + onEnabledChanged: { + if (enabled) { + content.forceActiveFocus(); + } + } + + Hifi.MessageDialog { + id: content + clip: true + anchors.fill: parent + anchors.topMargin: parent.topMargin + root.outerSpacing + anchors.leftMargin: parent.margins + root.outerSpacing + anchors.rightMargin: parent.margins + root.outerSpacing + anchors.bottomMargin: parent.margins + root.outerSpacing + implicitHeight: contentColumn.implicitHeight + outerSpacing * 2 + implicitWidth: Math.max(mainText.implicitWidth, buttonsRowImplicitWidth); + property real buttonsRowImplicitWidth: Screen.pixelDensity * 50 + + Keys.onPressed: { + console.log("Key press at content") + event.accepted = true + if (event.modifiers === Qt.ControlModifier) + switch (event.key) { + case Qt.Key_A: + console.log("Select All") + detailedText.selectAll() + break + case Qt.Key_C: + console.log("Copy") + detailedText.copy() + break + case Qt.Key_Period: + if (Qt.platform.os === "osx") + reject() + break + } else switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + console.log("Rejecting") + reject() + break + case Qt.Key_Enter: + case Qt.Key_Return: + console.log("Accepting") + accept() + break + } + } + + onImplicitWidthChanged: root.width = implicitWidth + + Component.onCompleted: { + root.title = title + } + + onTitleChanged: { + root.title = title + } + + Column { + id: contentColumn + spacing: root.outerSpacing + anchors { + top: parent.top + left: parent.left + right: parent.right + } + + Item { + width: parent.width + height: Math.max(icon.height, mainText.height + informativeText.height + root.spacing) + Image { + id: icon + source: content.standardIconSource + } + + Text { + id: mainText + anchors { + left: icon.right + leftMargin: root.spacing + right: parent.right + } + text: content.text + font.pointSize: 14 + font.weight: Font.Bold + wrapMode: Text.WordWrap + } + + Text { + id: informativeText + anchors { + left: icon.right + right: parent.right + top: mainText.bottom + leftMargin: root.spacing + topMargin: root.spacing + } + text: content.informativeText + font.pointSize: 14 + wrapMode: Text.WordWrap + } + } + + + Flow { + id: buttons + spacing: root.spacing + layoutDirection: Qt.RightToLeft + width: parent.width + CustomButton { + id: okButton + text: qsTr("OK") + onClicked: content.click(StandardButton.Ok) + visible: content.standardButtons & StandardButton.Ok + } + CustomButton { + id: openButton + text: qsTr("Open") + onClicked: content.click(StandardButton.Open) + visible: content.standardButtons & StandardButton.Open + } + CustomButton { + id: saveButton + text: qsTr("Save") + onClicked: content.click(StandardButton.Save) + visible: content.standardButtons & StandardButton.Save + } + CustomButton { + id: saveAllButton + text: qsTr("Save All") + onClicked: content.click(StandardButton.SaveAll) + visible: content.standardButtons & StandardButton.SaveAll + } + CustomButton { + id: retryButton + text: qsTr("Retry") + onClicked: content.click(StandardButton.Retry) + visible: content.standardButtons & StandardButton.Retry + } + CustomButton { + id: ignoreButton + text: qsTr("Ignore") + onClicked: content.click(StandardButton.Ignore) + visible: content.standardButtons & StandardButton.Ignore + } + CustomButton { + id: applyButton + text: qsTr("Apply") + onClicked: content.click(StandardButton.Apply) + visible: content.standardButtons & StandardButton.Apply + } + CustomButton { + id: yesButton + text: qsTr("Yes") + onClicked: content.click(StandardButton.Yes) + visible: content.standardButtons & StandardButton.Yes + } + CustomButton { + id: yesAllButton + text: qsTr("Yes to All") + onClicked: content.click(StandardButton.YesToAll) + visible: content.standardButtons & StandardButton.YesToAll + } + CustomButton { + id: noButton + text: qsTr("No") + onClicked: content.click(StandardButton.No) + visible: content.standardButtons & StandardButton.No + } + CustomButton { + id: noAllButton + text: qsTr("No to All") + onClicked: content.click(StandardButton.NoToAll) + visible: content.standardButtons & StandardButton.NoToAll + } + CustomButton { + id: discardButton + text: qsTr("Discard") + onClicked: content.click(StandardButton.Discard) + visible: content.standardButtons & StandardButton.Discard + } + CustomButton { + id: resetButton + text: qsTr("Reset") + onClicked: content.click(StandardButton.Reset) + visible: content.standardButtons & StandardButton.Reset + } + CustomButton { + id: restoreDefaultsButton + text: qsTr("Restore Defaults") + onClicked: content.click(StandardButton.RestoreDefaults) + visible: content.standardButtons & StandardButton.RestoreDefaults + } + CustomButton { + id: cancelButton + text: qsTr("Cancel") + onClicked: content.click(StandardButton.Cancel) + visible: content.standardButtons & StandardButton.Cancel + } + CustomButton { + id: abortButton + text: qsTr("Abort") + onClicked: content.click(StandardButton.Abort) + visible: content.standardButtons & StandardButton.Abort + } + CustomButton { + id: closeButton + text: qsTr("Close") + onClicked: content.click(StandardButton.Close) + visible: content.standardButtons & StandardButton.Close + } + CustomButton { + id: moreButton + text: qsTr("Show Details...") + onClicked: content.state = (content.state === "" ? "expanded" : "") + visible: content.detailedText.length > 0 + } + CustomButton { + id: helpButton + text: qsTr("Help") + onClicked: content.click(StandardButton.Help) + visible: content.standardButtons & StandardButton.Help + } + onVisibleChildrenChanged: root.calculateImplicitWidth() + } + } + + Item { + id: details + width: parent.width + implicitHeight: detailedText.implicitHeight + root.spacing + height: 0 + clip: true + + anchors { + left: parent.left + right: parent.right + top: contentColumn.bottom + topMargin: root.spacing + leftMargin: root.outerSpacing + rightMargin: root.outerSpacing + } + + Flickable { + id: flickable + contentHeight: detailedText.height + anchors.fill: parent + anchors.topMargin: root.spacing + anchors.bottomMargin: root.outerSpacing + TextEdit { + id: detailedText + text: content.detailedText + width: details.width + wrapMode: Text.WordWrap + readOnly: true + selectByMouse: true + } + } + } + + states: [ + State { + name: "expanded" + PropertyChanges { + target: details + height: root.height - contentColumn.height - root.spacing - root.outerSpacing + } + PropertyChanges { + target: content + implicitHeight: contentColumn.implicitHeight + root.spacing * 2 + + detailedText.implicitHeight + root.outerSpacing * 2 + } + PropertyChanges { + target: moreButton + text: qsTr("Hide Details") + } + } + ] + +/* + Rectangle { + + } + Component.onCompleted: calculateImplicitWidth() + */ + } +} diff --git a/interface/resources/qml/images/critical.png b/interface/resources/qml/images/critical.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9c5aebf453dd92dba60c48f060b34f0087e02c GIT binary patch literal 253 zcmVkNDWE^AyB8@ZEC00000NkvXXu0mjf DKfYr$ literal 0 HcmV?d00001 diff --git a/interface/resources/qml/images/information.png b/interface/resources/qml/images/information.png new file mode 100644 index 0000000000000000000000000000000000000000..0a2eb87d108d2a24b71559998627570a252ebe69 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8`~f~8uBj!u3?T4-=FFM@ z|NrludHNay0|R48kY6x^!?PP{3=9l&JzX3_G|sP`c#-$80*{Mh+yV`sgwlqP>#QC( z>X#+u7`Xm@Q`=BsWqr<)MUc^=nfrazYu@_ss|q3QYrOu5+ux47bKp#oZChf4k#&aW z_6qNdiK4+zLkc4MIa@Ri#52@3K4zcMoZ;%Na4X>suaM`rgBP8<|7A}r*;L-N)XQ^~ z*Qd}2Q;+ng3Z7t^78=O>`qh(QX^u+vLUu-L1y=d3FMU5VRZj!?kipZ{&t;ucLK6Te CT3=!S literal 0 HcmV?d00001 diff --git a/interface/resources/qml/images/question.png b/interface/resources/qml/images/question.png new file mode 100644 index 0000000000000000000000000000000000000000..2dd92fd7915a09de670b8b6022ddcf02d4cc90e1 GIT binary patch literal 257 zcmV+c0sj7pP)NklQ}7)nBez2^$+jK{Nw%L3xK4m{g6jm}2|@>7z7zk+b}w*O&>f9X*ioevByCmJtfv0xgg* zX&;ac>>nrw_75mp9NLlK=){M}g!K&|3b4W-F*J23VSVK);JN=%IJYXN$un1x$~;9b a#PS7=(1SoC6O>K>0000a literal 0 HcmV?d00001 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8c93418153..b7ba384a97 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -85,6 +85,7 @@ #include #include #include +#include #include @@ -762,11 +763,10 @@ void Application::initializeUi() { AddressBarDialog::registerType(); LoginDialog::registerType(); MarketplaceDialog::registerType(); + MessageDialog::registerType(); auto offscreenUi = DependencyManager::get(); offscreenUi->create(_glWidget->context()->contextHandle()); - offscreenUi->qmlEngine()->setNetworkAccessManagerFactory(new OAuthFactory()); - offscreenUi->qmlEngine()->networkAccessManager(); offscreenUi->resize(_glWidget->size()); offscreenUi->setProxyWindow(_window->windowHandle()); offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 4df42c0f15..5726818b2d 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -37,7 +37,9 @@ void LoginDialog::toggleAction() { } else { // change the menu item to login loginAction->setText("Login"); - connect(loginAction, &QAction::triggered, &LoginDialog::show); + connect(loginAction, &QAction::triggered, [] { + LoginDialog::show(); + }); } } diff --git a/interface/src/ui/MarketplaceDialog.cpp b/interface/src/ui/MarketplaceDialog.cpp index 34d3414ef4..ed30a2c120 100644 --- a/interface/src/ui/MarketplaceDialog.cpp +++ b/interface/src/ui/MarketplaceDialog.cpp @@ -10,40 +10,20 @@ #include "Application.h" #include "MarketplaceDialog.h" - - -#include - #include "DependencyManager.h" QML_DIALOG_DEF(MarketplaceDialog) MarketplaceDialog::MarketplaceDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { - this-> } bool MarketplaceDialog::navigationRequested(const QString & url) { qDebug() << url; if (Application::getInstance()->canAcceptURL(url)) { - qDebug() << "Trying to send url to the app"; if (Application::getInstance()->acceptURL(url)) { - qDebug() << "Sent url to the app"; return false; // we handled it, so QWebPage doesn't need to handle it } } return true; } - -//https://metaverse.highfidelity.com/marketplace - -// -//bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) { -// QString urlString = request.url().toString(); -// if (Application::getInstance()->canAcceptURL(urlString)) { -// if (Application::getInstance()->acceptURL(urlString)) { -// return false; // we handled it, so QWebPage doesn't need to handle it -// } -// } -// return true; -//} \ No newline at end of file diff --git a/libraries/render-utils/src/MessageDialog.cpp b/libraries/render-utils/src/MessageDialog.cpp new file mode 100644 index 0000000000..c16f5653e5 --- /dev/null +++ b/libraries/render-utils/src/MessageDialog.cpp @@ -0,0 +1,142 @@ +// +// +// MessageDialog.cpp +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 "MessageDialog.h" + +QML_DIALOG_DEF(MessageDialog) + + +MessageDialog::MessageDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { + _buttons = StandardButtons(Ok | Cancel); +} + +MessageDialog::~MessageDialog() { +} + +QString MessageDialog::text() const { + return _text; +} + +QString MessageDialog::informativeText() const { + return _informativeText; +} + +QString MessageDialog::detailedText() const { + return _detailedText; +} + +MessageDialog::Icon MessageDialog::icon() const { + return _icon; +} + +void MessageDialog::setVisible(bool v) { + OffscreenQmlDialog::setVisible(v); +} + +void MessageDialog::setText(const QString &arg) { + if (arg != _text) { + _text = arg; + emit textChanged(); + } +} + +void MessageDialog::setInformativeText(const QString &arg) { + if (arg != _informativeText) { + _informativeText = arg; + emit informativeTextChanged(); + } +} + +void MessageDialog::setDetailedText(const QString &arg) { + if (arg != _detailedText) { + _detailedText = arg; + emit detailedTextChanged(); + } +} + +void MessageDialog::setIcon(MessageDialog::Icon icon) { + if (icon != _icon) { + _icon = icon; + emit iconChanged(); + } +} + +void MessageDialog::setStandardButtons(StandardButtons buttons) { + if (buttons != _buttons) { + _buttons = buttons; + emit standardButtonsChanged(); + } +} + +void MessageDialog::click(StandardButton button) { + click(static_cast(button), + static_cast( + QPlatformDialogHelper::buttonRole(static_cast(button)))); +} + +QUrl MessageDialog::standardIconSource() { + switch (icon()) { + case QMessageDialogOptions::Information: + return QUrl("images/information.png"); + break; + case QMessageDialogOptions::Warning: + return QUrl("images/warning.png"); + break; + case QMessageDialogOptions::Critical: + return QUrl("images/critical.png"); + break; + case QMessageDialogOptions::Question: + return QUrl("images/question.png"); + break; + default: + return QUrl(); + break; + } +} + +MessageDialog::StandardButtons MessageDialog::standardButtons() const { + return _buttons; +} + +MessageDialog::StandardButton MessageDialog::clickedButton() const { + return _clickedButton; +} + +void MessageDialog::click(StandardButton button, QPlatformDialogHelper::ButtonRole) { + _clickedButton = button; + if (_resultCallback) { + _resultCallback(QMessageBox::StandardButton(_clickedButton)); + } + hide(); +} + +void MessageDialog::accept() { + // enter key is treated like OK + if (_clickedButton == NoButton) + _clickedButton = Ok; + if (_resultCallback) { + _resultCallback(QMessageBox::StandardButton(_clickedButton)); + } + OffscreenQmlDialog::accept(); +} + +void MessageDialog::reject() { + // escape key is treated like cancel + if (_clickedButton == NoButton) + _clickedButton = Cancel; + if (_resultCallback) { + _resultCallback(QMessageBox::StandardButton(_clickedButton)); + } + OffscreenQmlDialog::reject(); +} + +void MessageDialog::setResultCallback(OffscreenUi::ButtonCallback callback) { + _resultCallback = callback; +} diff --git a/libraries/render-utils/src/MessageDialog.h b/libraries/render-utils/src/MessageDialog.h new file mode 100644 index 0000000000..8b5a895068 --- /dev/null +++ b/libraries/render-utils/src/MessageDialog.h @@ -0,0 +1,98 @@ +// +// MessageDialog.h +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 +// + +#pragma once +#ifndef hifi_MessageDialog_h +#define hifi_MessageDialog_h + +#include "OffscreenQmlDialog.h" +#include <5.4.1/QtGui/qpa/qplatformdialoghelper.h> + +class MessageDialog : public OffscreenQmlDialog +{ + Q_OBJECT + QML_DIALOG_DECL + +private: + Q_ENUMS(Icon) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QString informativeText READ informativeText WRITE setInformativeText NOTIFY informativeTextChanged) + Q_PROPERTY(QString detailedText READ detailedText WRITE setDetailedText NOTIFY detailedTextChanged) + Q_PROPERTY(Icon icon READ icon WRITE setIcon NOTIFY iconChanged) + Q_PROPERTY(QUrl standardIconSource READ standardIconSource NOTIFY iconChanged) + Q_PROPERTY(StandardButtons standardButtons READ standardButtons WRITE setStandardButtons NOTIFY standardButtonsChanged) + Q_PROPERTY(StandardButton clickedButton READ clickedButton NOTIFY buttonClicked) + +public: + enum Icon { + NoIcon = QMessageDialogOptions::NoIcon, + Information = QMessageDialogOptions::Information, + Warning = QMessageDialogOptions::Warning, + Critical = QMessageDialogOptions::Critical, + Question = QMessageDialogOptions::Question + }; + + + MessageDialog(QQuickItem *parent = 0); + virtual ~MessageDialog(); + + QString text() const; + QString informativeText() const; + QString detailedText() const; + Icon icon() const; + +public slots: + virtual void setVisible(bool v); + void setText(const QString &arg); + void setInformativeText(const QString &arg); + void setDetailedText(const QString &arg); + void setIcon(Icon icon); + void setStandardButtons(StandardButtons buttons); + void setResultCallback(OffscreenUi::ButtonCallback callback); + void click(StandardButton button); + QUrl standardIconSource(); + StandardButtons standardButtons() const; + StandardButton clickedButton() const; + +signals: + void textChanged(); + void informativeTextChanged(); + void detailedTextChanged(); + void iconChanged(); + void standardButtonsChanged(); + void buttonClicked(); + void discard(); + void help(); + void yes(); + void no(); + void apply(); + void reset(); + +protected slots: + virtual void click(StandardButton button, QPlatformDialogHelper::ButtonRole); + virtual void accept(); + virtual void reject(); + +private: + QString _title; + QString _text; + QString _informativeText; + QString _detailedText; + Icon _icon{ Information }; + StandardButtons _buttons; + StandardButton _clickedButton{ NoButton }; + OffscreenUi::ButtonCallback _resultCallback; +}; + +#endif // hifi_MessageDialog_h + + + + diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/render-utils/src/OffscreenQmlDialog.cpp index d1e060245d..dbd621ad85 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.cpp +++ b/libraries/render-utils/src/OffscreenQmlDialog.cpp @@ -13,6 +13,30 @@ OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem* parent) : QQuickItem(parent) { } +OffscreenQmlDialog::~OffscreenQmlDialog() { +} + void OffscreenQmlDialog::hide() { static_cast(parent())->setEnabled(false); } + +QString OffscreenQmlDialog::title() const { + return _title; +} + +void OffscreenQmlDialog::setTitle(const QString &arg) { + if (arg != _title) { + _title = arg; + emit titleChanged(); + } +} + +void OffscreenQmlDialog::accept() { + hide(); + emit accepted(); +} + +void OffscreenQmlDialog::reject() { + hide(); + emit rejected(); +} diff --git a/libraries/render-utils/src/OffscreenQmlDialog.h b/libraries/render-utils/src/OffscreenQmlDialog.h index eca82261c0..c6c95981a6 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.h +++ b/libraries/render-utils/src/OffscreenQmlDialog.h @@ -13,6 +13,8 @@ #define hifi_OffscreenQmlDialog_h #include +#include <5.4.1/QtGui/qpa/qplatformdialoghelper.h> + #include "OffscreenUi.h" #define QML_DIALOG_DECL \ @@ -21,8 +23,8 @@ private: \ static const QUrl QML; \ public: \ static void registerType(); \ - static void show(); \ - static void toggle(); \ + static void show(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void toggle(std::function f = [](QQmlContext*, QQuickItem*) {}); \ private: #define QML_DIALOG_DEF(x) \ @@ -33,24 +35,70 @@ private: qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ } \ \ - void x::show() { \ + void x::show(std::function f) { \ auto offscreenUi = DependencyManager::get(); \ - offscreenUi->show(QML, NAME); \ + offscreenUi->show(QML, NAME, f); \ } \ \ - void x::toggle() { \ + void x::toggle(std::function f) { \ auto offscreenUi = DependencyManager::get(); \ - offscreenUi->toggle(QML, NAME); \ + offscreenUi->toggle(QML, NAME, f); \ } class OffscreenQmlDialog : public QQuickItem { Q_OBJECT + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + Q_ENUMS(StandardButton) + Q_FLAGS(StandardButtons) + public: OffscreenQmlDialog(QQuickItem* parent = nullptr); + virtual ~OffscreenQmlDialog(); + + enum StandardButton { + NoButton = QPlatformDialogHelper::NoButton, + Ok = QPlatformDialogHelper::Ok, + Save = QPlatformDialogHelper::Save, + SaveAll = QPlatformDialogHelper::SaveAll, + Open = QPlatformDialogHelper::Open, + Yes = QPlatformDialogHelper::Yes, + YesToAll = QPlatformDialogHelper::YesToAll, + No = QPlatformDialogHelper::No, + NoToAll = QPlatformDialogHelper::NoToAll, + Abort = QPlatformDialogHelper::Abort, + Retry = QPlatformDialogHelper::Retry, + Ignore = QPlatformDialogHelper::Ignore, + Close = QPlatformDialogHelper::Close, + Cancel = QPlatformDialogHelper::Cancel, + Discard = QPlatformDialogHelper::Discard, + Help = QPlatformDialogHelper::Help, + Apply = QPlatformDialogHelper::Apply, + Reset = QPlatformDialogHelper::Reset, + RestoreDefaults = QPlatformDialogHelper::RestoreDefaults, + NButtons + }; + Q_DECLARE_FLAGS(StandardButtons, StandardButton) protected: void hide(); + virtual void accept(); + virtual void reject(); + +public: + QString title() const; + void setTitle(const QString &arg); + +signals: + void accepted(); + void rejected(); + void titleChanged(); + +private: + QString _title; + }; +Q_DECLARE_OPERATORS_FOR_FLAGS(OffscreenQmlDialog::StandardButtons) + #endif diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 837affab59..d25d78300a 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -13,6 +13,7 @@ #include #include #include +#include "MessageDialog.h" // Time between receiving a request to render the offscreen UI actually triggering // the render. Could possibly be increased depending on the framerate we expect to @@ -140,13 +141,15 @@ void OffscreenUi::setBaseUrl(const QUrl& baseUrl) { _qmlEngine->setBaseUrl(baseUrl); } -void OffscreenUi::load(const QUrl& qmlSource, std::function f) { +void OffscreenUi::load(const QUrl& qmlSource, std::function f) { qDebug() << "Loading QML from URL " << qmlSource; _qmlComponent->loadUrl(qmlSource); - if (_qmlComponent->isLoading()) { - connect(_qmlComponent, &QQmlComponent::statusChanged, this, []{}); - } else { - finishQmlLoad(); + if (_qmlComponent->isLoading()) + connect(_qmlComponent, &QQmlComponent::statusChanged, this, [this, f] { + finishQmlLoad(f); + }); + else { + finishQmlLoad(f); } } @@ -163,7 +166,7 @@ void OffscreenUi::requestRender() { } } -void OffscreenUi::finishQmlLoad() { +void OffscreenUi::finishQmlLoad(std::function f) { disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); @@ -197,7 +200,7 @@ void OffscreenUi::finishQmlLoad() { // Make sure we make items focusable (critical for // supporting keyboard shortcuts) newItem->setFlag(QQuickItem::ItemIsFocusScope, true); - + f(_qmlEngine->contextForObject(newItem), newItem); if (!_rootItem) { // The root item is ready. Associate it with the window. _rootItem = newItem; @@ -390,54 +393,62 @@ void OffscreenUi::setProxyWindow(QWindow* window) { _renderControl->_renderWindow = window; } -void OffscreenUi::show(const QUrl& url, const QString& name) { +void OffscreenUi::show(const QUrl& url, const QString& name, std::function f) { QQuickItem* item = _rootItem->findChild(name); // First load? if (!item) { - load(url); + load(url, f); return; } item->setEnabled(true); } -void OffscreenUi::toggle(const QUrl& url, const QString& name) { +void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function f) { QQuickItem* item = _rootItem->findChild(name); // First load? if (!item) { - load(url); + load(url, f); return; } item->setEnabled(!item->isEnabled()); } void OffscreenUi::messageBox(const QString& title, const QString& text, + ButtonCallback callback, QMessageBox::Icon icon, - QMessageBox::StandardButtons buttons, - ButtonCallback f) { + QMessageBox::StandardButtons buttons) { + MessageDialog::show([=](QQmlContext*ctx, QQuickItem*item) { + MessageDialog * pDialog = item->findChild(); + pDialog->setIcon((MessageDialog::Icon)icon); + pDialog->setTitle(title); + pDialog->setText(text); + pDialog->setStandardButtons(MessageDialog::StandardButtons((int)buttons)); + pDialog->setResultCallback(callback); + }); } void OffscreenUi::information(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons, - ButtonCallback callback) { - callback(QMessageBox::information(nullptr, title, text, buttons)); + ButtonCallback callback, + QMessageBox::StandardButtons buttons) { + messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Information, buttons); } void OffscreenUi::question(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons, - ButtonCallback callback) { - callback(QMessageBox::question(nullptr, title, text, buttons)); + ButtonCallback callback, + QMessageBox::StandardButtons buttons) { + messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Question, buttons); } void OffscreenUi::warning(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons, - ButtonCallback callback) { - callback(QMessageBox::warning(nullptr, title, text, buttons)); + ButtonCallback callback, + QMessageBox::StandardButtons buttons) { + messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Warning, buttons); } void OffscreenUi::critical(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons, - ButtonCallback callback) { - callback(QMessageBox::critical(nullptr, title, text, buttons)); + ButtonCallback callback, + QMessageBox::StandardButtons buttons) { + messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Critical, buttons); } diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index c64d0d833c..b2805b2ded 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -59,12 +59,12 @@ public: virtual ~OffscreenUi(); void create(QOpenGLContext* context); void resize(const QSize& size); - void load(const QUrl& qmlSource, std::function f = [](QQmlContext*) {}); - void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*) {}) { + void load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QQuickItem*) {}); + void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QQuickItem*) {}) { load(QUrl(qmlSourceFile), f); } - void show(const QUrl& url, const QString& name); - void toggle(const QUrl& url, const QString& name); + void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QQuickItem*) {})); + void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QQuickItem*) {})); void setBaseUrl(const QUrl& baseUrl); void addImportPath(const QString& path); QQmlContext* qmlContext(); @@ -86,31 +86,32 @@ public: static ButtonCallback NO_OP_CALLBACK; static void messageBox(const QString& title, const QString& text, + static void messageBox(const QString &title, const QString &text, + ButtonCallback f, QMessageBox::Icon icon, - QMessageBox::StandardButtons buttons, - ButtonCallback f); + QMessageBox::StandardButtons buttons); static void information(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok, - ButtonCallback callback = NO_OP_CALLBACK); + ButtonCallback callback = NO_OP_CALLBACK, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); static void question(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), - ButtonCallback callback = [](QMessageBox::StandardButton) {}); + ButtonCallback callback = NO_OP_CALLBACK, + QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No)); static void warning(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok, - ButtonCallback callback = [](QMessageBox::StandardButton) {}); + ButtonCallback callback = NO_OP_CALLBACK, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); static void critical(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok, - ButtonCallback callback = [](QMessageBox::StandardButton) {}); + ButtonCallback callback = NO_OP_CALLBACK, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); protected: private slots: void updateQuick(); - void finishQmlLoad(); + void finishQmlLoad(std::function f); public slots: void requestUpdate(); From 3ba0df520147f5e7ced5481766d0fb020a68a712 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 20 Apr 2015 18:41:49 -0700 Subject: [PATCH 269/401] Fixing headers --- interface/src/ui/MarketplaceDialog.cpp | 2 +- interface/src/ui/MarketplaceDialog.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/MarketplaceDialog.cpp b/interface/src/ui/MarketplaceDialog.cpp index ed30a2c120..4893d47103 100644 --- a/interface/src/ui/MarketplaceDialog.cpp +++ b/interface/src/ui/MarketplaceDialog.cpp @@ -1,5 +1,5 @@ // -// AddressBarDialog.cpp +// MarketplaceDialog.cpp // // Created by Bradley Austin Davis on 2015/04/14 // Copyright 2015 High Fidelity, Inc. diff --git a/interface/src/ui/MarketplaceDialog.h b/interface/src/ui/MarketplaceDialog.h index 137bb0bea7..f5fa355201 100644 --- a/interface/src/ui/MarketplaceDialog.h +++ b/interface/src/ui/MarketplaceDialog.h @@ -1,5 +1,5 @@ // -// AddressBarDialog.h +// MarketplaceDialog.h // // Created by Bradley Austin Davis on 2015/04/14 // Copyright 2015 High Fidelity, Inc. From d2ff89aaecd150388ac858409ba33aa83ababb69 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 21 Apr 2015 14:21:59 -0700 Subject: [PATCH 270/401] Cleaning up qml --- interface/resources/qml/AddressBarDialog.qml | 10 +- interface/resources/qml/Browser.qml | 21 +- interface/resources/qml/CustomButton.qml | 27 -- interface/resources/qml/CustomTextArea.qml | 10 - interface/resources/qml/Icon.qml | 8 - interface/resources/qml/LoginDialog.qml | 29 +-- interface/resources/qml/MarketplaceDialog.qml | 5 +- interface/resources/qml/MenuTest.qml | 12 + interface/resources/qml/MessageDialog.qml | 41 +-- interface/resources/qml/Palettes.qml | 86 ------- interface/resources/qml/Root.qml | 5 +- interface/resources/qml/TestDialog.qml | 22 +- interface/resources/qml/TestRoot.qml | 28 +- interface/resources/qml/controls/Button.qml | 10 + .../{CustomDialog.qml => controls/Dialog.qml} | 242 ++++++++++-------- .../IconButton.qml} | 0 .../resources/qml/controls/MenuButton.qml | 9 + interface/resources/qml/controls/README.md | 2 + .../{CustomTextEdit.qml => controls/Text.qml} | 4 +- .../{CustomText.qml => controls/TextArea.qml} | 4 +- interface/resources/qml/controls/TextEdit.qml | 7 + .../TextInput.qml} | 4 +- interface/resources/qml/hifiConstants.js | 4 - .../{CustomBorder.qml => styles/Border.qml} | 1 - .../resources/qml/styles/ButtonStyle.qml | 24 ++ .../resources/qml/styles/HifiPalette.qml | 5 + .../resources/qml/styles/IconButtonStyle.qml | 15 ++ .../resources/qml/styles/MenuButtonStyle.qml | 24 ++ 28 files changed, 325 insertions(+), 334 deletions(-) delete mode 100644 interface/resources/qml/CustomButton.qml delete mode 100644 interface/resources/qml/CustomTextArea.qml delete mode 100644 interface/resources/qml/Icon.qml create mode 100644 interface/resources/qml/MenuTest.qml create mode 100644 interface/resources/qml/controls/Button.qml rename interface/resources/qml/{CustomDialog.qml => controls/Dialog.qml} (56%) rename interface/resources/qml/{IconControl.qml => controls/IconButton.qml} (100%) create mode 100644 interface/resources/qml/controls/MenuButton.qml create mode 100644 interface/resources/qml/controls/README.md rename interface/resources/qml/{CustomTextEdit.qml => controls/Text.qml} (54%) rename interface/resources/qml/{CustomText.qml => controls/TextArea.qml} (52%) create mode 100644 interface/resources/qml/controls/TextEdit.qml rename interface/resources/qml/{CustomTextInput.qml => controls/TextInput.qml} (90%) delete mode 100644 interface/resources/qml/hifiConstants.js rename interface/resources/qml/{CustomBorder.qml => styles/Border.qml} (99%) create mode 100644 interface/resources/qml/styles/ButtonStyle.qml create mode 100644 interface/resources/qml/styles/HifiPalette.qml create mode 100644 interface/resources/qml/styles/IconButtonStyle.qml create mode 100644 interface/resources/qml/styles/MenuButtonStyle.qml diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index ec1480928a..4c2631aa6d 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -1,10 +1,8 @@ import Hifi 1.0 import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Controls.Styles 1.3 +import "controls" -CustomDialog { +Dialog { title: "Go to..." objectName: "AddressBarDialog" height: 128 @@ -36,14 +34,14 @@ CustomDialog { anchors.margins: parent.margins anchors.topMargin: parent.topMargin - CustomBorder { + Border { height: 64 anchors.left: parent.left anchors.leftMargin: 0 anchors.right: goButton.left anchors.rightMargin: 8 anchors.verticalCenter: parent.verticalCenter - CustomTextInput { + TextInput { id: addressLine anchors.fill: parent helperText: "domain, location, @user, /x,y,z" diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index d7e08fbd97..a439f9114c 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -1,12 +1,10 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Dialogs 1.2 -import QtQuick.Controls.Styles 1.3 import QtWebKit 3.0 +import "controls" -CustomDialog { - title: "Test Dlg" +Dialog { + title: "Browser Window" id: testDialog objectName: "Browser" width: 1280 @@ -18,7 +16,6 @@ CustomDialog { anchors.fill: parent anchors.margins: parent.margins anchors.topMargin: parent.topMargin - ScrollView { anchors.fill: parent @@ -30,16 +27,4 @@ CustomDialog { } } - - } - - -/* - -// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property - -MouseArea { - anchors.fill: parent -} -*/ diff --git a/interface/resources/qml/CustomButton.qml b/interface/resources/qml/CustomButton.qml deleted file mode 100644 index fb1b544207..0000000000 --- a/interface/resources/qml/CustomButton.qml +++ /dev/null @@ -1,27 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.3 -import QtQuick.Window 2.2 -import QtQuick.Controls.Styles 1.3 - -Button { - SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - text: "Text" - style: ButtonStyle { - padding { - top: 8 - left: 12 - right: 12 - bottom: 8 - } - background: CustomBorder { - anchors.fill: parent - } - label: CustomText { - renderType: Text.NativeRendering - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - text: control.text - color: control.enabled ? myPalette.text : myPalette.dark - } - } -} diff --git a/interface/resources/qml/CustomTextArea.qml b/interface/resources/qml/CustomTextArea.qml deleted file mode 100644 index cf3308e2b7..0000000000 --- a/interface/resources/qml/CustomTextArea.qml +++ /dev/null @@ -1,10 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 - -TextArea { - font.family: "Helvetica" - font.pointSize: 18 - backgroundVisible: false - readOnly: true -} - diff --git a/interface/resources/qml/Icon.qml b/interface/resources/qml/Icon.qml deleted file mode 100644 index 0d60afb2b7..0000000000 --- a/interface/resources/qml/Icon.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick 1.0 - -Image { -id: icon -width: 64 -height: 64 -source: "file.svg" -} \ No newline at end of file diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index be69b65ef7..22162e323f 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -1,12 +1,11 @@ import Hifi 1.0 import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 import QtQuick.Controls.Styles 1.3 -import "hifiConstants.js" as HifiConstants +import "controls" -CustomDialog { +Dialog { title: "Login" + HifiPalette { id: hifiPalette } SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } objectName: "LoginDialog" height: 512 @@ -50,11 +49,11 @@ CustomDialog { source: "../images/hifi-logo.svg" } - CustomBorder { + Border { width: 304 height: 64 anchors.horizontalCenter: parent.horizontalCenter - CustomTextInput { + TextInput { id: username anchors.fill: parent helperText: "Username or Email" @@ -67,11 +66,11 @@ CustomDialog { } } - CustomBorder { + Border { width: 304 height: 64 anchors.horizontalCenter: parent.horizontalCenter - CustomTextInput { + TextInput { id: password anchors.fill: parent echoMode: TextInput.Password @@ -94,7 +93,7 @@ CustomDialog { } } - CustomText { + Text { anchors.horizontalCenter: parent.horizontalCenter textFormat: Text.StyledText width: parent.width @@ -117,7 +116,7 @@ CustomDialog { width: 192 height: 64 anchors.horizontalCenter: parent.horizontalCenter - color: HifiConstants.color + color: hifiPalette.hifiBlue border.width: 0 radius: 10 @@ -142,7 +141,7 @@ CustomDialog { width: 32 source: "../images/login.svg" } - CustomText { + Text { text: "Login" color: "white" width: 64 @@ -152,7 +151,7 @@ CustomDialog { } - CustomText { + Text { width: parent.width height: 24 horizontalAlignment: Text.AlignHCenter @@ -160,7 +159,7 @@ CustomDialog { text:"Create Account" font.pointSize: 12 font.bold: true - color: HifiConstants.color + color: hifiPalette.hifiBlue MouseArea { anchors.fill: parent @@ -170,14 +169,14 @@ CustomDialog { } } - CustomText { + Text { width: parent.width height: 24 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pointSize: 12 text: "Recover Password" - color: HifiConstants.color + color: hifiPalette.hifiBlue MouseArea { anchors.fill: parent diff --git a/interface/resources/qml/MarketplaceDialog.qml b/interface/resources/qml/MarketplaceDialog.qml index 3fdd9b2b4d..fe192179eb 100644 --- a/interface/resources/qml/MarketplaceDialog.qml +++ b/interface/resources/qml/MarketplaceDialog.qml @@ -1,12 +1,11 @@ import Hifi 1.0 import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Dialogs 1.2 import QtQuick.Controls.Styles 1.3 import QtWebKit 3.0 +import "controls" -CustomDialog { +Dialog { title: "Test Dlg" id: testDialog objectName: "Browser" diff --git a/interface/resources/qml/MenuTest.qml b/interface/resources/qml/MenuTest.qml new file mode 100644 index 0000000000..13fc997791 --- /dev/null +++ b/interface/resources/qml/MenuTest.qml @@ -0,0 +1,12 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.3 +import QtQuick.Controls.Styles 1.3 + +Item { + anchors.fill: parent + + Rectangle { + anchors.fill: parent + color: "red" + } +} diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml index f4a360baed..c7c1b23223 100644 --- a/interface/resources/qml/MessageDialog.qml +++ b/interface/resources/qml/MessageDialog.qml @@ -43,8 +43,9 @@ import QtQuick 2.2 import QtQuick.Controls 1.2 import QtQuick.Window 2.1 import QtQuick.Dialogs 1.2 +import "controls" -CustomDialog { +Dialog { id: root property real spacing: 8 property real outerSpacing: 16 @@ -179,115 +180,115 @@ CustomDialog { spacing: root.spacing layoutDirection: Qt.RightToLeft width: parent.width - CustomButton { + Button { id: okButton text: qsTr("OK") onClicked: content.click(StandardButton.Ok) visible: content.standardButtons & StandardButton.Ok } - CustomButton { + Button { id: openButton text: qsTr("Open") onClicked: content.click(StandardButton.Open) visible: content.standardButtons & StandardButton.Open } - CustomButton { + Button { id: saveButton text: qsTr("Save") onClicked: content.click(StandardButton.Save) visible: content.standardButtons & StandardButton.Save } - CustomButton { + Button { id: saveAllButton text: qsTr("Save All") onClicked: content.click(StandardButton.SaveAll) visible: content.standardButtons & StandardButton.SaveAll } - CustomButton { + Button { id: retryButton text: qsTr("Retry") onClicked: content.click(StandardButton.Retry) visible: content.standardButtons & StandardButton.Retry } - CustomButton { + Button { id: ignoreButton text: qsTr("Ignore") onClicked: content.click(StandardButton.Ignore) visible: content.standardButtons & StandardButton.Ignore } - CustomButton { + Button { id: applyButton text: qsTr("Apply") onClicked: content.click(StandardButton.Apply) visible: content.standardButtons & StandardButton.Apply } - CustomButton { + Button { id: yesButton text: qsTr("Yes") onClicked: content.click(StandardButton.Yes) visible: content.standardButtons & StandardButton.Yes } - CustomButton { + Button { id: yesAllButton text: qsTr("Yes to All") onClicked: content.click(StandardButton.YesToAll) visible: content.standardButtons & StandardButton.YesToAll } - CustomButton { + Button { id: noButton text: qsTr("No") onClicked: content.click(StandardButton.No) visible: content.standardButtons & StandardButton.No } - CustomButton { + Button { id: noAllButton text: qsTr("No to All") onClicked: content.click(StandardButton.NoToAll) visible: content.standardButtons & StandardButton.NoToAll } - CustomButton { + Button { id: discardButton text: qsTr("Discard") onClicked: content.click(StandardButton.Discard) visible: content.standardButtons & StandardButton.Discard } - CustomButton { + Button { id: resetButton text: qsTr("Reset") onClicked: content.click(StandardButton.Reset) visible: content.standardButtons & StandardButton.Reset } - CustomButton { + Button { id: restoreDefaultsButton text: qsTr("Restore Defaults") onClicked: content.click(StandardButton.RestoreDefaults) visible: content.standardButtons & StandardButton.RestoreDefaults } - CustomButton { + Button { id: cancelButton text: qsTr("Cancel") onClicked: content.click(StandardButton.Cancel) visible: content.standardButtons & StandardButton.Cancel } - CustomButton { + Button { id: abortButton text: qsTr("Abort") onClicked: content.click(StandardButton.Abort) visible: content.standardButtons & StandardButton.Abort } - CustomButton { + Button { id: closeButton text: qsTr("Close") onClicked: content.click(StandardButton.Close) visible: content.standardButtons & StandardButton.Close } - CustomButton { + Button { id: moreButton text: qsTr("Show Details...") onClicked: content.state = (content.state === "" ? "expanded" : "") visible: content.detailedText.length > 0 } - CustomButton { + Button { id: helpButton text: qsTr("Help") onClicked: content.click(StandardButton.Help) diff --git a/interface/resources/qml/Palettes.qml b/interface/resources/qml/Palettes.qml index c4b0953df7..2bdf6eba8b 100644 --- a/interface/resources/qml/Palettes.qml +++ b/interface/resources/qml/Palettes.qml @@ -1,8 +1,5 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Dialogs 1.2 -import QtQuick.Controls.Styles 1.3 Rectangle { color: "teal" @@ -150,87 +147,4 @@ Rectangle { Rectangle { height: parent.height; width: 16; color: spd.highlightedText} } } - - -/* - CustomDialog { - title: "Test Dlg" - anchors.fill: parent - - Rectangle { - property int d: 100 - id: square - objectName: "testRect" - width: d - height: d - anchors.centerIn: parent - color: "red" - NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } - } - - - CustomTextEdit { - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.right: parent.right - anchors.rightMargin: 12 - clip: true - text: "test edit" - anchors.top: parent.top - anchors.topMargin: parent.titleSize + 12 - } - - CustomButton { - x: 128 - y: 192 - anchors.bottom: parent.bottom - anchors.bottomMargin: 12 - anchors.right: parent.right - anchors.rightMargin: 12 - onClicked: { - console.log("Click"); - if (square.visible) { - square.visible = false - } else { - square.visible = true - } - } - } - - CustomButton { - id: customButton2 - y: 192 - text: "Close" - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.bottom: parent.bottom - anchors.bottomMargin: 12 - onClicked: { - onClicked: testDialog.x == 0 ? testDialog.x = 200 : testDialog.x = 0 - } - } - - Keys.onPressed: { - console.log("Key " + event.key); - switch (event.key) { - case Qt.Key_Q: - if (Qt.ControlModifier == event.modifiers) { - event.accepted = true; - break; - } - } - } - } -*/ - } - - -/* - -// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property - -MouseArea { - anchors.fill: parent -} -*/ diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index 9422ef123d..b2db7d18bf 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -1,9 +1,10 @@ import Hifi 1.0 import QtQuick 2.3 +// This is our primary 'window' object to which all dialogs and controls will +// be childed. Root { id: root - width: 1280 - height: 720 + anchors.fill: parent } diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml index 1fe8676bc6..15bd790c22 100644 --- a/interface/resources/qml/TestDialog.qml +++ b/interface/resources/qml/TestDialog.qml @@ -1,10 +1,9 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Dialogs 1.2 import QtQuick.Controls.Styles 1.3 +import "controls" -CustomDialog { +Dialog { title: "Test Dialog" id: testDialog objectName: "TestDialog" @@ -37,7 +36,7 @@ CustomDialog { } - CustomTextEdit { + TextEdit { id: edit anchors.left: parent.left anchors.leftMargin: 12 @@ -49,7 +48,7 @@ CustomDialog { anchors.topMargin: 12 } - CustomButton { + Button { x: 128 y: 192 text: "Test" @@ -68,7 +67,7 @@ CustomDialog { } } - CustomButton { + Button { id: customButton2 y: 192 text: "Move" @@ -92,15 +91,4 @@ CustomDialog { } } } - } - - -/* - -// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property - -MouseArea { - anchors.fill: parent -} -*/ diff --git a/interface/resources/qml/TestRoot.qml b/interface/resources/qml/TestRoot.qml index 158c0b7a54..0f48939935 100644 --- a/interface/resources/qml/TestRoot.qml +++ b/interface/resources/qml/TestRoot.qml @@ -1,12 +1,26 @@ import Hifi 1.0 import QtQuick 2.3 +// Import local folder last so that our own control customizations override +// the built in ones +import "controls" Root { id: root - width: 1280 - height: 720 + anchors.fill: parent - CustomButton { + onWidthChanged: { + console.log("Root width: " + width) + } + onHeightChanged: { + console.log("Root height: " + height) + } + + Component.onCompleted: { + console.log("Completed root") + root.forceActiveFocus() + } + + Button { id: messageBox anchors.right: createDialog.left anchors.rightMargin: 24 @@ -20,7 +34,7 @@ Root { } } - CustomButton { + Button { id: createDialog anchors.right: parent.right anchors.rightMargin: 24 @@ -28,8 +42,12 @@ Root { anchors.bottomMargin: 24 text: "Create" onClicked: { - root.loadChild("TestDialog.qml"); + root.loadChild("MenuTest.qml"); } } + + Keys.onPressed: { + console.log(event.key); + } } diff --git a/interface/resources/qml/controls/Button.qml b/interface/resources/qml/controls/Button.qml new file mode 100644 index 0000000000..215e0542f7 --- /dev/null +++ b/interface/resources/qml/controls/Button.qml @@ -0,0 +1,10 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 as Original +import QtQuick.Controls.Styles 1.3 +import "." +import "../styles" + +Original.Button { + style: ButtonStyle { + } +} diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/controls/Dialog.qml similarity index 56% rename from interface/resources/qml/CustomDialog.qml rename to interface/resources/qml/controls/Dialog.qml index 1e0351af4f..78642eaef4 100644 --- a/interface/resources/qml/CustomDialog.qml +++ b/interface/resources/qml/controls/Dialog.qml @@ -1,40 +1,78 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Dialogs 1.2 -import QtQuick.Controls.Styles 1.3 -import "hifiConstants.js" as HifiConstants +import "." +import "../styles" +/* + * FIXME Need to create a client property here so that objects can be + * placed in it without having to think about positioning within the outer + * window. + * + * Examine the QML ApplicationWindow.qml source for how it does this + * + */ Item { - SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - id: dialog - width: 256 - height: 256 - scale: 0.0 - enabled: false + id: root + + HifiPalette { id: hifiPalette } + SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } + property int animationDuration: 400 property bool destroyOnInvisible: false property bool destroyOnCloseButton: true property bool resizable: false property int minX: 256 property int minY: 256 - clip: true + property int topMargin: root.height - clientBorder.height + 8 + property int margins: 8 + property string title + property int titleSize: titleBorder.height + 12 + property string frameColor: hifiPalette.hifiBlue + property string backgroundColor: sysPalette.window + property string headerBackgroundColor: sysPalette.dark + clip: true + enabled: false + scale: 0.0 + + /* + * Support for animating the dialog in and out. + */ + + // The offscreen UI will enable an object, rather than manipulating it's + // visibility, so that we can do animations in both directions. Because + // visibility and enabled are boolean flags, they cannot be animated. So when + // enabled is change, we modify a property that can be animated, like scale or + // opacity. onEnabledChanged: { scale = enabled ? 1.0 : 0.0 } - + + // The actual animator + Behavior on scale { + NumberAnimation { + duration: root.animationDuration + easing.type: Easing.InOutBounce + } + } + + // We remove any load the dialog might have on the QML by toggling it's + // visibility based on the state of the animated property onScaleChanged: { visible = (scale != 0.0); } + // Some dialogs should be destroyed when they become invisible, so handle that onVisibleChanged: { if (!visible && destroyOnInvisible) { - console.log("Destroying closed component"); destroy(); } } + // our close function performs the same way as the OffscreenUI class: + // don't do anything but manipulate the enabled flag and let the other + // mechanisms decide if the window should be destoryed after the close + // animation completes function close() { if (destroyOnCloseButton) { destroyOnInvisible = true @@ -42,102 +80,14 @@ Item { enabled = false; } + /* + * Resize support + */ function deltaSize(dx, dy) { width = Math.max(width + dx, minX) height = Math.max(height + dy, minY) } - Behavior on scale { - NumberAnimation { - //This specifies how long the animation takes - duration: dialog.animationDuration - //This selects an easing curve to interpolate with, the default is Easing.Linear - easing.type: Easing.InOutBounce - } - } - - property int topMargin: dialog.height - clientBorder.height + 8 - property int margins: 8 - property string title - property int titleSize: titleBorder.height + 12 - property string frameColor: HifiConstants.color - property string backgroundColor: myPalette.window - property string headerBackgroundColor: myPalette.dark - - CustomBorder { - id: windowBorder - anchors.fill: parent - border.color: dialog.frameColor - color: dialog.backgroundColor - - CustomBorder { - id: titleBorder - height: 48 - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - border.color: dialog.frameColor - color: dialog.headerBackgroundColor - - CustomText { - id: titleText - color: "white" - text: dialog.title - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - anchors.fill: parent - } - - MouseArea { - id: titleDrag - anchors.right: closeButton.left - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.top: parent.top - anchors.rightMargin: 4 - drag { - target: dialog - minimumX: 0 - minimumY: 0 - maximumX: dialog.parent ? dialog.parent.width - dialog.width : 0 - maximumY: dialog.parent ? dialog.parent.height - dialog.height : 0 - } - } - Image { - id: closeButton - x: 360 - height: 16 - anchors.verticalCenter: parent.verticalCenter - width: 16 - anchors.right: parent.right - anchors.rightMargin: 12 - source: "../styles/close.svg" - MouseArea { - anchors.fill: parent - onClicked: { - dialog.close(); - } - } - } - } // header border - - CustomBorder { - id: clientBorder - border.color: dialog.frameColor - color: "#00000000" - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: titleBorder.bottom - anchors.topMargin: -titleBorder.border.width - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - clip: true - } // client border - } // window border - MouseArea { id: sizeDrag property int startX @@ -152,11 +102,91 @@ Item { startY = mouseY } onPositionChanged: { - if (pressed && dialog.resizable) { - dialog.deltaSize((mouseX - startX), (mouseY - startY)) + if (pressed && root.resizable) { + root.deltaSize((mouseX - startX), (mouseY - startY)) startX = mouseX startY = mouseY } } } + + /* + * Window decorations, with a title bar and frames + */ + Border { + id: windowBorder + anchors.fill: parent + border.color: root.frameColor + color: root.backgroundColor + + Border { + id: titleBorder + height: 48 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + border.color: root.frameColor + color: root.headerBackgroundColor + + Text { + id: titleText + // FIXME move all constant colors to our own palette class HifiPalette + color: "white" + text: root.title + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + } + + MouseArea { + id: titleDrag + anchors.right: closeButton.left + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.top: parent.top + anchors.rightMargin: 4 + drag { + target: root + minimumX: 0 + minimumY: 0 + maximumX: root.parent ? root.parent.width - root.width : 0 + maximumY: root.parent ? root.parent.height - root.height : 0 + } + } + Image { + id: closeButton + x: 360 + height: 16 + anchors.verticalCenter: parent.verticalCenter + width: 16 + anchors.right: parent.right + anchors.rightMargin: 12 + source: "../../styles/close.svg" + MouseArea { + anchors.fill: parent + onClicked: { + root.close(); + } + } + } + } // header border + + Border { + id: clientBorder + border.color: root.frameColor + // FIXME move all constant colors to our own palette class HifiPalette + color: "#00000000" + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: titleBorder.bottom + anchors.topMargin: -titleBorder.border.width + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + clip: true + } // client border + } // window border + } diff --git a/interface/resources/qml/IconControl.qml b/interface/resources/qml/controls/IconButton.qml similarity index 100% rename from interface/resources/qml/IconControl.qml rename to interface/resources/qml/controls/IconButton.qml diff --git a/interface/resources/qml/controls/MenuButton.qml b/interface/resources/qml/controls/MenuButton.qml new file mode 100644 index 0000000000..25ad4b2c48 --- /dev/null +++ b/interface/resources/qml/controls/MenuButton.qml @@ -0,0 +1,9 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 as Original +import QtQuick.Controls.Styles 1.3 +import "../styles" + +Original.Button { + style: MenuButtonStyle { + } +} diff --git a/interface/resources/qml/controls/README.md b/interface/resources/qml/controls/README.md new file mode 100644 index 0000000000..7f05f32a63 --- /dev/null +++ b/interface/resources/qml/controls/README.md @@ -0,0 +1,2 @@ +These are our own custom controls with the same names as existing controls, but +customized for readability / usability in VR. diff --git a/interface/resources/qml/CustomTextEdit.qml b/interface/resources/qml/controls/Text.qml similarity index 54% rename from interface/resources/qml/CustomTextEdit.qml rename to interface/resources/qml/controls/Text.qml index 0602bbc150..a9c19e70b4 100644 --- a/interface/resources/qml/CustomTextEdit.qml +++ b/interface/resources/qml/controls/Text.qml @@ -1,6 +1,6 @@ -import QtQuick 2.3 +import QtQuick 2.3 as Original -TextEdit { +Original.Text { font.family: "Helvetica" font.pointSize: 18 } diff --git a/interface/resources/qml/CustomText.qml b/interface/resources/qml/controls/TextArea.qml similarity index 52% rename from interface/resources/qml/CustomText.qml rename to interface/resources/qml/controls/TextArea.qml index 83229b783e..dfa177bcb6 100644 --- a/interface/resources/qml/CustomText.qml +++ b/interface/resources/qml/controls/TextArea.qml @@ -1,6 +1,6 @@ -import QtQuick 2.3 +import QtQuick 2.3 as Original -Text { +Original.TextArea { font.family: "Helvetica" font.pointSize: 18 } diff --git a/interface/resources/qml/controls/TextEdit.qml b/interface/resources/qml/controls/TextEdit.qml new file mode 100644 index 0000000000..28551bb171 --- /dev/null +++ b/interface/resources/qml/controls/TextEdit.qml @@ -0,0 +1,7 @@ +import QtQuick 2.3 as Original + +Original.TextEdit { + font.family: "Helvetica" + font.pointSize: 18 +} + diff --git a/interface/resources/qml/CustomTextInput.qml b/interface/resources/qml/controls/TextInput.qml similarity index 90% rename from interface/resources/qml/CustomTextInput.qml rename to interface/resources/qml/controls/TextInput.qml index a706187376..8ce3d85d81 100644 --- a/interface/resources/qml/CustomTextInput.qml +++ b/interface/resources/qml/controls/TextInput.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 1.2 TextInput { SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - property string helperText: "" + property string helperText font.family: "Helvetica" font.pointSize: 18 width: 256 @@ -24,7 +24,7 @@ TextInput { id: helperText anchors.fill: parent font.pointSize: parent.font.pointSize - font.family: "Helvetica" + font.family: parent.font.family verticalAlignment: TextInput.AlignVCenter text: parent.helperText color: myPalette.dark diff --git a/interface/resources/qml/hifiConstants.js b/interface/resources/qml/hifiConstants.js deleted file mode 100644 index 860226c963..0000000000 --- a/interface/resources/qml/hifiConstants.js +++ /dev/null @@ -1,4 +0,0 @@ -var color = "#0e7077" -var Colors = { - hifiBlue: "#0e7077" -} diff --git a/interface/resources/qml/CustomBorder.qml b/interface/resources/qml/styles/Border.qml similarity index 99% rename from interface/resources/qml/CustomBorder.qml rename to interface/resources/qml/styles/Border.qml index 1bb30d1ebc..7d38e7d277 100644 --- a/interface/resources/qml/CustomBorder.qml +++ b/interface/resources/qml/styles/Border.qml @@ -1,6 +1,5 @@ import QtQuick 2.3 - Rectangle { SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } property int margin: 5 diff --git a/interface/resources/qml/styles/ButtonStyle.qml b/interface/resources/qml/styles/ButtonStyle.qml new file mode 100644 index 0000000000..caf366364a --- /dev/null +++ b/interface/resources/qml/styles/ButtonStyle.qml @@ -0,0 +1,24 @@ +import QtQuick 2.4 as Original +import QtQuick.Controls.Styles 1.3 as OriginalStyles +import "." +import "../controls" + +OriginalStyles.ButtonStyle { + Original.SystemPalette { id: myPalette; colorGroup: Original.SystemPalette.Active } + padding { + top: 8 + left: 12 + right: 12 + bottom: 8 + } + background: Border { + anchors.fill: parent + } + label: Text { + renderType: Original.Text.NativeRendering + verticalAlignment: Original.Text.AlignVCenter + horizontalAlignment: Original.Text.AlignHCenter + text: control.text + color: control.enabled ? myPalette.text : myPalette.dark + } +} diff --git a/interface/resources/qml/styles/HifiPalette.qml b/interface/resources/qml/styles/HifiPalette.qml new file mode 100644 index 0000000000..641d533e3d --- /dev/null +++ b/interface/resources/qml/styles/HifiPalette.qml @@ -0,0 +1,5 @@ +import QtQuick 2.4 + +QtObject { + property string hifiBlue: "#0e7077" +} \ No newline at end of file diff --git a/interface/resources/qml/styles/IconButtonStyle.qml b/interface/resources/qml/styles/IconButtonStyle.qml new file mode 100644 index 0000000000..b341e5d6dd --- /dev/null +++ b/interface/resources/qml/styles/IconButtonStyle.qml @@ -0,0 +1,15 @@ +ButtonStyle { + background: Item { anchors.fill: parent } + label: Text { + id: icon + width: height + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + font.family: iconFont.name + font.pointSize: 18 + property alias unicode: icon.text + FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; } + text: control.text + color: control.enabled ? "white" : "dimgray" + } +} diff --git a/interface/resources/qml/styles/MenuButtonStyle.qml b/interface/resources/qml/styles/MenuButtonStyle.qml new file mode 100644 index 0000000000..1dca89ffea --- /dev/null +++ b/interface/resources/qml/styles/MenuButtonStyle.qml @@ -0,0 +1,24 @@ +import "../controls" +import "." + +ButtonStyle { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + padding { + top: 8 + left: 12 + right: 12 + bottom: 8 + } + background: Border { + anchors.fill: parent + color: "#00000000" + borderColor: "red" + } + label: Text { + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.text + color: control.enabled ? myPalette.text : myPalette.dark + } +} From 8cb298a55b9ed36ad161c21d50021aa97cc22707 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 18:11:42 -0700 Subject: [PATCH 271/401] Working on menus --- interface/CMakeLists.txt | 2 +- .../resources/fonts/fontawesome-webfont.ttf | Bin 0 -> 122092 bytes interface/resources/qml/AddressBarDialog.qml | 1 + interface/resources/qml/HifiAction.qml | 20 + interface/resources/qml/LoginDialog.qml | 1 + interface/resources/qml/Menu.qml | 375 +++++++++++++ interface/resources/qml/MenuTest.qml | 12 - interface/resources/qml/MessageDialog.qml | 1 - interface/resources/qml/controls/Dialog.qml | 5 +- .../resources/qml/controls/MenuButton.qml | 6 +- .../resources/qml/styles/MenuButtonStyle.qml | 20 +- interface/src/Application.cpp | 109 ++-- interface/src/Application.h | 6 +- interface/src/Bookmarks.cpp | 67 +-- interface/src/Bookmarks.h | 13 +- interface/src/Menu.cpp | 258 ++++++--- interface/src/Menu.h | 99 ++-- interface/src/devices/OculusManager.cpp | 2 +- interface/src/ui/HMDToolsDialog.cpp | 1 + interface/src/ui/LoginDialog.cpp | 17 +- interface/src/ui/MenuQml.cpp | 19 + interface/src/ui/MenuQml.h | 26 + interface/src/ui/RunningScriptsWidget.cpp | 8 +- interface/src/ui/ToolWindow.cpp | 3 +- libraries/ui/CMakeLists.txt | 12 + libraries/ui/src/MenuConstants.cpp | 50 ++ libraries/ui/src/MenuConstants.h | 503 ++++++++++++++++++ .../src/MessageDialog.cpp | 0 .../{render-utils => ui}/src/MessageDialog.h | 0 .../src/OffscreenQmlDialog.cpp | 0 .../src/OffscreenQmlDialog.h | 0 .../{render-utils => ui}/src/OffscreenUi.cpp | 12 +- .../{render-utils => ui}/src/OffscreenUi.h | 33 ++ tests/render-utils/src/main.cpp | 108 +--- tests/ui/CMakeLists.txt | 15 + tests/ui/src/main.cpp | 302 +++++++++++ 36 files changed, 1717 insertions(+), 389 deletions(-) create mode 100644 interface/resources/fonts/fontawesome-webfont.ttf create mode 100644 interface/resources/qml/HifiAction.qml create mode 100644 interface/resources/qml/Menu.qml delete mode 100644 interface/resources/qml/MenuTest.qml create mode 100644 interface/src/ui/MenuQml.cpp create mode 100644 interface/src/ui/MenuQml.h create mode 100644 libraries/ui/CMakeLists.txt create mode 100644 libraries/ui/src/MenuConstants.cpp create mode 100644 libraries/ui/src/MenuConstants.h rename libraries/{render-utils => ui}/src/MessageDialog.cpp (100%) rename libraries/{render-utils => ui}/src/MessageDialog.h (100%) rename libraries/{render-utils => ui}/src/OffscreenQmlDialog.cpp (100%) rename libraries/{render-utils => ui}/src/OffscreenQmlDialog.h (100%) rename libraries/{render-utils => ui}/src/OffscreenUi.cpp (99%) rename libraries/{render-utils => ui}/src/OffscreenUi.h (78%) create mode 100644 tests/ui/CMakeLists.txt create mode 100644 tests/ui/src/main.cpp diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 7688036c94..b4e0e3a244 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -128,7 +128,7 @@ target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES}) # link required hifi libraries link_hifi_libraries(shared octree environment gpu model fbx networking entities avatars audio audio-client animation script-engine physics - render-utils entities-renderer) + render-utils entities-renderer ui) add_dependency_external_projects(sdl2) diff --git a/interface/resources/fonts/fontawesome-webfont.ttf b/interface/resources/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ed9372f8ea0fbaa04f42630a48887e4b38945345 GIT binary patch literal 122092 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 literal 0 HcmV?d00001 diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 4c2631aa6d..d12737081e 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -1,6 +1,7 @@ import Hifi 1.0 import QtQuick 2.3 import "controls" +import "styles" Dialog { title: "Go to..." diff --git a/interface/resources/qml/HifiAction.qml b/interface/resources/qml/HifiAction.qml new file mode 100644 index 0000000000..8e6e7d59b4 --- /dev/null +++ b/interface/resources/qml/HifiAction.qml @@ -0,0 +1,20 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.3 + +Action { + property string name + objectName: name + "HifiAction" + text: qsTr(name) + + signal triggeredByName(string name); + signal toggledByName(string name); + + onTriggered: { + triggeredByName(name); + } + + onToggled: { + toggledByName(name, checked); + } +} + diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index 22162e323f..b3b926bbe3 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -2,6 +2,7 @@ import Hifi 1.0 import QtQuick 2.3 import QtQuick.Controls.Styles 1.3 import "controls" +import "styles" Dialog { title: "Login" diff --git a/interface/resources/qml/Menu.qml b/interface/resources/qml/Menu.qml new file mode 100644 index 0000000000..f76b9485fb --- /dev/null +++ b/interface/resources/qml/Menu.qml @@ -0,0 +1,375 @@ +import Hifi 1.0 as Hifi +import QtQuick 2.4 +import QtQuick.Controls 1.3 +import QtQuick.Controls.Styles 1.3 +import "controls" +import "styles" + +Hifi.Menu { + id: root + anchors.fill: parent + objectName: "Menu" + enabled: false + opacity: 0.0 + property int animationDuration: 200 + HifiPalette { id: hifiPalette } + + onEnabledChanged: { + if (enabled && columns.length == 0) { + pushColumn(menu.items); + } + opacity = enabled ? 1.0 : 0.0 + if (enabled) { + forceActiveFocus() + } + } + + // The actual animator + Behavior on opacity { + NumberAnimation { + duration: root.animationDuration + easing.type: Easing.InOutBounce + } + } + + onOpacityChanged: { + visible = (opacity != 0.0); + } + + onVisibleChanged: { + if (!visible) reset(); + } + + + property var menu: Menu {} + property var models: [] + property var columns: [] + property var itemBuilder: Component { + Text { + SystemPalette { id: sp; colorGroup: SystemPalette.Active } + + id: thisText + property var source + property var root + property var listViewIndex + property var listView + text: typedText() + height: implicitHeight + width: implicitWidth + color: source.enabled ? "black" : "gray" + + onImplicitWidthChanged: { + width = implicitWidth + if (listView) { + listView.minWidth = Math.max(listView.minWidth, implicitWidth); + listView.recalculateSize(); + } + } + + onImplicitHeightChanged: { + height = implicitHeight + } + + function typedText() { + switch(source.type) { + case 2: + return source.title; + case 1: + return source.text; + case 0: + return "-----" + } + } + + MouseArea { + id: mouseArea + acceptedButtons: Qt.LeftButton + anchors.fill: parent + onClicked: { + listView.currentIndex = listViewIndex + parent.root.selectItem(parent.source); + } + } + } + } + + + property var menuBuilder: Component { + Border { + SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } + x: root.models.length * 60; + anchors.verticalCenter: parent.verticalCenter + border.color: hifiPalette.hifiBlue + color: sysPalette.window + + ListView { + spacing: 6 + property int outerMargin: 8 + property real minWidth: 0 + anchors.fill: parent + anchors.margins: outerMargin + id: listView + height: root.height + currentIndex: -1 + + onCountChanged: { + recalculateSize() + } + + function recalculateSize() { + var newHeight = 0 + var newWidth = minWidth; + for (var i = 0; i < children.length; ++i) { + var item = children[i]; + newHeight += item.height + } + parent.height = newHeight + outerMargin * 2; + parent.width = newWidth + outerMargin * 2 + } + + highlight: Rectangle { + width: 0; height: 32 + color: sysPalette.highlight + y: (listView.currentItem) ? listView.currentItem.y : 0; + Behavior on y { + NumberAnimation { + duration: 100 + easing.type: Easing.InOutQuint + } + } + } + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Escape: + console.log("Backing out") + root.popColumn() + event.accepted = true; + } + } + + + property int columnIndex: root.models.length - 1 + model: root.models[columnIndex] + delegate: Loader { + id: loader + sourceComponent: root.itemBuilder + Binding { + target: loader.item + property: "root" + value: root + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "source" + value: modelData + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "listViewIndex" + value: index + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "listView" + value: listView + when: loader.status == Loader.Ready + } + } + + } + + } + } + + + function lastColumn() { + return columns[root.columns.length - 1]; + } + + function pushColumn(items) { + models.push(items) + if (columns.length) { + var oldColumn = lastColumn(); + oldColumn.enabled = false; + oldColumn.opacity = 0.5; + } + var newColumn = menuBuilder.createObject(root); + columns.push(newColumn); + newColumn.forceActiveFocus(); + } + + function popColumn() { + if (columns.length > 1) { + var curColumn = columns.pop(); + console.log(curColumn); + curColumn.visible = false; + curColumn.destroy(); + models.pop(); + curColumn = lastColumn(); + curColumn.enabled = true; + curColumn.opacity = 1.0; + curColumn.forceActiveFocus(); + } else { + enabled = false; + } + } + + function selectItem(source) { + switch (source.type) { + case 2: + pushColumn(source.items) + break; + case 1: + console.log("Triggering " + source.text); + source.trigger() + enabled = false + break; + case 0: + break; + } + } + + function reset() { + console.log("Resettting") + while (columns.length > 1) { + popColumn(); + } + lastColumn().children[0].currentIndex = -1 + console.log(lastColumn().children[0]) + } + + /* + HifiMenu { + id: rootMenu + Menu { + id: menu + Menu { + title: "File" + MenuItem { + action: HifiAction { + name: rootMenu.login + } + } + MenuItem { + action: HifiAction { + name: "Test" + checkable: true + } + } + MenuItem { + action: HifiAction { + name: rootMenu.quit + } + } + } + Menu { + title: "Edit" + MenuItem { + action: HifiAction { + text: "Copy" + shortcut: StandardKey.Copy + } + } + MenuItem { + action: HifiAction { + text: "Cut" + shortcut: StandardKey.Cut + } + } + MenuItem { + action: HifiAction { + text: "Paste" + shortcut: StandardKey.Paste + } + } + MenuItem { + action: HifiAction { + text: "Undo" + shortcut: StandardKey.Undo + } + } + MenuItem { + action: HifiAction { + text: "Redo" + shortcut: StandardKey.Redo + } + } + MenuItem { + action: HifiAction { + name: rootMenu.attachments + } + } + MenuItem { + action: HifiAction { + name: rootMenu.animations + } + } + } + + Menu { + title: "Scripts" + MenuItem { + action: HifiAction { + name: rootMenu.scriptEditor + } + } + MenuItem { + action: HifiAction { + name: rootMenu.loadScript + } + } + MenuItem { + action: HifiAction { + name: rootMenu.loadScriptURL + } + } + MenuItem { + action: HifiAction { + name: rootMenu.stopAllScripts + } + } + MenuItem { + action: HifiAction { + name: rootMenu.reloadAllScripts + } + } + MenuItem { + action: HifiAction { + name: rootMenu.runningScripts + } + } + } + Menu { + title: "Location" + MenuItem { + action: HifiAction { + name: rootMenu.addressBar + } + } + MenuItem { + action: HifiAction { + name: rootMenu.copyAddress + } + } + MenuItem { + action: HifiAction { + name: rootMenu.copyPath + } + } + } + } + } + */ + + MouseArea { + anchors.fill: parent + id: mouseArea + acceptedButtons: Qt.RightButton + onClicked: { + root.popColumn(); + } + } +} diff --git a/interface/resources/qml/MenuTest.qml b/interface/resources/qml/MenuTest.qml deleted file mode 100644 index 13fc997791..0000000000 --- a/interface/resources/qml/MenuTest.qml +++ /dev/null @@ -1,12 +0,0 @@ -import QtQuick 2.4 -import QtQuick.Controls 1.3 -import QtQuick.Controls.Styles 1.3 - -Item { - anchors.fill: parent - - Rectangle { - anchors.fill: parent - color: "red" - } -} diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml index c7c1b23223..eaf304b16a 100644 --- a/interface/resources/qml/MessageDialog.qml +++ b/interface/resources/qml/MessageDialog.qml @@ -41,7 +41,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.2 import QtQuick.Controls 1.2 -import QtQuick.Window 2.1 import QtQuick.Dialogs 1.2 import "controls" diff --git a/interface/resources/qml/controls/Dialog.qml b/interface/resources/qml/controls/Dialog.qml index 78642eaef4..109889f738 100644 --- a/interface/resources/qml/controls/Dialog.qml +++ b/interface/resources/qml/controls/Dialog.qml @@ -30,14 +30,13 @@ Item { property string frameColor: hifiPalette.hifiBlue property string backgroundColor: sysPalette.window property string headerBackgroundColor: sysPalette.dark - clip: true - enabled: false - scale: 0.0 /* * Support for animating the dialog in and out. */ + enabled: false + scale: 0.0 // The offscreen UI will enable an object, rather than manipulating it's // visibility, so that we can do animations in both directions. Because diff --git a/interface/resources/qml/controls/MenuButton.qml b/interface/resources/qml/controls/MenuButton.qml index 25ad4b2c48..740995a199 100644 --- a/interface/resources/qml/controls/MenuButton.qml +++ b/interface/resources/qml/controls/MenuButton.qml @@ -1,9 +1,5 @@ import QtQuick 2.3 import QtQuick.Controls 1.3 as Original -import QtQuick.Controls.Styles 1.3 import "../styles" +import "../controls" -Original.Button { - style: MenuButtonStyle { - } -} diff --git a/interface/resources/qml/styles/MenuButtonStyle.qml b/interface/resources/qml/styles/MenuButtonStyle.qml index 1dca89ffea..f30ade3d33 100644 --- a/interface/resources/qml/styles/MenuButtonStyle.qml +++ b/interface/resources/qml/styles/MenuButtonStyle.qml @@ -1,24 +1,22 @@ +import QtQuick 2.4 +import QtQuick.Controls.Styles 1.3 import "../controls" import "." ButtonStyle { - SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + HifiPalette { id: hifiPalette } padding { - top: 8 - left: 12 - right: 12 - bottom: 8 + top: 2 + left: 4 + right: 4 + bottom: 2 } - background: Border { - anchors.fill: parent - color: "#00000000" - borderColor: "red" - } + background: Item {} label: Text { renderType: Text.NativeRendering verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter text: control.text - color: control.enabled ? myPalette.text : myPalette.dark + color: control.enabled ? "yellow" : "brown" } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b7ba384a97..c435ca2f0b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -149,6 +149,23 @@ extern "C" { } #endif +enum CustomEventTypes { + Lambda = QEvent::User + 1 +}; + +class LambdaEvent : public QEvent { + std::function _fun; +public: + LambdaEvent(const std::function & fun) : + QEvent(static_cast(Lambda)), _fun(fun) { + } + LambdaEvent(std::function && fun) : + QEvent(static_cast(Lambda)), _fun(fun) { + } + void call() { _fun(); } +}; + + using namespace std; // Starfield information @@ -345,9 +362,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _bookmarks = new Bookmarks(); // Before setting up the menu - // call Menu getInstance static method to set up the menu - _window->setMenuBar(Menu::getInstance()); - _runningScriptsWidget = new RunningScriptsWidget(_window); // start the nodeThread so its event loop is running @@ -497,8 +511,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); - _fullscreenMenuWidget->setParent(_glWidget); - _menuBarHeight = Menu::getInstance()->height(); if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) { setFullscreen(true); // Initialize menu bar show/hide } @@ -712,6 +724,13 @@ void Application::initializeGL() { initDisplay(); qCDebug(interfaceapp, "Initialized Display."); + // The UI can't be created until the primary OpenGL + // context is created, because it needs to share + // texture resources + initializeUi(); + qCDebug(interfaceapp, "Initialized Offscreen UI."); + _glWidget->makeCurrent(); + init(); qCDebug(interfaceapp, "init() complete."); @@ -740,11 +759,6 @@ void Application::initializeGL() { // update before the first render update(1.0f / _fps); - // The UI can't be created until the primary OpenGL - // context is created, because it needs to share - // texture resources - initializeUi(); - InfoView::showFirstTime(INFO_HELP_PATH); } @@ -764,6 +778,7 @@ void Application::initializeUi() { LoginDialog::registerType(); MarketplaceDialog::registerType(); MessageDialog::registerType(); + Menu::registerType(); auto offscreenUi = DependencyManager::get(); offscreenUi->create(_glWidget->context()->contextHandle()); @@ -898,9 +913,7 @@ void Application::runTests() { } void Application::audioMuteToggled() { - QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteAudio); - Q_CHECK_PTR(muteAction); - muteAction->setChecked(DependencyManager::get()->isMuted()); + Menu::getInstance()->setIsOptionChecked(MenuOption::MuteAudio, DependencyManager::get()->isMuted()); } void Application::aboutApp() { @@ -982,6 +995,10 @@ bool Application::importSVOFromURL(const QString& urlString) { bool Application::event(QEvent* event) { switch (event->type()) { + case Lambda: + ((LambdaEvent*)event)->call(); + return true; + case QEvent::MouseMove: mouseMoveEvent((QMouseEvent*)event); return true; @@ -1061,8 +1078,10 @@ bool Application::eventFilter(QObject* object, QEvent* event) { return false; } -void Application::keyPressEvent(QKeyEvent* event) { +static bool _altPressed; +void Application::keyPressEvent(QKeyEvent* event) { + _altPressed = event->key() == Qt::Key_Alt; _keysPressed.insert(event->key()); _controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts @@ -1314,6 +1333,9 @@ void Application::keyPressEvent(QKeyEvent* event) { } void Application::keyReleaseEvent(QKeyEvent* event) { + if (event->key() == Qt::Key_Alt && _altPressed) { + Menu::toggle(); + } _keysPressed.remove(event->key()); @@ -1420,18 +1442,6 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { return; } - if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen) - && !Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { - // Show/hide menu bar in fullscreen - if (event->globalY() > _menuBarHeight) { - _fullscreenMenuWidget->setFixedHeight(0); - Menu::getInstance()->setFixedHeight(0); - } else { - _fullscreenMenuWidget->setFixedHeight(_menuBarHeight); - Menu::getInstance()->setFixedHeight(_menuBarHeight); - } - } - _entities.mouseMoveEvent(event, deviceID); _controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts @@ -1439,7 +1449,6 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { if (_controllerScriptingInterface.isMouseCaptured()) { return; } - } void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { @@ -1724,34 +1733,6 @@ void Application::setFullscreen(bool fullscreen) { Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen); } -// The following code block is useful on platforms that can have a visible -// app menu in a fullscreen window. However the OSX mechanism hides the -// application menu for fullscreen apps, so the check is not required. -#ifndef Q_OS_MAC - if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { - if (fullscreen) { - // Menu hide() disables menu commands, and show() after hide() doesn't work with Rift VR display. - // So set height instead. - _window->menuBar()->setMaximumHeight(0); - } else { - _window->menuBar()->setMaximumHeight(QWIDGETSIZE_MAX); - } - } else { - if (fullscreen) { - // Move menu to a QWidget floating above _glWidget so that show/hide doesn't adjust viewport. - _menuBarHeight = Menu::getInstance()->height(); - Menu::getInstance()->setParent(_fullscreenMenuWidget); - Menu::getInstance()->setFixedWidth(_window->windowHandle()->screen()->size().width()); - _fullscreenMenuWidget->show(); - } else { - // Restore menu to being part of MainWindow. - _fullscreenMenuWidget->hide(); - _window->setMenuBar(Menu::getInstance()); - _window->menuBar()->setMaximumHeight(QWIDGETSIZE_MAX); - } - } -#endif - // Work around Qt bug that prevents floating menus being shown when in fullscreen mode. // https://bugreports.qt.io/browse/QTBUG-41883 // Known issue: Top-level menu items don't highlight when cursor hovers. This is probably a side-effect of the work-around. @@ -2004,16 +1985,18 @@ void Application::init() { OculusManager::connect(); if (OculusManager::isConnected()) { - QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), - "trigger", - Qt::QueuedConnection); + // perform as a post-event so that the code is run after init is complete + qApp->postLambdaEvent([] { + Menu::getInstance()->triggerOption(MenuOption::Fullscreen); + }); } TV3DManager::connect(); if (TV3DManager::isConnected()) { - QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), - "trigger", - Qt::QueuedConnection); + // perform as a post-event so that the code is run after init is complete + qApp->postLambdaEvent([] { + Menu::getInstance()->triggerOption(MenuOption::Fullscreen); + }); } _timerStart.start(); @@ -4434,3 +4417,7 @@ void Application::friendsWindowClosed() { delete _friendsWindow; _friendsWindow = NULL; } + +void Application::postLambdaEvent(std::function f) { + QCoreApplication::postEvent(this, new LambdaEvent(f)); +} diff --git a/interface/src/Application.h b/interface/src/Application.h index 89de18dde5..f63f548c47 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -147,6 +148,8 @@ public: Application(int& argc, char** argv, QElapsedTimer &startup_time); ~Application(); + void postLambdaEvent(std::function f); + void loadScripts(); QString getPreviousScriptLocation(); void setPreviousScriptLocation(const QString& previousScriptLocation); @@ -620,9 +623,6 @@ private: void checkSkeleton(); - QWidget* _fullscreenMenuWidget = new QWidget(); - int _menuBarHeight; - QHash _acceptedExtensions; QList _domainConnectionRefusals; diff --git a/interface/src/Bookmarks.cpp b/interface/src/Bookmarks.cpp index 4f022623dc..5af8234c7f 100644 --- a/interface/src/Bookmarks.cpp +++ b/interface/src/Bookmarks.cpp @@ -84,13 +84,16 @@ void Bookmarks::persistToFile() { saveFile.write(data); } -void Bookmarks::setupMenus(Menu* menubar, QMenu* menu) { +void Bookmarks::setupMenus(const QString & parentMenu) { // Add menus/actions - menubar->addActionToQMenuAndActionHash(menu, MenuOption::BookmarkLocation, 0, - this, SLOT(bookmarkLocation())); - _bookmarksMenu = menu->addMenu(MenuOption::Bookmarks); - _deleteBookmarksAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::DeleteBookmark, 0, - this, SLOT(deleteBookmark())); + Menu * menu = Menu::getInstance(); + menu->addMenuItem(parentMenu, MenuOption::BookmarkLocation, [this] { + bookmarkLocation(); + }); + menu->addMenu(parentMenu, MenuOption::Bookmarks); + menu->addMenuItem(parentMenu, MenuOption::DeleteBookmark, [this] { + deleteBookmark(); + }); // Enable/Disable menus as needed enableMenuItems(_bookmarks.count() > 0); @@ -99,7 +102,7 @@ void Bookmarks::setupMenus(Menu* menubar, QMenu* menu) { for (auto it = _bookmarks.begin(); it != _bookmarks.end(); ++it ) { QString bookmarkName = it.key(); QString bookmarkAddress = it.value().toString(); - addLocationToMenu(menubar, bookmarkName, bookmarkAddress); + addLocationToMenu(bookmarkName, bookmarkAddress); } } @@ -134,29 +137,20 @@ void Bookmarks::bookmarkLocation() { if (duplicateBookmarkMessage.exec() == QMessageBox::No) { return; } - removeLocationFromMenu(menubar, bookmarkName); + removeLocationFromMenu(bookmarkName); } - addLocationToMenu(menubar, bookmarkName, bookmarkAddress); + addLocationToMenu(bookmarkName, bookmarkAddress); insert(bookmarkName, bookmarkAddress); // Overwrites any item with the same bookmarkName. enableMenuItems(true); } -void Bookmarks::teleportToBookmark() { - QAction* action = qobject_cast(sender()); - QString address = action->data().toString(); - DependencyManager::get()->handleLookupString(address); -} - void Bookmarks::deleteBookmark() { - QStringList bookmarkList; - QList menuItems = _bookmarksMenu->actions(); - for (int i = 0; i < menuItems.count(); i += 1) { - bookmarkList.append(menuItems[i]->text()); - } - + bookmarkList.append(_bookmarks.keys()); + + QInputDialog deleteBookmarkDialog(qApp->getWindow()); deleteBookmarkDialog.setWindowTitle("Delete Bookmark"); deleteBookmarkDialog.setLabelText("Select the bookmark to delete"); @@ -174,34 +168,29 @@ void Bookmarks::deleteBookmark() { return; } - removeLocationFromMenu(Menu::getInstance(), bookmarkName); + removeLocationFromMenu(bookmarkName); remove(bookmarkName); - - if (_bookmarksMenu->actions().count() == 0) { + + if (_bookmarks.keys().isEmpty()) { enableMenuItems(false); } } void Bookmarks::enableMenuItems(bool enabled) { - if (_bookmarksMenu) { - _bookmarksMenu->setEnabled(enabled); - } - if (_deleteBookmarksAction) { - _deleteBookmarksAction->setEnabled(enabled); - } + Menu* menu = Menu::getInstance(); + menu->enableMenuItem(MenuOption::Bookmarks, enabled); + menu->enableMenuItem(MenuOption::DeleteBookmark, enabled); } -void Bookmarks::addLocationToMenu(Menu* menubar, QString& name, QString& address) { - QAction* teleportAction = new QAction(_bookmarksMenu); - teleportAction->setData(address); - connect(teleportAction, SIGNAL(triggered()), this, SLOT(teleportToBookmark())); - - menubar->addActionToQMenuAndActionHash(_bookmarksMenu, teleportAction, - name, 0, QAction::NoRole); +void Bookmarks::addLocationToMenu(QString& name, QString& address) { + + Menu::getInstance()->addMenuItem(MenuOption::Bookmarks, name, [=] { + DependencyManager::get()->handleLookupString(address); + }); } -void Bookmarks::removeLocationFromMenu(Menu* menubar, QString& name) { - menubar->removeAction(_bookmarksMenu, name); +void Bookmarks::removeLocationFromMenu(QString& name) { + Menu::getInstance()->removeMenuItem(name); } diff --git a/interface/src/Bookmarks.h b/interface/src/Bookmarks.h index 59f9efb1b1..d996d7c0f0 100644 --- a/interface/src/Bookmarks.h +++ b/interface/src/Bookmarks.h @@ -26,19 +26,16 @@ class Bookmarks: public QObject { public: Bookmarks(); - void setupMenus(Menu* menubar, QMenu* menu); + void setupMenus(const QString & menu); private slots: void bookmarkLocation(); - void teleportToBookmark(); void deleteBookmark(); private: + // FIXME bookmarks should be more categorizable + // Can we leverage a system browser favorites API? QVariantMap _bookmarks; // { name: address, ... } - - QPointer _bookmarksMenu; - QPointer _deleteBookmarksAction; - const QString BOOKMARKS_FILENAME = "bookmarks.json"; QString _bookmarksFilename; @@ -50,8 +47,8 @@ private: void persistToFile(); void enableMenuItems(bool enabled); - void addLocationToMenu(Menu* menubar, QString& name, QString& address); - void removeLocationFromMenu(Menu* menubar, QString& name); + void addLocationToMenu(QString& name, QString& address); + void removeLocationFromMenu(QString& name); }; #endif // hifi_Bookmarks_h \ No newline at end of file diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9b9e93a4c9..026af1442f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -20,7 +21,7 @@ #include #include #include - +#include #include "Application.h" #include "AccountManager.h" #include "audio/AudioIOStatsRenderer.h" @@ -42,64 +43,176 @@ #include "Menu.h" -Menu* Menu::_instance = NULL; +// Proxy object to simplify porting over +HifiAction::HifiAction(const QString & menuOption) : _menuOption(menuOption) { +} + +//void HifiAction::setCheckable(bool) { +// Menu::getInstance()->set +// qFatal("Not implemented"); +//} + +void HifiAction::setChecked(bool) { + qFatal("Not implemented"); +} + +void HifiAction::setVisible(bool) { + qFatal("Not implemented"); +} + +const QString & HifiAction::shortcut() const { + qFatal("Not implemented"); + return ""; +} + +void HifiAction::setText(const QString &) { + qFatal("Not implemented"); +} + +void HifiAction::setTriggerAction(std::function f) { + qFatal("Not implemented"); +} + +void HifiAction::setToggleAction(std::function f) { + qFatal("Not implemented"); +} + +HIFI_QML_DEF(Menu) + + +Menu* Menu::_instance = nullptr; Menu* Menu::getInstance() { - static QMutex menuInstanceMutex; - - // lock the menu instance mutex to make sure we don't race and create two menus and crash - menuInstanceMutex.lock(); - + // Optimistic check for menu existence if (!_instance) { - qCDebug(interfaceapp, "First call to Menu::getInstance() - initing menu."); + static QMutex menuInstanceMutex; + withLock(menuInstanceMutex, [] { + if (!_instance) { + OffscreenUi * offscreenUi = DependencyManager::get().data(); + QQmlContext * qmlContext = offscreenUi->qmlContext(); + qmlContext->setContextProperty("foo", QVariant::fromValue(foo)); +// qmlContext->setContextProperty("presetsModel", QVariant::fromValue(dataList)); - _instance = new Menu(); + qCDebug(interfaceapp, "First call to Menu::getInstance() - initing menu."); + load([&](QQmlContext *, QQuickItem* item) { + _instance = dynamic_cast(item); + }); + if (!_instance) { + qFatal("Could not load menu QML"); + } else { + _instance->init(); + } + } + }); } - - menuInstanceMutex.unlock(); - return _instance; } -Menu::Menu() { - QMenu* fileMenu = addMenu("File"); +Menu::Menu(QQuickItem * parent) : QQuickItem(parent) { +} + +QObject * _rootMenu; +static const QString FILE_MENU{ "File" }; +static const QString EDIT_MENU{ "Edit" }; +static const QString TOOLS_MENU{ "Tools" }; +static const QString AVATAR_MENU{ "Avatar" }; + + +static const QString MENU_SUFFIX{ "__Menu" }; + +QObject * addMenu(QObject * parent, const QString & text) { + // FIXME add more checking here to ensure no name conflicts + QVariant returnedValue; + QMetaObject::invokeMethod(parent, "addMenu", + Q_RETURN_ARG(QVariant, returnedValue), + Q_ARG(QVariant, text)); + QObject * result = returnedValue.value(); + if (result) { + result->setObjectName(text + MENU_SUFFIX); + } + return result; +} + +class QQuickMenuItem; +QObject * addItem(QObject * parent, const QString & text) { + // FIXME add more checking here to ensure no name conflicts + QQuickMenuItem* returnedValue; + QMetaObject::invokeMethod(parent, "addItem", + Q_RETURN_ARG(QQuickMenuItem*, returnedValue), + Q_ARG(QString, text)); + QObject* result = reinterpret_cast(returnedValue); + if (result) { + result->setObjectName(text + MENU_SUFFIX); + } + return result; +} + +void Menu::init() { + _rootMenu = property("menu").value(); + QObject * fileMenu = ::addMenu(_rootMenu, FILE_MENU); -#ifdef Q_OS_MAC - addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); -#endif auto dialogsManager = DependencyManager::get(); AccountManager& accountManager = AccountManager::getInstance(); { - addActionToQMenuAndActionHash(fileMenu, MenuOption::Login); - + ::addItem(fileMenu, MenuOption::Login); + // connect to the appropriate signal of the AccountManager so that we can change the Login/Logout menu item connect(&accountManager, &AccountManager::profileChanged, - dialogsManager.data(), &DialogsManager::toggleLoginDialog); + dialogsManager.data(), &DialogsManager::toggleLoginDialog); connect(&accountManager, &AccountManager::logoutComplete, - dialogsManager.data(), &DialogsManager::toggleLoginDialog); + dialogsManager.data(), &DialogsManager::toggleLoginDialog); } - - addDisabledActionAndSeparator(fileMenu, "Scripts"); - addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, - qApp, SLOT(loadDialog())); - addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL, - Qt::CTRL | Qt::SHIFT | Qt::Key_O, qApp, SLOT(loadScriptURLDialog())); - addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, qApp, SLOT(stopAllScripts())); - addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::Key_R, - qApp, SLOT(reloadAllScripts())); - addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, - qApp, SLOT(toggleRunningScriptsWidget())); - addDisabledActionAndSeparator(fileMenu, "Location"); - qApp->getBookmarks()->setupMenus(this, fileMenu); + +#ifdef Q_OS_MAC + addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); +#endif + + { + static const QString SCRIPTS_MENU{ "Scripts" }; + addMenu(FILE_MENU, SCRIPTS_MENU); + //Qt::CTRL | Qt::Key_O + addMenuItem(SCRIPTS_MENU, MenuOption::LoadScript, [=] { + qApp->loadDialog(); + }); + //Qt::CTRL | Qt::SHIFT | Qt::Key_O + addMenuItem(SCRIPTS_MENU, MenuOption::LoadScriptURL, [=] { + qApp->loadScriptURLDialog(); + }); + addMenuItem(SCRIPTS_MENU, MenuOption::StopAllScripts, [=] { + qApp->stopAllScripts(); + }); + //Qt::CTRL | Qt::Key_R, + addMenuItem(SCRIPTS_MENU, MenuOption::ReloadAllScripts, [=] { + qApp->reloadAllScripts(); + }); + // Qt::CTRL | Qt::Key_J, + addMenuItem(SCRIPTS_MENU, MenuOption::RunningScripts, [=] { + qApp->toggleRunningScriptsWidget(); + }); + } + + { + static const QString LOCATION_MENU{ "Location" }; + addMenu(FILE_MENU, LOCATION_MENU); + qApp->getBookmarks()->setupMenus(LOCATION_MENU); + //Qt::CTRL | Qt::Key_L + addMenuItem(LOCATION_MENU, MenuOption::AddressBar, [=] { + auto dialogsManager = DependencyManager::get(); + dialogsManager->toggleAddressBar(); + }); + addMenuItem(LOCATION_MENU, MenuOption::CopyAddress, [=] { + auto addressManager = DependencyManager::get(); + addressManager->copyAddress(); + }); + addMenuItem(LOCATION_MENU, MenuOption::CopyAddress, [=] { + auto addressManager = DependencyManager::get(); + addressManager->copyPath(); + }); + } +#if 0 - addActionToQMenuAndActionHash(fileMenu, - MenuOption::AddressBar, - Qt::CTRL | Qt::Key_L, - dialogsManager.data(), - SLOT(toggleAddressBar())); - auto addressManager = DependencyManager::get(); addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyAddress, 0, addressManager.data(), SLOT(copyAddress())); addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyPath, 0, @@ -556,15 +669,17 @@ Menu::Menu() { QAction* aboutAction = helpMenu->addAction(MenuOption::AboutApp); connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutApp())); #endif +#endif } void Menu::loadSettings() { - scanMenuBar(&Menu::loadAction); +// scanMenuBar(&Menu::loadAction); } void Menu::saveSettings() { - scanMenuBar(&Menu::saveAction); +// scanMenuBar(&Menu::saveAction); } +#if 0 void Menu::loadAction(Settings& settings, QAction& action) { if (action.isChecked() != settings.value(action.text(), action.isChecked()).toBool()) { @@ -708,36 +823,20 @@ void Menu::removeAction(QMenu* menu, const QString& actionName) { _actionHash.remove(actionName); } +#endif + void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(Menu::getInstance(), "setIsOptionChecked", Qt::BlockingQueuedConnection, - Q_ARG(const QString&, menuOption), - Q_ARG(bool, isChecked)); - return; - } - QAction* menu = _actionHash.value(menuOption); - if (menu) { - menu->setChecked(isChecked); - } } bool Menu::isOptionChecked(const QString& menuOption) const { - const QAction* menu = _actionHash.value(menuOption); - if (menu) { - return menu->isChecked(); - } return false; } void Menu::triggerOption(const QString& menuOption) { - QAction* action = _actionHash.value(menuOption); - if (action) { - action->trigger(); - } else { - qCDebug(interfaceapp) << "NULL Action for menuOption '" << menuOption << "'"; - } } +#if 0 + QAction* Menu::getActionForOption(const QString& menuOption) { return _actionHash.value(menuOption); } @@ -951,15 +1050,12 @@ void Menu::addMenuItem(const MenuItemProperties& properties) { QMenuBar::repaint(); } } +#endif -void Menu::removeMenuItem(const QString& menu, const QString& menuitem) { - QMenu* menuObj = getMenu(menu); - if (menuObj) { - removeAction(menuObj, menuitem); - QMenuBar::repaint(); - } +void Menu::removeMenuItem(const QString& menuitem) { }; +#if 0 bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { QAction* menuItemAction = _actionHash.value(menuitem); if (menuItemAction) { @@ -967,3 +1063,29 @@ bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { } return false; }; + +#endif + +void Menu::setOptionText(const QString& menuitem, const QString& text) { +} + +void Menu::addMenu(const QString& parentMenu, const QString& text) { +} + +void Menu::addMenuItem(const QString& parentMenu, const QString& menuItem) { +} + +void Menu::addMenuItem(const QString& parentMenu, const QString& menuItem, std::function f) { + addMenuItem(parentMenu, menuItem); + setOptionTriggerAction(parentMenu, f); +} + +void Menu::enableMenuItem(const QString& menuItem, bool enable) { +} + +void Menu::setOptionTriggerAction(const QString& menuOption, std::function f) { + _triggerActions[menuOption] = f; +} +void Menu::setOptionToggleAction(const QString& menuOption, std::function f) { + _toggleActions[menuOption] = f; +} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 5a162d31bc..04275fcb32 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -18,85 +18,69 @@ #include #include #include - +#include #include +#include + #include "DiscoverabilityManager.h" class Settings; -class Menu : public QMenuBar { - Q_OBJECT +// Proxy object to simplify porting over +class HifiAction { + const QString _menuOption; public: + HifiAction(const QString & menuOption); + void setCheckable(bool); + void setChecked(bool); + void setVisible(bool); + const QString & shortcut() const; + void setText(const QString &); + void setTriggerAction(std::function); + void setToggleAction(std::function); +}; + +class Menu : public QQuickItem { + Q_OBJECT + HIFI_QML_DECL +public: + Menu(QQuickItem * parent = 0); static Menu* getInstance(); void loadSettings(); void saveSettings(); - - QMenu* getMenu(const QString& menuName); - - void triggerOption(const QString& menuOption); - QAction* getActionForOption(const QString& menuOption); - - QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu, - const QString& actionName, - const QKeySequence& shortcut = 0, - const QObject* receiver = NULL, - const char* member = NULL, - QAction::MenuRole role = QAction::NoRole, - int menuItemLocation = UNSPECIFIED_POSITION); - QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu, - QAction* action, - const QString& actionName = QString(), - const QKeySequence& shortcut = 0, - QAction::MenuRole role = QAction::NoRole, - int menuItemLocation = UNSPECIFIED_POSITION); - - void removeAction(QMenu* menu, const QString& actionName); - -public slots: - QMenu* addMenu(const QString& menuName); + HifiAction * getActionForOption(const QString& menuOption) { + return new HifiAction(menuOption); + } +// QMenu* addMenu(const QString& menuName); void removeMenu(const QString& menuName); bool menuExists(const QString& menuName); void addSeparator(const QString& menuName, const QString& separatorName); void removeSeparator(const QString& menuName, const QString& separatorName); void addMenuItem(const MenuItemProperties& properties); - void removeMenuItem(const QString& menuName, const QString& menuitem); + void removeMenuItem(const QString& menuitem); bool menuItemExists(const QString& menuName, const QString& menuitem); bool isOptionChecked(const QString& menuOption) const; void setIsOptionChecked(const QString& menuOption, bool isChecked); - + void triggerOption(const QString& menuOption); + void setOptionText(const QString& menuOption, const QString & text); + void setOptionTriggerAction(const QString& menuOption, std::function f); + void setOptionToggleAction(const QString& menuOption, std::function f); + void addMenuItem(const QString & parentMenu, const QString & menuOption, std::function f); + void addMenuItem(const QString & parentMenu, const QString & menuOption); + void addMenu(const QString & parentMenu, const QString & menuOption); + void enableMenuItem(const QString & menuOption, bool enabled = true); + +private: + void init(); + private: static Menu* _instance; - Menu(); - typedef void(*settingsAction)(Settings&, QAction&); - static void loadAction(Settings& settings, QAction& action); - static void saveAction(Settings& settings, QAction& action); - void scanMenuBar(settingsAction modifySetting); - void scanMenu(QMenu& menu, settingsAction modifySetting, Settings& settings); - - /// helper method to have separators with labels that are also compatible with OS X - void addDisabledActionAndSeparator(QMenu* destinationMenu, const QString& actionName, - int menuItemLocation = UNSPECIFIED_POSITION); - - QAction* addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu, - const QString& actionName, - const QKeySequence& shortcut = 0, - const bool checked = false, - const QObject* receiver = NULL, - const char* member = NULL, - int menuItemLocation = UNSPECIFIED_POSITION); - - QAction* getActionFromName(const QString& menuName, QMenu* menu); - QMenu* getSubMenuFromName(const QString& menuName, QMenu* menu); - QMenu* getMenuParent(const QString& menuName, QString& finalMenuPart); - - QAction* getMenuAction(const QString& menuName); - int findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem); - int positionBeforeSeparatorIfNeeded(QMenu* menu, int requestedPosition); - - QHash _actionHash; + QHash> _triggerActions; + QHash> _toggleActions; + }; namespace MenuOption { @@ -251,5 +235,4 @@ namespace MenuOption { const QString VisibleToNoOne = "No one"; const QString Wireframe = "Wireframe"; } - #endif // hifi_Menu_h diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 7d719873f4..043d5bf40d 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -216,7 +216,7 @@ void OculusManager::connect() { _isConnected = false; // we're definitely not in "VR mode" so tell the menu that - Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); + Menu::getInstance()->setIsOptionChecked(MenuOption::EnableVRMode, false); } } diff --git a/interface/src/ui/HMDToolsDialog.cpp b/interface/src/ui/HMDToolsDialog.cpp index 4a899a641e..cedb26fd9b 100644 --- a/interface/src/ui/HMDToolsDialog.cpp +++ b/interface/src/ui/HMDToolsDialog.cpp @@ -8,6 +8,7 @@ // 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 diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 5726818b2d..b8a4d6006b 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -25,19 +25,18 @@ LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent), _root } void LoginDialog::toggleAction() { - AccountManager& accountManager = AccountManager::getInstance(); - QAction* loginAction = Menu::getInstance()->getActionForOption(MenuOption::Login); - Q_CHECK_PTR(loginAction); - disconnect(loginAction, 0, 0, 0); - + AccountManager & accountManager = AccountManager::getInstance(); + Menu* menu = Menu::getInstance(); if (accountManager.isLoggedIn()) { // change the menu item to logout - loginAction->setText("Logout " + accountManager.getAccountInfo().getUsername()); - connect(loginAction, &QAction::triggered, &accountManager, &AccountManager::logout); + menu->setOptionText(MenuOption::Login, "Logout " + accountManager.getAccountInfo().getUsername()); + menu->setOptionTriggerAction(MenuOption::Login, [] { + AccountManager::getInstance().logout(); + }); } else { // change the menu item to login - loginAction->setText("Login"); - connect(loginAction, &QAction::triggered, [] { + menu->setOptionText(MenuOption::Login, "Login"); + menu->setOptionTriggerAction(MenuOption::Login, [] { LoginDialog::show(); }); } diff --git a/interface/src/ui/MenuQml.cpp b/interface/src/ui/MenuQml.cpp new file mode 100644 index 0000000000..991b7e4574 --- /dev/null +++ b/interface/src/ui/MenuQml.cpp @@ -0,0 +1,19 @@ +// +// MenuQml.cpp +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 "Application.h" +#include "MenuQml.h" + +QML_DIALOG_DEF(MenuQml) + +MenuQml::MenuQml(QQuickItem *parent) : QQuickItem(parent) { + auto menu = Menu::getInstance(); + +} diff --git a/interface/src/ui/MenuQml.h b/interface/src/ui/MenuQml.h new file mode 100644 index 0000000000..a007ec8735 --- /dev/null +++ b/interface/src/ui/MenuQml.h @@ -0,0 +1,26 @@ +// +// MenuQml.h +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 +// + +#pragma once +#ifndef hifi_MenuQml_h +#define hifi_MenuQml_h + +#include + +class MenuQml : public QQuickItem +{ + Q_OBJECT + QML_DIALOG_DECL + +public: + MenuQml(QQuickItem *parent = 0); +}; + +#endif diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index f892deabb6..4c8d29d84c 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -44,8 +44,9 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : connect(&_scriptsModelFilter, &QSortFilterProxyModel::modelReset, this, &RunningScriptsWidget::selectFirstInList); - QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText); - ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts."); + // FIXME + // QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText); + // ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts."); _scriptsModelFilter.setSourceModel(&_scriptsModel); _scriptsModelFilter.sort(0, Qt::AscendingOrder); @@ -161,8 +162,7 @@ void RunningScriptsWidget::showEvent(QShowEvent* event) { QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry(); int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); - int menuBarHeight = Menu::getInstance()->geometry().height(); - int topMargin = titleBarHeight + menuBarHeight; + int topMargin = titleBarHeight; setGeometry(parentGeometry.topLeft().x(), parentGeometry.topLeft().y() + topMargin, size().width(), parentWidget()->height() - topMargin); diff --git a/interface/src/ui/ToolWindow.cpp b/interface/src/ui/ToolWindow.cpp index 5888b83f4a..4edae4f2a4 100644 --- a/interface/src/ui/ToolWindow.cpp +++ b/interface/src/ui/ToolWindow.cpp @@ -38,8 +38,7 @@ bool ToolWindow::event(QEvent* event) { QRect mainGeometry = mainWindow->geometry(); int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); - int menuBarHeight = Menu::getInstance()->geometry().height(); - int topMargin = titleBarHeight + menuBarHeight; + int topMargin = titleBarHeight; _lastGeometry = QRect(mainGeometry.topLeft().x(), mainGeometry.topLeft().y() + topMargin, DEFAULT_WIDTH, mainGeometry.height() - topMargin); diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt new file mode 100644 index 0000000000..36a0a1a846 --- /dev/null +++ b/libraries/ui/CMakeLists.txt @@ -0,0 +1,12 @@ +set(TARGET_NAME ui) + +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(OpenGL Network Qml Quick Script) + +link_hifi_libraries(render-utils shared) + +add_dependency_external_projects(glm) +find_package(GLM REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + + diff --git a/libraries/ui/src/MenuConstants.cpp b/libraries/ui/src/MenuConstants.cpp new file mode 100644 index 0000000000..eeaf7b456b --- /dev/null +++ b/libraries/ui/src/MenuConstants.cpp @@ -0,0 +1,50 @@ +#include "MenuConstants.h" +#include + +QML_DIALOG_DEF(HifiMenu) + +static bool init = false; + +HifiMenu::HifiMenu(QQuickItem * parent) : QQuickItem(parent) { + this->setEnabled(false); + qWarning() << "Setting up connection"; + connect(this, &HifiMenu::enabledChanged, this, [=]() { + if (init) { + return; + } + init = true; + foreach(QObject * action, findChildren(QRegularExpression(".*HifiAction"))) { + connect(action, SIGNAL(triggeredByName(QString)), this, SLOT(onTriggeredByName(QString))); + connect(action, SIGNAL(toggledByName(QString)), this, SLOT(onToggledByName(QString))); + } + }); +} + +void HifiMenu::onTriggeredByName(const QString & name) { + qDebug() << name << " triggered"; + if (triggerActions.count(name)) { + triggerActions[name](); + } +} + +void HifiMenu::onToggledByName(const QString & name) { + qDebug() << name << " toggled"; + if (triggerActions.count(name)) { + if (toggleActions.count(name)) { + QObject * action = findChild(name + "HifiAction"); + bool checked = action->property("checked").toBool(); + toggleActions[name](checked); + } + } +} + +QHash> HifiMenu::triggerActions; +QHash> HifiMenu::toggleActions; + +void HifiMenu::setToggleAction(const QString & name, std::function f) { + toggleActions[name] = f; +} + +void HifiMenu::setTriggerAction(const QString & name, std::function f) { + triggerActions[name] = f; +} diff --git a/libraries/ui/src/MenuConstants.h b/libraries/ui/src/MenuConstants.h new file mode 100644 index 0000000000..e2d50b10a6 --- /dev/null +++ b/libraries/ui/src/MenuConstants.h @@ -0,0 +1,503 @@ +// +// MenuConstants.h +// +// Created by Bradley Austin Davis on 2015/04/21 +// Copyright 2015 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 +// + +#pragma once +#ifndef hifi_MenuContants_h +#define hifi_MenuConstants_h + +#include +#include +#include +#include "OffscreenQmlDialog.h" + +namespace MenuOption { + const QString AboutApp = "About Interface"; + const QString AddRemoveFriends = "Add/Remove Friends..."; + const QString AddressBar = "Show Address Bar"; + const QString AlignForearmsWithWrists = "Align Forearms with Wrists"; + const QString AlternateIK = "Alternate IK"; + const QString AmbientOcclusion = "Ambient Occlusion"; + const QString Animations = "Animations..."; + const QString Atmosphere = "Atmosphere"; + const QString Attachments = "Attachments..."; + const QString AudioNoiseReduction = "Audio Noise Reduction"; + const QString AudioScope = "Show Scope"; + const QString AudioScopeFiftyFrames = "Fifty"; + const QString AudioScopeFiveFrames = "Five"; + const QString AudioScopeFrames = "Display Frames"; + const QString AudioScopePause = "Pause Scope"; + const QString AudioScopeTwentyFrames = "Twenty"; + const QString AudioStats = "Audio Stats"; + const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams"; + const QString BandwidthDetails = "Bandwidth Details"; + const QString BlueSpeechSphere = "Blue Sphere While Speaking"; + const QString BookmarkLocation = "Bookmark Location"; + const QString Bookmarks = "Bookmarks"; + const QString CascadedShadows = "Cascaded"; + const QString CachesSize = "RAM Caches Size"; + const QString Chat = "Chat..."; + const QString Collisions = "Collisions"; + const QString Console = "Console..."; + const QString ControlWithSpeech = "Control With Speech"; + const QString CopyAddress = "Copy Address to Clipboard"; + const QString CopyPath = "Copy Path to Clipboard"; + const QString DDEFaceRegression = "DDE Face Regression"; + const QString DDEFiltering = "DDE Filtering"; + const QString DecreaseAvatarSize = "Decrease Avatar Size"; + const QString DeleteBookmark = "Delete Bookmark..."; + const QString DisableActivityLogger = "Disable Activity Logger"; + const QString DisableLightEntities = "Disable Light Entities"; + const QString DisableNackPackets = "Disable NACK Packets"; + const QString DiskCacheEditor = "Disk Cache Editor"; + const QString DisplayHands = "Show Hand Info"; + const QString DisplayHandTargets = "Show Hand Targets"; + const QString DisplayModelBounds = "Display Model Bounds"; + const QString DisplayModelTriangles = "Display Model Triangles"; + const QString DisplayModelElementChildProxies = "Display Model Element Children"; + const QString DisplayModelElementProxy = "Display Model Element Bounds"; + const QString DisplayDebugTimingDetails = "Display Timing Details"; + const QString DontDoPrecisionPicking = "Don't Do Precision Picking"; + const QString DontFadeOnOctreeServerChanges = "Don't Fade In/Out on Octree Server Changes"; + const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene"; + const QString EchoLocalAudio = "Echo Local Audio"; + const QString EchoServerAudio = "Echo Server Audio"; + const QString EditEntitiesHelp = "Edit Entities Help..."; + const QString Enable3DTVMode = "Enable 3DTV Mode"; + const QString EnableCharacterController = "Enable avatar collisions"; + const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)"; + const QString EnableVRMode = "Enable VR Mode"; + const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation"; + const QString ExpandMyAvatarTiming = "Expand /myAvatar"; + const QString ExpandOtherAvatarTiming = "Expand /otherAvatar"; + const QString ExpandPaintGLTiming = "Expand /paintGL"; + const QString ExpandUpdateTiming = "Expand /update"; + const QString Faceshift = "Faceshift"; + const QString FilterSixense = "Smooth Sixense Movement"; + const QString FirstPerson = "First Person"; + const QString FrameTimer = "Show Timer"; + const QString Fullscreen = "Fullscreen"; + const QString FullscreenMirror = "Fullscreen Mirror"; + const QString GlowWhenSpeaking = "Glow When Speaking"; + const QString NamesAboveHeads = "Names Above Heads"; + const QString GoToUser = "Go To User"; + const QString HMDTools = "HMD Tools"; + const QString IncreaseAvatarSize = "Increase Avatar Size"; + const QString KeyboardMotorControl = "Enable Keyboard Motor Control"; + const QString LeapMotionOnHMD = "Leap Motion on HMD"; + const QString LoadScript = "Open and Run Script File..."; + const QString LoadScriptURL = "Open and Run Script from URL..."; + const QString LoadRSSDKFile = "Load .rssdk file"; + const QString LodTools = "LOD Tools"; + const QString Login = "Login"; + const QString Log = "Log"; + const QString LowVelocityFilter = "Low Velocity Filter"; + const QString Mirror = "Mirror"; + const QString MuteAudio = "Mute Microphone"; + const QString MuteEnvironment = "Mute Environment"; + const QString NoFaceTracking = "None"; + const QString OctreeStats = "Entity Statistics"; + const QString OffAxisProjection = "Off-Axis Projection"; + const QString OnlyDisplayTopTen = "Only Display Top Ten"; + const QString PackageModel = "Package Model..."; + const QString Pair = "Pair"; + const QString PipelineWarnings = "Log Render Pipeline Warnings"; + const QString Preferences = "Preferences..."; + const QString Quit = "Quit"; + const QString ReloadAllScripts = "Reload All Scripts"; + const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes"; + const QString RenderFocusIndicator = "Show Eye Focus"; + const QString RenderHeadCollisionShapes = "Show Head Collision Shapes"; + const QString RenderLookAtVectors = "Show Look-at Vectors"; + const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes"; + const QString RenderTargetFramerate = "Framerate"; + const QString RenderTargetFramerateUnlimited = "Unlimited"; + const QString RenderTargetFramerate60 = "60"; + const QString RenderTargetFramerate50 = "50"; + const QString RenderTargetFramerate40 = "40"; + const QString RenderTargetFramerate30 = "30"; + const QString RenderTargetFramerateVSyncOn = "V-Sync On"; + const QString RenderResolution = "Scale Resolution"; + const QString RenderResolutionOne = "1"; + const QString RenderResolutionTwoThird = "2/3"; + const QString RenderResolutionHalf = "1/2"; + const QString RenderResolutionThird = "1/3"; + const QString RenderResolutionQuarter = "1/4"; + const QString RenderAmbientLight = "Ambient Light"; + const QString RenderAmbientLightGlobal = "Global"; + const QString RenderAmbientLight0 = "OLD_TOWN_SQUARE"; + const QString RenderAmbientLight1 = "GRACE_CATHEDRAL"; + const QString RenderAmbientLight2 = "EUCALYPTUS_GROVE"; + const QString RenderAmbientLight3 = "ST_PETERS_BASILICA"; + const QString RenderAmbientLight4 = "UFFIZI_GALLERY"; + const QString RenderAmbientLight5 = "GALILEOS_TOMB"; + const QString RenderAmbientLight6 = "VINE_STREET_KITCHEN"; + const QString RenderAmbientLight7 = "BREEZEWAY"; + const QString RenderAmbientLight8 = "CAMPUS_SUNSET"; + const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET"; + const QString ResetAvatarSize = "Reset Avatar Size"; + const QString ResetDDETracking = "Reset DDE Tracking"; + const QString ResetSensors = "Reset Sensors"; + const QString RunningScripts = "Running Scripts"; + const QString RunTimingTests = "Run Timing Tests"; + const QString ScriptEditor = "Script Editor..."; + const QString ScriptedMotorControl = "Enable Scripted Motor Control"; + const QString ShowBordersEntityNodes = "Show Entity Nodes"; + const QString ShowIKConstraints = "Show IK Constraints"; + const QString SimpleShadows = "Simple"; + const QString SixenseEnabled = "Enable Hydra Support"; + const QString SixenseMouseInput = "Enable Sixense Mouse Input"; + const QString SixenseLasers = "Enable Sixense UI Lasers"; + const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations"; + const QString Stars = "Stars"; + const QString Stats = "Stats"; + const QString StereoAudio = "Stereo Audio (disables spatial sound)"; + const QString StopAllScripts = "Stop All Scripts"; + const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; + const QString TestPing = "Test Ping"; + const QString ToolWindow = "Tool Window"; + const QString TransmitterDrive = "Transmitter Drive"; + const QString TurnWithHead = "Turn using Head"; + const QString UseAudioForMouth = "Use Audio for Mouth"; + const QString VisibleToEveryone = "Everyone"; + const QString VisibleToFriends = "Friends"; + const QString VisibleToNoOne = "No one"; + const QString Wireframe = "Wireframe"; +} + + +class HifiMenu : public QQuickItem +{ + Q_OBJECT + QML_DIALOG_DECL + + Q_PROPERTY(QString aboutApp READ aboutApp CONSTANT) + Q_PROPERTY(QString addRemoveFriends READ addRemoveFriends CONSTANT) + Q_PROPERTY(QString addressBar READ addressBar CONSTANT) + Q_PROPERTY(QString alignForearmsWithWrists READ alignForearmsWithWrists CONSTANT) + Q_PROPERTY(QString alternateIK READ alternateIK CONSTANT) + Q_PROPERTY(QString ambientOcclusion READ ambientOcclusion CONSTANT) + Q_PROPERTY(QString animations READ animations CONSTANT) + Q_PROPERTY(QString atmosphere READ atmosphere CONSTANT) + Q_PROPERTY(QString attachments READ attachments CONSTANT) + Q_PROPERTY(QString audioNoiseReduction READ audioNoiseReduction CONSTANT) + Q_PROPERTY(QString audioScope READ audioScope CONSTANT) + Q_PROPERTY(QString audioScopeFiftyFrames READ audioScopeFiftyFrames CONSTANT) + Q_PROPERTY(QString audioScopeFiveFrames READ audioScopeFiveFrames CONSTANT) + Q_PROPERTY(QString audioScopeFrames READ audioScopeFrames CONSTANT) + Q_PROPERTY(QString audioScopePause READ audioScopePause CONSTANT) + Q_PROPERTY(QString audioScopeTwentyFrames READ audioScopeTwentyFrames CONSTANT) + Q_PROPERTY(QString audioStats READ audioStats CONSTANT) + Q_PROPERTY(QString audioStatsShowInjectedStreams READ audioStatsShowInjectedStreams CONSTANT) + Q_PROPERTY(QString bandwidthDetails READ bandwidthDetails CONSTANT) + Q_PROPERTY(QString blueSpeechSphere READ blueSpeechSphere CONSTANT) + Q_PROPERTY(QString bookmarkLocation READ bookmarkLocation CONSTANT) + Q_PROPERTY(QString bookmarks READ bookmarks CONSTANT) + Q_PROPERTY(QString cascadedShadows READ cascadedShadows CONSTANT) + Q_PROPERTY(QString cachesSize READ cachesSize CONSTANT) + Q_PROPERTY(QString chat READ chat CONSTANT) + Q_PROPERTY(QString collisions READ collisions CONSTANT) + Q_PROPERTY(QString console READ console CONSTANT) + Q_PROPERTY(QString controlWithSpeech READ controlWithSpeech CONSTANT) + Q_PROPERTY(QString copyAddress READ copyAddress CONSTANT) + Q_PROPERTY(QString copyPath READ copyPath CONSTANT) + Q_PROPERTY(QString ddeFaceRegression READ ddeFaceRegression CONSTANT) + Q_PROPERTY(QString ddeFiltering READ ddeFiltering CONSTANT) + Q_PROPERTY(QString decreaseAvatarSize READ decreaseAvatarSize CONSTANT) + Q_PROPERTY(QString deleteBookmark READ deleteBookmark CONSTANT) + Q_PROPERTY(QString disableActivityLogger READ disableActivityLogger CONSTANT) + Q_PROPERTY(QString disableLightEntities READ disableLightEntities CONSTANT) + Q_PROPERTY(QString disableNackPackets READ disableNackPackets CONSTANT) + Q_PROPERTY(QString diskCacheEditor READ diskCacheEditor CONSTANT) + Q_PROPERTY(QString displayHands READ displayHands CONSTANT) + Q_PROPERTY(QString displayHandTargets READ displayHandTargets CONSTANT) + Q_PROPERTY(QString displayModelBounds READ displayModelBounds CONSTANT) + Q_PROPERTY(QString displayModelTriangles READ displayModelTriangles CONSTANT) + Q_PROPERTY(QString displayModelElementChildProxies READ displayModelElementChildProxies CONSTANT) + Q_PROPERTY(QString displayModelElementProxy READ displayModelElementProxy CONSTANT) + Q_PROPERTY(QString displayDebugTimingDetails READ displayDebugTimingDetails CONSTANT) + Q_PROPERTY(QString dontDoPrecisionPicking READ dontDoPrecisionPicking CONSTANT) + Q_PROPERTY(QString dontFadeOnOctreeServerChanges READ dontFadeOnOctreeServerChanges CONSTANT) + Q_PROPERTY(QString dontRenderEntitiesAsScene READ dontRenderEntitiesAsScene CONSTANT) + Q_PROPERTY(QString echoLocalAudio READ echoLocalAudio CONSTANT) + Q_PROPERTY(QString echoServerAudio READ echoServerAudio CONSTANT) + Q_PROPERTY(QString editEntitiesHelp READ editEntitiesHelp CONSTANT) + Q_PROPERTY(QString enable3DTVMode READ enable3DTVMode CONSTANT) + Q_PROPERTY(QString enableCharacterController READ enableCharacterController CONSTANT) + Q_PROPERTY(QString enableGlowEffect READ enableGlowEffect CONSTANT) + Q_PROPERTY(QString enableVRMode READ enableVRMode CONSTANT) + Q_PROPERTY(QString expandMyAvatarSimulateTiming READ expandMyAvatarSimulateTiming CONSTANT) + Q_PROPERTY(QString expandMyAvatarTiming READ expandMyAvatarTiming CONSTANT) + Q_PROPERTY(QString expandOtherAvatarTiming READ expandOtherAvatarTiming CONSTANT) + Q_PROPERTY(QString expandPaintGLTiming READ expandPaintGLTiming CONSTANT) + Q_PROPERTY(QString expandUpdateTiming READ expandUpdateTiming CONSTANT) + Q_PROPERTY(QString faceshift READ faceshift CONSTANT) + Q_PROPERTY(QString filterSixense READ filterSixense CONSTANT) + Q_PROPERTY(QString firstPerson READ firstPerson CONSTANT) + Q_PROPERTY(QString frameTimer READ frameTimer CONSTANT) + Q_PROPERTY(QString fullscreen READ fullscreen CONSTANT) + Q_PROPERTY(QString fullscreenMirror READ fullscreenMirror CONSTANT) + Q_PROPERTY(QString glowWhenSpeaking READ glowWhenSpeaking CONSTANT) + Q_PROPERTY(QString namesAboveHeads READ namesAboveHeads CONSTANT) + Q_PROPERTY(QString goToUser READ goToUser CONSTANT) + Q_PROPERTY(QString hmdTools READ hmdTools CONSTANT) + Q_PROPERTY(QString increaseAvatarSize READ increaseAvatarSize CONSTANT) + Q_PROPERTY(QString keyboardMotorControl READ keyboardMotorControl CONSTANT) + Q_PROPERTY(QString leapMotionOnHMD READ leapMotionOnHMD CONSTANT) + Q_PROPERTY(QString loadScript READ loadScript CONSTANT) + Q_PROPERTY(QString loadScriptURL READ loadScriptURL CONSTANT) + Q_PROPERTY(QString loadRSSDKFile READ loadRSSDKFile CONSTANT) + Q_PROPERTY(QString lodTools READ lodTools CONSTANT) + Q_PROPERTY(QString login READ login CONSTANT) + Q_PROPERTY(QString log READ log CONSTANT) + Q_PROPERTY(QString lowVelocityFilter READ lowVelocityFilter CONSTANT) + Q_PROPERTY(QString mirror READ mirror CONSTANT) + Q_PROPERTY(QString muteAudio READ muteAudio CONSTANT) + Q_PROPERTY(QString muteEnvironment READ muteEnvironment CONSTANT) + Q_PROPERTY(QString noFaceTracking READ noFaceTracking CONSTANT) + Q_PROPERTY(QString octreeStats READ octreeStats CONSTANT) + Q_PROPERTY(QString offAxisProjection READ offAxisProjection CONSTANT) + Q_PROPERTY(QString onlyDisplayTopTen READ onlyDisplayTopTen CONSTANT) + Q_PROPERTY(QString packageModel READ packageModel CONSTANT) + Q_PROPERTY(QString pair READ pair CONSTANT) + Q_PROPERTY(QString pipelineWarnings READ pipelineWarnings CONSTANT) + Q_PROPERTY(QString preferences READ preferences CONSTANT) + Q_PROPERTY(QString quit READ quit CONSTANT) + Q_PROPERTY(QString reloadAllScripts READ reloadAllScripts CONSTANT) + Q_PROPERTY(QString renderBoundingCollisionShapes READ renderBoundingCollisionShapes CONSTANT) + Q_PROPERTY(QString renderFocusIndicator READ renderFocusIndicator CONSTANT) + Q_PROPERTY(QString renderHeadCollisionShapes READ renderHeadCollisionShapes CONSTANT) + Q_PROPERTY(QString renderLookAtVectors READ renderLookAtVectors CONSTANT) + Q_PROPERTY(QString renderSkeletonCollisionShapes READ renderSkeletonCollisionShapes CONSTANT) + Q_PROPERTY(QString renderTargetFramerate READ renderTargetFramerate CONSTANT) + Q_PROPERTY(QString renderTargetFramerateUnlimited READ renderTargetFramerateUnlimited CONSTANT) + Q_PROPERTY(QString renderTargetFramerate60 READ renderTargetFramerate60 CONSTANT) + Q_PROPERTY(QString renderTargetFramerate50 READ renderTargetFramerate50 CONSTANT) + Q_PROPERTY(QString renderTargetFramerate40 READ renderTargetFramerate40 CONSTANT) + Q_PROPERTY(QString renderTargetFramerate30 READ renderTargetFramerate30 CONSTANT) + Q_PROPERTY(QString renderTargetFramerateVSyncOn READ renderTargetFramerateVSyncOn CONSTANT) + Q_PROPERTY(QString renderResolution READ renderResolution CONSTANT) + Q_PROPERTY(QString renderResolutionOne READ renderResolutionOne CONSTANT) + Q_PROPERTY(QString renderResolutionTwoThird READ renderResolutionTwoThird CONSTANT) + Q_PROPERTY(QString renderResolutionHalf READ renderResolutionHalf CONSTANT) + Q_PROPERTY(QString renderResolutionThird READ renderResolutionThird CONSTANT) + Q_PROPERTY(QString renderResolutionQuarter READ renderResolutionQuarter CONSTANT) + Q_PROPERTY(QString renderAmbientLight READ renderAmbientLight CONSTANT) + Q_PROPERTY(QString renderAmbientLightGlobal READ renderAmbientLightGlobal CONSTANT) + Q_PROPERTY(QString renderAmbientLight0 READ renderAmbientLight0 CONSTANT) + Q_PROPERTY(QString renderAmbientLight1 READ renderAmbientLight1 CONSTANT) + Q_PROPERTY(QString renderAmbientLight2 READ renderAmbientLight2 CONSTANT) + Q_PROPERTY(QString renderAmbientLight3 READ renderAmbientLight3 CONSTANT) + Q_PROPERTY(QString renderAmbientLight4 READ renderAmbientLight4 CONSTANT) + Q_PROPERTY(QString renderAmbientLight5 READ renderAmbientLight5 CONSTANT) + Q_PROPERTY(QString renderAmbientLight6 READ renderAmbientLight6 CONSTANT) + Q_PROPERTY(QString renderAmbientLight7 READ renderAmbientLight7 CONSTANT) + Q_PROPERTY(QString renderAmbientLight8 READ renderAmbientLight8 CONSTANT) + Q_PROPERTY(QString renderAmbientLight9 READ renderAmbientLight9 CONSTANT) + Q_PROPERTY(QString resetAvatarSize READ resetAvatarSize CONSTANT) + Q_PROPERTY(QString resetDDETracking READ resetDDETracking CONSTANT) + Q_PROPERTY(QString resetSensors READ resetSensors CONSTANT) + Q_PROPERTY(QString runningScripts READ runningScripts CONSTANT) + Q_PROPERTY(QString runTimingTests READ runTimingTests CONSTANT) + Q_PROPERTY(QString scriptEditor READ scriptEditor CONSTANT) + Q_PROPERTY(QString scriptedMotorControl READ scriptedMotorControl CONSTANT) + Q_PROPERTY(QString showBordersEntityNodes READ showBordersEntityNodes CONSTANT) + Q_PROPERTY(QString showIKConstraints READ showIKConstraints CONSTANT) + Q_PROPERTY(QString simpleShadows READ simpleShadows CONSTANT) + Q_PROPERTY(QString sixenseEnabled READ sixenseEnabled CONSTANT) + Q_PROPERTY(QString sixenseMouseInput READ sixenseMouseInput CONSTANT) + Q_PROPERTY(QString sixenseLasers READ sixenseLasers CONSTANT) + Q_PROPERTY(QString shiftHipsForIdleAnimations READ shiftHipsForIdleAnimations CONSTANT) + Q_PROPERTY(QString stars READ stars CONSTANT) + Q_PROPERTY(QString stats READ stats CONSTANT) + Q_PROPERTY(QString stereoAudio READ stereoAudio CONSTANT) + Q_PROPERTY(QString stopAllScripts READ stopAllScripts CONSTANT) + Q_PROPERTY(QString suppressShortTimings READ suppressShortTimings CONSTANT) + Q_PROPERTY(QString testPing READ testPing CONSTANT) + Q_PROPERTY(QString toolWindow READ toolWindow CONSTANT) + Q_PROPERTY(QString transmitterDrive READ transmitterDrive CONSTANT) + Q_PROPERTY(QString turnWithHead READ turnWithHead CONSTANT) + Q_PROPERTY(QString useAudioForMouth READ useAudioForMouth CONSTANT) + Q_PROPERTY(QString visibleToEveryone READ visibleToEveryone CONSTANT) + Q_PROPERTY(QString visibleToFriends READ visibleToFriends CONSTANT) + Q_PROPERTY(QString visibleToNoOne READ visibleToNoOne CONSTANT) + Q_PROPERTY(QString wireframe READ wireframe CONSTANT) + +public: + + const QString & aboutApp() { return MenuOption::AboutApp; } + const QString & addRemoveFriends() { return MenuOption::AddRemoveFriends; } + const QString & addressBar() { return MenuOption::AddressBar; } + const QString & alignForearmsWithWrists() { return MenuOption::AlignForearmsWithWrists; } + const QString & alternateIK() { return MenuOption::AlternateIK; } + const QString & ambientOcclusion() { return MenuOption::AmbientOcclusion; } + const QString & animations() { return MenuOption::Animations; } + const QString & atmosphere() { return MenuOption::Atmosphere; } + const QString & attachments() { return MenuOption::Attachments; } + const QString & audioNoiseReduction() { return MenuOption::AudioNoiseReduction; } + const QString & audioScope() { return MenuOption::AudioScope; } + const QString & audioScopeFiftyFrames() { return MenuOption::AudioScopeFiftyFrames; } + const QString & audioScopeFiveFrames() { return MenuOption::AudioScopeFiveFrames; } + const QString & audioScopeFrames() { return MenuOption::AudioScopeFrames; } + const QString & audioScopePause() { return MenuOption::AudioScopePause; } + const QString & audioScopeTwentyFrames() { return MenuOption::AudioScopeTwentyFrames; } + const QString & audioStats() { return MenuOption::AudioStats; } + const QString & audioStatsShowInjectedStreams() { return MenuOption::AudioStatsShowInjectedStreams; } + const QString & bandwidthDetails() { return MenuOption::BandwidthDetails; } + const QString & blueSpeechSphere() { return MenuOption::BlueSpeechSphere; } + const QString & bookmarkLocation() { return MenuOption::BookmarkLocation; } + const QString & bookmarks() { return MenuOption::Bookmarks; } + const QString & cascadedShadows() { return MenuOption::CascadedShadows; } + const QString & cachesSize() { return MenuOption::CachesSize; } + const QString & chat() { return MenuOption::Chat; } + const QString & collisions() { return MenuOption::Collisions; } + const QString & console() { return MenuOption::Console; } + const QString & controlWithSpeech() { return MenuOption::ControlWithSpeech; } + const QString & copyAddress() { return MenuOption::CopyAddress; } + const QString & copyPath() { return MenuOption::CopyPath; } + const QString & ddeFaceRegression() { return MenuOption::DDEFaceRegression; } + const QString & ddeFiltering() { return MenuOption::DDEFiltering; } + const QString & decreaseAvatarSize() { return MenuOption::DecreaseAvatarSize; } + const QString & deleteBookmark() { return MenuOption::DeleteBookmark; } + const QString & disableActivityLogger() { return MenuOption::DisableActivityLogger; } + const QString & disableLightEntities() { return MenuOption::DisableLightEntities; } + const QString & disableNackPackets() { return MenuOption::DisableNackPackets; } + const QString & diskCacheEditor() { return MenuOption::DiskCacheEditor; } + const QString & displayHands() { return MenuOption::DisplayHands; } + const QString & displayHandTargets() { return MenuOption::DisplayHandTargets; } + const QString & displayModelBounds() { return MenuOption::DisplayModelBounds; } + const QString & displayModelTriangles() { return MenuOption::DisplayModelTriangles; } + const QString & displayModelElementChildProxies() { return MenuOption::DisplayModelElementChildProxies; } + const QString & displayModelElementProxy() { return MenuOption::DisplayModelElementProxy; } + const QString & displayDebugTimingDetails() { return MenuOption::DisplayDebugTimingDetails; } + const QString & dontDoPrecisionPicking() { return MenuOption::DontDoPrecisionPicking; } + const QString & dontFadeOnOctreeServerChanges() { return MenuOption::DontFadeOnOctreeServerChanges; } + const QString & dontRenderEntitiesAsScene() { return MenuOption::DontRenderEntitiesAsScene; } + const QString & echoLocalAudio() { return MenuOption::EchoLocalAudio; } + const QString & echoServerAudio() { return MenuOption::EchoServerAudio; } + const QString & editEntitiesHelp() { return MenuOption::EditEntitiesHelp; } + const QString & enable3DTVMode() { return MenuOption::Enable3DTVMode; } + const QString & enableCharacterController() { return MenuOption::EnableCharacterController; } + const QString & enableGlowEffect() { return MenuOption::EnableGlowEffect; } + const QString & enableVRMode() { return MenuOption::EnableVRMode; } + const QString & expandMyAvatarSimulateTiming() { return MenuOption::ExpandMyAvatarSimulateTiming; } + const QString & expandMyAvatarTiming() { return MenuOption::ExpandMyAvatarTiming; } + const QString & expandOtherAvatarTiming() { return MenuOption::ExpandOtherAvatarTiming; } + const QString & expandPaintGLTiming() { return MenuOption::ExpandPaintGLTiming; } + const QString & expandUpdateTiming() { return MenuOption::ExpandUpdateTiming; } + const QString & faceshift() { return MenuOption::Faceshift; } + const QString & filterSixense() { return MenuOption::FilterSixense; } + const QString & firstPerson() { return MenuOption::FirstPerson; } + const QString & frameTimer() { return MenuOption::FrameTimer; } + const QString & fullscreen() { return MenuOption::Fullscreen; } + const QString & fullscreenMirror() { return MenuOption::FullscreenMirror; } + const QString & glowWhenSpeaking() { return MenuOption::GlowWhenSpeaking; } + const QString & namesAboveHeads() { return MenuOption::NamesAboveHeads; } + const QString & goToUser() { return MenuOption::GoToUser; } + const QString & hmdTools() { return MenuOption::HMDTools; } + const QString & increaseAvatarSize() { return MenuOption::IncreaseAvatarSize; } + const QString & keyboardMotorControl() { return MenuOption::KeyboardMotorControl; } + const QString & leapMotionOnHMD() { return MenuOption::LeapMotionOnHMD; } + const QString & loadScript() { return MenuOption::LoadScript; } + const QString & loadScriptURL() { return MenuOption::LoadScriptURL; } + const QString & loadRSSDKFile() { return MenuOption::LoadRSSDKFile; } + const QString & lodTools() { return MenuOption::LodTools; } + const QString & login() { return MenuOption::Login; } + const QString & log() { return MenuOption::Log; } + const QString & lowVelocityFilter() { return MenuOption::LowVelocityFilter; } + const QString & mirror() { return MenuOption::Mirror; } + const QString & muteAudio() { return MenuOption::MuteAudio; } + const QString & muteEnvironment() { return MenuOption::MuteEnvironment; } + const QString & noFaceTracking() { return MenuOption::NoFaceTracking; } + const QString & octreeStats() { return MenuOption::OctreeStats; } + const QString & offAxisProjection() { return MenuOption::OffAxisProjection; } + const QString & onlyDisplayTopTen() { return MenuOption::OnlyDisplayTopTen; } + const QString & packageModel() { return MenuOption::PackageModel; } + const QString & pair() { return MenuOption::Pair; } + const QString & pipelineWarnings() { return MenuOption::PipelineWarnings; } + const QString & preferences() { return MenuOption::Preferences; } + const QString & quit() { return MenuOption::Quit; } + const QString & reloadAllScripts() { return MenuOption::ReloadAllScripts; } + const QString & renderBoundingCollisionShapes() { return MenuOption::RenderBoundingCollisionShapes; } + const QString & renderFocusIndicator() { return MenuOption::RenderFocusIndicator; } + const QString & renderHeadCollisionShapes() { return MenuOption::RenderHeadCollisionShapes; } + const QString & renderLookAtVectors() { return MenuOption::RenderLookAtVectors; } + const QString & renderSkeletonCollisionShapes() { return MenuOption::RenderSkeletonCollisionShapes; } + const QString & renderTargetFramerate() { return MenuOption::RenderTargetFramerate; } + const QString & renderTargetFramerateUnlimited() { return MenuOption::RenderTargetFramerateUnlimited; } + const QString & renderTargetFramerate60() { return MenuOption::RenderTargetFramerate60; } + const QString & renderTargetFramerate50() { return MenuOption::RenderTargetFramerate50; } + const QString & renderTargetFramerate40() { return MenuOption::RenderTargetFramerate40; } + const QString & renderTargetFramerate30() { return MenuOption::RenderTargetFramerate30; } + const QString & renderTargetFramerateVSyncOn() { return MenuOption::RenderTargetFramerateVSyncOn; } + const QString & renderResolution() { return MenuOption::RenderResolution; } + const QString & renderResolutionOne() { return MenuOption::RenderResolutionOne; } + const QString & renderResolutionTwoThird() { return MenuOption::RenderResolutionTwoThird; } + const QString & renderResolutionHalf() { return MenuOption::RenderResolutionHalf; } + const QString & renderResolutionThird() { return MenuOption::RenderResolutionThird; } + const QString & renderResolutionQuarter() { return MenuOption::RenderResolutionQuarter; } + const QString & renderAmbientLight() { return MenuOption::RenderAmbientLight; } + const QString & renderAmbientLightGlobal() { return MenuOption::RenderAmbientLightGlobal; } + const QString & renderAmbientLight0() { return MenuOption::RenderAmbientLight0; } + const QString & renderAmbientLight1() { return MenuOption::RenderAmbientLight1; } + const QString & renderAmbientLight2() { return MenuOption::RenderAmbientLight2; } + const QString & renderAmbientLight3() { return MenuOption::RenderAmbientLight3; } + const QString & renderAmbientLight4() { return MenuOption::RenderAmbientLight4; } + const QString & renderAmbientLight5() { return MenuOption::RenderAmbientLight5; } + const QString & renderAmbientLight6() { return MenuOption::RenderAmbientLight6; } + const QString & renderAmbientLight7() { return MenuOption::RenderAmbientLight7; } + const QString & renderAmbientLight8() { return MenuOption::RenderAmbientLight8; } + const QString & renderAmbientLight9() { return MenuOption::RenderAmbientLight9; } + const QString & resetAvatarSize() { return MenuOption::ResetAvatarSize; } + const QString & resetDDETracking() { return MenuOption::ResetDDETracking; } + const QString & resetSensors() { return MenuOption::ResetSensors; } + const QString & runningScripts() { return MenuOption::RunningScripts; } + const QString & runTimingTests() { return MenuOption::RunTimingTests; } + const QString & scriptEditor() { return MenuOption::ScriptEditor; } + const QString & scriptedMotorControl() { return MenuOption::ScriptedMotorControl; } + const QString & showBordersEntityNodes() { return MenuOption::ShowBordersEntityNodes; } + const QString & showIKConstraints() { return MenuOption::ShowIKConstraints; } + const QString & simpleShadows() { return MenuOption::SimpleShadows; } + const QString & sixenseEnabled() { return MenuOption::SixenseEnabled; } + const QString & sixenseMouseInput() { return MenuOption::SixenseMouseInput; } + const QString & sixenseLasers() { return MenuOption::SixenseLasers; } + const QString & shiftHipsForIdleAnimations() { return MenuOption::ShiftHipsForIdleAnimations; } + const QString & stars() { return MenuOption::Stars; } + const QString & stats() { return MenuOption::Stats; } + const QString & stereoAudio() { return MenuOption::StereoAudio; } + const QString & stopAllScripts() { return MenuOption::StopAllScripts; } + const QString & suppressShortTimings() { return MenuOption::SuppressShortTimings; } + const QString & testPing() { return MenuOption::TestPing; } + const QString & toolWindow() { return MenuOption::ToolWindow; } + const QString & transmitterDrive() { return MenuOption::TransmitterDrive; } + const QString & turnWithHead() { return MenuOption::TurnWithHead; } + const QString & useAudioForMouth() { return MenuOption::UseAudioForMouth; } + const QString & visibleToEveryone() { return MenuOption::VisibleToEveryone; } + const QString & visibleToFriends() { return MenuOption::VisibleToFriends; } + const QString & visibleToNoOne() { return MenuOption::VisibleToNoOne; } + const QString & wireframe() { return MenuOption::Wireframe; } + +public slots: + void onTriggeredByName(const QString & name); + void onToggledByName(const QString & name); + +public: + HifiMenu(QQuickItem * parent = nullptr); + static void setToggleAction(const QString & name, std::function f); + static void setTriggerAction(const QString & name, std::function f); +private: + static QHash> triggerActions; + static QHash> toggleActions; +}; + +#endif // hifi_MenuConstants_h + + + + diff --git a/libraries/render-utils/src/MessageDialog.cpp b/libraries/ui/src/MessageDialog.cpp similarity index 100% rename from libraries/render-utils/src/MessageDialog.cpp rename to libraries/ui/src/MessageDialog.cpp diff --git a/libraries/render-utils/src/MessageDialog.h b/libraries/ui/src/MessageDialog.h similarity index 100% rename from libraries/render-utils/src/MessageDialog.h rename to libraries/ui/src/MessageDialog.h diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/ui/src/OffscreenQmlDialog.cpp similarity index 100% rename from libraries/render-utils/src/OffscreenQmlDialog.cpp rename to libraries/ui/src/OffscreenQmlDialog.cpp diff --git a/libraries/render-utils/src/OffscreenQmlDialog.h b/libraries/ui/src/OffscreenQmlDialog.h similarity index 100% rename from libraries/render-utils/src/OffscreenQmlDialog.h rename to libraries/ui/src/OffscreenQmlDialog.h diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp similarity index 99% rename from libraries/render-utils/src/OffscreenUi.cpp rename to libraries/ui/src/OffscreenUi.cpp index d25d78300a..b14951f054 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -118,15 +118,17 @@ void OffscreenUi::resize(const QSize& newSize) { qDebug() << "Offscreen UI resizing to " << newSize.width() << "x" << newSize.height() << " with pixel ratio " << pixelRatio; _fboCache.setSize(newSize * pixelRatio); + if (_quickWindow) { + _quickWindow->setGeometry(QRect(QPoint(), newSize)); + } + + _quickWindow->contentItem()->setSize(newSize); + // Update our members if (_rootItem) { _rootItem->setSize(newSize); } - if (_quickWindow) { - _quickWindow->setGeometry(QRect(QPoint(), newSize)); - } - doneCurrent(); } @@ -190,6 +192,7 @@ void OffscreenUi::finishQmlLoad(std::function f QQuickItem* newItem = qobject_cast(newObject); if (!newItem) { qWarning("run: Not a QQuickItem"); + return; delete newObject; if (!_rootItem) { qFatal("Unable to find root QQuickItem"); @@ -206,6 +209,7 @@ void OffscreenUi::finishQmlLoad(std::function f _rootItem = newItem; _rootItem->setParentItem(_quickWindow->contentItem()); _rootItem->setSize(_quickWindow->renderTargetSize()); + _rootItem->forceActiveFocus(); } else { // Allow child windows to be destroyed from JS QQmlEngine::setObjectOwnership(newItem, QQmlEngine::JavaScriptOwnership); diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h similarity index 78% rename from libraries/render-utils/src/OffscreenUi.h rename to libraries/ui/src/OffscreenUi.h index b2805b2ded..64837baf2d 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -32,6 +32,39 @@ #include "FboCache.h" #include +#define HIFI_QML_DECL \ +private: \ + static const QString NAME; \ + static const QUrl QML; \ +public: \ + static void registerType(); \ + static void show(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void toggle(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void load(std::function f = [](QQmlContext*, QQuickItem*) {}); \ +private: + +#define HIFI_QML_DEF(x) \ + const QUrl x::QML = QUrl(#x ".qml"); \ + const QString x::NAME = #x; \ + \ + void x::registerType() { \ + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ + } \ + \ + void x::show(std::function f) { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->show(QML, NAME, f); \ + } \ + \ + void x::toggle(std::function f) { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->toggle(QML, NAME, f); \ + } \ + void x::load(std::function f) { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->load(QML, f); \ + } + class OffscreenUi : public OffscreenGlCanvas, public Dependency { Q_OBJECT diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 28d542e51a..5e45bf23a2 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -10,7 +10,6 @@ #include "TextRenderer.h" #include "MatrixStack.h" -#include "OffscreenUi.h" #include #include @@ -27,7 +26,6 @@ #include #include #include -#include #include #include @@ -82,6 +80,7 @@ const QString& getQmlDir() { } return dir; } + // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { Q_OBJECT @@ -90,24 +89,17 @@ class QTestWindow : public QWindow { QSize _size; TextRenderer* _textRenderer[4]; RateCounter fps; - int testQmlTexture{ 0 }; - //ProgramPtr _planeProgam; - //ShapeWrapperPtr _planeShape; protected: - void renderText(); - void renderQml(); private: void resizeWindow(const QSize& size) { _size = size; - DependencyManager::get()->resize(_size); } public: QTestWindow() { - DependencyManager::set(); setSurfaceType(QSurface::OpenGLSurface); QSurfaceFormat format; @@ -167,32 +159,10 @@ public: glClearColor(0.2f, 0.2f, 0.2f, 1); glDisable(GL_DEPTH_TEST); - auto offscreenUi = DependencyManager::get(); - offscreenUi->create(_context); - // FIXME, need to switch to a QWindow for mouse and keyboard input to work - offscreenUi->setProxyWindow(this); - // "#0e7077" + makeCurrent(); + setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); - - offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); - offscreenUi->load(QUrl("TestRoot.qml")); - offscreenUi->addImportPath(getQmlDir()); - offscreenUi->addImportPath("."); - - connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { - offscreenUi->lockTexture(textureId); - assert(!glGetError()); - GLuint oldTexture = testQmlTexture; - testQmlTexture = textureId; - if (oldTexture) { - offscreenUi->releaseTexture(oldTexture); - } - }); - installEventFilter(offscreenUi.data()); - offscreenUi->resume(); - QWebEnginePage *page = new QWebEnginePage; - page->runJavaScript("'Java''' 'Script'", [](const QVariant &result) { qDebug() << result; }); } virtual ~QTestWindow() { @@ -208,41 +178,6 @@ protected: void resizeEvent(QResizeEvent* ev) override { resizeWindow(ev->size()); } - - - void keyPressEvent(QKeyEvent* event) { - switch (event->key()) { - case Qt::Key_L: - if (event->modifiers() & Qt::CTRL) { - auto offscreenUi = DependencyManager::get(); - offscreenUi->qmlEngine()->clearComponentCache(); - DependencyManager::get()->toggle(QString("TestDialog.qml"), "TestDialog"); - } - break; - case Qt::Key_K: - if (event->modifiers() & Qt::CTRL) { - DependencyManager::get()->toggle(QString("Browser.qml"), "Browser"); - } - break; - case Qt::Key_J: - if (event->modifiers() & Qt::CTRL) { - QObject * obj = DependencyManager::get()->findObject("WebView"); - qDebug() << obj; - } - break; - } - QWindow::keyPressEvent(event); - } - - void moveEvent(QMoveEvent* event) { - static qreal oldPixelRatio = 0.0; - if (devicePixelRatio() != oldPixelRatio) { - oldPixelRatio = devicePixelRatio(); - resizeWindow(size()); - } - - QWindow::moveEvent(event); - } }; #ifndef SERIF_FONT_FAMILY @@ -299,39 +234,16 @@ void QTestWindow::renderText() { } } -void QTestWindow::renderQml() { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - if (testQmlTexture > 0) { - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, testQmlTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - glBegin(GL_QUADS); - { - glTexCoord2f(0, 0); - glVertex2f(-1, -1); - glTexCoord2f(0, 1); - glVertex2f(-1, 1); - glTexCoord2f(1, 1); - glVertex2f(1, 1); - glTexCoord2f(1, 0); - glVertex2f(1, -1); - } - glEnd(); -} - void QTestWindow::draw() { + if (!isVisible()) { + return; + } + makeCurrent(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); - //renderText(); - renderQml(); + renderText(); _context->swapBuffers(this); glFinish(); @@ -344,10 +256,8 @@ void QTestWindow::draw() { } int main(int argc, char** argv) { - QApplication app(argc, argv); - //QLoggingCategory::setFilterRules("qt.quick.mouse.debug = true"); + QGuiApplication app(argc, argv); QTestWindow window; - QTimer timer; timer.setInterval(1); app.connect(&timer, &QTimer::timeout, &app, [&] { diff --git a/tests/ui/CMakeLists.txt b/tests/ui/CMakeLists.txt new file mode 100644 index 0000000000..3ff8555fa2 --- /dev/null +++ b/tests/ui/CMakeLists.txt @@ -0,0 +1,15 @@ +set(TARGET_NAME ui-tests) + +setup_hifi_project(Widgets OpenGL Network Qml Quick Script) + +if (WIN32) + add_dependency_external_projects(glew) + find_package(GLEW REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} wsock32.lib opengl32.lib Winmm.lib) +endif() + +# link in the shared libraries +link_hifi_libraries(ui render-utils gpu shared) + +copy_dlls_beside_windows_executable() \ No newline at end of file diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp new file mode 100644 index 0000000000..00d0bc80fd --- /dev/null +++ b/tests/ui/src/main.cpp @@ -0,0 +1,302 @@ +// +// main.cpp +// tests/render-utils/src +// +// 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 "OffscreenUi.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "MessageDialog.h" +#include "MenuConstants.h" + +class RateCounter { + std::vector times; + QElapsedTimer timer; +public: + RateCounter() { + timer.start(); + } + + void reset() { + times.clear(); + } + + unsigned int count() const { + return times.size() - 1; + } + + float elapsed() const { + if (times.size() < 1) { + return 0.0f; + } + float elapsed = *times.rbegin() - *times.begin(); + return elapsed; + } + + void increment() { + times.push_back(timer.elapsed() / 1000.0f); + } + + float rate() const { + if (elapsed() == 0.0f) { + return NAN; + } + return (float) count() / elapsed(); + } +}; + + +const QString & getQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/qml/")) + "/"; + qDebug() << "Qml Path: " << dir; + } + return dir; +} + +// Create a simple OpenGL window that renders text in various ways +class QTestWindow : public QWindow, private QOpenGLFunctions { + Q_OBJECT + + QOpenGLContext * _context{ nullptr }; + QSize _size; + bool _altPressed{ false }; + RateCounter fps; + QTimer _timer; + int testQmlTexture{ 0 }; + +public: + QTestWindow() { + _timer.setInterval(1); + connect(&_timer, &QTimer::timeout, [=] { + draw(); + }); + + DependencyManager::set(); + setSurfaceType(QSurface::OpenGLSurface); + + QSurfaceFormat format; + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + format.setVersion(4, 1); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + format.setOption(QSurfaceFormat::DebugContext); + + setFormat(format); + + _context = new QOpenGLContext; + _context->setFormat(format); + if (!_context->create()) { + qFatal("Could not create OpenGL context"); + } + + show(); + makeCurrent(); + initializeOpenGLFunctions(); + + { + QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + logger->initialize(); // initializes in the current context, i.e. ctx + logger->enableMessages(); + connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { + qDebug() << debugMessage; + }); + // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); + } + + qDebug() << (const char*)this->glGetString(GL_VERSION); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glClearColor(0.2f, 0.2f, 0.2f, 1); + glDisable(GL_DEPTH_TEST); + + MessageDialog::registerType(); + HifiMenu::registerType(); + + auto offscreenUi = DependencyManager::get(); + offscreenUi->create(_context); + + makeCurrent(); + + offscreenUi->setProxyWindow(this); + setFramePosition(QPoint(-1000, 0)); + resize(QSize(800, 600)); + + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); + offscreenUi->load(QUrl("TestRoot.qml")); + offscreenUi->addImportPath(getQmlDir()); + offscreenUi->addImportPath("."); + + connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { + offscreenUi->lockTexture(textureId); + assert(!glGetError()); + GLuint oldTexture = testQmlTexture; + testQmlTexture = textureId; + if (oldTexture) { + offscreenUi->releaseTexture(oldTexture); + } + }); + installEventFilter(offscreenUi.data()); + HifiMenu::setTriggerAction(MenuOption::Quit, [] { + QApplication::quit(); + }); + offscreenUi->resume(); + _timer.start(); + } + + virtual ~QTestWindow() { + DependencyManager::destroy(); + } + +private: + void draw() { + if (!isVisible()) { + return; + } + + makeCurrent(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); + + renderQml(); + + _context->swapBuffers(this); + glFinish(); + + fps.increment(); + if (fps.elapsed() >= 2.0f) { + qDebug() << "FPS: " << fps.rate(); + fps.reset(); + } + } + + void makeCurrent() { + _context->makeCurrent(this); + } + + void renderQml(); + + void resizeWindow(const QSize & size) { + _size = size; + DependencyManager::get()->resize(_size); + } + + +protected: + void resizeEvent(QResizeEvent * ev) override { + resizeWindow(ev->size()); + } + + void keyPressEvent(QKeyEvent *event) { + _altPressed = Qt::Key_Alt == event->key(); + switch (event->key()) { + case Qt::Key_L: + if (event->modifiers() & Qt::CTRL) { + //auto offscreenUi = DependencyManager::get(); + //DependencyManager::get()->toggle(QString("TestDialog.qml"), "TestDialog"); + //DependencyManager::get()->toggle(QString("MenuTest.qml"), "MenuTest"); + //HifiMenu::toggle(); + } + break; + case Qt::Key_K: + if (event->modifiers() & Qt::CTRL) { + OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){ + qDebug() << b; + }); + } + break; + case Qt::Key_J: + if (event->modifiers() & Qt::CTRL) { + } + break; + } + QWindow::keyPressEvent(event); + } + + void keyReleaseEvent(QKeyEvent *event) { + if (_altPressed && Qt::Key_Alt == event->key()) { + HifiMenu::toggle(); + } + } + + void moveEvent(QMoveEvent *event) { + static qreal oldPixelRatio = 0.0; + if (devicePixelRatio() != oldPixelRatio) { + oldPixelRatio = devicePixelRatio(); + resizeWindow(size()); + } + QWindow::moveEvent(event); + } +}; + +void QTestWindow::renderQml() { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + if (testQmlTexture > 0) { + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, testQmlTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + glBegin(GL_QUADS); + { + glTexCoord2f(0, 0); + glVertex2f(-1, -1); + glTexCoord2f(0, 1); + glVertex2f(-1, 1); + glTexCoord2f(1, 1); + glVertex2f(1, 1); + glTexCoord2f(1, 0); + glVertex2f(1, -1); + } + glEnd(); +} + + +const char * LOG_FILTER_RULES = R"V0G0N( +*.debug=false +qt.quick.dialogs.registration=true +qt.quick.mouse.debug = true +)V0G0N"; + +int main(int argc, char** argv) { + QGuiApplication app(argc, argv); + //QLoggingCategory::setFilterRules(LOG_FILTER_RULES); + QTestWindow window; + app.exec(); + return 0; +} + +#include "main.moc" From 9a8207610d1e10b106355dacd8816c71e6d6c436 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 19:56:47 -0700 Subject: [PATCH 272/401] Bad merge --- libraries/ui/src/OffscreenUi.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index 64837baf2d..d04eb63bff 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -96,8 +96,8 @@ public: void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QQuickItem*) {}) { load(QUrl(qmlSourceFile), f); } - void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QQuickItem*) {})); - void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QQuickItem*) {})); + void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QQuickItem*) {}); + void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QQuickItem*) {}); void setBaseUrl(const QUrl& baseUrl); void addImportPath(const QString& path); QQmlContext* qmlContext(); @@ -119,7 +119,6 @@ public: static ButtonCallback NO_OP_CALLBACK; static void messageBox(const QString& title, const QString& text, - static void messageBox(const QString &title, const QString &text, ButtonCallback f, QMessageBox::Icon icon, QMessageBox::StandardButtons buttons); From bb1c73adc7e1730ad7568a5195f204d09f04c3f3 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 23 Apr 2015 00:24:24 -0700 Subject: [PATCH 273/401] Working on menus --- .../resources/qml/{Menu.qml => HifiMenu.qml} | 38 +- interface/resources/qml/Root.qml | 30 ++ interface/resources/qml/RootMenu.qml | 34 ++ interface/resources/qml/TestRoot.qml | 3 +- libraries/ui/src/MenuConstants.h | 467 +----------------- libraries/ui/src/OffscreenQmlDialog.h | 8 +- libraries/ui/src/OffscreenUi.cpp | 41 +- libraries/ui/src/OffscreenUi.h | 14 +- tests/ui/main.qml | 161 ++++++ tests/ui/qml/ButtonPage.qml | 128 +++++ tests/ui/qml/InputPage.qml | 114 +++++ tests/ui/qml/ProgressPage.qml | 90 ++++ tests/ui/qml/UI.js | 45 ++ tests/ui/src/main.cpp | 82 ++- 14 files changed, 724 insertions(+), 531 deletions(-) rename interface/resources/qml/{Menu.qml => HifiMenu.qml} (94%) create mode 100644 interface/resources/qml/RootMenu.qml create mode 100644 tests/ui/main.qml create mode 100644 tests/ui/qml/ButtonPage.qml create mode 100644 tests/ui/qml/InputPage.qml create mode 100644 tests/ui/qml/ProgressPage.qml create mode 100644 tests/ui/qml/UI.js diff --git a/interface/resources/qml/Menu.qml b/interface/resources/qml/HifiMenu.qml similarity index 94% rename from interface/resources/qml/Menu.qml rename to interface/resources/qml/HifiMenu.qml index f76b9485fb..8bdda71558 100644 --- a/interface/resources/qml/Menu.qml +++ b/interface/resources/qml/HifiMenu.qml @@ -5,10 +5,10 @@ import QtQuick.Controls.Styles 1.3 import "controls" import "styles" -Hifi.Menu { +Hifi.HifiMenu { id: root anchors.fill: parent - objectName: "Menu" + objectName: "HifiMenu" enabled: false opacity: 0.0 property int animationDuration: 200 @@ -16,7 +16,7 @@ Hifi.Menu { onEnabledChanged: { if (enabled && columns.length == 0) { - pushColumn(menu.items); + pushColumn(rootMenu.items); } opacity = enabled ? 1.0 : 0.0 if (enabled) { @@ -202,19 +202,23 @@ Hifi.Menu { } function popColumn() { - if (columns.length > 1) { + if (columns.length > 0) { var curColumn = columns.pop(); console.log(curColumn); curColumn.visible = false; curColumn.destroy(); models.pop(); - curColumn = lastColumn(); - curColumn.enabled = true; - curColumn.opacity = 1.0; - curColumn.forceActiveFocus(); - } else { + } + + if (columns.length == 0) { enabled = false; - } + return; + } + + curColumn = lastColumn(); + curColumn.enabled = true; + curColumn.opacity = 1.0; + curColumn.forceActiveFocus(); } function selectItem(source) { @@ -223,7 +227,6 @@ Hifi.Menu { pushColumn(source.items) break; case 1: - console.log("Triggering " + source.text); source.trigger() enabled = false break; @@ -233,12 +236,9 @@ Hifi.Menu { } function reset() { - console.log("Resettting") - while (columns.length > 1) { + while (columns.length > 0) { popColumn(); } - lastColumn().children[0].currentIndex = -1 - console.log(lastColumn().children[0]) } /* @@ -367,9 +367,13 @@ Hifi.Menu { MouseArea { anchors.fill: parent id: mouseArea - acceptedButtons: Qt.RightButton + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - root.popColumn(); + if(mouseArea.pressedButtons & Qt.RightButton) { + root.popColumn(); + } else { + root.enabled = false; + } } } } diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index b2db7d18bf..92ad922cce 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -6,5 +6,35 @@ import QtQuick 2.3 Root { id: root anchors.fill: parent + Item { + Menu { + objectName: "rootMenu" + Menu { + title: "File" + MenuItem { + text: "Test" + checkable: true + } + MenuItem { + text: "Quit" + } + } + Menu { + title: "Edit" + MenuItem { + text: "Copy" + } + MenuItem { + text: "Cut" + } + MenuItem { + text: "Paste" + } + MenuItem { + text: "Undo" + } + } + } + } } diff --git a/interface/resources/qml/RootMenu.qml b/interface/resources/qml/RootMenu.qml new file mode 100644 index 0000000000..46cae2cf4a --- /dev/null +++ b/interface/resources/qml/RootMenu.qml @@ -0,0 +1,34 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.3 + +Item { + Menu { + id: rootMenuFooBar + objectName: "rootMenu" + Menu { + title: "File" + MenuItem { + text: "Test" + checkable: true + } + MenuItem { + text: "Quit" + } + } + Menu { + title: "Edit" + MenuItem { + text: "Copy" + } + MenuItem { + text: "Cut" + } + MenuItem { + text: "Paste" + } + MenuItem { + text: "Undo" + } + } + } +} diff --git a/interface/resources/qml/TestRoot.qml b/interface/resources/qml/TestRoot.qml index 0f48939935..0b0f890361 100644 --- a/interface/resources/qml/TestRoot.qml +++ b/interface/resources/qml/TestRoot.qml @@ -1,5 +1,6 @@ import Hifi 1.0 import QtQuick 2.3 +import QtQuick.Controls 1.3 // Import local folder last so that our own control customizations override // the built in ones import "controls" @@ -19,7 +20,7 @@ Root { console.log("Completed root") root.forceActiveFocus() } - + Button { id: messageBox anchors.right: createDialog.left diff --git a/libraries/ui/src/MenuConstants.h b/libraries/ui/src/MenuConstants.h index e2d50b10a6..e986410c5b 100644 --- a/libraries/ui/src/MenuConstants.h +++ b/libraries/ui/src/MenuConstants.h @@ -17,480 +17,19 @@ #include #include "OffscreenQmlDialog.h" -namespace MenuOption { - const QString AboutApp = "About Interface"; - const QString AddRemoveFriends = "Add/Remove Friends..."; - const QString AddressBar = "Show Address Bar"; - const QString AlignForearmsWithWrists = "Align Forearms with Wrists"; - const QString AlternateIK = "Alternate IK"; - const QString AmbientOcclusion = "Ambient Occlusion"; - const QString Animations = "Animations..."; - const QString Atmosphere = "Atmosphere"; - const QString Attachments = "Attachments..."; - const QString AudioNoiseReduction = "Audio Noise Reduction"; - const QString AudioScope = "Show Scope"; - const QString AudioScopeFiftyFrames = "Fifty"; - const QString AudioScopeFiveFrames = "Five"; - const QString AudioScopeFrames = "Display Frames"; - const QString AudioScopePause = "Pause Scope"; - const QString AudioScopeTwentyFrames = "Twenty"; - const QString AudioStats = "Audio Stats"; - const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams"; - const QString BandwidthDetails = "Bandwidth Details"; - const QString BlueSpeechSphere = "Blue Sphere While Speaking"; - const QString BookmarkLocation = "Bookmark Location"; - const QString Bookmarks = "Bookmarks"; - const QString CascadedShadows = "Cascaded"; - const QString CachesSize = "RAM Caches Size"; - const QString Chat = "Chat..."; - const QString Collisions = "Collisions"; - const QString Console = "Console..."; - const QString ControlWithSpeech = "Control With Speech"; - const QString CopyAddress = "Copy Address to Clipboard"; - const QString CopyPath = "Copy Path to Clipboard"; - const QString DDEFaceRegression = "DDE Face Regression"; - const QString DDEFiltering = "DDE Filtering"; - const QString DecreaseAvatarSize = "Decrease Avatar Size"; - const QString DeleteBookmark = "Delete Bookmark..."; - const QString DisableActivityLogger = "Disable Activity Logger"; - const QString DisableLightEntities = "Disable Light Entities"; - const QString DisableNackPackets = "Disable NACK Packets"; - const QString DiskCacheEditor = "Disk Cache Editor"; - const QString DisplayHands = "Show Hand Info"; - const QString DisplayHandTargets = "Show Hand Targets"; - const QString DisplayModelBounds = "Display Model Bounds"; - const QString DisplayModelTriangles = "Display Model Triangles"; - const QString DisplayModelElementChildProxies = "Display Model Element Children"; - const QString DisplayModelElementProxy = "Display Model Element Bounds"; - const QString DisplayDebugTimingDetails = "Display Timing Details"; - const QString DontDoPrecisionPicking = "Don't Do Precision Picking"; - const QString DontFadeOnOctreeServerChanges = "Don't Fade In/Out on Octree Server Changes"; - const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene"; - const QString EchoLocalAudio = "Echo Local Audio"; - const QString EchoServerAudio = "Echo Server Audio"; - const QString EditEntitiesHelp = "Edit Entities Help..."; - const QString Enable3DTVMode = "Enable 3DTV Mode"; - const QString EnableCharacterController = "Enable avatar collisions"; - const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)"; - const QString EnableVRMode = "Enable VR Mode"; - const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation"; - const QString ExpandMyAvatarTiming = "Expand /myAvatar"; - const QString ExpandOtherAvatarTiming = "Expand /otherAvatar"; - const QString ExpandPaintGLTiming = "Expand /paintGL"; - const QString ExpandUpdateTiming = "Expand /update"; - const QString Faceshift = "Faceshift"; - const QString FilterSixense = "Smooth Sixense Movement"; - const QString FirstPerson = "First Person"; - const QString FrameTimer = "Show Timer"; - const QString Fullscreen = "Fullscreen"; - const QString FullscreenMirror = "Fullscreen Mirror"; - const QString GlowWhenSpeaking = "Glow When Speaking"; - const QString NamesAboveHeads = "Names Above Heads"; - const QString GoToUser = "Go To User"; - const QString HMDTools = "HMD Tools"; - const QString IncreaseAvatarSize = "Increase Avatar Size"; - const QString KeyboardMotorControl = "Enable Keyboard Motor Control"; - const QString LeapMotionOnHMD = "Leap Motion on HMD"; - const QString LoadScript = "Open and Run Script File..."; - const QString LoadScriptURL = "Open and Run Script from URL..."; - const QString LoadRSSDKFile = "Load .rssdk file"; - const QString LodTools = "LOD Tools"; - const QString Login = "Login"; - const QString Log = "Log"; - const QString LowVelocityFilter = "Low Velocity Filter"; - const QString Mirror = "Mirror"; - const QString MuteAudio = "Mute Microphone"; - const QString MuteEnvironment = "Mute Environment"; - const QString NoFaceTracking = "None"; - const QString OctreeStats = "Entity Statistics"; - const QString OffAxisProjection = "Off-Axis Projection"; - const QString OnlyDisplayTopTen = "Only Display Top Ten"; - const QString PackageModel = "Package Model..."; - const QString Pair = "Pair"; - const QString PipelineWarnings = "Log Render Pipeline Warnings"; - const QString Preferences = "Preferences..."; - const QString Quit = "Quit"; - const QString ReloadAllScripts = "Reload All Scripts"; - const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes"; - const QString RenderFocusIndicator = "Show Eye Focus"; - const QString RenderHeadCollisionShapes = "Show Head Collision Shapes"; - const QString RenderLookAtVectors = "Show Look-at Vectors"; - const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes"; - const QString RenderTargetFramerate = "Framerate"; - const QString RenderTargetFramerateUnlimited = "Unlimited"; - const QString RenderTargetFramerate60 = "60"; - const QString RenderTargetFramerate50 = "50"; - const QString RenderTargetFramerate40 = "40"; - const QString RenderTargetFramerate30 = "30"; - const QString RenderTargetFramerateVSyncOn = "V-Sync On"; - const QString RenderResolution = "Scale Resolution"; - const QString RenderResolutionOne = "1"; - const QString RenderResolutionTwoThird = "2/3"; - const QString RenderResolutionHalf = "1/2"; - const QString RenderResolutionThird = "1/3"; - const QString RenderResolutionQuarter = "1/4"; - const QString RenderAmbientLight = "Ambient Light"; - const QString RenderAmbientLightGlobal = "Global"; - const QString RenderAmbientLight0 = "OLD_TOWN_SQUARE"; - const QString RenderAmbientLight1 = "GRACE_CATHEDRAL"; - const QString RenderAmbientLight2 = "EUCALYPTUS_GROVE"; - const QString RenderAmbientLight3 = "ST_PETERS_BASILICA"; - const QString RenderAmbientLight4 = "UFFIZI_GALLERY"; - const QString RenderAmbientLight5 = "GALILEOS_TOMB"; - const QString RenderAmbientLight6 = "VINE_STREET_KITCHEN"; - const QString RenderAmbientLight7 = "BREEZEWAY"; - const QString RenderAmbientLight8 = "CAMPUS_SUNSET"; - const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET"; - const QString ResetAvatarSize = "Reset Avatar Size"; - const QString ResetDDETracking = "Reset DDE Tracking"; - const QString ResetSensors = "Reset Sensors"; - const QString RunningScripts = "Running Scripts"; - const QString RunTimingTests = "Run Timing Tests"; - const QString ScriptEditor = "Script Editor..."; - const QString ScriptedMotorControl = "Enable Scripted Motor Control"; - const QString ShowBordersEntityNodes = "Show Entity Nodes"; - const QString ShowIKConstraints = "Show IK Constraints"; - const QString SimpleShadows = "Simple"; - const QString SixenseEnabled = "Enable Hydra Support"; - const QString SixenseMouseInput = "Enable Sixense Mouse Input"; - const QString SixenseLasers = "Enable Sixense UI Lasers"; - const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations"; - const QString Stars = "Stars"; - const QString Stats = "Stats"; - const QString StereoAudio = "Stereo Audio (disables spatial sound)"; - const QString StopAllScripts = "Stop All Scripts"; - const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; - const QString TestPing = "Test Ping"; - const QString ToolWindow = "Tool Window"; - const QString TransmitterDrive = "Transmitter Drive"; - const QString TurnWithHead = "Turn using Head"; - const QString UseAudioForMouth = "Use Audio for Mouth"; - const QString VisibleToEveryone = "Everyone"; - const QString VisibleToFriends = "Friends"; - const QString VisibleToNoOne = "No one"; - const QString Wireframe = "Wireframe"; -} - - class HifiMenu : public QQuickItem { Q_OBJECT QML_DIALOG_DECL - Q_PROPERTY(QString aboutApp READ aboutApp CONSTANT) - Q_PROPERTY(QString addRemoveFriends READ addRemoveFriends CONSTANT) - Q_PROPERTY(QString addressBar READ addressBar CONSTANT) - Q_PROPERTY(QString alignForearmsWithWrists READ alignForearmsWithWrists CONSTANT) - Q_PROPERTY(QString alternateIK READ alternateIK CONSTANT) - Q_PROPERTY(QString ambientOcclusion READ ambientOcclusion CONSTANT) - Q_PROPERTY(QString animations READ animations CONSTANT) - Q_PROPERTY(QString atmosphere READ atmosphere CONSTANT) - Q_PROPERTY(QString attachments READ attachments CONSTANT) - Q_PROPERTY(QString audioNoiseReduction READ audioNoiseReduction CONSTANT) - Q_PROPERTY(QString audioScope READ audioScope CONSTANT) - Q_PROPERTY(QString audioScopeFiftyFrames READ audioScopeFiftyFrames CONSTANT) - Q_PROPERTY(QString audioScopeFiveFrames READ audioScopeFiveFrames CONSTANT) - Q_PROPERTY(QString audioScopeFrames READ audioScopeFrames CONSTANT) - Q_PROPERTY(QString audioScopePause READ audioScopePause CONSTANT) - Q_PROPERTY(QString audioScopeTwentyFrames READ audioScopeTwentyFrames CONSTANT) - Q_PROPERTY(QString audioStats READ audioStats CONSTANT) - Q_PROPERTY(QString audioStatsShowInjectedStreams READ audioStatsShowInjectedStreams CONSTANT) - Q_PROPERTY(QString bandwidthDetails READ bandwidthDetails CONSTANT) - Q_PROPERTY(QString blueSpeechSphere READ blueSpeechSphere CONSTANT) - Q_PROPERTY(QString bookmarkLocation READ bookmarkLocation CONSTANT) - Q_PROPERTY(QString bookmarks READ bookmarks CONSTANT) - Q_PROPERTY(QString cascadedShadows READ cascadedShadows CONSTANT) - Q_PROPERTY(QString cachesSize READ cachesSize CONSTANT) - Q_PROPERTY(QString chat READ chat CONSTANT) - Q_PROPERTY(QString collisions READ collisions CONSTANT) - Q_PROPERTY(QString console READ console CONSTANT) - Q_PROPERTY(QString controlWithSpeech READ controlWithSpeech CONSTANT) - Q_PROPERTY(QString copyAddress READ copyAddress CONSTANT) - Q_PROPERTY(QString copyPath READ copyPath CONSTANT) - Q_PROPERTY(QString ddeFaceRegression READ ddeFaceRegression CONSTANT) - Q_PROPERTY(QString ddeFiltering READ ddeFiltering CONSTANT) - Q_PROPERTY(QString decreaseAvatarSize READ decreaseAvatarSize CONSTANT) - Q_PROPERTY(QString deleteBookmark READ deleteBookmark CONSTANT) - Q_PROPERTY(QString disableActivityLogger READ disableActivityLogger CONSTANT) - Q_PROPERTY(QString disableLightEntities READ disableLightEntities CONSTANT) - Q_PROPERTY(QString disableNackPackets READ disableNackPackets CONSTANT) - Q_PROPERTY(QString diskCacheEditor READ diskCacheEditor CONSTANT) - Q_PROPERTY(QString displayHands READ displayHands CONSTANT) - Q_PROPERTY(QString displayHandTargets READ displayHandTargets CONSTANT) - Q_PROPERTY(QString displayModelBounds READ displayModelBounds CONSTANT) - Q_PROPERTY(QString displayModelTriangles READ displayModelTriangles CONSTANT) - Q_PROPERTY(QString displayModelElementChildProxies READ displayModelElementChildProxies CONSTANT) - Q_PROPERTY(QString displayModelElementProxy READ displayModelElementProxy CONSTANT) - Q_PROPERTY(QString displayDebugTimingDetails READ displayDebugTimingDetails CONSTANT) - Q_PROPERTY(QString dontDoPrecisionPicking READ dontDoPrecisionPicking CONSTANT) - Q_PROPERTY(QString dontFadeOnOctreeServerChanges READ dontFadeOnOctreeServerChanges CONSTANT) - Q_PROPERTY(QString dontRenderEntitiesAsScene READ dontRenderEntitiesAsScene CONSTANT) - Q_PROPERTY(QString echoLocalAudio READ echoLocalAudio CONSTANT) - Q_PROPERTY(QString echoServerAudio READ echoServerAudio CONSTANT) - Q_PROPERTY(QString editEntitiesHelp READ editEntitiesHelp CONSTANT) - Q_PROPERTY(QString enable3DTVMode READ enable3DTVMode CONSTANT) - Q_PROPERTY(QString enableCharacterController READ enableCharacterController CONSTANT) - Q_PROPERTY(QString enableGlowEffect READ enableGlowEffect CONSTANT) - Q_PROPERTY(QString enableVRMode READ enableVRMode CONSTANT) - Q_PROPERTY(QString expandMyAvatarSimulateTiming READ expandMyAvatarSimulateTiming CONSTANT) - Q_PROPERTY(QString expandMyAvatarTiming READ expandMyAvatarTiming CONSTANT) - Q_PROPERTY(QString expandOtherAvatarTiming READ expandOtherAvatarTiming CONSTANT) - Q_PROPERTY(QString expandPaintGLTiming READ expandPaintGLTiming CONSTANT) - Q_PROPERTY(QString expandUpdateTiming READ expandUpdateTiming CONSTANT) - Q_PROPERTY(QString faceshift READ faceshift CONSTANT) - Q_PROPERTY(QString filterSixense READ filterSixense CONSTANT) - Q_PROPERTY(QString firstPerson READ firstPerson CONSTANT) - Q_PROPERTY(QString frameTimer READ frameTimer CONSTANT) - Q_PROPERTY(QString fullscreen READ fullscreen CONSTANT) - Q_PROPERTY(QString fullscreenMirror READ fullscreenMirror CONSTANT) - Q_PROPERTY(QString glowWhenSpeaking READ glowWhenSpeaking CONSTANT) - Q_PROPERTY(QString namesAboveHeads READ namesAboveHeads CONSTANT) - Q_PROPERTY(QString goToUser READ goToUser CONSTANT) - Q_PROPERTY(QString hmdTools READ hmdTools CONSTANT) - Q_PROPERTY(QString increaseAvatarSize READ increaseAvatarSize CONSTANT) - Q_PROPERTY(QString keyboardMotorControl READ keyboardMotorControl CONSTANT) - Q_PROPERTY(QString leapMotionOnHMD READ leapMotionOnHMD CONSTANT) - Q_PROPERTY(QString loadScript READ loadScript CONSTANT) - Q_PROPERTY(QString loadScriptURL READ loadScriptURL CONSTANT) - Q_PROPERTY(QString loadRSSDKFile READ loadRSSDKFile CONSTANT) - Q_PROPERTY(QString lodTools READ lodTools CONSTANT) - Q_PROPERTY(QString login READ login CONSTANT) - Q_PROPERTY(QString log READ log CONSTANT) - Q_PROPERTY(QString lowVelocityFilter READ lowVelocityFilter CONSTANT) - Q_PROPERTY(QString mirror READ mirror CONSTANT) - Q_PROPERTY(QString muteAudio READ muteAudio CONSTANT) - Q_PROPERTY(QString muteEnvironment READ muteEnvironment CONSTANT) - Q_PROPERTY(QString noFaceTracking READ noFaceTracking CONSTANT) - Q_PROPERTY(QString octreeStats READ octreeStats CONSTANT) - Q_PROPERTY(QString offAxisProjection READ offAxisProjection CONSTANT) - Q_PROPERTY(QString onlyDisplayTopTen READ onlyDisplayTopTen CONSTANT) - Q_PROPERTY(QString packageModel READ packageModel CONSTANT) - Q_PROPERTY(QString pair READ pair CONSTANT) - Q_PROPERTY(QString pipelineWarnings READ pipelineWarnings CONSTANT) - Q_PROPERTY(QString preferences READ preferences CONSTANT) - Q_PROPERTY(QString quit READ quit CONSTANT) - Q_PROPERTY(QString reloadAllScripts READ reloadAllScripts CONSTANT) - Q_PROPERTY(QString renderBoundingCollisionShapes READ renderBoundingCollisionShapes CONSTANT) - Q_PROPERTY(QString renderFocusIndicator READ renderFocusIndicator CONSTANT) - Q_PROPERTY(QString renderHeadCollisionShapes READ renderHeadCollisionShapes CONSTANT) - Q_PROPERTY(QString renderLookAtVectors READ renderLookAtVectors CONSTANT) - Q_PROPERTY(QString renderSkeletonCollisionShapes READ renderSkeletonCollisionShapes CONSTANT) - Q_PROPERTY(QString renderTargetFramerate READ renderTargetFramerate CONSTANT) - Q_PROPERTY(QString renderTargetFramerateUnlimited READ renderTargetFramerateUnlimited CONSTANT) - Q_PROPERTY(QString renderTargetFramerate60 READ renderTargetFramerate60 CONSTANT) - Q_PROPERTY(QString renderTargetFramerate50 READ renderTargetFramerate50 CONSTANT) - Q_PROPERTY(QString renderTargetFramerate40 READ renderTargetFramerate40 CONSTANT) - Q_PROPERTY(QString renderTargetFramerate30 READ renderTargetFramerate30 CONSTANT) - Q_PROPERTY(QString renderTargetFramerateVSyncOn READ renderTargetFramerateVSyncOn CONSTANT) - Q_PROPERTY(QString renderResolution READ renderResolution CONSTANT) - Q_PROPERTY(QString renderResolutionOne READ renderResolutionOne CONSTANT) - Q_PROPERTY(QString renderResolutionTwoThird READ renderResolutionTwoThird CONSTANT) - Q_PROPERTY(QString renderResolutionHalf READ renderResolutionHalf CONSTANT) - Q_PROPERTY(QString renderResolutionThird READ renderResolutionThird CONSTANT) - Q_PROPERTY(QString renderResolutionQuarter READ renderResolutionQuarter CONSTANT) - Q_PROPERTY(QString renderAmbientLight READ renderAmbientLight CONSTANT) - Q_PROPERTY(QString renderAmbientLightGlobal READ renderAmbientLightGlobal CONSTANT) - Q_PROPERTY(QString renderAmbientLight0 READ renderAmbientLight0 CONSTANT) - Q_PROPERTY(QString renderAmbientLight1 READ renderAmbientLight1 CONSTANT) - Q_PROPERTY(QString renderAmbientLight2 READ renderAmbientLight2 CONSTANT) - Q_PROPERTY(QString renderAmbientLight3 READ renderAmbientLight3 CONSTANT) - Q_PROPERTY(QString renderAmbientLight4 READ renderAmbientLight4 CONSTANT) - Q_PROPERTY(QString renderAmbientLight5 READ renderAmbientLight5 CONSTANT) - Q_PROPERTY(QString renderAmbientLight6 READ renderAmbientLight6 CONSTANT) - Q_PROPERTY(QString renderAmbientLight7 READ renderAmbientLight7 CONSTANT) - Q_PROPERTY(QString renderAmbientLight8 READ renderAmbientLight8 CONSTANT) - Q_PROPERTY(QString renderAmbientLight9 READ renderAmbientLight9 CONSTANT) - Q_PROPERTY(QString resetAvatarSize READ resetAvatarSize CONSTANT) - Q_PROPERTY(QString resetDDETracking READ resetDDETracking CONSTANT) - Q_PROPERTY(QString resetSensors READ resetSensors CONSTANT) - Q_PROPERTY(QString runningScripts READ runningScripts CONSTANT) - Q_PROPERTY(QString runTimingTests READ runTimingTests CONSTANT) - Q_PROPERTY(QString scriptEditor READ scriptEditor CONSTANT) - Q_PROPERTY(QString scriptedMotorControl READ scriptedMotorControl CONSTANT) - Q_PROPERTY(QString showBordersEntityNodes READ showBordersEntityNodes CONSTANT) - Q_PROPERTY(QString showIKConstraints READ showIKConstraints CONSTANT) - Q_PROPERTY(QString simpleShadows READ simpleShadows CONSTANT) - Q_PROPERTY(QString sixenseEnabled READ sixenseEnabled CONSTANT) - Q_PROPERTY(QString sixenseMouseInput READ sixenseMouseInput CONSTANT) - Q_PROPERTY(QString sixenseLasers READ sixenseLasers CONSTANT) - Q_PROPERTY(QString shiftHipsForIdleAnimations READ shiftHipsForIdleAnimations CONSTANT) - Q_PROPERTY(QString stars READ stars CONSTANT) - Q_PROPERTY(QString stats READ stats CONSTANT) - Q_PROPERTY(QString stereoAudio READ stereoAudio CONSTANT) - Q_PROPERTY(QString stopAllScripts READ stopAllScripts CONSTANT) - Q_PROPERTY(QString suppressShortTimings READ suppressShortTimings CONSTANT) - Q_PROPERTY(QString testPing READ testPing CONSTANT) - Q_PROPERTY(QString toolWindow READ toolWindow CONSTANT) - Q_PROPERTY(QString transmitterDrive READ transmitterDrive CONSTANT) - Q_PROPERTY(QString turnWithHead READ turnWithHead CONSTANT) - Q_PROPERTY(QString useAudioForMouth READ useAudioForMouth CONSTANT) - Q_PROPERTY(QString visibleToEveryone READ visibleToEveryone CONSTANT) - Q_PROPERTY(QString visibleToFriends READ visibleToFriends CONSTANT) - Q_PROPERTY(QString visibleToNoOne READ visibleToNoOne CONSTANT) - Q_PROPERTY(QString wireframe READ wireframe CONSTANT) - -public: - - const QString & aboutApp() { return MenuOption::AboutApp; } - const QString & addRemoveFriends() { return MenuOption::AddRemoveFriends; } - const QString & addressBar() { return MenuOption::AddressBar; } - const QString & alignForearmsWithWrists() { return MenuOption::AlignForearmsWithWrists; } - const QString & alternateIK() { return MenuOption::AlternateIK; } - const QString & ambientOcclusion() { return MenuOption::AmbientOcclusion; } - const QString & animations() { return MenuOption::Animations; } - const QString & atmosphere() { return MenuOption::Atmosphere; } - const QString & attachments() { return MenuOption::Attachments; } - const QString & audioNoiseReduction() { return MenuOption::AudioNoiseReduction; } - const QString & audioScope() { return MenuOption::AudioScope; } - const QString & audioScopeFiftyFrames() { return MenuOption::AudioScopeFiftyFrames; } - const QString & audioScopeFiveFrames() { return MenuOption::AudioScopeFiveFrames; } - const QString & audioScopeFrames() { return MenuOption::AudioScopeFrames; } - const QString & audioScopePause() { return MenuOption::AudioScopePause; } - const QString & audioScopeTwentyFrames() { return MenuOption::AudioScopeTwentyFrames; } - const QString & audioStats() { return MenuOption::AudioStats; } - const QString & audioStatsShowInjectedStreams() { return MenuOption::AudioStatsShowInjectedStreams; } - const QString & bandwidthDetails() { return MenuOption::BandwidthDetails; } - const QString & blueSpeechSphere() { return MenuOption::BlueSpeechSphere; } - const QString & bookmarkLocation() { return MenuOption::BookmarkLocation; } - const QString & bookmarks() { return MenuOption::Bookmarks; } - const QString & cascadedShadows() { return MenuOption::CascadedShadows; } - const QString & cachesSize() { return MenuOption::CachesSize; } - const QString & chat() { return MenuOption::Chat; } - const QString & collisions() { return MenuOption::Collisions; } - const QString & console() { return MenuOption::Console; } - const QString & controlWithSpeech() { return MenuOption::ControlWithSpeech; } - const QString & copyAddress() { return MenuOption::CopyAddress; } - const QString & copyPath() { return MenuOption::CopyPath; } - const QString & ddeFaceRegression() { return MenuOption::DDEFaceRegression; } - const QString & ddeFiltering() { return MenuOption::DDEFiltering; } - const QString & decreaseAvatarSize() { return MenuOption::DecreaseAvatarSize; } - const QString & deleteBookmark() { return MenuOption::DeleteBookmark; } - const QString & disableActivityLogger() { return MenuOption::DisableActivityLogger; } - const QString & disableLightEntities() { return MenuOption::DisableLightEntities; } - const QString & disableNackPackets() { return MenuOption::DisableNackPackets; } - const QString & diskCacheEditor() { return MenuOption::DiskCacheEditor; } - const QString & displayHands() { return MenuOption::DisplayHands; } - const QString & displayHandTargets() { return MenuOption::DisplayHandTargets; } - const QString & displayModelBounds() { return MenuOption::DisplayModelBounds; } - const QString & displayModelTriangles() { return MenuOption::DisplayModelTriangles; } - const QString & displayModelElementChildProxies() { return MenuOption::DisplayModelElementChildProxies; } - const QString & displayModelElementProxy() { return MenuOption::DisplayModelElementProxy; } - const QString & displayDebugTimingDetails() { return MenuOption::DisplayDebugTimingDetails; } - const QString & dontDoPrecisionPicking() { return MenuOption::DontDoPrecisionPicking; } - const QString & dontFadeOnOctreeServerChanges() { return MenuOption::DontFadeOnOctreeServerChanges; } - const QString & dontRenderEntitiesAsScene() { return MenuOption::DontRenderEntitiesAsScene; } - const QString & echoLocalAudio() { return MenuOption::EchoLocalAudio; } - const QString & echoServerAudio() { return MenuOption::EchoServerAudio; } - const QString & editEntitiesHelp() { return MenuOption::EditEntitiesHelp; } - const QString & enable3DTVMode() { return MenuOption::Enable3DTVMode; } - const QString & enableCharacterController() { return MenuOption::EnableCharacterController; } - const QString & enableGlowEffect() { return MenuOption::EnableGlowEffect; } - const QString & enableVRMode() { return MenuOption::EnableVRMode; } - const QString & expandMyAvatarSimulateTiming() { return MenuOption::ExpandMyAvatarSimulateTiming; } - const QString & expandMyAvatarTiming() { return MenuOption::ExpandMyAvatarTiming; } - const QString & expandOtherAvatarTiming() { return MenuOption::ExpandOtherAvatarTiming; } - const QString & expandPaintGLTiming() { return MenuOption::ExpandPaintGLTiming; } - const QString & expandUpdateTiming() { return MenuOption::ExpandUpdateTiming; } - const QString & faceshift() { return MenuOption::Faceshift; } - const QString & filterSixense() { return MenuOption::FilterSixense; } - const QString & firstPerson() { return MenuOption::FirstPerson; } - const QString & frameTimer() { return MenuOption::FrameTimer; } - const QString & fullscreen() { return MenuOption::Fullscreen; } - const QString & fullscreenMirror() { return MenuOption::FullscreenMirror; } - const QString & glowWhenSpeaking() { return MenuOption::GlowWhenSpeaking; } - const QString & namesAboveHeads() { return MenuOption::NamesAboveHeads; } - const QString & goToUser() { return MenuOption::GoToUser; } - const QString & hmdTools() { return MenuOption::HMDTools; } - const QString & increaseAvatarSize() { return MenuOption::IncreaseAvatarSize; } - const QString & keyboardMotorControl() { return MenuOption::KeyboardMotorControl; } - const QString & leapMotionOnHMD() { return MenuOption::LeapMotionOnHMD; } - const QString & loadScript() { return MenuOption::LoadScript; } - const QString & loadScriptURL() { return MenuOption::LoadScriptURL; } - const QString & loadRSSDKFile() { return MenuOption::LoadRSSDKFile; } - const QString & lodTools() { return MenuOption::LodTools; } - const QString & login() { return MenuOption::Login; } - const QString & log() { return MenuOption::Log; } - const QString & lowVelocityFilter() { return MenuOption::LowVelocityFilter; } - const QString & mirror() { return MenuOption::Mirror; } - const QString & muteAudio() { return MenuOption::MuteAudio; } - const QString & muteEnvironment() { return MenuOption::MuteEnvironment; } - const QString & noFaceTracking() { return MenuOption::NoFaceTracking; } - const QString & octreeStats() { return MenuOption::OctreeStats; } - const QString & offAxisProjection() { return MenuOption::OffAxisProjection; } - const QString & onlyDisplayTopTen() { return MenuOption::OnlyDisplayTopTen; } - const QString & packageModel() { return MenuOption::PackageModel; } - const QString & pair() { return MenuOption::Pair; } - const QString & pipelineWarnings() { return MenuOption::PipelineWarnings; } - const QString & preferences() { return MenuOption::Preferences; } - const QString & quit() { return MenuOption::Quit; } - const QString & reloadAllScripts() { return MenuOption::ReloadAllScripts; } - const QString & renderBoundingCollisionShapes() { return MenuOption::RenderBoundingCollisionShapes; } - const QString & renderFocusIndicator() { return MenuOption::RenderFocusIndicator; } - const QString & renderHeadCollisionShapes() { return MenuOption::RenderHeadCollisionShapes; } - const QString & renderLookAtVectors() { return MenuOption::RenderLookAtVectors; } - const QString & renderSkeletonCollisionShapes() { return MenuOption::RenderSkeletonCollisionShapes; } - const QString & renderTargetFramerate() { return MenuOption::RenderTargetFramerate; } - const QString & renderTargetFramerateUnlimited() { return MenuOption::RenderTargetFramerateUnlimited; } - const QString & renderTargetFramerate60() { return MenuOption::RenderTargetFramerate60; } - const QString & renderTargetFramerate50() { return MenuOption::RenderTargetFramerate50; } - const QString & renderTargetFramerate40() { return MenuOption::RenderTargetFramerate40; } - const QString & renderTargetFramerate30() { return MenuOption::RenderTargetFramerate30; } - const QString & renderTargetFramerateVSyncOn() { return MenuOption::RenderTargetFramerateVSyncOn; } - const QString & renderResolution() { return MenuOption::RenderResolution; } - const QString & renderResolutionOne() { return MenuOption::RenderResolutionOne; } - const QString & renderResolutionTwoThird() { return MenuOption::RenderResolutionTwoThird; } - const QString & renderResolutionHalf() { return MenuOption::RenderResolutionHalf; } - const QString & renderResolutionThird() { return MenuOption::RenderResolutionThird; } - const QString & renderResolutionQuarter() { return MenuOption::RenderResolutionQuarter; } - const QString & renderAmbientLight() { return MenuOption::RenderAmbientLight; } - const QString & renderAmbientLightGlobal() { return MenuOption::RenderAmbientLightGlobal; } - const QString & renderAmbientLight0() { return MenuOption::RenderAmbientLight0; } - const QString & renderAmbientLight1() { return MenuOption::RenderAmbientLight1; } - const QString & renderAmbientLight2() { return MenuOption::RenderAmbientLight2; } - const QString & renderAmbientLight3() { return MenuOption::RenderAmbientLight3; } - const QString & renderAmbientLight4() { return MenuOption::RenderAmbientLight4; } - const QString & renderAmbientLight5() { return MenuOption::RenderAmbientLight5; } - const QString & renderAmbientLight6() { return MenuOption::RenderAmbientLight6; } - const QString & renderAmbientLight7() { return MenuOption::RenderAmbientLight7; } - const QString & renderAmbientLight8() { return MenuOption::RenderAmbientLight8; } - const QString & renderAmbientLight9() { return MenuOption::RenderAmbientLight9; } - const QString & resetAvatarSize() { return MenuOption::ResetAvatarSize; } - const QString & resetDDETracking() { return MenuOption::ResetDDETracking; } - const QString & resetSensors() { return MenuOption::ResetSensors; } - const QString & runningScripts() { return MenuOption::RunningScripts; } - const QString & runTimingTests() { return MenuOption::RunTimingTests; } - const QString & scriptEditor() { return MenuOption::ScriptEditor; } - const QString & scriptedMotorControl() { return MenuOption::ScriptedMotorControl; } - const QString & showBordersEntityNodes() { return MenuOption::ShowBordersEntityNodes; } - const QString & showIKConstraints() { return MenuOption::ShowIKConstraints; } - const QString & simpleShadows() { return MenuOption::SimpleShadows; } - const QString & sixenseEnabled() { return MenuOption::SixenseEnabled; } - const QString & sixenseMouseInput() { return MenuOption::SixenseMouseInput; } - const QString & sixenseLasers() { return MenuOption::SixenseLasers; } - const QString & shiftHipsForIdleAnimations() { return MenuOption::ShiftHipsForIdleAnimations; } - const QString & stars() { return MenuOption::Stars; } - const QString & stats() { return MenuOption::Stats; } - const QString & stereoAudio() { return MenuOption::StereoAudio; } - const QString & stopAllScripts() { return MenuOption::StopAllScripts; } - const QString & suppressShortTimings() { return MenuOption::SuppressShortTimings; } - const QString & testPing() { return MenuOption::TestPing; } - const QString & toolWindow() { return MenuOption::ToolWindow; } - const QString & transmitterDrive() { return MenuOption::TransmitterDrive; } - const QString & turnWithHead() { return MenuOption::TurnWithHead; } - const QString & useAudioForMouth() { return MenuOption::UseAudioForMouth; } - const QString & visibleToEveryone() { return MenuOption::VisibleToEveryone; } - const QString & visibleToFriends() { return MenuOption::VisibleToFriends; } - const QString & visibleToNoOne() { return MenuOption::VisibleToNoOne; } - const QString & wireframe() { return MenuOption::Wireframe; } - -public slots: - void onTriggeredByName(const QString & name); - void onToggledByName(const QString & name); public: HifiMenu(QQuickItem * parent = nullptr); static void setToggleAction(const QString & name, std::function f); static void setTriggerAction(const QString & name, std::function f); +private slots: + void onTriggeredByName(const QString & name); + void onToggledByName(const QString & name); private: static QHash> triggerActions; static QHash> toggleActions; diff --git a/libraries/ui/src/OffscreenQmlDialog.h b/libraries/ui/src/OffscreenQmlDialog.h index c6c95981a6..7b7c83ad65 100644 --- a/libraries/ui/src/OffscreenQmlDialog.h +++ b/libraries/ui/src/OffscreenQmlDialog.h @@ -23,8 +23,8 @@ private: \ static const QUrl QML; \ public: \ static void registerType(); \ - static void show(std::function f = [](QQmlContext*, QQuickItem*) {}); \ - static void toggle(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void show(std::function f = [](QQmlContext*, QObject*) {}); \ + static void toggle(std::function f = [](QQmlContext*, QObject*) {}); \ private: #define QML_DIALOG_DEF(x) \ @@ -35,12 +35,12 @@ private: qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ } \ \ - void x::show(std::function f) { \ + void x::show(std::function f) { \ auto offscreenUi = DependencyManager::get(); \ offscreenUi->show(QML, NAME, f); \ } \ \ - void x::toggle(std::function f) { \ + void x::toggle(std::function f) { \ auto offscreenUi = DependencyManager::get(); \ offscreenUi->toggle(QML, NAME, f); \ } diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index b14951f054..d44a5dd282 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -132,22 +132,27 @@ void OffscreenUi::resize(const QSize& newSize) { doneCurrent(); } -QQmlContext* OffscreenUi::qmlContext() { - if (nullptr == _rootItem) { - return _qmlComponent->creationContext(); - } - return QQmlEngine::contextForObject(_rootItem); +QQuickItem* OffscreenUi::getRootItem() { + return _rootItem; } +//QQmlContext* OffscreenUi::qmlContext() { +// if (nullptr == _rootItem) { +// return _qmlComponent->creationContext(); +// } +// return QQmlEngine::contextForObject(_rootItem); +//} + void OffscreenUi::setBaseUrl(const QUrl& baseUrl) { _qmlEngine->setBaseUrl(baseUrl); } -void OffscreenUi::load(const QUrl& qmlSource, std::function f) { +void OffscreenUi::load(const QUrl& qmlSource, std::function f) { qDebug() << "Loading QML from URL " << qmlSource; _qmlComponent->loadUrl(qmlSource); if (_qmlComponent->isLoading()) - connect(_qmlComponent, &QQmlComponent::statusChanged, this, [this, f] { + connect(_qmlComponent, &QQmlComponent::statusChanged, this, + [this, f](QQmlComponent::Status){ finishQmlLoad(f); }); else { @@ -168,8 +173,8 @@ void OffscreenUi::requestRender() { } } -void OffscreenUi::finishQmlLoad(std::function f) { - disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad); +void OffscreenUi::finishQmlLoad(std::function f) { + disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, 0); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); foreach(const QQmlError &error, errorList) { @@ -178,7 +183,8 @@ void OffscreenUi::finishQmlLoad(std::function f return; } - QObject* newObject = _qmlComponent->create(); + QQmlContext * newContext = new QQmlContext(_qmlEngine, qApp); + QObject* newObject = _qmlComponent->beginCreate(newContext); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); foreach(const QQmlError &error, errorList) @@ -189,6 +195,9 @@ void OffscreenUi::finishQmlLoad(std::function f return; } + f(newContext, newObject); + _qmlComponent->completeCreate(); + QQuickItem* newItem = qobject_cast(newObject); if (!newItem) { qWarning("run: Not a QQuickItem"); @@ -203,7 +212,6 @@ void OffscreenUi::finishQmlLoad(std::function f // Make sure we make items focusable (critical for // supporting keyboard shortcuts) newItem->setFlag(QQuickItem::ItemIsFocusScope, true); - f(_qmlEngine->contextForObject(newItem), newItem); if (!_rootItem) { // The root item is ready. Associate it with the window. _rootItem = newItem; @@ -215,7 +223,6 @@ void OffscreenUi::finishQmlLoad(std::function f QQmlEngine::setObjectOwnership(newItem, QQmlEngine::JavaScriptOwnership); newItem->setParent(_rootItem); newItem->setParentItem(_rootItem); - newItem->setEnabled(true); } } @@ -397,22 +404,22 @@ void OffscreenUi::setProxyWindow(QWindow* window) { _renderControl->_renderWindow = window; } -void OffscreenUi::show(const QUrl& url, const QString& name, std::function f) { +void OffscreenUi::show(const QUrl& url, const QString& name, std::function f) { QQuickItem* item = _rootItem->findChild(name); // First load? if (!item) { load(url, f); - return; + item = _rootItem->findChild(name); } item->setEnabled(true); } -void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function f) { +void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function f) { QQuickItem* item = _rootItem->findChild(name); // First load? if (!item) { load(url, f); - return; + item = _rootItem->findChild(name); } item->setEnabled(!item->isEnabled()); } @@ -421,7 +428,7 @@ void OffscreenUi::messageBox(const QString& title, const QString& text, ButtonCallback callback, QMessageBox::Icon icon, QMessageBox::StandardButtons buttons) { - MessageDialog::show([=](QQmlContext*ctx, QQuickItem*item) { + MessageDialog::show([=](QQmlContext*ctx, QObject*item) { MessageDialog * pDialog = item->findChild(); pDialog->setIcon((MessageDialog::Icon)icon); pDialog->setTitle(title); diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index d04eb63bff..33fb46b28a 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -92,16 +92,16 @@ public: virtual ~OffscreenUi(); void create(QOpenGLContext* context); void resize(const QSize& size); - void load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QQuickItem*) {}); - void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QQuickItem*) {}) { + void load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); + void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { load(QUrl(qmlSourceFile), f); } - void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QQuickItem*) {}); - void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QQuickItem*) {}); + void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); + void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); void setBaseUrl(const QUrl& baseUrl); void addImportPath(const QString& path); - QQmlContext* qmlContext(); - + //QQmlContext* getQmlContext(); + QQuickItem* getRootItem(); void pause(); void resume(); bool isPaused() const; @@ -143,7 +143,7 @@ protected: private slots: void updateQuick(); - void finishQmlLoad(std::function f); + void finishQmlLoad(std::function f); public slots: void requestUpdate(); diff --git a/tests/ui/main.qml b/tests/ui/main.qml new file mode 100644 index 0000000000..89dac3d1af --- /dev/null +++ b/tests/ui/main.qml @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Controls 1.2 +import "qml/UI.js" as UI +import "qml" +//import "/Users/bdavis/Git/hifi/interface/resources/qml" + +Item { + anchors.fill: parent + visible: true + //title: "Qt Quick Controls Gallery" + + MessageDialog { + id: aboutDialog + icon: StandardIcon.Information + title: "About" + text: "Qt Quick Controls Gallery" + informativeText: "This example demonstrates most of the available Qt Quick Controls." + } + + Action { + id: copyAction + text: "&Copy" + shortcut: StandardKey.Copy + iconName: "edit-copy" + enabled: (!!activeFocusItem && !!activeFocusItem["copy"]) + onTriggered: activeFocusItem.copy() + } + + Action { + id: cutAction + text: "Cu&t" + shortcut: StandardKey.Cut + iconName: "edit-cut" + enabled: (!!activeFocusItem && !!activeFocusItem["cut"]) + onTriggered: activeFocusItem.cut() + } + + Action { + id: pasteAction + text: "&Paste" + shortcut: StandardKey.Paste + iconName: "edit-paste" + enabled: (!!activeFocusItem && !!activeFocusItem["paste"]) + onTriggered: activeFocusItem.paste() + } + +// toolBar: ToolBar { +// RowLayout { +// anchors.fill: parent +// anchors.margins: spacing +// Label { +// text: UI.label +// } +// Item { Layout.fillWidth: true } +// CheckBox { +// id: enabler +// text: "Enabled" +// checked: true +// } +// } +// } + +// menuBar: MenuBar { +// Menu { +// title: "&File" +// MenuItem { +// text: "E&xit" +// shortcut: StandardKey.Quit +// onTriggered: Qt.quit() +// } +// } +// Menu { +// title: "&Edit" +// visible: tabView.currentIndex == 2 +// MenuItem { action: cutAction } +// MenuItem { action: copyAction } +// MenuItem { action: pasteAction } +// } +// Menu { +// title: "&Help" +// MenuItem { +// text: "About..." +// onTriggered: aboutDialog.open() +// } +// } +// } + + TabView { + id: tabView + + anchors.fill: parent + anchors.margins: UI.margin + tabPosition: UI.tabPosition + + Layout.minimumWidth: 360 + Layout.minimumHeight: 360 + Layout.preferredWidth: 480 + Layout.preferredHeight: 640 + + Tab { + title: "Buttons" + ButtonPage { + enabled: enabler.checked + } + } + Tab { + title: "Progress" + ProgressPage { + enabled: enabler.checked + } + } + Tab { + title: "Input" + InputPage { + enabled: enabler.checked + } + } + } +} diff --git a/tests/ui/qml/ButtonPage.qml b/tests/ui/qml/ButtonPage.qml new file mode 100644 index 0000000000..0ed7e2d6ad --- /dev/null +++ b/tests/ui/qml/ButtonPage.qml @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 + +ScrollView { + id: page + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + Item { + id: content + + width: Math.max(page.viewport.width, grid.implicitWidth + 2 * grid.rowSpacing) + height: Math.max(page.viewport.height, grid.implicitHeight + 2 * grid.columnSpacing) + + GridLayout { + id: grid + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: grid.rowSpacing + anchors.rightMargin: grid.rowSpacing + anchors.topMargin: grid.columnSpacing + + columns: page.width < page.height ? 1 : 2 + + GroupBox { + title: "Button" + Layout.fillWidth: true + Layout.columnSpan: grid.columns + RowLayout { + anchors.fill: parent + Button { text: "OK"; isDefault: true } + Button { text: "Cancel" } + Item { Layout.fillWidth: true } + Button { + text: "Attach" + menu: Menu { + MenuItem { text: "Image" } + MenuItem { text: "Document" } + } + } + } + } + + GroupBox { + title: "CheckBox" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + CheckBox { text: "E-mail"; checked: true } + CheckBox { text: "Calendar"; checked: true } + CheckBox { text: "Contacts" } + } + } + + GroupBox { + title: "RadioButton" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + ExclusiveGroup { id: radioGroup } + RadioButton { text: "Portrait"; exclusiveGroup: radioGroup } + RadioButton { text: "Landscape"; exclusiveGroup: radioGroup } + RadioButton { text: "Automatic"; exclusiveGroup: radioGroup; checked: true } + } + } + + GroupBox { + title: "Switch" + Layout.fillWidth: true + Layout.columnSpan: grid.columns + ColumnLayout { + anchors.fill: parent + RowLayout { + Label { text: "Wi-Fi"; Layout.fillWidth: true } + Switch { checked: true } + } + RowLayout { + Label { text: "Bluetooth"; Layout.fillWidth: true } + Switch { checked: false } + } + } + } + } + } +} diff --git a/tests/ui/qml/InputPage.qml b/tests/ui/qml/InputPage.qml new file mode 100644 index 0000000000..cb1878d023 --- /dev/null +++ b/tests/ui/qml/InputPage.qml @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 + +ScrollView { + id: page + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + Item { + id: content + + width: Math.max(page.viewport.width, column.implicitWidth + 2 * column.spacing) + height: Math.max(page.viewport.height, column.implicitHeight + 2 * column.spacing) + + ColumnLayout { + id: column + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: column.spacing + + GroupBox { + title: "TextField" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + TextField { placeholderText: "..."; Layout.fillWidth: true; z: 1 } + TextField { placeholderText: "Password"; echoMode: TextInput.Password; Layout.fillWidth: true } + } + } + + GroupBox { + title: "ComboBox" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + ComboBox { + model: Qt.fontFamilies() + Layout.fillWidth: true + } + ComboBox { + editable: true + model: ListModel { + id: listModel + ListElement { text: "Apple" } + ListElement { text: "Banana" } + ListElement { text: "Coconut" } + ListElement { text: "Orange" } + } + onAccepted: { + if (find(currentText) === -1) { + listModel.append({text: editText}) + currentIndex = find(editText) + } + } + Layout.fillWidth: true + } + } + } + + GroupBox { + title: "SpinBox" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + SpinBox { value: 99; Layout.fillWidth: true; z: 1 } + SpinBox { decimals: 2; Layout.fillWidth: true } + } + } + } + } +} diff --git a/tests/ui/qml/ProgressPage.qml b/tests/ui/qml/ProgressPage.qml new file mode 100644 index 0000000000..a1fa596f79 --- /dev/null +++ b/tests/ui/qml/ProgressPage.qml @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 + +ScrollView { + id: page + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + Item { + id: content + + width: Math.max(page.viewport.width, column.implicitWidth + 2 * column.spacing) + height: Math.max(page.viewport.height, column.implicitHeight + 2 * column.spacing) + + ColumnLayout { + id: column + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: column.spacing + + GroupBox { + title: "ProgressBar" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + ProgressBar { indeterminate: true; Layout.fillWidth: true } + ProgressBar { value: slider.value; Layout.fillWidth: true } + } + } + + GroupBox { + title: "Slider" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + Slider { id: slider; value: 0.5; Layout.fillWidth: true } + } + } + + GroupBox { + title: "BusyIndicator" + Layout.fillWidth: true + BusyIndicator { running: true } + } + } + } +} diff --git a/tests/ui/qml/UI.js b/tests/ui/qml/UI.js new file mode 100644 index 0000000000..0286ac56a6 --- /dev/null +++ b/tests/ui/qml/UI.js @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +.pragma library + +var margin = 2 +var tabPosition = Qt.TopEdge +var label = "" diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 00d0bc80fd..e84e5674c1 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -83,6 +84,17 @@ const QString & getQmlDir() { return dir; } +const QString & getTestQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; + qDebug() << "Qml Test Path: " << dir; + } + return dir; +} + // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow, private QOpenGLFunctions { Q_OBJECT @@ -95,6 +107,8 @@ class QTestWindow : public QWindow, private QOpenGLFunctions { int testQmlTexture{ 0 }; public: + QObject * rootMenu; + QTestWindow() { _timer.setInterval(1); connect(&_timer, &QTimer::timeout, [=] { @@ -144,18 +158,6 @@ public: auto offscreenUi = DependencyManager::get(); offscreenUi->create(_context); - - makeCurrent(); - - offscreenUi->setProxyWindow(this); - setFramePosition(QPoint(-1000, 0)); - resize(QSize(800, 600)); - - offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); - offscreenUi->load(QUrl("TestRoot.qml")); - offscreenUi->addImportPath(getQmlDir()); - offscreenUi->addImportPath("."); - connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { offscreenUi->lockTexture(textureId); assert(!glGetError()); @@ -165,10 +167,25 @@ public: offscreenUi->releaseTexture(oldTexture); } }); + + makeCurrent(); + + offscreenUi->setProxyWindow(this); + setFramePosition(QPoint(-1000, 0)); + resize(QSize(800, 600)); + +#ifdef QML_CONTROL_GALLERY + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir())); + offscreenUi->load(QUrl("main.qml")); +#else + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); + offscreenUi->load(QUrl("TestRoot.qml")); + offscreenUi->load(QUrl("RootMenu.qml")); +#endif installEventFilter(offscreenUi.data()); - HifiMenu::setTriggerAction(MenuOption::Quit, [] { - QApplication::quit(); - }); + //HifiMenu::setTriggerAction(MenuOption::Quit, [] { + // QApplication::quit(); + //}); offscreenUi->resume(); _timer.start(); } @@ -216,15 +233,30 @@ protected: resizeWindow(ev->size()); } + + static QObject * addMenu(QObject * parent, const QString & text) { + // FIXME add more checking here to ensure no name conflicts + QVariant returnedValue; + QMetaObject::invokeMethod(parent, "addMenu", + Q_RETURN_ARG(QVariant, returnedValue), + Q_ARG(QVariant, text)); + QObject * result = returnedValue.value(); + return result; + } + void keyPressEvent(QKeyEvent *event) { _altPressed = Qt::Key_Alt == event->key(); switch (event->key()) { case Qt::Key_L: if (event->modifiers() & Qt::CTRL) { - //auto offscreenUi = DependencyManager::get(); - //DependencyManager::get()->toggle(QString("TestDialog.qml"), "TestDialog"); - //DependencyManager::get()->toggle(QString("MenuTest.qml"), "MenuTest"); - //HifiMenu::toggle(); + auto offscreenUi = DependencyManager::get(); + rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); + QObject * result = addMenu(rootMenu, "Test 3"); + result->setParent(rootMenu); + qDebug() << "Added " << result; + if (menuContext) { + menuContext->setContextProperty("rootMenu", rootMenu); + } } break; case Qt::Key_K: @@ -236,15 +268,23 @@ protected: break; case Qt::Key_J: if (event->modifiers() & Qt::CTRL) { + auto offscreenUi = DependencyManager::get(); + rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); + QMetaObject::invokeMethod(rootMenu, "popup"); } break; } QWindow::keyPressEvent(event); } - + QQmlContext* menuContext{ nullptr }; void keyReleaseEvent(QKeyEvent *event) { if (_altPressed && Qt::Key_Alt == event->key()) { - HifiMenu::toggle(); + HifiMenu::toggle([=](QQmlContext* context, QObject* newItem) { + auto offscreenUi = DependencyManager::get(); + rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); + menuContext = context; + menuContext->setContextProperty("rootMenu", rootMenu); + }); } } From 1678d77af6b063f930f36776b221da0e9b60d818 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 23 Apr 2015 17:18:32 -0700 Subject: [PATCH 274/401] Log DDE FPS after a reset --- interface/src/devices/DdeFaceTracker.cpp | 30 ++++++++++++++++++++++-- interface/src/devices/DdeFaceTracker.h | 6 +++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 03989c6ffb..9cf8942cf7 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include @@ -136,6 +136,9 @@ struct Packet { const float STARTING_DDE_MESSAGE_TIME = 0.033f; +const int FPS_TIMER_DELAY = 2000; // ms +const int FPS_TIMER_DURATION = 2000; // ms + DdeFaceTracker::DdeFaceTracker() : DdeFaceTracker(QHostAddress::Any, DDE_SERVER_PORT, DDE_CONTROL_PORT) { @@ -168,7 +171,9 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui _lastLeftEyeBlink(0.0f), _filteredLeftEyeBlink(0.0f), _lastRightEyeBlink(0.0f), - _filteredRightEyeBlink(0.0f) + _filteredRightEyeBlink(0.0f), + _isCalculatingFPS(false), + _frameCount(0) { _coefficients.resize(NUM_FACESHIFT_BLENDSHAPES); @@ -229,6 +234,12 @@ void DdeFaceTracker::reset() { const char* DDE_RESET_COMMAND = "reset"; _udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort); + // Log camera FPS after a reset + if (!_isCalculatingFPS) { + QTimer::singleShot(FPS_TIMER_DELAY, this, SLOT(startFPSTimer())); + _isCalculatingFPS = true; + } + _reset = true; } @@ -407,9 +418,24 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { + (1.0f - FRAME_AVERAGING_FACTOR) * (float)(usecsNow - _lastMessageReceived) / 1000000.0f; } _lastMessageReceived = usecsNow; + + // Count frames if timing + if (_isCalculatingFPS) { + _frameCount++; + } } else { qCDebug(interfaceapp) << "[Error] DDE Face Tracker Decode Error"; } _lastReceiveTimestamp = usecTimestampNow(); } + +void DdeFaceTracker::startFPSTimer() { + _frameCount = 0; + QTimer::singleShot(FPS_TIMER_DURATION, this, SLOT(finishFPSTimer())); +} + +void DdeFaceTracker::finishFPSTimer() { + qDebug() << "[Info] DDE FPS =" << (float)_frameCount / ((float)FPS_TIMER_DURATION / 1000.0f); + _isCalculatingFPS = false; +} diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 506e2974b6..7cca1e31be 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -58,6 +58,9 @@ private slots: void socketErrorOccurred(QAbstractSocket::SocketError socketError); void readPendingDatagrams(); void socketStateChanged(QAbstractSocket::SocketState socketState); + + void startFPSTimer(); + void finishFPSTimer(); private: DdeFaceTracker(); @@ -108,6 +111,9 @@ private: float _filteredLeftEyeBlink; float _lastRightEyeBlink; float _filteredRightEyeBlink; + + bool _isCalculatingFPS; + int _frameCount; }; #endif // hifi_DdeFaceTracker_h \ No newline at end of file From cf0499e6715901d2ef3697d2f775705653becb67 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Apr 2015 21:07:04 -0700 Subject: [PATCH 275/401] various physics-related experiments --- libraries/entities/src/EntityItem.cpp | 68 +++++++++++---- libraries/entities/src/EntityItem.h | 9 +- libraries/physics/src/EntityMotionState.cpp | 27 +++--- libraries/physics/src/PhysicsEngine.cpp | 91 ++++++++++++++------- libraries/physics/src/PhysicsEngine.h | 5 +- 5 files changed, 141 insertions(+), 59 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f968244ab3..6c09569037 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -65,7 +65,13 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), _physicsInfo(NULL), _dirtyFlags(0), - _element(NULL) + _element(NULL), + _previousPositionFromServer(ENTITY_ITEM_ZERO_VEC3), + _previousRotationFromServer(ENTITY_ITEM_DEFAULT_ROTATION), + _previousVelocityFromServer(ENTITY_ITEM_ZERO_VEC3), + _previousAngularVelocityFromServer(ENTITY_ITEM_ZERO_VEC3), + _previousGravityFromServer(ENTITY_ITEM_ZERO_VEC3), + _previousAccelerationFromServer(ENTITY_ITEM_ZERO_VEC3) { quint64 now = usecTimestampNow(); _lastSimulated = now; @@ -592,7 +598,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef #ifdef WANT_DEBUG qCDebug(entities) << "skipTimeForward:" << skipTimeForward; #endif - simulateKinematicMotion(skipTimeForward); + + // we want to extrapolate the motion forward to compensate for packet travel time, but + // we don't want the side effect of flag setting. + simulateKinematicMotion(skipTimeForward, false); } _lastSimulated = now; } @@ -725,7 +734,7 @@ void EntityItem::simulate(const quint64& now) { _lastSimulated = now; } -void EntityItem::simulateKinematicMotion(float timeElapsed) { +void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { if (hasAngularVelocity()) { // angular damping if (_angularDamping > 0.0f) { @@ -740,7 +749,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) { const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { - if (angularSpeed > 0.0f) { + if (setFlags && angularSpeed > 0.0f) { _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; } _angularVelocity = ENTITY_ITEM_ZERO_VEC3; @@ -802,7 +811,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) { const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) { setVelocity(ENTITY_ITEM_ZERO_VEC3); - if (speed > 0.0f) { + if (setFlags && speed > 0.0f) { _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; } } else { @@ -1089,8 +1098,11 @@ void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { } void EntityItem::updatePosition(const glm::vec3& value) { - if (glm::distance(_position, value) > MIN_POSITION_DELTA) { + if (value == _previousPositionFromServer) { _position = value; + } else if (glm::distance(_position, value) > MIN_POSITION_DELTA) { + _position = value; + _previousPositionFromServer = value; _dirtyFlags |= EntityItem::DIRTY_POSITION; } } @@ -1108,8 +1120,11 @@ void EntityItem::updateDimensions(const glm::vec3& value) { } void EntityItem::updateRotation(const glm::quat& rotation) { - if (glm::dot(_rotation, rotation) < MIN_ALIGNMENT_DOT) { - _rotation = rotation; + if (rotation == _previousRotationFromServer) { + _rotation = rotation; + } else if (glm::abs(glm::dot(_rotation, rotation)) < MIN_ALIGNMENT_DOT) { + _rotation = rotation; + _previousRotationFromServer = rotation; _dirtyFlags |= EntityItem::DIRTY_POSITION; } } @@ -1144,12 +1159,19 @@ void EntityItem::updateVelocityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateVelocity(const glm::vec3& value) { - if (glm::distance(_velocity, value) > MIN_VELOCITY_DELTA) { + if (value == _previousVelocityFromServer) { if (glm::length(value) < MIN_VELOCITY_DELTA) { _velocity = ENTITY_ITEM_ZERO_VEC3; } else { _velocity = value; } + } else if (glm::distance(_velocity, value) > MIN_VELOCITY_DELTA) { + if (glm::length(value) < MIN_VELOCITY_DELTA) { + _velocity = ENTITY_ITEM_ZERO_VEC3; + } else { + _velocity = value; + } + _previousVelocityFromServer = value; _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } @@ -1167,20 +1189,38 @@ void EntityItem::updateGravityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateGravity(const glm::vec3& value) { - if ( glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) { + if (value == _previousGravityFromServer) { _gravity = value; + } else if (glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) { + _gravity = value; + _previousGravityFromServer = value; _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } void EntityItem::updateAcceleration(const glm::vec3& value) { - _acceleration = value; - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + if (value == _previousAccelerationFromServer) { + _acceleration = value; + } else if (glm::distance(_acceleration, value) > MIN_ACCELERATION_DELTA) { + _acceleration = value; + _previousAccelerationFromServer = value; + _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + } } void EntityItem::updateAngularVelocity(const glm::vec3& value) { - if (glm::distance(_angularVelocity, value) > MIN_SPIN_DELTA) { - _angularVelocity = value; + if (value == _previousAngularVelocityFromServer) { + if (glm::length(value) < MIN_SPIN_DELTA) { + _angularVelocity = ENTITY_ITEM_ZERO_VEC3; + } else { + _angularVelocity = value; + } + } else if (glm::distance(_angularVelocity, value) > MIN_SPIN_DELTA) { + if (glm::length(value) < MIN_SPIN_DELTA) { + _angularVelocity = ENTITY_ITEM_ZERO_VEC3; + } else { + _angularVelocity = value; + } _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index fda8167564..fa6efd72a1 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -132,7 +132,7 @@ public: // perform linear extrapolation for SimpleEntitySimulation void simulate(const quint64& now); - void simulateKinematicMotion(float timeElapsed); + void simulateKinematicMotion(float timeElapsed, bool setFlags=true); virtual bool needsToCallUpdate() const { return false; } @@ -368,6 +368,13 @@ protected: uint32_t _dirtyFlags; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation EntityTreeElement* _element; // back pointer to containing Element + + glm::vec3 _previousPositionFromServer; + glm::quat _previousRotationFromServer; + glm::vec3 _previousVelocityFromServer; + glm::vec3 _previousAngularVelocityFromServer; + glm::vec3 _previousGravityFromServer; + glm::vec3 _previousAccelerationFromServer; }; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d1571fbcc5..0f4bf05fb4 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -189,21 +189,21 @@ float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const { } bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { + if (getShouldClaimSimulationOwnership()) { + return true; + } + bool baseResult = this->ObjectMotionState::shouldSendUpdate(simulationFrame); if (!baseResult) { return false; } - if (getShouldClaimSimulationOwnership()) { - return true; - } - auto nodeList = DependencyManager::get(); const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& simulatorID = _entity->getSimulatorID(); - if (simulatorID != myNodeID) { + if (simulatorID != myNodeID && !simulatorID.isNull()) { // some other Node owns the simulating of this, so don't broadcast the results of local simulation. return false; } @@ -286,15 +286,18 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); - if (getShouldClaimSimulationOwnership()) { - _entity->setSimulatorID(myNodeID); - properties.setSimulatorID(myNodeID); - setShouldClaimSimulationOwnership(false); + if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { + // the entity is moving and no node has claimed simulation ownership. try to claim it. + setShouldClaimSimulationOwnership(true); } - if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { - // we are the simulator and the object has stopped. give up "simulator" status - _entity->setSimulatorID(QUuid()); + if (getShouldClaimSimulationOwnership()) { + // _entity->setSimulatorID(myNodeID); + properties.setSimulatorID(myNodeID); + setShouldClaimSimulationOwnership(false); + } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { + // we are the simulator and the entity has stopped. give up "simulator" status + // _entity->setSimulatorID(QUuid()); properties.setSimulatorID(QUuid()); } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 45f3c97e30..9d50b71514 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -119,8 +119,10 @@ void PhysicsEngine::entityChangedInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { - ObjectMotionState* motionState = static_cast(physicsInfo); - _incomingChanges.insert(motionState); + if ((entity->getDirtyFlags() & (HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS)) > 0) { + ObjectMotionState* motionState = static_cast(physicsInfo); + _incomingChanges.insert(motionState); + } } else { // try to add this entity again (maybe something changed such that it will work this time) addEntity(entity); @@ -366,15 +368,46 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { } } -void PhysicsEngine::computeCollisionEvents() { - BT_PROFILE("computeCollisionEvents"); + +void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) { + if (!objectA || !objectB) { + return; + } auto nodeList = DependencyManager::get(); QUuid myNodeID = nodeList->getSessionUUID(); - const btCollisionObject* characterCollisionObject = _characterController ? _characterController->getCollisionObject() : NULL; + ObjectMotionState* a = static_cast(objectA->getUserPointer()); + ObjectMotionState* b = static_cast(objectB->getUserPointer()); + EntityItem* entityA = a ? a->getEntity() : NULL; + EntityItem* entityB = b ? b->getEntity() : NULL; + bool aIsDynamic = entityA && !objectA->isStaticOrKinematicObject(); + bool bIsDynamic = entityB && !objectB->isStaticOrKinematicObject(); + + // collisions cause infectious spread of simulation-ownership. we also attempt to take + // ownership of anything that collides with our avatar. + if ((aIsDynamic && entityA->getSimulatorID() == myNodeID) || + (a && a->getShouldClaimSimulationOwnership()) || + (objectA == characterCollisionObject)) { + if (bIsDynamic) { + b->setShouldClaimSimulationOwnership(true); + } + } + if ((bIsDynamic && entityB->getSimulatorID() == myNodeID) || + (b && b->getShouldClaimSimulationOwnership()) || + (objectB == characterCollisionObject)) { + if (aIsDynamic) { + a->setShouldClaimSimulationOwnership(true); + } + } +} + + +void PhysicsEngine::computeCollisionEvents() { + BT_PROFILE("computeCollisionEvents"); + // update all contacts every frame int numManifolds = _collisionDispatcher->getNumManifolds(); for (int i = 0; i < numManifolds; ++i) { @@ -393,31 +426,12 @@ void PhysicsEngine::computeCollisionEvents() { ObjectMotionState* a = static_cast(objectA->getUserPointer()); ObjectMotionState* b = static_cast(objectB->getUserPointer()); - EntityItem* entityA = a ? a->getEntity() : NULL; - EntityItem* entityB = b ? b->getEntity() : NULL; - bool aIsDynamic = entityA && !objectA->isStaticOrKinematicObject(); - bool bIsDynamic = entityB && !objectB->isStaticOrKinematicObject(); - if (a || b) { // the manifold has up to 4 distinct points, but only extract info from the first _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); } - // collisions cause infectious spread of simulation-ownership. we also attempt to take - // ownership of anything that collides with our avatar. - if ((aIsDynamic && entityA->getSimulatorID() == myNodeID) || - (a && a->getShouldClaimSimulationOwnership()) || - (objectA == characterCollisionObject)) { - if (bIsDynamic) { - b->setShouldClaimSimulationOwnership(true); - } - } - if ((bIsDynamic && entityB->getSimulatorID() == myNodeID) || - (b && b->getShouldClaimSimulationOwnership()) || - (objectB == characterCollisionObject)) { - if (aIsDynamic) { - a->setShouldClaimSimulationOwnership(true); - } - } + + doOwnershipInfection(objectA, objectB); } } @@ -453,6 +467,16 @@ void PhysicsEngine::computeCollisionEvents() { if (type == CONTACT_EVENT_TYPE_END) { ContactMap::iterator iterToDelete = contactItr; ++contactItr; + + // const ContactKey& contactKey = (*iterToDelete).first; + // const ObjectMotionState* objectMotionStateA = static_cast(contactKey._a); + // const ObjectMotionState* objectMotionStateB = static_cast(contactKey._b); + // const btCollisionObject* objectA = + // objectMotionStateA ? static_cast(objectMotionStateA->getRigidBody()) : NULL; + // const btCollisionObject* objectB = + // objectMotionStateB ? static_cast(objectMotionStateB->getRigidBody()) : NULL; + // doOwnershipInfection(objectA, objectB); + _contactMap.erase(iterToDelete); } else { ++contactItr; @@ -576,11 +600,16 @@ void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { assert(motionState); btRigidBody* body = motionState->getRigidBody(); - // set the about-to-be-deleted entity active in order to wake up the island it's part of. this is done - // so that anything resting on top of it will fall. - // body->setActivationState(ACTIVE_TAG); - EntityItem* entity = static_cast(motionState)->getEntity(); - bump(entity); + // activate this before deleting it so that anything resting on it will begin to fall. + // + // body->activate(); + // + // motionState->setShouldClaimSimulationOwnership(true); + // computeCollisionEvents(); + // + EntityItem* entityItem = motionState ? motionState->getEntity() : NULL; + bump(entityItem); + if (body) { const btCollisionShape* shape = body->getCollisionShape(); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 148261c6d2..9fe632d462 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -89,16 +89,19 @@ public: void dumpNextStats() { _dumpNextStats = true; } + void bump(EntityItem* bumpEntity); + private: /// \param motionState pointer to Object's MotionState void removeObjectFromBullet(ObjectMotionState* motionState); void removeContacts(ObjectMotionState* motionState); + void doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB); + // return 'true' of update was successful bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); - void bump(EntityItem* bumpEntity); btClock _clock; btDefaultCollisionConfiguration* _collisionConfig = NULL; From f17387fab40ed225157362b6db154c2937e5acb8 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 23 Apr 2015 21:23:21 -0700 Subject: [PATCH 276/401] Working on menus --- BUILD_WIN.md | 6 +- interface/resources/qml/Root.qml | 30 - interface/resources/qml/RootMenu.qml | 27 +- interface/src/Application.cpp | 9 + interface/src/Menu.cpp | 1061 +++++++++----------------- interface/src/Menu.h | 61 +- libraries/ui/src/HifiMenu.cpp | 221 ++++++ libraries/ui/src/HifiMenu.h | 72 ++ libraries/ui/src/MenuConstants.cpp | 50 -- libraries/ui/src/MenuConstants.h | 42 - libraries/ui/src/OffscreenUi.cpp | 8 +- libraries/ui/src/OffscreenUi.h | 30 + tests/ui/src/main.cpp | 56 +- 13 files changed, 749 insertions(+), 924 deletions(-) create mode 100644 libraries/ui/src/HifiMenu.cpp create mode 100644 libraries/ui/src/HifiMenu.h delete mode 100644 libraries/ui/src/MenuConstants.cpp delete mode 100644 libraries/ui/src/MenuConstants.h diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 39252ec4f2..80b8c35502 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -29,12 +29,12 @@ NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit * [Download the online installer](http://qt-project.org/downloads) * When it asks you to select components, ONLY select the following: - * Qt > Qt 5.3.2 > **msvc2013 32-bit OpenGL** + * Qt > Qt 5.4.1 > **msvc2013 32-bit OpenGL** -* [Download the offline installer](http://download.qt-project.org/official_releases/qt/5.3/5.3.2/qt-opensource-windows-x86-msvc2013_opengl-5.3.2.exe) +* [Download the offline installer](http://download.qt.io/official_releases/qt/5.4/5.4.1/qt-opensource-windows-x86-msvc2013_opengl-5.4.1.exe) Once Qt is installed, you need to manually configure the following: -* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.3.2\msvc2013_opengl\lib\cmake` directory. +* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.4.1\msvc2013_opengl\lib\cmake` directory. * You can set an environment variable from Control Panel > System > Advanced System Settings > Environment Variables > New ###External Libraries diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index 92ad922cce..b2db7d18bf 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -6,35 +6,5 @@ import QtQuick 2.3 Root { id: root anchors.fill: parent - Item { - Menu { - objectName: "rootMenu" - Menu { - title: "File" - MenuItem { - text: "Test" - checkable: true - } - MenuItem { - text: "Quit" - } - } - Menu { - title: "Edit" - MenuItem { - text: "Copy" - } - MenuItem { - text: "Cut" - } - MenuItem { - text: "Paste" - } - MenuItem { - text: "Undo" - } - } - } - } } diff --git a/interface/resources/qml/RootMenu.qml b/interface/resources/qml/RootMenu.qml index 46cae2cf4a..dc2e36f89a 100644 --- a/interface/resources/qml/RootMenu.qml +++ b/interface/resources/qml/RootMenu.qml @@ -3,32 +3,7 @@ import QtQuick.Controls 1.3 Item { Menu { - id: rootMenuFooBar + id: root objectName: "rootMenu" - Menu { - title: "File" - MenuItem { - text: "Test" - checkable: true - } - MenuItem { - text: "Quit" - } - } - Menu { - title: "Edit" - MenuItem { - text: "Copy" - } - MenuItem { - text: "Cut" - } - MenuItem { - text: "Paste" - } - MenuItem { - text: "Undo" - } - } } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c435ca2f0b..d281282fc8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -786,6 +786,7 @@ void Application::initializeUi() { offscreenUi->setProxyWindow(_window->windowHandle()); offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); offscreenUi->load("Root.qml"); + offscreenUi->load("RootMenu.qml"); offscreenUi->setMouseTranslator([this](const QPointF& p){ if (OculusManager::isConnected()) { glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p)); @@ -1079,9 +1080,11 @@ bool Application::eventFilter(QObject* object, QEvent* event) { } static bool _altPressed; +static bool _ctrlPressed; void Application::keyPressEvent(QKeyEvent* event) { _altPressed = event->key() == Qt::Key_Alt; + _ctrlPressed = event->key() == Qt::Key_Control; _keysPressed.insert(event->key()); _controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts @@ -1336,6 +1339,12 @@ void Application::keyReleaseEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Alt && _altPressed) { Menu::toggle(); } + if (event->key() == Qt::Key_Control && _ctrlPressed) { + auto offscreenUi = DependencyManager::get(); + auto rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); + QMetaObject::invokeMethod(rootMenu, "popup"); + } + _ctrlPressed = event->key() == Qt::Key_Control; _keysPressed.remove(event->key()); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 026af1442f..529fca5e66 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include @@ -52,34 +52,43 @@ HifiAction::HifiAction(const QString & menuOption) : _menuOption(menuOption) { // qFatal("Not implemented"); //} -void HifiAction::setChecked(bool) { - qFatal("Not implemented"); +void HifiAction::setChecked(bool checked) { + Menu::getInstance()->setChecked(_menuOption, checked); } -void HifiAction::setVisible(bool) { - qFatal("Not implemented"); +void HifiAction::setVisible(bool visible) { + QObject* result = Menu::getInstance()->findMenuObject(_menuOption); + if (result) { + result->setProperty("visible", visible); + } } const QString & HifiAction::shortcut() const { - qFatal("Not implemented"); - return ""; + static const QString NONE; + QObject* result = Menu::getInstance()->findMenuObject(_menuOption); + if (!result) { + return NONE; + } + QObject* shortcut = result->property("shortcut").value(); + if (!shortcut) { + return NONE; + } + shortcut->dumpObjectInfo(); + return NONE; } -void HifiAction::setText(const QString &) { - qFatal("Not implemented"); +void HifiAction::setText(const QString & text) { + Menu::getInstance()->setText(_menuOption, text); } void HifiAction::setTriggerAction(std::function f) { - qFatal("Not implemented"); + Menu::getInstance()->setTriggerAction(_menuOption, f); } void HifiAction::setToggleAction(std::function f) { - qFatal("Not implemented"); + Menu::getInstance()->setToggleAction(_menuOption, f); } -HIFI_QML_DEF(Menu) - - Menu* Menu::_instance = nullptr; Menu* Menu::getInstance() { @@ -88,15 +97,11 @@ Menu* Menu::getInstance() { static QMutex menuInstanceMutex; withLock(menuInstanceMutex, [] { if (!_instance) { - OffscreenUi * offscreenUi = DependencyManager::get().data(); - QQmlContext * qmlContext = offscreenUi->qmlContext(); - qmlContext->setContextProperty("foo", QVariant::fromValue(foo)); -// qmlContext->setContextProperty("presetsModel", QVariant::fromValue(dataList)); - + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); qCDebug(interfaceapp, "First call to Menu::getInstance() - initing menu."); - load([&](QQmlContext *, QQuickItem* item) { - _instance = dynamic_cast(item); - }); + Menu::load(); + auto uiRoot = DependencyManager::get()->getRootItem(); + _instance = uiRoot->findChild(NAME); if (!_instance) { qFatal("Could not load menu QML"); } else { @@ -108,380 +113,362 @@ Menu* Menu::getInstance() { return _instance; } -Menu::Menu(QQuickItem * parent) : QQuickItem(parent) { +Menu::Menu(QQuickItem * parent) : HifiMenu(parent) { } -QObject * _rootMenu; -static const QString FILE_MENU{ "File" }; -static const QString EDIT_MENU{ "Edit" }; -static const QString TOOLS_MENU{ "Tools" }; -static const QString AVATAR_MENU{ "Avatar" }; - - -static const QString MENU_SUFFIX{ "__Menu" }; - -QObject * addMenu(QObject * parent, const QString & text) { - // FIXME add more checking here to ensure no name conflicts - QVariant returnedValue; - QMetaObject::invokeMethod(parent, "addMenu", - Q_RETURN_ARG(QVariant, returnedValue), - Q_ARG(QVariant, text)); - QObject * result = returnedValue.value(); - if (result) { - result->setObjectName(text + MENU_SUFFIX); - } - return result; -} - -class QQuickMenuItem; -QObject * addItem(QObject * parent, const QString & text) { - // FIXME add more checking here to ensure no name conflicts - QQuickMenuItem* returnedValue; - QMetaObject::invokeMethod(parent, "addItem", - Q_RETURN_ARG(QQuickMenuItem*, returnedValue), - Q_ARG(QString, text)); - QObject* result = reinterpret_cast(returnedValue); - if (result) { - result->setObjectName(text + MENU_SUFFIX); - } - return result; -} void Menu::init() { - _rootMenu = property("menu").value(); - QObject * fileMenu = ::addMenu(_rootMenu, FILE_MENU); - auto dialogsManager = DependencyManager::get(); AccountManager& accountManager = AccountManager::getInstance(); - + static const QString ROOT_MENU; { - ::addItem(fileMenu, MenuOption::Login); - - // connect to the appropriate signal of the AccountManager so that we can change the Login/Logout menu item - connect(&accountManager, &AccountManager::profileChanged, - dialogsManager.data(), &DialogsManager::toggleLoginDialog); - connect(&accountManager, &AccountManager::logoutComplete, - dialogsManager.data(), &DialogsManager::toggleLoginDialog); - } - + static const QString FILE_MENU{ "File" }; + addMenu(ROOT_MENU, FILE_MENU); + { + addMenuItem(FILE_MENU, MenuOption::Login); + // connect to the appropriate signal of the AccountManager so that we can change the Login/Logout menu item + connect(&accountManager, &AccountManager::profileChanged, + dialogsManager.data(), &DialogsManager::toggleLoginDialog); + connect(&accountManager, &AccountManager::logoutComplete, + dialogsManager.data(), &DialogsManager::toggleLoginDialog); + } #ifdef Q_OS_MAC - addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); + addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); #endif - { - static const QString SCRIPTS_MENU{ "Scripts" }; - addMenu(FILE_MENU, SCRIPTS_MENU); - //Qt::CTRL | Qt::Key_O - addMenuItem(SCRIPTS_MENU, MenuOption::LoadScript, [=] { - qApp->loadDialog(); - }); - //Qt::CTRL | Qt::SHIFT | Qt::Key_O - addMenuItem(SCRIPTS_MENU, MenuOption::LoadScriptURL, [=] { - qApp->loadScriptURLDialog(); - }); - addMenuItem(SCRIPTS_MENU, MenuOption::StopAllScripts, [=] { - qApp->stopAllScripts(); - }); - //Qt::CTRL | Qt::Key_R, - addMenuItem(SCRIPTS_MENU, MenuOption::ReloadAllScripts, [=] { - qApp->reloadAllScripts(); - }); - // Qt::CTRL | Qt::Key_J, - addMenuItem(SCRIPTS_MENU, MenuOption::RunningScripts, [=] { - qApp->toggleRunningScriptsWidget(); + { + static const QString SCRIPTS_MENU{ "Scripts" }; + addMenu(FILE_MENU, SCRIPTS_MENU); + //Qt::CTRL | Qt::Key_O + addMenuItem(SCRIPTS_MENU, MenuOption::LoadScript, [=] { + qApp->loadDialog(); + }); + //Qt::CTRL | Qt::SHIFT | Qt::Key_O + addMenuItem(SCRIPTS_MENU, MenuOption::LoadScriptURL, [=] { + qApp->loadScriptURLDialog(); + }); + addMenuItem(SCRIPTS_MENU, MenuOption::StopAllScripts, [=] { + qApp->stopAllScripts(); + }); + //Qt::CTRL | Qt::Key_R, + addMenuItem(SCRIPTS_MENU, MenuOption::ReloadAllScripts, [=] { + qApp->reloadAllScripts(); + }); + // Qt::CTRL | Qt::Key_J, + addMenuItem(SCRIPTS_MENU, MenuOption::RunningScripts, [=] { + qApp->toggleRunningScriptsWidget(); + }); + } + + { + static const QString LOCATION_MENU{ "Location" }; + addMenu(FILE_MENU, LOCATION_MENU); + qApp->getBookmarks()->setupMenus(LOCATION_MENU); + //Qt::CTRL | Qt::Key_L + addMenuItem(LOCATION_MENU, MenuOption::AddressBar, [=] { + auto dialogsManager = DependencyManager::get(); + dialogsManager->toggleAddressBar(); + }); + addMenuItem(LOCATION_MENU, MenuOption::CopyAddress, [=] { + auto addressManager = DependencyManager::get(); + addressManager->copyAddress(); + }); + addMenuItem(LOCATION_MENU, MenuOption::CopyPath, [=] { + auto addressManager = DependencyManager::get(); + addressManager->copyPath(); + }); + } + + // Qt::CTRL | Qt::Key_Q + // QAction::QuitRole + addMenuItem(FILE_MENU, MenuOption::Quit, [=] { + qApp->quit(); }); } + { - static const QString LOCATION_MENU{ "Location" }; - addMenu(FILE_MENU, LOCATION_MENU); - qApp->getBookmarks()->setupMenus(LOCATION_MENU); - //Qt::CTRL | Qt::Key_L - addMenuItem(LOCATION_MENU, MenuOption::AddressBar, [=] { - auto dialogsManager = DependencyManager::get(); - dialogsManager->toggleAddressBar(); - }); - addMenuItem(LOCATION_MENU, MenuOption::CopyAddress, [=] { - auto addressManager = DependencyManager::get(); - addressManager->copyAddress(); - }); - addMenuItem(LOCATION_MENU, MenuOption::CopyAddress, [=] { - auto addressManager = DependencyManager::get(); - addressManager->copyPath(); - }); - } + static const QString EDIT_MENU{ "Edit" }; + addMenu(ROOT_MENU, EDIT_MENU); #if 0 - - addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyAddress, 0, - addressManager.data(), SLOT(copyAddress())); - addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyPath, 0, - addressManager.data(), SLOT(copyPath())); + QUndoStack* undoStack = qApp->getUndoStack(); + QAction* undoAction = undoStack->createUndoAction(editMenu); + undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); + addActionToQMenuAndActionHash(editMenu, undoAction); - addActionToQMenuAndActionHash(fileMenu, - MenuOption::Quit, - Qt::CTRL | Qt::Key_Q, - qApp, - SLOT(quit()), - QAction::QuitRole); + QAction* redoAction = undoStack->createRedoAction(editMenu); + redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); + addActionToQMenuAndActionHash(editMenu, redoAction); +#endif + // Qt::CTRL | Qt::Key_Comma + // QAction::PreferencesRole + addMenuItem(EDIT_MENU, MenuOption::Preferences, [=] { + dialogsManager->editPreferences(); + }); + addMenuItem(EDIT_MENU, MenuOption::Animations, [=] { + dialogsManager->editAnimations(); + }); + } - QMenu* editMenu = addMenu("Edit"); - - QUndoStack* undoStack = qApp->getUndoStack(); - QAction* undoAction = undoStack->createUndoAction(editMenu); - undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); - addActionToQMenuAndActionHash(editMenu, undoAction); - - QAction* redoAction = undoStack->createRedoAction(editMenu); - redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); - addActionToQMenuAndActionHash(editMenu, redoAction); - - addActionToQMenuAndActionHash(editMenu, - MenuOption::Preferences, - Qt::CTRL | Qt::Key_Comma, - dialogsManager.data(), - SLOT(editPreferences()), - QAction::PreferencesRole); - - addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0, - dialogsManager.data(), SLOT(editAttachments())); - addActionToQMenuAndActionHash(editMenu, MenuOption::Animations, 0, - dialogsManager.data(), SLOT(editAnimations())); - - QMenu* toolsMenu = addMenu("Tools"); - addActionToQMenuAndActionHash(toolsMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S, - dialogsManager.data(), SLOT(showScriptEditor())); + { + static const QString TOOLS_MENU{ "Tools" }; + addMenu(ROOT_MENU, TOOLS_MENU); #if defined(Q_OS_MAC) || defined(Q_OS_WIN) - auto speechRecognizer = DependencyManager::get(); - QAction* speechRecognizerAction = addCheckableActionToQMenuAndActionHash(toolsMenu, MenuOption::ControlWithSpeech, - Qt::CTRL | Qt::SHIFT | Qt::Key_C, - speechRecognizer->getEnabled(), - speechRecognizer.data(), - SLOT(setEnabled(bool))); - connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool))); + auto speechRecognizer = DependencyManager::get(); + //Qt::CTRL | Qt::SHIFT | Qt::Key_C + addMenuItem(TOOLS_MENU, MenuOption::ControlWithSpeech); + setChecked(MenuOption::ControlWithSpeech, speechRecognizer->getEnabled()); + connect(speechRecognizer.data(), &SpeechRecognizer::enabledUpdated, [=] { + setChecked(MenuOption::ControlWithSpeech, speechRecognizer->getEnabled()); + }); #endif - - addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, - 0, // QML Qt::Key_Backslash, - dialogsManager.data(), SLOT(showIRCLink())); - addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0, - qApp, SLOT(showFriendsWindow())); + // Qt::ALT | Qt::Key_S, + addMenuItem(TOOLS_MENU, MenuOption::ScriptEditor, [=] { + dialogsManager->showScriptEditor(); + }); + // QML Qt::Key_Backslash, + addMenuItem(TOOLS_MENU, MenuOption::Chat, [=] { + dialogsManager->showIRCLink(); + }); + addMenuItem(TOOLS_MENU, MenuOption::AddRemoveFriends, [=] { + qApp->showFriendsWindow(); + }); - QMenu* visibilityMenu = toolsMenu->addMenu("I Am Visible To"); - { - QActionGroup* visibilityGroup = new QActionGroup(toolsMenu); - auto discoverabilityManager = DependencyManager::get(); +#if 0 + QMenu* visibilityMenu = toolsMenu->addMenu("I Am Visible To"); + { + QActionGroup* visibilityGroup = new QActionGroup(toolsMenu); + auto discoverabilityManager = DependencyManager::get(); - QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToEveryone); + QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, + discoverabilityManager.data(), SLOT(setVisibility())); + visibilityGroup->addAction(visibleToEveryone); - QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToFriends); + QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, + discoverabilityManager.data(), SLOT(setVisibility())); + visibilityGroup->addAction(visibleToFriends); - QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToNoOne); + QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, + discoverabilityManager.data(), SLOT(setVisibility())); + visibilityGroup->addAction(visibleToNoOne); - connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, - discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged); + connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, + discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged); + } +#endif + //Qt::CTRL | Qt::ALT | Qt::Key_T, + addMenuItem(TOOLS_MENU, MenuOption::ToolWindow, [=] { +// dialogsManager->toggleToolWindow(); + }); + + //Qt::CTRL | Qt::ALT | Qt::Key_J, + addMenuItem(TOOLS_MENU, MenuOption::Console, [=] { + DependencyManager::get()->toggleConsole(); + }); + + // QML Qt::Key_Apostrophe, + addMenuItem(TOOLS_MENU, MenuOption::ResetSensors, [=] { + qApp->resetSensors(); + }); + + addMenuItem(TOOLS_MENU, MenuOption::PackageModel, [=] { + qApp->packageModel(); + }); } - addActionToQMenuAndActionHash(toolsMenu, - MenuOption::ToolWindow, - Qt::CTRL | Qt::ALT | Qt::Key_T, - dialogsManager.data(), - SLOT(toggleToolWindow())); - - addActionToQMenuAndActionHash(toolsMenu, - MenuOption::Console, - Qt::CTRL | Qt::ALT | Qt::Key_J, - DependencyManager::get().data(), - SLOT(toggleConsole())); - - addActionToQMenuAndActionHash(toolsMenu, - MenuOption::ResetSensors, - 0, // QML Qt::Key_Apostrophe, - qApp, - SLOT(resetSensors())); - - addActionToQMenuAndActionHash(toolsMenu, MenuOption::PackageModel, 0, - qApp, SLOT(packageModel())); - - QMenu* avatarMenu = addMenu("Avatar"); - QObject* avatar = DependencyManager::get()->getMyAvatar(); - - QMenu* avatarSizeMenu = avatarMenu->addMenu("Size"); - addActionToQMenuAndActionHash(avatarSizeMenu, - MenuOption::IncreaseAvatarSize, - 0, // QML Qt::Key_Plus, - avatar, - SLOT(increaseSize())); - addActionToQMenuAndActionHash(avatarSizeMenu, - MenuOption::DecreaseAvatarSize, - 0, // QML Qt::Key_Minus, - avatar, - SLOT(decreaseSize())); - addActionToQMenuAndActionHash(avatarSizeMenu, - MenuOption::ResetAvatarSize, - 0, // QML Qt::Key_Equal, - avatar, - SLOT(resetSize())); - - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::KeyboardMotorControl, - Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehavior())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ScriptedMotorControl, 0, true, - avatar, SLOT(updateMotionBehavior())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true, - avatar, SLOT(updateMotionBehavior())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false, - avatar, SLOT(updateMotionBehavior())); - - QMenu* viewMenu = addMenu("View"); - - addCheckableActionToQMenuAndActionHash(viewMenu, - MenuOption::Fullscreen, -#ifdef Q_OS_MAC - Qt::CTRL | Qt::META | Qt::Key_F, -#else - Qt::CTRL | Qt::Key_F, -#endif - false, - qApp, - SLOT(setFullscreen(bool))); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, - 0, // QML Qt::Key_P, - true, qApp, SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, - 0, //QML Qt::SHIFT | Qt::Key_H, - true); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, - 0, // QML Qt::Key_H, - false, qApp, SLOT(cameraMenuChanged())); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, -#ifdef Q_OS_MAC - Qt::META | Qt::Key_H, -#else - Qt::CTRL | Qt::Key_H, -#endif - false, - dialogsManager.data(), - SLOT(hmdTools(bool))); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0, - false, - qApp, - SLOT(setEnableVRMode(bool))); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0, - false, - qApp, - SLOT(setEnable3DTVMode(bool))); - - - QMenu* nodeBordersMenu = viewMenu->addMenu("Server Borders"); - NodeBounds& nodeBounds = qApp->getNodeBoundsDisplay(); - addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersEntityNodes, - Qt::CTRL | Qt::SHIFT | Qt::Key_1, false, - &nodeBounds, SLOT(setShowEntityNodes(bool))); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); - - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, - 0); // QML Qt::Key_Slash); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats); - addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, - Qt::CTRL | Qt::SHIFT | Qt::Key_L, - qApp, SLOT(toggleLogDialog())); - addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, - dialogsManager.data(), SLOT(bandwidthDetails())); - addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, - dialogsManager.data(), SLOT(octreeStatsDetails())); - - - QMenu* developerMenu = addMenu("Developer"); - - QMenu* renderOptionsMenu = developerMenu->addMenu("Render"); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, - 0, // QML Qt::SHIFT | Qt::Key_A, - true); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges); - - QMenu* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight); - QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu); - ambientLightGroup->setExclusive(true); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLightGlobal, 0, true)); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight0, 0, false)); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight1, 0, false)); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight2, 0, false)); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight3, 0, false)); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight4, 0, false)); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight5, 0, false)); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight6, 0, false)); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight7, 0, false)); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false)); - ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false)); - - QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows"); - QActionGroup* shadowGroup = new QActionGroup(shadowMenu); - shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true)); - shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); - shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); - { - QMenu* framerateMenu = renderOptionsMenu->addMenu(MenuOption::RenderTargetFramerate); - QActionGroup* framerateGroup = new QActionGroup(framerateMenu); - framerateGroup->setExclusive(true); - framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerateUnlimited, 0, true)); - framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate60, 0, false)); - framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate50, 0, false)); - framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate40, 0, false)); - framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate30, 0, false)); + static const QString AVATAR_MENU{ "Avatar" }; + addMenu(ROOT_MENU, AVATAR_MENU); + auto avatar = DependencyManager::get()->getMyAvatar(); + { + static const QString SIZE_MENU{ "Size" }; + addMenu(AVATAR_MENU, SIZE_MENU); + // QML Qt::Key_Plus, + addMenuItem(SIZE_MENU, MenuOption::IncreaseAvatarSize, [=] { + avatar->increaseSize(); + }); + // QML Qt::Key_Minus, + addMenuItem(SIZE_MENU, MenuOption::DecreaseAvatarSize, [=] { + avatar->decreaseSize(); + }); + // QML Qt::Key_Equal, + addMenuItem(SIZE_MENU, MenuOption::ResetAvatarSize, [=] { + avatar->resetSize(); + }); -#if defined(Q_OS_MAC) -#else - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderTargetFramerateVSyncOn, 0, true, - qApp, SLOT(setVSyncEnabled())); -#endif + addMenuItem(SIZE_MENU, MenuOption::ResetAvatarSize, [=] { + avatar->resetSize(); + }); + } + + //Qt::CTRL | Qt::SHIFT | Qt::Key_K + addCheckableMenuItem(AVATAR_MENU, MenuOption::KeyboardMotorControl, true, [=](bool) { + avatar->updateMotionBehavior(); + }); + addCheckableMenuItem(AVATAR_MENU, MenuOption::ScriptedMotorControl, true); + addCheckableMenuItem(AVATAR_MENU, MenuOption::NamesAboveHeads, true); + addCheckableMenuItem(AVATAR_MENU, MenuOption::GlowWhenSpeaking, true); + addCheckableMenuItem(AVATAR_MENU, MenuOption::BlueSpeechSphere, true); + addCheckableMenuItem(AVATAR_MENU, MenuOption::EnableCharacterController, true, [=](bool) { + avatar->updateMotionBehavior(); + }); + addCheckableMenuItem(AVATAR_MENU, MenuOption::ShiftHipsForIdleAnimations, false, [=](bool) { + avatar->updateMotionBehavior(); + }); } + { + static const QString VIEW_MENU{ "View" }; + addMenu(ROOT_MENU, VIEW_MENU); - QMenu* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution); - QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu); - resolutionGroup->setExclusive(true); - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionOne, 0, true)); - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionTwoThird, 0, false)); - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionHalf, 0, false)); - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false)); - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false)); + // Mac Qt::CTRL | Qt::META | Qt::Key_F, + // Win32/Linux Qt::CTRL | Qt::Key_F, + addCheckableMenuItem(VIEW_MENU, MenuOption::Fullscreen, false, [=](bool checked) { +// qApp->setFullscreen(checked); + }); + // QML Qt::Key_P, + addCheckableMenuItem(VIEW_MENU, MenuOption::FirstPerson, true, [=](bool checked) { +// qApp->cameraMenuChanged(); + }); + //QML Qt::SHIFT | Qt::Key_H, + addCheckableMenuItem(VIEW_MENU, MenuOption::Mirror, true); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, - 0, // QML Qt::Key_Asterisk, - true); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true, - DependencyManager::get().data(), SLOT(toggleGlowEffect(bool))); + // QML Qt::Key_H, + addCheckableMenuItem(VIEW_MENU, MenuOption::FullscreenMirror, true, [=](bool checked) { +// qApp->cameraMenuChanged(); + }); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Wireframe, Qt::ALT | Qt::Key_W, false); - addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, - 0, // QML Qt::SHIFT | Qt::Key_L, - dialogsManager.data(), SLOT(lodTools())); + // Mac Qt::META | Qt::Key_H, + // Win32/Linux Qt::CTRL | Qt::Key_H, + addCheckableMenuItem(VIEW_MENU, MenuOption::HMDTools, false, [=](bool checked) { + dialogsManager->hmdTools(checked); + }); + addCheckableMenuItem(VIEW_MENU, MenuOption::EnableVRMode, false, [=](bool checked) { +// qApp->setEnableVRMode(checked); + }); + addCheckableMenuItem(VIEW_MENU, MenuOption::Enable3DTVMode, false, [=](bool checked) { +// qApp->setEnable3DTVMode(checked); + }); - QMenu* avatarDebugMenu = developerMenu->addMenu("Avatar"); + { + static const QString BORDER_MENU{ "View" }; + addMenu(VIEW_MENU, BORDER_MENU); + // Qt::CTRL | Qt::SHIFT | Qt::Key_1 + addCheckableMenuItem(BORDER_MENU, MenuOption::ShowBordersEntityNodes, false, [=](bool checked) { + qApp->getNodeBoundsDisplay().setShowEntityNodes(checked); + }); + } + addCheckableMenuItem(VIEW_MENU, MenuOption::OffAxisProjection, false); + addCheckableMenuItem(VIEW_MENU, MenuOption::TurnWithHead, false); + // QML Qt::Key_Slash + addCheckableMenuItem(VIEW_MENU, MenuOption::Stats, false); + // Qt::CTRL | Qt::SHIFT | Qt::Key_L + addMenuItem(VIEW_MENU, MenuOption::Log, [=] { + qApp->toggleLogDialog(); + }); + addMenuItem(VIEW_MENU, MenuOption::BandwidthDetails, [=] { + dialogsManager->bandwidthDetails(); + }); + addMenuItem(VIEW_MENU, MenuOption::OctreeStats, [=] { + dialogsManager->octreeStatsDetails(); + }); + } + + { + static const QString DEV_MENU{ "Developer" }; + addMenu(ROOT_MENU, DEV_MENU); + { + static const QString RENDER_MENU{ "Render" }; + addMenu(DEV_MENU, RENDER_MENU); + // QML Qt::SHIFT | Qt::Key_A, + addCheckableMenuItem(RENDER_MENU, MenuOption::Atmosphere, true); + addCheckableMenuItem(RENDER_MENU, MenuOption::AmbientOcclusion); + addCheckableMenuItem(RENDER_MENU, MenuOption::DontFadeOnOctreeServerChanges); + { + static const QString LIGHT_MENU{ MenuOption::RenderAmbientLight }; + addMenu(RENDER_MENU, LIGHT_MENU); + static QStringList LIGHTS{ + MenuOption::RenderAmbientLightGlobal, + MenuOption::RenderAmbientLight0, + MenuOption::RenderAmbientLight1, + MenuOption::RenderAmbientLight2, + MenuOption::RenderAmbientLight3, + MenuOption::RenderAmbientLight4, + MenuOption::RenderAmbientLight5, + MenuOption::RenderAmbientLight6, + MenuOption::RenderAmbientLight7, + MenuOption::RenderAmbientLight8, + MenuOption::RenderAmbientLight9, + }; + foreach(QString option, LIGHTS) { + addCheckableMenuItem(LIGHT_MENU, option); + // FIXME + // setExclusiveGroup() + } + setChecked(MenuOption::RenderAmbientLightGlobal, true); + } + { + static const QString SHADOWS_MENU{ "Shadows" }; + addMenu(RENDER_MENU, SHADOWS_MENU); + addCheckableMenuItem(SHADOWS_MENU, "No Shadows", true); + addCheckableMenuItem(SHADOWS_MENU, MenuOption::SimpleShadows); + addCheckableMenuItem(SHADOWS_MENU, MenuOption::CascadedShadows); + } + { + static const QString FRAMERATE_MENU{ MenuOption::RenderTargetFramerate }; + addMenu(RENDER_MENU, FRAMERATE_MENU); + //framerateGroup->setExclusive(true); + addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerateUnlimited, true); + addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate60); + addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate50); + addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate40); + addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate30); + } +#if !defined(Q_OS_MAC) + addCheckableMenuItem(RENDER_MENU, MenuOption::RenderTargetFramerateVSyncOn, true, [](bool checked) { + qApp->setVSyncEnabled(); + }); +#endif + { + static const QString RES_MENU{ MenuOption::RenderResolution }; + addMenu(RENDER_MENU, RES_MENU); + // resolutionGroup->setExclusive(true); + addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionOne, true); + addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionTwoThird); + addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionHalf); + addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionThird); + addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionQuarter); + } + // QML Qt::Key_Asterisk, + addCheckableMenuItem(RENDER_MENU, MenuOption::Stars, true); + addCheckableMenuItem(RENDER_MENU, MenuOption::EnableGlowEffect, true, [](bool checked){ + DependencyManager::get()->toggleGlowEffect(checked); + }); + //Qt::ALT | Qt::Key_W + addCheckableMenuItem(RENDER_MENU, MenuOption::Wireframe); + // QML Qt::SHIFT | Qt::Key_L, + addMenuItem(RENDER_MENU, MenuOption::LodTools, [=] { + dialogsManager->lodTools(); + }); + } + + { + static const QString AVATAR_MENU{ "Avatar Dev" }; + addMenu(DEV_MENU, AVATAR_MENU); + setText(AVATAR_MENU, "Avatar"); + { + } + } + } + +#if 0 QMenu* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking"); { QActionGroup* faceTrackerGroup = new QActionGroup(avatarDebugMenu); @@ -730,362 +717,4 @@ void Menu::addDisabledActionAndSeparator(QMenu* destinationMenu, const QString& } } -QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu, - const QString& actionName, - const QKeySequence& shortcut, - const QObject* receiver, - const char* member, - QAction::MenuRole role, - int menuItemLocation) { - QAction* action = NULL; - QAction* actionBefore = NULL; - - if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) { - actionBefore = destinationMenu->actions()[menuItemLocation]; - } - - if (!actionBefore) { - if (receiver && member) { - action = destinationMenu->addAction(actionName, receiver, member, shortcut); - } else { - action = destinationMenu->addAction(actionName); - action->setShortcut(shortcut); - } - } else { - action = new QAction(actionName, destinationMenu); - action->setShortcut(shortcut); - destinationMenu->insertAction(actionBefore, action); - - if (receiver && member) { - connect(action, SIGNAL(triggered()), receiver, member); - } - } - action->setMenuRole(role); - - _actionHash.insert(actionName, action); - - return action; -} - -QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu, - QAction* action, - const QString& actionName, - const QKeySequence& shortcut, - QAction::MenuRole role, - int menuItemLocation) { - QAction* actionBefore = NULL; - - if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) { - actionBefore = destinationMenu->actions()[menuItemLocation]; - } - - if (!actionName.isEmpty()) { - action->setText(actionName); - } - - if (shortcut != 0) { - action->setShortcut(shortcut); - } - - if (role != QAction::NoRole) { - action->setMenuRole(role); - } - - if (!actionBefore) { - destinationMenu->addAction(action); - } else { - destinationMenu->insertAction(actionBefore, action); - } - - _actionHash.insert(action->text(), action); - - return action; -} - -QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu, - const QString& actionName, - const QKeySequence& shortcut, - const bool checked, - const QObject* receiver, - const char* member, - int menuItemLocation) { - - QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member, - QAction::NoRole, menuItemLocation); - action->setCheckable(true); - action->setChecked(checked); - - return action; -} - -void Menu::removeAction(QMenu* menu, const QString& actionName) { - menu->removeAction(_actionHash.value(actionName)); - _actionHash.remove(actionName); -} - #endif - -void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { -} - -bool Menu::isOptionChecked(const QString& menuOption) const { - return false; -} - -void Menu::triggerOption(const QString& menuOption) { -} - -#if 0 - -QAction* Menu::getActionForOption(const QString& menuOption) { - return _actionHash.value(menuOption); -} - -QAction* Menu::getActionFromName(const QString& menuName, QMenu* menu) { - QList menuActions; - if (menu) { - menuActions = menu->actions(); - } else { - menuActions = actions(); - } - - foreach (QAction* menuAction, menuActions) { - if (menuName == menuAction->text()) { - return menuAction; - } - } - return NULL; -} - -QMenu* Menu::getSubMenuFromName(const QString& menuName, QMenu* menu) { - QAction* action = getActionFromName(menuName, menu); - if (action) { - return action->menu(); - } - return NULL; -} - -QMenu* Menu::getMenuParent(const QString& menuName, QString& finalMenuPart) { - QStringList menuTree = menuName.split(">"); - QMenu* parent = NULL; - QMenu* menu = NULL; - foreach (QString menuTreePart, menuTree) { - parent = menu; - finalMenuPart = menuTreePart.trimmed(); - menu = getSubMenuFromName(finalMenuPart, parent); - if (!menu) { - break; - } - } - return parent; -} - -QMenu* Menu::getMenu(const QString& menuName) { - QStringList menuTree = menuName.split(">"); - QMenu* parent = NULL; - QMenu* menu = NULL; - int item = 0; - foreach (QString menuTreePart, menuTree) { - menu = getSubMenuFromName(menuTreePart.trimmed(), parent); - if (!menu) { - break; - } - parent = menu; - item++; - } - return menu; -} - -QAction* Menu::getMenuAction(const QString& menuName) { - QStringList menuTree = menuName.split(">"); - QMenu* parent = NULL; - QAction* action = NULL; - foreach (QString menuTreePart, menuTree) { - action = getActionFromName(menuTreePart.trimmed(), parent); - if (!action) { - break; - } - parent = action->menu(); - } - return action; -} - -int Menu::findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem) { - int position = 0; - foreach(QAction* action, menu->actions()) { - if (action->text() == searchMenuItem) { - return position; - } - position++; - } - return UNSPECIFIED_POSITION; // not found -} - -int Menu::positionBeforeSeparatorIfNeeded(QMenu* menu, int requestedPosition) { - QList menuActions = menu->actions(); - if (requestedPosition > 1 && requestedPosition < menuActions.size()) { - QAction* beforeRequested = menuActions[requestedPosition - 1]; - if (beforeRequested->isSeparator()) { - requestedPosition--; - } - } - return requestedPosition; -} - - -QMenu* Menu::addMenu(const QString& menuName) { - QStringList menuTree = menuName.split(">"); - QMenu* addTo = NULL; - QMenu* menu = NULL; - foreach (QString menuTreePart, menuTree) { - menu = getSubMenuFromName(menuTreePart.trimmed(), addTo); - if (!menu) { - if (!addTo) { - menu = QMenuBar::addMenu(menuTreePart.trimmed()); - } else { - menu = addTo->addMenu(menuTreePart.trimmed()); - } - } - addTo = menu; - } - - QMenuBar::repaint(); - return menu; -} - -void Menu::removeMenu(const QString& menuName) { - QAction* action = getMenuAction(menuName); - - // only proceed if the menu actually exists - if (action) { - QString finalMenuPart; - QMenu* parent = getMenuParent(menuName, finalMenuPart); - if (parent) { - parent->removeAction(action); - } else { - QMenuBar::removeAction(action); - } - - QMenuBar::repaint(); - } -} - -bool Menu::menuExists(const QString& menuName) { - QAction* action = getMenuAction(menuName); - - // only proceed if the menu actually exists - if (action) { - return true; - } - return false; -} - -void Menu::addSeparator(const QString& menuName, const QString& separatorName) { - QMenu* menuObj = getMenu(menuName); - if (menuObj) { - addDisabledActionAndSeparator(menuObj, separatorName); - } -} - -void Menu::removeSeparator(const QString& menuName, const QString& separatorName) { - QMenu* menu = getMenu(menuName); - bool separatorRemoved = false; - if (menu) { - int textAt = findPositionOfMenuItem(menu, separatorName); - QList menuActions = menu->actions(); - QAction* separatorText = menuActions[textAt]; - if (textAt > 0 && textAt < menuActions.size()) { - QAction* separatorLine = menuActions[textAt - 1]; - if (separatorLine) { - if (separatorLine->isSeparator()) { - menu->removeAction(separatorText); - menu->removeAction(separatorLine); - separatorRemoved = true; - } - } - } - } - if (separatorRemoved) { - QMenuBar::repaint(); - } -} - -void Menu::addMenuItem(const MenuItemProperties& properties) { - QMenu* menuObj = getMenu(properties.menuName); - if (menuObj) { - QShortcut* shortcut = NULL; - if (!properties.shortcutKeySequence.isEmpty()) { - shortcut = new QShortcut(properties.shortcutKeySequence, this); - } - - // check for positioning requests - int requestedPosition = properties.position; - if (requestedPosition == UNSPECIFIED_POSITION && !properties.beforeItem.isEmpty()) { - requestedPosition = findPositionOfMenuItem(menuObj, properties.beforeItem); - // double check that the requested location wasn't a separator label - requestedPosition = positionBeforeSeparatorIfNeeded(menuObj, requestedPosition); - } - if (requestedPosition == UNSPECIFIED_POSITION && !properties.afterItem.isEmpty()) { - int afterPosition = findPositionOfMenuItem(menuObj, properties.afterItem); - if (afterPosition != UNSPECIFIED_POSITION) { - requestedPosition = afterPosition + 1; - } - } - - QAction* menuItemAction = NULL; - if (properties.isSeparator) { - addDisabledActionAndSeparator(menuObj, properties.menuItemName, requestedPosition); - } else if (properties.isCheckable) { - menuItemAction = addCheckableActionToQMenuAndActionHash(menuObj, properties.menuItemName, - properties.shortcutKeySequence, properties.isChecked, - MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), requestedPosition); - } else { - menuItemAction = addActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence, - MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), - QAction::NoRole, requestedPosition); - } - if (shortcut && menuItemAction) { - connect(shortcut, SIGNAL(activated()), menuItemAction, SLOT(trigger())); - } - QMenuBar::repaint(); - } -} -#endif - -void Menu::removeMenuItem(const QString& menuitem) { -}; - -#if 0 -bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { - QAction* menuItemAction = _actionHash.value(menuitem); - if (menuItemAction) { - return (getMenu(menu) != NULL); - } - return false; -}; - -#endif - -void Menu::setOptionText(const QString& menuitem, const QString& text) { -} - -void Menu::addMenu(const QString& parentMenu, const QString& text) { -} - -void Menu::addMenuItem(const QString& parentMenu, const QString& menuItem) { -} - -void Menu::addMenuItem(const QString& parentMenu, const QString& menuItem, std::function f) { - addMenuItem(parentMenu, menuItem); - setOptionTriggerAction(parentMenu, f); -} - -void Menu::enableMenuItem(const QString& menuItem, bool enable) { -} - -void Menu::setOptionTriggerAction(const QString& menuOption, std::function f) { - _triggerActions[menuOption] = f; -} -void Menu::setOptionToggleAction(const QString& menuOption, std::function f) { - _toggleActions[menuOption] = f; -} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 04275fcb32..e02dd7a789 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -24,6 +24,7 @@ #include #include "DiscoverabilityManager.h" +#include class Settings; @@ -41,46 +42,58 @@ public: void setToggleAction(std::function); }; -class Menu : public QQuickItem { +class Menu : public HifiMenu { Q_OBJECT - HIFI_QML_DECL + public: Menu(QQuickItem * parent = 0); static Menu* getInstance(); - + + // Override the base type HifiMenu with this class instead + static void registerType() { + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); + } + void loadSettings(); void saveSettings(); HifiAction * getActionForOption(const QString& menuOption) { return new HifiAction(menuOption); } // QMenu* addMenu(const QString& menuName); - void removeMenu(const QString& menuName); - bool menuExists(const QString& menuName); - void addSeparator(const QString& menuName, const QString& separatorName); - void removeSeparator(const QString& menuName, const QString& separatorName); - void addMenuItem(const MenuItemProperties& properties); - void removeMenuItem(const QString& menuitem); - bool menuItemExists(const QString& menuName, const QString& menuitem); - bool isOptionChecked(const QString& menuOption) const; - void setIsOptionChecked(const QString& menuOption, bool isChecked); - void triggerOption(const QString& menuOption); - void setOptionText(const QString& menuOption, const QString & text); - void setOptionTriggerAction(const QString& menuOption, std::function f); - void setOptionToggleAction(const QString& menuOption, std::function f); - void addMenuItem(const QString & parentMenu, const QString & menuOption, std::function f); - void addMenuItem(const QString & parentMenu, const QString & menuOption); - void addMenu(const QString & parentMenu, const QString & menuOption); - void enableMenuItem(const QString & menuOption, bool enabled = true); + //void removeMenu(const QString& menuName); + //bool menuExists(const QString& menuName); + //void addSeparator(const QString& menuName, const QString& separatorName); + //void removeSeparator(const QString& menuName, const QString& separatorName); + //void addMenuItem(const MenuItemProperties& properties); + //void removeMenuItem(const QString& menuitem); + //bool menuItemExists(const QString& menuName, const QString& menuitem); + bool isOptionChecked(const QString& menuOption) const { + return HifiMenu::isChecked(menuOption); + } + void setIsOptionChecked(const QString& menuOption, bool isChecked) { + HifiMenu::setChecked(menuOption, isChecked); + } + void triggerOption(const QString& menuOption) { + HifiMenu::triggerMenuItem(menuOption); + } + void setOptionText(const QString& menuOption, const QString & text) { + HifiMenu::setText(menuOption, text); + } + void setOptionTriggerAction(const QString& menuOption, std::function f) { + HifiMenu::setTriggerAction(menuOption, f); + } + //void setOptionToggleAction(const QString& menuOption, std::function f); + //void addMenuItem(const QString & parentMenu, const QString & menuOption, std::function f); + //void addMenuItem(const QString & parentMenu, const QString & menuOption); + //void addMenu(const QString & parentMenu, const QString & menuOption); + //void enableMenuItem(const QString & menuOption, bool enabled = true); private: void init(); private: static Menu* _instance; - - QHash> _triggerActions; - QHash> _toggleActions; - + friend class HifiAction; }; namespace MenuOption { diff --git a/libraries/ui/src/HifiMenu.cpp b/libraries/ui/src/HifiMenu.cpp new file mode 100644 index 0000000000..6ca034522c --- /dev/null +++ b/libraries/ui/src/HifiMenu.cpp @@ -0,0 +1,221 @@ +#include "HifiMenu.h" +#include + +// FIXME can this be made a class member? +static const QString MENU_SUFFIX{ "__Menu" }; + +HIFI_QML_DEF_LAMBDA(HifiMenu, [=](QQmlContext* context, QObject* newItem) { + auto offscreenUi = DependencyManager::get(); + QObject * rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); + Q_ASSERT(rootMenu); + static_cast(newItem)->setRootMenu(rootMenu); + context->setContextProperty("rootMenu", rootMenu); +}); + +HifiMenu::HifiMenu(QQuickItem* parent) : QQuickItem(parent), _triggerMapper(this), _toggleMapper(this) { + this->setEnabled(false); + connect(&_triggerMapper, SIGNAL(mapped(QString)), this, SLOT(onTriggeredByName(const QString &))); + connect(&_toggleMapper, SIGNAL(mapped(QString)), this, SLOT(onToggledByName(const QString &))); +} + +void HifiMenu::onTriggeredByName(const QString & name) { + qDebug() << name << " triggered"; + if (_triggerActions.count(name)) { + _triggerActions[name](); + } +} + +void HifiMenu::onToggledByName(const QString & name) { + qDebug() << name << " toggled"; + if (_toggleActions.count(name)) { + QObject* menu = findMenuObject(name); + bool checked = menu->property("checked").toBool(); + _toggleActions[name](checked); + } +} + +void HifiMenu::setToggleAction(const QString & name, std::function f) { + _toggleActions[name] = f; +} + +void HifiMenu::setTriggerAction(const QString & name, std::function f) { + _triggerActions[name] = f; +} + +QObject* addMenu(QObject* parent, const QString & text) { + // FIXME add more checking here to ensure no name conflicts + QVariant returnedValue; + QMetaObject::invokeMethod(parent, "addMenu", + Q_RETURN_ARG(QVariant, returnedValue), + Q_ARG(QVariant, text)); + QObject* result = returnedValue.value(); + if (result) { + result->setObjectName(text + MENU_SUFFIX); + } + return result; +} + +class QQuickMenuItem; +QObject* addItem(QObject* parent, const QString& text) { + // FIXME add more checking here to ensure no name conflicts + QQuickMenuItem* returnedValue{ nullptr }; + bool invokeResult = QMetaObject::invokeMethod(parent, "addItem", + Q_RETURN_ARG(QQuickMenuItem*, returnedValue), + Q_ARG(QString, text)); + Q_ASSERT(invokeResult); + QObject* result = reinterpret_cast(returnedValue); + return result; +} + +const QObject* HifiMenu::findMenuObject(const QString & menuOption) const { + if (menuOption.isEmpty()) { + return _rootMenu; + } + const QObject* result = _rootMenu->findChild(menuOption + MENU_SUFFIX); + return result; +} + +QObject* HifiMenu::findMenuObject(const QString & menuOption) { + if (menuOption.isEmpty()) { + return _rootMenu; + } + QObject* result = _rootMenu->findChild(menuOption + MENU_SUFFIX); + return result; +} + +void HifiMenu::addMenu(const QString & parentMenu, const QString & menuOption) { + QObject* parent = findMenuObject(parentMenu); + QObject* result = ::addMenu(parent, menuOption); + Q_ASSERT(result); + result->setObjectName(menuOption + MENU_SUFFIX); + Q_ASSERT(findMenuObject(menuOption)); +} + +void HifiMenu::removeMenu(const QString& menuName) { + QObject* menu = findMenuObject(menuName); + Q_ASSERT(menu); + Q_ASSERT(menu != _rootMenu); + QMetaObject::invokeMethod(menu->parent(), "removeItem", + Q_ARG(QVariant, QVariant::fromValue(menu))); +} + +bool HifiMenu::menuExists(const QString& menuName) const { + return findMenuObject(menuName); +} + +void HifiMenu::addSeparator(const QString& parentMenu, const QString& separatorName) { + // FIXME 'add sep' +// addMenu(parentMenu, separatorName); +// setEnabled() +} + +void HifiMenu::removeSeparator(const QString& parentMenu, const QString& separatorName) { +} + +void HifiMenu::addMenuItem(const QString & parentMenu, const QString & menuOption) { + QObject* parent = findMenuObject(parentMenu); + Q_ASSERT(parent); + QObject* result = ::addItem(parent, menuOption); + Q_ASSERT(result); + result->setObjectName(menuOption + MENU_SUFFIX); + Q_ASSERT(findMenuObject(menuOption)); + + _triggerMapper.setMapping(result, menuOption); + connect(result, SIGNAL(triggered()), &_triggerMapper, SLOT(map())); + + _toggleMapper.setMapping(result, menuOption); + connect(result, SIGNAL(toggled(bool)), &_toggleMapper, SLOT(map())); +} + +void HifiMenu::addMenuItem(const QString & parentMenu, const QString & menuOption, std::function f) { + setTriggerAction(menuOption, f); + addMenuItem(parentMenu, menuOption); +} + +void HifiMenu::removeMenuItem(const QString& menuOption) { + removeMenu(menuOption); +} + +bool HifiMenu::menuItemExists(const QString& menuName, const QString& menuitem) const { + return findMenuObject(menuName); +} + +void HifiMenu::triggerMenuItem(const QString& menuOption) { + QObject* menuItem = findMenuObject(menuOption); + Q_ASSERT(menuItem); + Q_ASSERT(menuItem != _rootMenu); + QMetaObject::invokeMethod(menuItem, "trigger"); +} + +QHash warned; +void warn(const QString & menuOption) { + if (!warned.contains(menuOption)) { + warned[menuOption] = menuOption; + qWarning() << "No menu item: " << menuOption; + } +} + +bool HifiMenu::isChecked(const QString& menuOption) const { + const QObject* menuItem = findMenuObject(menuOption); + if (!menuItem) { + warn(menuOption); + return false; + } + return menuItem->property("checked").toBool(); +} + +void HifiMenu::setChecked(const QString& menuOption, bool isChecked) { + QObject* menuItem = findMenuObject(menuOption); + if (!menuItem) { + warn(menuOption); + return; + } + menuItem->setProperty("checked", QVariant::fromValue(isChecked)); + Q_ASSERT(menuItem->property("checked").toBool() == isChecked); +} + +void HifiMenu::setCheckable(const QString& menuOption, bool checkable) { + QObject* menuItem = findMenuObject(menuOption); + if (!menuItem) { + warn(menuOption); + return; + } + + menuItem->setProperty("checkable", QVariant::fromValue(checkable)); + Q_ASSERT(menuItem->property("checkable").toBool() == checkable); +} + +void HifiMenu::setText(const QString& menuOption, const QString & text) { + QObject* menuItem = findMenuObject(menuOption); + if (!menuItem) { + warn(menuOption); + return; + } + menuItem->setProperty("text", QVariant::fromValue(text)); +} + +void HifiMenu::setRootMenu(QObject* rootMenu) { + _rootMenu = rootMenu; +} + +void HifiMenu::enableMenuItem(const QString & menuOption, bool enabled) { + QObject* menuItem = findMenuObject(menuOption); + if (!menuItem) { + warn(menuOption); + return; + } + menuItem->setProperty("enabled", QVariant::fromValue(enabled)); +} + +void HifiMenu::addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked) { + addMenuItem(parentMenu, menuOption); + setCheckable(menuOption); + if (checked) { + setChecked(menuOption, checked); + } +} + +void HifiMenu::addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f) { + setToggleAction(menuOption, f); + addCheckableMenuItem(parentMenu, menuOption, checked); +} diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/HifiMenu.h new file mode 100644 index 0000000000..4d7d860224 --- /dev/null +++ b/libraries/ui/src/HifiMenu.h @@ -0,0 +1,72 @@ +// +// MenuConstants.h +// +// Created by Bradley Austin Davis on 2015/04/21 +// Copyright 2015 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 +// + +#pragma once +#ifndef hifi_MenuContants_h +#define hifi_MenuConstants_h + +#include +#include +#include +#include +#include "OffscreenUi.h" + +class HifiMenu : public QQuickItem { + Q_OBJECT + HIFI_QML_DECL_LAMBDA + +public: + HifiMenu(QQuickItem* parent = nullptr); + + void setToggleAction(const QString& name, std::function f); + void setTriggerAction(const QString& name, std::function f); + + void addMenu(const QString& parentMenu, const QString& menuOption); + void removeMenu(const QString& menuName); + bool menuExists(const QString& menuName) const; + + void addSeparator(const QString& menuName, const QString& separatorName); + void removeSeparator(const QString& menuName, const QString& separatorName); + + void addMenuItem(const QString& parentMenu, const QString& menuOption); + void addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked = false); + void addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f); + void addMenuItem(const QString& parentMenu, const QString& menuOption, std::function f); + void removeMenuItem(const QString& menuitem); + bool menuItemExists(const QString& menuName, const QString& menuitem) const; + void triggerMenuItem(const QString& menuOption); + void enableMenuItem(const QString& menuOption, bool enabled = true); + bool isChecked(const QString& menuOption) const; + void setChecked(const QString& menuOption, bool isChecked = true); + void setCheckable(const QString& menuOption, bool checkable = true); + void setExclusiveGroup(const QString& menuOption, const QString & groupName); + void setText(const QString& menuOption, const QString& text); + + void setRootMenu(QObject * rootMenu); + +private slots: + void onTriggeredByName(const QString& name); + void onToggledByName(const QString& name); + +protected: + QHash> _triggerActions; + QHash> _toggleActions; + QObject* findMenuObject(const QString& name); + const QObject* findMenuObject(const QString& name) const; + QObject* _rootMenu{ nullptr }; + QSignalMapper _triggerMapper; + QSignalMapper _toggleMapper; +}; + +#endif // hifi_MenuConstants_h + + + + diff --git a/libraries/ui/src/MenuConstants.cpp b/libraries/ui/src/MenuConstants.cpp deleted file mode 100644 index eeaf7b456b..0000000000 --- a/libraries/ui/src/MenuConstants.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "MenuConstants.h" -#include - -QML_DIALOG_DEF(HifiMenu) - -static bool init = false; - -HifiMenu::HifiMenu(QQuickItem * parent) : QQuickItem(parent) { - this->setEnabled(false); - qWarning() << "Setting up connection"; - connect(this, &HifiMenu::enabledChanged, this, [=]() { - if (init) { - return; - } - init = true; - foreach(QObject * action, findChildren(QRegularExpression(".*HifiAction"))) { - connect(action, SIGNAL(triggeredByName(QString)), this, SLOT(onTriggeredByName(QString))); - connect(action, SIGNAL(toggledByName(QString)), this, SLOT(onToggledByName(QString))); - } - }); -} - -void HifiMenu::onTriggeredByName(const QString & name) { - qDebug() << name << " triggered"; - if (triggerActions.count(name)) { - triggerActions[name](); - } -} - -void HifiMenu::onToggledByName(const QString & name) { - qDebug() << name << " toggled"; - if (triggerActions.count(name)) { - if (toggleActions.count(name)) { - QObject * action = findChild(name + "HifiAction"); - bool checked = action->property("checked").toBool(); - toggleActions[name](checked); - } - } -} - -QHash> HifiMenu::triggerActions; -QHash> HifiMenu::toggleActions; - -void HifiMenu::setToggleAction(const QString & name, std::function f) { - toggleActions[name] = f; -} - -void HifiMenu::setTriggerAction(const QString & name, std::function f) { - triggerActions[name] = f; -} diff --git a/libraries/ui/src/MenuConstants.h b/libraries/ui/src/MenuConstants.h deleted file mode 100644 index e986410c5b..0000000000 --- a/libraries/ui/src/MenuConstants.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// MenuConstants.h -// -// Created by Bradley Austin Davis on 2015/04/21 -// Copyright 2015 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 -// - -#pragma once -#ifndef hifi_MenuContants_h -#define hifi_MenuConstants_h - -#include -#include -#include -#include "OffscreenQmlDialog.h" - -class HifiMenu : public QQuickItem -{ - Q_OBJECT - QML_DIALOG_DECL - - -public: - HifiMenu(QQuickItem * parent = nullptr); - static void setToggleAction(const QString & name, std::function f); - static void setTriggerAction(const QString & name, std::function f); -private slots: - void onTriggeredByName(const QString & name); - void onToggledByName(const QString & name); -private: - static QHash> triggerActions; - static QHash> toggleActions; -}; - -#endif // hifi_MenuConstants_h - - - - diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index d44a5dd282..7b84bb763f 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -15,6 +15,10 @@ #include #include "MessageDialog.h" + +Q_DECLARE_LOGGING_CATEGORY(offscreenFocus) +Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus") + // Time between receiving a request to render the offscreen UI actually triggering // the render. Could possibly be increased depending on the framerate we expect to // achieve. @@ -93,10 +97,10 @@ void OffscreenUi::create(QOpenGLContext* shareContext) { #ifdef DEBUG connect(_quickWindow, &QQuickWindow::focusObjectChanged, [this]{ - qDebug() << "New focus item " << _quickWindow->focusObject(); + qCDebug(offscreenFocus) << "New focus item " << _quickWindow->focusObject(); }); connect(_quickWindow, &QQuickWindow::activeFocusItemChanged, [this] { - qDebug() << "New active focus item " << _quickWindow->activeFocusItem(); + qCDebug(offscreenFocus) << "New active focus item " << _quickWindow->activeFocusItem(); }); #endif diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index 33fb46b28a..b58b4e59cb 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -43,6 +43,17 @@ public: \ static void load(std::function f = [](QQmlContext*, QQuickItem*) {}); \ private: +#define HIFI_QML_DECL_LAMBDA \ +protected: \ + static const QString NAME; \ + static const QUrl QML; \ +public: \ + static void registerType(); \ + static void show(); \ + static void toggle(); \ + static void load(); \ +private: + #define HIFI_QML_DEF(x) \ const QUrl x::QML = QUrl(#x ".qml"); \ const QString x::NAME = #x; \ @@ -65,6 +76,25 @@ private: offscreenUi->load(QML, f); \ } +#define HIFI_QML_DEF_LAMBDA(x, f) \ + const QUrl x::QML = QUrl(#x ".qml"); \ + const QString x::NAME = #x; \ + \ + void x::registerType() { \ + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ + } \ + void x::show() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->show(QML, NAME, f); \ + } \ + void x::toggle() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->toggle(QML, NAME, f); \ + } \ + void x::load() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->load(QML, f); \ + } class OffscreenUi : public OffscreenGlCanvas, public Dependency { Q_OBJECT diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index e84e5674c1..4189282de1 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -34,7 +34,7 @@ #include #include "MessageDialog.h" -#include "MenuConstants.h" +#include "HifiMenu.h" class RateCounter { std::vector times; @@ -181,11 +181,25 @@ public: offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); offscreenUi->load(QUrl("TestRoot.qml")); offscreenUi->load(QUrl("RootMenu.qml")); + HifiMenu::load(); + QObject* menuObject = offscreenUi->getRootItem()->findChild("HifiMenu"); + HifiMenu* menu = offscreenUi->getRootItem()->findChild(); + menu->addMenu("", "File"); + menu->addMenuItem("File", "Quit", []{ + QApplication::quit(); + }); + menu->addCheckableMenuItem("File", "Toggle", false, [](bool toggled) { + qDebug() << "Toggle is " << toggled; + }); + menu->addMenu("", "Edit"); + menu->addMenuItem("Edit", "Undo"); + menu->addMenuItem("Edit", "Redo"); + menu->addMenuItem("Edit", "Copy"); + menu->addMenuItem("Edit", "Cut"); + menu->addMenuItem("Edit", "Paste"); + menu->addMenu("", "Long Menu Name..."); #endif installEventFilter(offscreenUi.data()); - //HifiMenu::setTriggerAction(MenuOption::Quit, [] { - // QApplication::quit(); - //}); offscreenUi->resume(); _timer.start(); } @@ -233,30 +247,16 @@ protected: resizeWindow(ev->size()); } - - static QObject * addMenu(QObject * parent, const QString & text) { - // FIXME add more checking here to ensure no name conflicts - QVariant returnedValue; - QMetaObject::invokeMethod(parent, "addMenu", - Q_RETURN_ARG(QVariant, returnedValue), - Q_ARG(QVariant, text)); - QObject * result = returnedValue.value(); - return result; - } - + void keyPressEvent(QKeyEvent *event) { _altPressed = Qt::Key_Alt == event->key(); switch (event->key()) { case Qt::Key_L: if (event->modifiers() & Qt::CTRL) { auto offscreenUi = DependencyManager::get(); - rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); - QObject * result = addMenu(rootMenu, "Test 3"); - result->setParent(rootMenu); - qDebug() << "Added " << result; - if (menuContext) { - menuContext->setContextProperty("rootMenu", rootMenu); - } + HifiMenu * menu = offscreenUi->findChild(); + menu->addMenuItem("", "Test 3"); + menu->addMenuItem("File", "Test 3"); } break; case Qt::Key_K: @@ -279,12 +279,7 @@ protected: QQmlContext* menuContext{ nullptr }; void keyReleaseEvent(QKeyEvent *event) { if (_altPressed && Qt::Key_Alt == event->key()) { - HifiMenu::toggle([=](QQmlContext* context, QObject* newItem) { - auto offscreenUi = DependencyManager::get(); - rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); - menuContext = context; - menuContext->setContextProperty("rootMenu", rootMenu); - }); + HifiMenu::toggle(); } } @@ -327,13 +322,12 @@ void QTestWindow::renderQml() { const char * LOG_FILTER_RULES = R"V0G0N( *.debug=false -qt.quick.dialogs.registration=true -qt.quick.mouse.debug = true +qt.quick.mouse.debug=false )V0G0N"; int main(int argc, char** argv) { QGuiApplication app(argc, argv); - //QLoggingCategory::setFilterRules(LOG_FILTER_RULES); +// QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QTestWindow window; app.exec(); return 0; From d68d13489daa4310d8d1b5070d9856ae2a5f4171 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 23 Apr 2015 21:55:31 -0700 Subject: [PATCH 277/401] Working on appearance of menus --- interface/resources/qml/HifiMenu.qml | 50 ++++++++++++------- .../resources/qml/controls/FontAwesome.qml | 16 ++++++ 2 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 interface/resources/qml/controls/FontAwesome.qml diff --git a/interface/resources/qml/HifiMenu.qml b/interface/resources/qml/HifiMenu.qml index 8bdda71558..254ae32520 100644 --- a/interface/resources/qml/HifiMenu.qml +++ b/interface/resources/qml/HifiMenu.qml @@ -47,8 +47,8 @@ Hifi.HifiMenu { property var itemBuilder: Component { Text { SystemPalette { id: sp; colorGroup: SystemPalette.Active } - id: thisText + x: 32 property var source property var root property var listViewIndex @@ -59,17 +59,25 @@ Hifi.HifiMenu { color: source.enabled ? "black" : "gray" onImplicitWidthChanged: { - width = implicitWidth if (listView) { - listView.minWidth = Math.max(listView.minWidth, implicitWidth); + listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64); listView.recalculateSize(); } } - - onImplicitHeightChanged: { - height = implicitHeight + + FontAwesome { + visible: source.type == 1 && source.checkable + x: -32 + text: (source.type == 1 && source.checked) ? "\uF05D" : "\uF10C" } + FontAwesome { + visible: source.type == 2 + x: listView.width - 64 + text: "\uF0DA" + } + + function typedText() { switch(source.type) { case 2: @@ -84,7 +92,11 @@ Hifi.HifiMenu { MouseArea { id: mouseArea acceptedButtons: Qt.LeftButton - anchors.fill: parent + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: parent.top + anchors.topMargin: 0 + width: listView.width onClicked: { listView.currentIndex = listViewIndex parent.root.selectItem(parent.source); @@ -114,7 +126,7 @@ Hifi.HifiMenu { onCountChanged: { recalculateSize() - } + } function recalculateSize() { var newHeight = 0 @@ -128,7 +140,7 @@ Hifi.HifiMenu { } highlight: Rectangle { - width: 0; height: 32 + width: listView.minWidth; height: 32 color: sysPalette.highlight y: (listView.currentItem) ? listView.currentItem.y : 0; Behavior on y { @@ -138,15 +150,7 @@ Hifi.HifiMenu { } } } - Keys.onPressed: { - switch (event.key) { - case Qt.Key_Escape: - console.log("Backing out") - root.popColumn() - event.accepted = true; - } - } - + property int columnIndex: root.models.length - 1 model: root.models[columnIndex] @@ -364,12 +368,20 @@ Hifi.HifiMenu { } */ + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Escape: + root.popColumn() + event.accepted = true; + } + } + MouseArea { anchors.fill: parent id: mouseArea acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - if(mouseArea.pressedButtons & Qt.RightButton) { + if (mouse.button == Qt.RightButton) { root.popColumn(); } else { root.enabled = false; diff --git a/interface/resources/qml/controls/FontAwesome.qml b/interface/resources/qml/controls/FontAwesome.qml new file mode 100644 index 0000000000..16fd4a6ecc --- /dev/null +++ b/interface/resources/qml/controls/FontAwesome.qml @@ -0,0 +1,16 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 +import QtQuick.Controls.Styles 1.3 + +Text { + id: root + FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; } + property int size: 32 + width: size + height: size + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + font.family: iconFont.name + font.pointSize: 18 +} + From 1d316a187294788182206acc620b5486779d092b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 23 Apr 2015 23:41:09 -0700 Subject: [PATCH 278/401] Still working on menus --- interface/src/Bookmarks.cpp | 12 +- interface/src/Menu.cpp | 535 ++++++++++++++++------------------ interface/src/Menu.h | 27 +- libraries/ui/src/HifiMenu.cpp | 60 +++- libraries/ui/src/HifiMenu.h | 27 +- 5 files changed, 334 insertions(+), 327 deletions(-) diff --git a/interface/src/Bookmarks.cpp b/interface/src/Bookmarks.cpp index 5af8234c7f..76ab607ff5 100644 --- a/interface/src/Bookmarks.cpp +++ b/interface/src/Bookmarks.cpp @@ -87,11 +87,11 @@ void Bookmarks::persistToFile() { void Bookmarks::setupMenus(const QString & parentMenu) { // Add menus/actions Menu * menu = Menu::getInstance(); - menu->addMenuItem(parentMenu, MenuOption::BookmarkLocation, [this] { + menu->addItem(parentMenu, MenuOption::BookmarkLocation, [this] { bookmarkLocation(); }); menu->addMenu(parentMenu, MenuOption::Bookmarks); - menu->addMenuItem(parentMenu, MenuOption::DeleteBookmark, [this] { + menu->addItem(parentMenu, MenuOption::DeleteBookmark, [this] { deleteBookmark(); }); @@ -178,19 +178,19 @@ void Bookmarks::deleteBookmark() { void Bookmarks::enableMenuItems(bool enabled) { Menu* menu = Menu::getInstance(); - menu->enableMenuItem(MenuOption::Bookmarks, enabled); - menu->enableMenuItem(MenuOption::DeleteBookmark, enabled); + menu->enableItem(MenuOption::Bookmarks, enabled); + menu->enableItem(MenuOption::DeleteBookmark, enabled); } void Bookmarks::addLocationToMenu(QString& name, QString& address) { - Menu::getInstance()->addMenuItem(MenuOption::Bookmarks, name, [=] { + Menu::getInstance()->addItem(MenuOption::Bookmarks, name, [=] { DependencyManager::get()->handleLookupString(address); }); } void Bookmarks::removeLocationFromMenu(QString& name) { - Menu::getInstance()->removeMenuItem(name); + Menu::getInstance()->removeItem(name); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 529fca5e66..029c150884 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -42,6 +42,7 @@ #include "InterfaceLogging.h" #include "Menu.h" +#include "Util.h" // Proxy object to simplify porting over HifiAction::HifiAction(const QString & menuOption) : _menuOption(menuOption) { @@ -57,28 +58,15 @@ void HifiAction::setChecked(bool checked) { } void HifiAction::setVisible(bool visible) { - QObject* result = Menu::getInstance()->findMenuObject(_menuOption); - if (result) { - result->setProperty("visible", visible); - } + return Menu::getInstance()->setItemVisible(_menuOption); } -const QString & HifiAction::shortcut() const { - static const QString NONE; - QObject* result = Menu::getInstance()->findMenuObject(_menuOption); - if (!result) { - return NONE; - } - QObject* shortcut = result->property("shortcut").value(); - if (!shortcut) { - return NONE; - } - shortcut->dumpObjectInfo(); - return NONE; +QString HifiAction::shortcut() const { + return Menu::getInstance()->getItemShortcut(_menuOption); } void HifiAction::setText(const QString & text) { - Menu::getInstance()->setText(_menuOption, text); + Menu::getInstance()->setItemText(_menuOption, text); } void HifiAction::setTriggerAction(std::function f) { @@ -116,7 +104,6 @@ Menu* Menu::getInstance() { Menu::Menu(QQuickItem * parent) : HifiMenu(parent) { } - void Menu::init() { auto dialogsManager = DependencyManager::get(); AccountManager& accountManager = AccountManager::getInstance(); @@ -125,7 +112,7 @@ void Menu::init() { static const QString FILE_MENU{ "File" }; addMenu(ROOT_MENU, FILE_MENU); { - addMenuItem(FILE_MENU, MenuOption::Login); + addItem(FILE_MENU, MenuOption::Login); // connect to the appropriate signal of the AccountManager so that we can change the Login/Logout menu item connect(&accountManager, &AccountManager::profileChanged, dialogsManager.data(), &DialogsManager::toggleLoginDialog); @@ -141,22 +128,22 @@ void Menu::init() { static const QString SCRIPTS_MENU{ "Scripts" }; addMenu(FILE_MENU, SCRIPTS_MENU); //Qt::CTRL | Qt::Key_O - addMenuItem(SCRIPTS_MENU, MenuOption::LoadScript, [=] { + addItem(SCRIPTS_MENU, MenuOption::LoadScript, [=] { qApp->loadDialog(); }); //Qt::CTRL | Qt::SHIFT | Qt::Key_O - addMenuItem(SCRIPTS_MENU, MenuOption::LoadScriptURL, [=] { + addItem(SCRIPTS_MENU, MenuOption::LoadScriptURL, [=] { qApp->loadScriptURLDialog(); }); - addMenuItem(SCRIPTS_MENU, MenuOption::StopAllScripts, [=] { + addItem(SCRIPTS_MENU, MenuOption::StopAllScripts, [=] { qApp->stopAllScripts(); }); //Qt::CTRL | Qt::Key_R, - addMenuItem(SCRIPTS_MENU, MenuOption::ReloadAllScripts, [=] { + addItem(SCRIPTS_MENU, MenuOption::ReloadAllScripts, [=] { qApp->reloadAllScripts(); }); // Qt::CTRL | Qt::Key_J, - addMenuItem(SCRIPTS_MENU, MenuOption::RunningScripts, [=] { + addItem(SCRIPTS_MENU, MenuOption::RunningScripts, [=] { qApp->toggleRunningScriptsWidget(); }); } @@ -166,15 +153,15 @@ void Menu::init() { addMenu(FILE_MENU, LOCATION_MENU); qApp->getBookmarks()->setupMenus(LOCATION_MENU); //Qt::CTRL | Qt::Key_L - addMenuItem(LOCATION_MENU, MenuOption::AddressBar, [=] { + addItem(LOCATION_MENU, MenuOption::AddressBar, [=] { auto dialogsManager = DependencyManager::get(); dialogsManager->toggleAddressBar(); }); - addMenuItem(LOCATION_MENU, MenuOption::CopyAddress, [=] { + addItem(LOCATION_MENU, MenuOption::CopyAddress, [=] { auto addressManager = DependencyManager::get(); addressManager->copyAddress(); }); - addMenuItem(LOCATION_MENU, MenuOption::CopyPath, [=] { + addItem(LOCATION_MENU, MenuOption::CopyPath, [=] { auto addressManager = DependencyManager::get(); addressManager->copyPath(); }); @@ -182,7 +169,7 @@ void Menu::init() { // Qt::CTRL | Qt::Key_Q // QAction::QuitRole - addMenuItem(FILE_MENU, MenuOption::Quit, [=] { + addItem(FILE_MENU, MenuOption::Quit, [=] { qApp->quit(); }); } @@ -204,10 +191,10 @@ void Menu::init() { // Qt::CTRL | Qt::Key_Comma // QAction::PreferencesRole - addMenuItem(EDIT_MENU, MenuOption::Preferences, [=] { + addItem(EDIT_MENU, MenuOption::Preferences, [=] { dialogsManager->editPreferences(); }); - addMenuItem(EDIT_MENU, MenuOption::Animations, [=] { + addItem(EDIT_MENU, MenuOption::Animations, [=] { dialogsManager->editAnimations(); }); } @@ -219,65 +206,60 @@ void Menu::init() { #if defined(Q_OS_MAC) || defined(Q_OS_WIN) auto speechRecognizer = DependencyManager::get(); //Qt::CTRL | Qt::SHIFT | Qt::Key_C - addMenuItem(TOOLS_MENU, MenuOption::ControlWithSpeech); + addItem(TOOLS_MENU, MenuOption::ControlWithSpeech); setChecked(MenuOption::ControlWithSpeech, speechRecognizer->getEnabled()); connect(speechRecognizer.data(), &SpeechRecognizer::enabledUpdated, [=] { setChecked(MenuOption::ControlWithSpeech, speechRecognizer->getEnabled()); }); #endif // Qt::ALT | Qt::Key_S, - addMenuItem(TOOLS_MENU, MenuOption::ScriptEditor, [=] { + addItem(TOOLS_MENU, MenuOption::ScriptEditor, [=] { dialogsManager->showScriptEditor(); }); // QML Qt::Key_Backslash, - addMenuItem(TOOLS_MENU, MenuOption::Chat, [=] { + addItem(TOOLS_MENU, MenuOption::Chat, [=] { dialogsManager->showIRCLink(); }); - addMenuItem(TOOLS_MENU, MenuOption::AddRemoveFriends, [=] { + addItem(TOOLS_MENU, MenuOption::AddRemoveFriends, [=] { qApp->showFriendsWindow(); }); -#if 0 - QMenu* visibilityMenu = toolsMenu->addMenu("I Am Visible To"); { - QActionGroup* visibilityGroup = new QActionGroup(toolsMenu); + static const QString VIZ_MENU{ "I Am Visible To" }; + addMenu(TOOLS_MENU, VIZ_MENU); auto discoverabilityManager = DependencyManager::get(); - - QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToEveryone); - - QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToFriends); - - QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne, - 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, - discoverabilityManager.data(), SLOT(setVisibility())); - visibilityGroup->addAction(visibleToNoOne); + // FIXME group + addCheckableItem(VIZ_MENU, MenuOption::VisibleToEveryone, + discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, + [=](bool) { discoverabilityManager->setVisibility(); }); + addCheckableItem(VIZ_MENU, MenuOption::VisibleToFriends, + discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, + [=](bool) { discoverabilityManager->setVisibility(); }); + addCheckableItem(VIZ_MENU, MenuOption::VisibleToNoOne, + discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, + [=](bool) { discoverabilityManager->setVisibility(); }); connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged); + } -#endif + //Qt::CTRL | Qt::ALT | Qt::Key_T, - addMenuItem(TOOLS_MENU, MenuOption::ToolWindow, [=] { + addItem(TOOLS_MENU, MenuOption::ToolWindow, [=] { // dialogsManager->toggleToolWindow(); }); //Qt::CTRL | Qt::ALT | Qt::Key_J, - addMenuItem(TOOLS_MENU, MenuOption::Console, [=] { + addItem(TOOLS_MENU, MenuOption::Console, [=] { DependencyManager::get()->toggleConsole(); }); // QML Qt::Key_Apostrophe, - addMenuItem(TOOLS_MENU, MenuOption::ResetSensors, [=] { + addItem(TOOLS_MENU, MenuOption::ResetSensors, [=] { qApp->resetSensors(); }); - addMenuItem(TOOLS_MENU, MenuOption::PackageModel, [=] { + addItem(TOOLS_MENU, MenuOption::PackageModel, [=] { qApp->packageModel(); }); } @@ -290,35 +272,35 @@ void Menu::init() { static const QString SIZE_MENU{ "Size" }; addMenu(AVATAR_MENU, SIZE_MENU); // QML Qt::Key_Plus, - addMenuItem(SIZE_MENU, MenuOption::IncreaseAvatarSize, [=] { + addItem(SIZE_MENU, MenuOption::IncreaseAvatarSize, [=] { avatar->increaseSize(); }); // QML Qt::Key_Minus, - addMenuItem(SIZE_MENU, MenuOption::DecreaseAvatarSize, [=] { + addItem(SIZE_MENU, MenuOption::DecreaseAvatarSize, [=] { avatar->decreaseSize(); }); // QML Qt::Key_Equal, - addMenuItem(SIZE_MENU, MenuOption::ResetAvatarSize, [=] { + addItem(SIZE_MENU, MenuOption::ResetAvatarSize, [=] { avatar->resetSize(); }); - addMenuItem(SIZE_MENU, MenuOption::ResetAvatarSize, [=] { + addItem(SIZE_MENU, MenuOption::ResetAvatarSize, [=] { avatar->resetSize(); }); } //Qt::CTRL | Qt::SHIFT | Qt::Key_K - addCheckableMenuItem(AVATAR_MENU, MenuOption::KeyboardMotorControl, true, [=](bool) { + addCheckableItem(AVATAR_MENU, MenuOption::KeyboardMotorControl, true, [=](bool) { avatar->updateMotionBehavior(); }); - addCheckableMenuItem(AVATAR_MENU, MenuOption::ScriptedMotorControl, true); - addCheckableMenuItem(AVATAR_MENU, MenuOption::NamesAboveHeads, true); - addCheckableMenuItem(AVATAR_MENU, MenuOption::GlowWhenSpeaking, true); - addCheckableMenuItem(AVATAR_MENU, MenuOption::BlueSpeechSphere, true); - addCheckableMenuItem(AVATAR_MENU, MenuOption::EnableCharacterController, true, [=](bool) { + addCheckableItem(AVATAR_MENU, MenuOption::ScriptedMotorControl, true); + addCheckableItem(AVATAR_MENU, MenuOption::NamesAboveHeads, true); + addCheckableItem(AVATAR_MENU, MenuOption::GlowWhenSpeaking, true); + addCheckableItem(AVATAR_MENU, MenuOption::BlueSpeechSphere, true); + addCheckableItem(AVATAR_MENU, MenuOption::EnableCharacterController, true, [=](bool) { avatar->updateMotionBehavior(); }); - addCheckableMenuItem(AVATAR_MENU, MenuOption::ShiftHipsForIdleAnimations, false, [=](bool) { + addCheckableItem(AVATAR_MENU, MenuOption::ShiftHipsForIdleAnimations, false, [=](bool) { avatar->updateMotionBehavior(); }); } @@ -329,57 +311,58 @@ void Menu::init() { // Mac Qt::CTRL | Qt::META | Qt::Key_F, // Win32/Linux Qt::CTRL | Qt::Key_F, - addCheckableMenuItem(VIEW_MENU, MenuOption::Fullscreen, false, [=](bool checked) { + addCheckableItem(VIEW_MENU, MenuOption::Fullscreen, false, [=](bool checked) { // qApp->setFullscreen(checked); }); // QML Qt::Key_P, - addCheckableMenuItem(VIEW_MENU, MenuOption::FirstPerson, true, [=](bool checked) { + addCheckableItem(VIEW_MENU, MenuOption::FirstPerson, true, [=](bool checked) { // qApp->cameraMenuChanged(); }); //QML Qt::SHIFT | Qt::Key_H, - addCheckableMenuItem(VIEW_MENU, MenuOption::Mirror, true); + addCheckableItem(VIEW_MENU, MenuOption::Mirror, true); // QML Qt::Key_H, - addCheckableMenuItem(VIEW_MENU, MenuOption::FullscreenMirror, true, [=](bool checked) { + addCheckableItem(VIEW_MENU, MenuOption::FullscreenMirror, true, [=](bool checked) { // qApp->cameraMenuChanged(); }); // Mac Qt::META | Qt::Key_H, // Win32/Linux Qt::CTRL | Qt::Key_H, - addCheckableMenuItem(VIEW_MENU, MenuOption::HMDTools, false, [=](bool checked) { + addCheckableItem(VIEW_MENU, MenuOption::HMDTools, false, [=](bool checked) { dialogsManager->hmdTools(checked); }); - addCheckableMenuItem(VIEW_MENU, MenuOption::EnableVRMode, false, [=](bool checked) { + addCheckableItem(VIEW_MENU, MenuOption::EnableVRMode, false, [=](bool checked) { // qApp->setEnableVRMode(checked); }); - addCheckableMenuItem(VIEW_MENU, MenuOption::Enable3DTVMode, false, [=](bool checked) { + addCheckableItem(VIEW_MENU, MenuOption::Enable3DTVMode, false, [=](bool checked) { // qApp->setEnable3DTVMode(checked); }); { - static const QString BORDER_MENU{ "View" }; + static const QString BORDER_MENU{ "Server Borders" }; addMenu(VIEW_MENU, BORDER_MENU); // Qt::CTRL | Qt::SHIFT | Qt::Key_1 - addCheckableMenuItem(BORDER_MENU, MenuOption::ShowBordersEntityNodes, false, [=](bool checked) { + addCheckableItem(BORDER_MENU, MenuOption::ShowBordersEntityNodes, false, [=](bool checked) { qApp->getNodeBoundsDisplay().setShowEntityNodes(checked); }); } - addCheckableMenuItem(VIEW_MENU, MenuOption::OffAxisProjection, false); - addCheckableMenuItem(VIEW_MENU, MenuOption::TurnWithHead, false); + addCheckableItem(VIEW_MENU, MenuOption::OffAxisProjection, false); + addCheckableItem(VIEW_MENU, MenuOption::TurnWithHead, false); // QML Qt::Key_Slash - addCheckableMenuItem(VIEW_MENU, MenuOption::Stats, false); + addCheckableItem(VIEW_MENU, MenuOption::Stats, false); // Qt::CTRL | Qt::SHIFT | Qt::Key_L - addMenuItem(VIEW_MENU, MenuOption::Log, [=] { + addItem(VIEW_MENU, MenuOption::Log, [=] { qApp->toggleLogDialog(); }); - addMenuItem(VIEW_MENU, MenuOption::BandwidthDetails, [=] { + addItem(VIEW_MENU, MenuOption::BandwidthDetails, [=] { dialogsManager->bandwidthDetails(); }); - addMenuItem(VIEW_MENU, MenuOption::OctreeStats, [=] { + addItem(VIEW_MENU, MenuOption::OctreeStats, [=] { dialogsManager->octreeStatsDetails(); }); } + { static const QString DEV_MENU{ "Developer" }; @@ -388,9 +371,9 @@ void Menu::init() { static const QString RENDER_MENU{ "Render" }; addMenu(DEV_MENU, RENDER_MENU); // QML Qt::SHIFT | Qt::Key_A, - addCheckableMenuItem(RENDER_MENU, MenuOption::Atmosphere, true); - addCheckableMenuItem(RENDER_MENU, MenuOption::AmbientOcclusion); - addCheckableMenuItem(RENDER_MENU, MenuOption::DontFadeOnOctreeServerChanges); + addCheckableItem(RENDER_MENU, MenuOption::Atmosphere, true); + addCheckableItem(RENDER_MENU, MenuOption::AmbientOcclusion); + addCheckableItem(RENDER_MENU, MenuOption::DontFadeOnOctreeServerChanges); { static const QString LIGHT_MENU{ MenuOption::RenderAmbientLight }; addMenu(RENDER_MENU, LIGHT_MENU); @@ -408,7 +391,7 @@ void Menu::init() { MenuOption::RenderAmbientLight9, }; foreach(QString option, LIGHTS) { - addCheckableMenuItem(LIGHT_MENU, option); + addCheckableItem(LIGHT_MENU, option); // FIXME // setExclusiveGroup() } @@ -417,22 +400,22 @@ void Menu::init() { { static const QString SHADOWS_MENU{ "Shadows" }; addMenu(RENDER_MENU, SHADOWS_MENU); - addCheckableMenuItem(SHADOWS_MENU, "No Shadows", true); - addCheckableMenuItem(SHADOWS_MENU, MenuOption::SimpleShadows); - addCheckableMenuItem(SHADOWS_MENU, MenuOption::CascadedShadows); + addCheckableItem(SHADOWS_MENU, "No Shadows", true); + addCheckableItem(SHADOWS_MENU, MenuOption::SimpleShadows); + addCheckableItem(SHADOWS_MENU, MenuOption::CascadedShadows); } { static const QString FRAMERATE_MENU{ MenuOption::RenderTargetFramerate }; addMenu(RENDER_MENU, FRAMERATE_MENU); //framerateGroup->setExclusive(true); - addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerateUnlimited, true); - addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate60); - addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate50); - addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate40); - addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate30); + addCheckableItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerateUnlimited, true); + addCheckableItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate60); + addCheckableItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate50); + addCheckableItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate40); + addCheckableItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate30); } #if !defined(Q_OS_MAC) - addCheckableMenuItem(RENDER_MENU, MenuOption::RenderTargetFramerateVSyncOn, true, [](bool checked) { + addCheckableItem(RENDER_MENU, MenuOption::RenderTargetFramerateVSyncOn, true, [](bool checked) { qApp->setVSyncEnabled(); }); #endif @@ -440,223 +423,211 @@ void Menu::init() { static const QString RES_MENU{ MenuOption::RenderResolution }; addMenu(RENDER_MENU, RES_MENU); // resolutionGroup->setExclusive(true); - addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionOne, true); - addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionTwoThird); - addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionHalf); - addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionThird); - addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionQuarter); + addCheckableItem(RES_MENU, MenuOption::RenderResolutionOne, true); + addCheckableItem(RES_MENU, MenuOption::RenderResolutionTwoThird); + addCheckableItem(RES_MENU, MenuOption::RenderResolutionHalf); + addCheckableItem(RES_MENU, MenuOption::RenderResolutionThird); + addCheckableItem(RES_MENU, MenuOption::RenderResolutionQuarter); } // QML Qt::Key_Asterisk, - addCheckableMenuItem(RENDER_MENU, MenuOption::Stars, true); - addCheckableMenuItem(RENDER_MENU, MenuOption::EnableGlowEffect, true, [](bool checked){ + addCheckableItem(RENDER_MENU, MenuOption::Stars, true); + addCheckableItem(RENDER_MENU, MenuOption::EnableGlowEffect, true, [](bool checked){ DependencyManager::get()->toggleGlowEffect(checked); }); //Qt::ALT | Qt::Key_W - addCheckableMenuItem(RENDER_MENU, MenuOption::Wireframe); + addCheckableItem(RENDER_MENU, MenuOption::Wireframe); // QML Qt::SHIFT | Qt::Key_L, - addMenuItem(RENDER_MENU, MenuOption::LodTools, [=] { + addItem(RENDER_MENU, MenuOption::LodTools, [=] { dialogsManager->lodTools(); }); - } + } // Developer -> Render { static const QString AVATAR_MENU{ "Avatar Dev" }; addMenu(DEV_MENU, AVATAR_MENU); - setText(AVATAR_MENU, "Avatar"); + setItemText(AVATAR_MENU, "Avatar"); { - } - } - } - -#if 0 - QMenu* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking"); - { - QActionGroup* faceTrackerGroup = new QActionGroup(avatarDebugMenu); - - QAction* noFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::NoFaceTracking, - 0, true, - qApp, SLOT(setActiveFaceTracker())); - faceTrackerGroup->addAction(noFaceTracker); - + static const QString FACE_MENU{ "Face Tracking" }; + addMenu(AVATAR_MENU, FACE_MENU); + // FIXME GROUP + addCheckableItem(FACE_MENU, MenuOption::NoFaceTracking, true, [](bool checked) { + qApp->setActiveFaceTracker(); + }); #ifdef HAVE_FACESHIFT - QAction* faceshiftFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Faceshift, - 0, false, - qApp, SLOT(setActiveFaceTracker())); - faceTrackerGroup->addAction(faceshiftFaceTracker); + addCheckableItem(FACE_MENU, MenuOption::Faceshift, true, [](bool checked) { + qApp->setActiveFaceTracker(); + }); #endif #ifdef HAVE_DDE - QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseCamera, - 0, false, - qApp, SLOT(setActiveFaceTracker())); - faceTrackerGroup->addAction(ddeFaceTracker); -#endif - } -#ifdef HAVE_DDE - faceTrackingMenu->addSeparator(); - QAction* useAudioForMouth = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseAudioForMouth, 0, true); - useAudioForMouth->setVisible(false); - QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true); - ddeFiltering->setVisible(false); + addCheckableItem(FACE_MENU, MenuOption::UseCamera, true, [](bool checked) { + qApp->setActiveFaceTracker(); + }); #endif + addCheckableItem(FACE_MENU, MenuOption::UseAudioForMouth, true); + // FIXME integrate the visibility into the main API + getActionForOption(MenuOption::UseAudioForMouth)->setVisible(false); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderHeadCollisionShapes); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false); - - QMenu* handOptionsMenu = developerMenu->addMenu("Hands"); - addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, false); - addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); - addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true); - addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); - addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false); - - QMenu* sixenseOptionsMenu = handOptionsMenu->addMenu("Sixense"); + addCheckableItem(FACE_MENU, MenuOption::VelocityFilter, true); + // FIXME integrate the visibility into the main API + getActionForOption(MenuOption::VelocityFilter)->setVisible(false); + } + addCheckableItem(AVATAR_MENU, MenuOption::RenderSkeletonCollisionShapes); + addCheckableItem(AVATAR_MENU, MenuOption::RenderHeadCollisionShapes); + addCheckableItem(AVATAR_MENU, MenuOption::RenderBoundingCollisionShapes); + addCheckableItem(AVATAR_MENU, MenuOption::RenderLookAtVectors); + addCheckableItem(AVATAR_MENU, MenuOption::RenderFocusIndicator); + { + static const QString HANDS_MENU{ "Hands" }; + addMenu(AVATAR_MENU, HANDS_MENU); + addCheckableItem(HANDS_MENU, MenuOption::AlignForearmsWithWrists); + addCheckableItem(HANDS_MENU, MenuOption::AlternateIK); + addCheckableItem(HANDS_MENU, MenuOption::DisplayHands, true); + addCheckableItem(HANDS_MENU, MenuOption::DisplayHandTargets); + addCheckableItem(HANDS_MENU, MenuOption::ShowIKConstraints); + { + static const QString SIXENSE_MENU{ "Sixense" }; + addMenu(HANDS_MENU, SIXENSE_MENU); #ifdef __APPLE__ - addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, - MenuOption::SixenseEnabled, - 0, false, - &SixenseManager::getInstance(), - SLOT(toggleSixense(bool))); + addCheckableItem(SIXENSE_MENU, MenuOption::SixenseEnabled, false, [](bool checked) { + SixenseManager::getInstance().toggleSixense(checked); + }); #endif - addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, - MenuOption::FilterSixense, - 0, - true, - &SixenseManager::getInstance(), - SLOT(setFilter(bool))); - addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, - MenuOption::LowVelocityFilter, - 0, - true, - qApp, - SLOT(setLowVelocityFilter(bool))); - addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true); - addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseLasers, 0, false); + addCheckableItem(SIXENSE_MENU, MenuOption::FilterSixense, true, [](bool checked) { + SixenseManager::getInstance().setFilter(checked); + }); + addCheckableItem(SIXENSE_MENU, MenuOption::LowVelocityFilter, true, [](bool checked) { + qApp->setLowVelocityFilter(checked); + }); + addCheckableItem(SIXENSE_MENU, MenuOption::SixenseMouseInput, true); + addCheckableItem(SIXENSE_MENU, MenuOption::SixenseLasers); + } - QMenu* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion"); - addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false); + { + static const QString LEAP_MENU{ "Leap Motion" }; + addMenu(HANDS_MENU, LEAP_MENU); + addCheckableItem(LEAP_MENU, MenuOption::LeapMotionOnHMD); + addCheckableItem(LEAP_MENU, MenuOption::LeapMotionOnHMD); + } #ifdef HAVE_RSSDK - QMenu* realSenseOptionsMenu = handOptionsMenu->addMenu("RealSense"); - addActionToQMenuAndActionHash(realSenseOptionsMenu, MenuOption::LoadRSSDKFile, 0, - RealSense::getInstance(), SLOT(loadRSSDKFile())); + { + static const QString RSS_MENU{ "RealSense" }; + addMenu(HANDS_MENU, RSS_MENU); + addItem(RSS_MENU, MenuOption::LoadRSSDKFile, [] { + RealSense::getInstance()->loadRSSDKFile(); + }); + addCheckableItem(RSS_MENU, MenuOption::LeapMotionOnHMD); + } #endif + } // Developer -> Hands - QMenu* networkMenu = developerMenu->addMenu("Network"); - addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false); - addCheckableActionToQMenuAndActionHash(networkMenu, - MenuOption::DisableActivityLogger, - 0, - false, - &UserActivityLogger::getInstance(), - SLOT(disable(bool))); - addActionToQMenuAndActionHash(networkMenu, MenuOption::CachesSize, 0, - dialogsManager.data(), SLOT(cachesSizeDialog())); - addActionToQMenuAndActionHash(networkMenu, MenuOption::DiskCacheEditor, 0, - dialogsManager.data(), SLOT(toggleDiskCacheEditor())); + { + static const QString NETWORK_MENU{ "Network" }; + addMenu(DEV_MENU, NETWORK_MENU); + addCheckableItem(NETWORK_MENU, MenuOption::DisableNackPackets); + addCheckableItem(NETWORK_MENU, MenuOption::DisableActivityLogger, false, [](bool checked) { + UserActivityLogger::getInstance().disable(checked); + }); + addItem(NETWORK_MENU, MenuOption::CachesSize, [=] { + dialogsManager->cachesSizeDialog(); + }); + addItem(NETWORK_MENU, MenuOption::DiskCacheEditor, [=] { + dialogsManager->toggleDiskCacheEditor(); + }); + } // Developer -> Network - QMenu* timingMenu = developerMenu->addMenu("Timing and Stats"); - QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer"); - addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false); - addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true); - addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false); - addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false); - addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarSimulateTiming, 0, false); - addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandOtherAvatarTiming, 0, false); - addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false); + { + static const QString TIMING_MENU{ "Timing and Stats" }; + addMenu(DEV_MENU, TIMING_MENU); + { + static const QString PERF_MENU{ "Performance Timer" }; + addMenu(TIMING_MENU, PERF_MENU); + addCheckableItem(PERF_MENU, MenuOption::DisplayDebugTimingDetails); + addCheckableItem(PERF_MENU, MenuOption::OnlyDisplayTopTen, true); + addCheckableItem(PERF_MENU, MenuOption::ExpandUpdateTiming); + addCheckableItem(PERF_MENU, MenuOption::ExpandMyAvatarTiming); + addCheckableItem(PERF_MENU, MenuOption::ExpandMyAvatarSimulateTiming); + addCheckableItem(PERF_MENU, MenuOption::ExpandOtherAvatarTiming); + addCheckableItem(PERF_MENU, MenuOption::ExpandPaintGLTiming); + } + addCheckableItem(TIMING_MENU, MenuOption::TestPing, true); + addCheckableItem(TIMING_MENU, MenuOption::FrameTimer); + addItem(TIMING_MENU, MenuOption::RunTimingTests, [] { runTimingTests(); }); + addCheckableItem(TIMING_MENU, MenuOption::PipelineWarnings); + addCheckableItem(TIMING_MENU, MenuOption::SuppressShortTimings); + } // Developer -> Timing and Stats - addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::TestPing, 0, true); - addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer); - addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, qApp, SLOT(runTests())); - addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::PipelineWarnings); - addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SuppressShortTimings); + { + static const QString AUDIO_MENU{ "Audio" }; + addMenu(DEV_MENU, AUDIO_MENU); + auto audioIO = DependencyManager::get(); + addCheckableItem(AUDIO_MENU, MenuOption::AudioNoiseReduction, true, [=](bool checked) { + audioIO->toggleAudioNoiseReduction(); + }); + addCheckableItem(AUDIO_MENU, MenuOption::EchoServerAudio, false, [=](bool checked) { + audioIO->toggleServerEcho(); + }); + addCheckableItem(AUDIO_MENU, MenuOption::EchoLocalAudio, false, [=](bool checked) { + audioIO->toggleLocalEcho(); + }); + addCheckableItem(AUDIO_MENU, MenuOption::StereoAudio, false, [=](bool checked) { + audioIO->toggleStereoInput(); + }); + // Qt::CTRL | Qt::Key_M, + addCheckableItem(AUDIO_MENU, MenuOption::MuteAudio, false, [=](bool checked) { + audioIO->toggleMute(); + }); + addCheckableItem(AUDIO_MENU, MenuOption::MuteEnvironment, false, [=](bool checked) { + audioIO->sendMuteEnvironmentPacket(); + }); + { + static const QString SCOPE_MENU{ "Audio Scope" }; + addMenu(AUDIO_MENU, SCOPE_MENU); + auto scope = DependencyManager::get(); + // Qt::CTRL | Qt::Key_P + addCheckableItem(SCOPE_MENU, MenuOption::AudioScope, false, [=](bool checked) { + scope->toggle(); + }); + // Qt::CTRL | Qt::SHIFT | Qt::Key_P + addCheckableItem(SCOPE_MENU, MenuOption::AudioScopePause, false, [=](bool checked) { + scope->togglePause(); + }); + addSeparator(SCOPE_MENU, "Display Frames"); - auto audioIO = DependencyManager::get(); - QMenu* audioDebugMenu = developerMenu->addMenu("Audio"); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, - 0, - true, - audioIO.data(), - SLOT(toggleAudioNoiseReduction())); + // FIXME GROUP + addCheckableItem(SCOPE_MENU, MenuOption::AudioScopeFiveFrames, true, [=](bool checked) { + scope->selectAudioScopeFiveFrames(); + }); + addCheckableItem(SCOPE_MENU, MenuOption::AudioScopeTwentyFrames, false, [=](bool checked) { + scope->selectAudioScopeTwentyFrames(); + }); + addCheckableItem(SCOPE_MENU, MenuOption::AudioScopeFiftyFrames, false, [=](bool checked) { + scope->selectAudioScopeFiftyFrames(); + }); + } + auto statsRenderer = DependencyManager::get(); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio, 0, false, - audioIO.data(), SLOT(toggleServerEcho())); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio, 0, false, - audioIO.data(), SLOT(toggleLocalEcho())); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false, - audioIO.data(), SLOT(toggleStereoInput())); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteAudio, - Qt::CTRL | Qt::Key_M, - false, - audioIO.data(), - SLOT(toggleMute())); - addActionToQMenuAndActionHash(audioDebugMenu, - MenuOption::MuteEnvironment, - 0, - audioIO.data(), - SLOT(sendMuteEnvironmentPacket())); - - auto scope = DependencyManager::get(); + // Qt::CTRL | Qt::SHIFT | Qt::Key_A, + addCheckableItem(AUDIO_MENU, MenuOption::AudioStats, false, [=](bool checked) { + statsRenderer->toggle(); + }); + addCheckableItem(AUDIO_MENU, MenuOption::AudioStatsShowInjectedStreams, false, [=](bool checked) { + statsRenderer->toggleShowInjectedStreams(); + }); + } // Developer -> Audio + } // Developer - QMenu* audioScopeMenu = audioDebugMenu->addMenu("Audio Scope"); - addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScope, - Qt::CTRL | Qt::Key_P, false, - scope.data(), - SLOT(toggle())); - addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopePause, - Qt::CTRL | Qt::SHIFT | Qt::Key_P , - false, - scope.data(), - SLOT(togglePause())); - addDisabledActionAndSeparator(audioScopeMenu, "Display Frames"); - { - QAction *fiveFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeFiveFrames, - 0, - true, - scope.data(), - SLOT(selectAudioScopeFiveFrames())); - - QAction *twentyFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeTwentyFrames, - 0, - false, - scope.data(), - SLOT(selectAudioScopeTwentyFrames())); - - QAction *fiftyFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeFiftyFrames, - 0, - false, - scope.data(), - SLOT(selectAudioScopeFiftyFrames())); - - QActionGroup* audioScopeFramesGroup = new QActionGroup(audioScopeMenu); - audioScopeFramesGroup->addAction(fiveFrames); - audioScopeFramesGroup->addAction(twentyFrames); - audioScopeFramesGroup->addAction(fiftyFrames); + { + static const QString HELP_MENU{ "Help" }; + addMenu(ROOT_MENU, HELP_MENU); + addItem(HELP_MENU, MenuOption::EditEntitiesHelp, [] { + qApp->showEditEntitiesHelp(); + }); + addItem(HELP_MENU, MenuOption::AboutApp, [] { + qApp->aboutApp(); + }); + } // Help } - - auto statsRenderer = DependencyManager::get(); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioStats, - Qt::CTRL | Qt::SHIFT | Qt::Key_A, - false, - statsRenderer.data(), - SLOT(toggle())); - - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioStatsShowInjectedStreams, - 0, - false, - statsRenderer.data(), - SLOT(toggleShowInjectedStreams())); - - QMenu* helpMenu = addMenu("Help"); - addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp())); - -#ifndef Q_OS_MAC - QAction* aboutAction = helpMenu->addAction(MenuOption::AboutApp); - connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutApp())); -#endif -#endif } void Menu::loadSettings() { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index e02dd7a789..d23d7658d0 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -36,7 +36,7 @@ public: void setCheckable(bool); void setChecked(bool); void setVisible(bool); - const QString & shortcut() const; + QString shortcut() const; void setText(const QString &); void setTriggerAction(std::function); void setToggleAction(std::function); @@ -56,37 +56,32 @@ public: void loadSettings(); void saveSettings(); + HifiAction * getActionForOption(const QString& menuOption) { return new HifiAction(menuOption); } -// QMenu* addMenu(const QString& menuName); - //void removeMenu(const QString& menuName); - //bool menuExists(const QString& menuName); - //void addSeparator(const QString& menuName, const QString& separatorName); - //void removeSeparator(const QString& menuName, const QString& separatorName); - //void addMenuItem(const MenuItemProperties& properties); - //void removeMenuItem(const QString& menuitem); - //bool menuItemExists(const QString& menuName, const QString& menuitem); + + void addMenuItem(const MenuItemProperties& properties); + bool isOptionChecked(const QString& menuOption) const { return HifiMenu::isChecked(menuOption); } + void setIsOptionChecked(const QString& menuOption, bool isChecked) { HifiMenu::setChecked(menuOption, isChecked); } + void triggerOption(const QString& menuOption) { - HifiMenu::triggerMenuItem(menuOption); + HifiMenu::triggerItem(menuOption); } + void setOptionText(const QString& menuOption, const QString & text) { - HifiMenu::setText(menuOption, text); + HifiMenu::setItemText(menuOption, text); } + void setOptionTriggerAction(const QString& menuOption, std::function f) { HifiMenu::setTriggerAction(menuOption, f); } - //void setOptionToggleAction(const QString& menuOption, std::function f); - //void addMenuItem(const QString & parentMenu, const QString & menuOption, std::function f); - //void addMenuItem(const QString & parentMenu, const QString & menuOption); - //void addMenu(const QString & parentMenu, const QString & menuOption); - //void enableMenuItem(const QString & menuOption, bool enabled = true); private: void init(); diff --git a/libraries/ui/src/HifiMenu.cpp b/libraries/ui/src/HifiMenu.cpp index 6ca034522c..0c488e05a3 100644 --- a/libraries/ui/src/HifiMenu.cpp +++ b/libraries/ui/src/HifiMenu.cpp @@ -112,7 +112,7 @@ void HifiMenu::addSeparator(const QString& parentMenu, const QString& separatorN void HifiMenu::removeSeparator(const QString& parentMenu, const QString& separatorName) { } -void HifiMenu::addMenuItem(const QString & parentMenu, const QString & menuOption) { +void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption) { QObject* parent = findMenuObject(parentMenu); Q_ASSERT(parent); QObject* result = ::addItem(parent, menuOption); @@ -127,20 +127,20 @@ void HifiMenu::addMenuItem(const QString & parentMenu, const QString & menuOptio connect(result, SIGNAL(toggled(bool)), &_toggleMapper, SLOT(map())); } -void HifiMenu::addMenuItem(const QString & parentMenu, const QString & menuOption, std::function f) { +void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption, std::function f) { setTriggerAction(menuOption, f); - addMenuItem(parentMenu, menuOption); + addItem(parentMenu, menuOption); } -void HifiMenu::removeMenuItem(const QString& menuOption) { +void HifiMenu::removeItem(const QString& menuOption) { removeMenu(menuOption); } -bool HifiMenu::menuItemExists(const QString& menuName, const QString& menuitem) const { +bool HifiMenu::itemExists(const QString& menuName, const QString& menuitem) const { return findMenuObject(menuName); } -void HifiMenu::triggerMenuItem(const QString& menuOption) { +void HifiMenu::triggerItem(const QString& menuOption) { QObject* menuItem = findMenuObject(menuOption); Q_ASSERT(menuItem); Q_ASSERT(menuItem != _rootMenu); @@ -185,20 +185,24 @@ void HifiMenu::setCheckable(const QString& menuOption, bool checkable) { Q_ASSERT(menuItem->property("checkable").toBool() == checkable); } -void HifiMenu::setText(const QString& menuOption, const QString & text) { +void HifiMenu::setItemText(const QString& menuOption, const QString & text) { QObject* menuItem = findMenuObject(menuOption); if (!menuItem) { warn(menuOption); return; } - menuItem->setProperty("text", QVariant::fromValue(text)); + if (menuItem->property("type").toInt() == 2) { + menuItem->setProperty("title", QVariant::fromValue(text)); + } else { + menuItem->setProperty("text", QVariant::fromValue(text)); + } } void HifiMenu::setRootMenu(QObject* rootMenu) { _rootMenu = rootMenu; } -void HifiMenu::enableMenuItem(const QString & menuOption, bool enabled) { +void HifiMenu::enableItem(const QString & menuOption, bool enabled) { QObject* menuItem = findMenuObject(menuOption); if (!menuItem) { warn(menuOption); @@ -207,15 +211,45 @@ void HifiMenu::enableMenuItem(const QString & menuOption, bool enabled) { menuItem->setProperty("enabled", QVariant::fromValue(enabled)); } -void HifiMenu::addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked) { - addMenuItem(parentMenu, menuOption); +void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked) { + addItem(parentMenu, menuOption); setCheckable(menuOption); if (checked) { setChecked(menuOption, checked); } } -void HifiMenu::addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f) { +void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f) { setToggleAction(menuOption, f); - addCheckableMenuItem(parentMenu, menuOption, checked); + addCheckableItem(parentMenu, menuOption, checked); +} + +void HifiMenu::setItemVisible(const QString& menuOption, bool visible) { + QObject* result = findMenuObject(menuOption); + if (result) { + result->setProperty("visible", visible); + } +} + +bool HifiMenu::isItemVisible(const QString& menuOption) { + QObject* result = findMenuObject(menuOption); + if (result) { + return result->property("visible").toBool(); + } + return false; +} + +void HifiMenu::setItemShortcut(const QString& menuOption, const QString& shortcut) { + QObject* result = findMenuObject(menuOption); + if (result) { + result->setProperty("shortcut", shortcut); + } +} + +QString HifiMenu::getItemShortcut(const QString& menuOption) { + QObject* result = findMenuObject(menuOption); + if (result) { + return result->property("shortcut").toString(); + } + return QString(); } diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/HifiMenu.h index 4d7d860224..299a927bc9 100644 --- a/libraries/ui/src/HifiMenu.h +++ b/libraries/ui/src/HifiMenu.h @@ -35,19 +35,26 @@ public: void addSeparator(const QString& menuName, const QString& separatorName); void removeSeparator(const QString& menuName, const QString& separatorName); - void addMenuItem(const QString& parentMenu, const QString& menuOption); - void addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked = false); - void addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f); - void addMenuItem(const QString& parentMenu, const QString& menuOption, std::function f); - void removeMenuItem(const QString& menuitem); - bool menuItemExists(const QString& menuName, const QString& menuitem) const; - void triggerMenuItem(const QString& menuOption); - void enableMenuItem(const QString& menuOption, bool enabled = true); + void addItem(const QString& parentMenu, const QString& menuOption); + void addItem(const QString& parentMenu, const QString& menuOption, std::function f); + + void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked = false); + void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f); + + void removeItem(const QString& menuitem); + bool itemExists(const QString& menuName, const QString& menuitem) const; + void triggerItem(const QString& menuOption); + void enableItem(const QString& menuOption, bool enabled = true); bool isChecked(const QString& menuOption) const; - void setChecked(const QString& menuOption, bool isChecked = true); + void setChecked(const QString& menuOption, bool checked = true); void setCheckable(const QString& menuOption, bool checkable = true); void setExclusiveGroup(const QString& menuOption, const QString & groupName); - void setText(const QString& menuOption, const QString& text); + void setItemText(const QString& menuOption, const QString& text); + void setItemVisible(const QString& menuOption, bool visible = true); + bool isItemVisible(const QString& menuOption); + + void setItemShortcut(const QString& menuOption, const QString & shortcut); + QString getItemShortcut(const QString& menuOption); void setRootMenu(QObject * rootMenu); From fff8b99d10af10b26ffed39fca16ea5043113a65 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Apr 2015 15:31:25 +0200 Subject: [PATCH 279/401] Fix keylight color Was an integer division producing a float --- libraries/entities/src/ZoneEntityItem.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 3577e69162..4f081969ad 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -55,9 +55,9 @@ public: glm::vec3 getKeyLightColorVec3() const { const quint8 MAX_COLOR = 255; - glm::vec3 color = { _keyLightColor[RED_INDEX] / MAX_COLOR, - _keyLightColor[GREEN_INDEX] / MAX_COLOR, - _keyLightColor[BLUE_INDEX] / MAX_COLOR }; + glm::vec3 color = { (float)_keyLightColor[RED_INDEX] / (float)MAX_COLOR, + (float)_keyLightColor[GREEN_INDEX] / (float)MAX_COLOR, + (float)_keyLightColor[BLUE_INDEX] / (float)MAX_COLOR }; return color; } From a26d9ef353fb52405ca9bbd7aff56416e2ec0847 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Apr 2015 16:49:18 +0200 Subject: [PATCH 280/401] Fix ShapeType/String conversion --- .../entities/src/EntityItemProperties.cpp | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 7d5a40f6fd..734f7897bb 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -192,31 +192,34 @@ void EntityItemProperties::setLastEdited(quint64 usecTime) { _lastEdited = usecTime > _created ? usecTime : _created; } -const char* shapeTypeNames[] = {"none", "box", "sphere", "ellipsoid", "convex-hull", "plane", "compound", "capsule-x", +const char* shapeTypeNames[] = {"none", "box", "sphere", "ellipsoid", "plane", "compound", "capsule-x", "capsule-y", "capsule-z", "cylinder-x", "cylinder-y", "cylinder-z"}; QHash stringToShapeTypeLookup; +void addShapeType(ShapeType type) { + stringToShapeTypeLookup[shapeTypeNames[type]] = type; +} + void buildStringToShapeTypeLookup() { - stringToShapeTypeLookup["none"] = SHAPE_TYPE_NONE; - stringToShapeTypeLookup["box"] = SHAPE_TYPE_BOX; - stringToShapeTypeLookup["sphere"] = SHAPE_TYPE_SPHERE; - stringToShapeTypeLookup["ellipsoid"] = SHAPE_TYPE_ELLIPSOID; - stringToShapeTypeLookup["convex-hull"] = SHAPE_TYPE_COMPOUND; - stringToShapeTypeLookup["plane"] = SHAPE_TYPE_PLANE; - stringToShapeTypeLookup["compound"] = SHAPE_TYPE_COMPOUND; - stringToShapeTypeLookup["capsule-x"] = SHAPE_TYPE_CAPSULE_X; - stringToShapeTypeLookup["capsule-y"] = SHAPE_TYPE_CAPSULE_Y; - stringToShapeTypeLookup["capsule-z"] = SHAPE_TYPE_CAPSULE_Z; - stringToShapeTypeLookup["cylinder-x"] = SHAPE_TYPE_CYLINDER_X; - stringToShapeTypeLookup["cylinder-y"] = SHAPE_TYPE_CYLINDER_Y; - stringToShapeTypeLookup["cylinder-z"] = SHAPE_TYPE_CYLINDER_Z; + addShapeType(SHAPE_TYPE_NONE); + addShapeType(SHAPE_TYPE_BOX); + addShapeType(SHAPE_TYPE_SPHERE); + addShapeType(SHAPE_TYPE_ELLIPSOID); + addShapeType(SHAPE_TYPE_PLANE); + addShapeType(SHAPE_TYPE_COMPOUND); + addShapeType(SHAPE_TYPE_CAPSULE_X); + addShapeType(SHAPE_TYPE_CAPSULE_Y); + addShapeType(SHAPE_TYPE_CAPSULE_Z); + addShapeType(SHAPE_TYPE_CYLINDER_X); + addShapeType(SHAPE_TYPE_CYLINDER_Y); + addShapeType(SHAPE_TYPE_CYLINDER_Z); } QString EntityItemProperties::getShapeTypeAsString() const { if (_shapeType < sizeof(shapeTypeNames) / sizeof(char *)) return QString(shapeTypeNames[_shapeType]); - return QString("none"); + return QString(shapeTypeNames[SHAPE_TYPE_NONE]); } void EntityItemProperties::setShapeTypeFromString(const QString& shapeName) { From 32b78f02b46171902d44dcb9bb7192f66ac7b03b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Apr 2015 16:52:51 +0200 Subject: [PATCH 281/401] Group ShapeType and CompoundShapeURL + add it to Zones --- examples/html/entityProperties.html | 33 ++++++++++--------- examples/libraries/ToolTip.js | 1 + examples/libraries/entityPropertyDialogBox.js | 3 ++ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index a8290dc3fa..352ffebaa9 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -162,6 +162,7 @@ var elModelSections = document.querySelectorAll(".model-section"); var elModelURL = document.getElementById("property-model-url"); + var elShapeType = document.getElementById("property-shape-type"); var elCompoundShapeURL = document.getElementById("property-compound-shape-url"); var elModelAnimationURL = document.getElementById("property-model-animation-url"); var elModelAnimationPlaying = document.getElementById("property-model-animation-playing"); @@ -170,7 +171,6 @@ var elModelAnimationSettings = document.getElementById("property-model-animation-settings"); var elModelTextures = document.getElementById("property-model-textures"); var elModelOriginalTextures = document.getElementById("property-model-original-textures"); - var elModelShapeType = document.getElementById("property-model-shape"); var elTextSections = document.querySelectorAll(".text-section"); var elTextText = document.getElementById("property-text-text"); @@ -323,6 +323,7 @@ } elModelURL.value = properties.modelURL; + elShapeType.value = properties.shapeType; elCompoundShapeURL.value = properties.compoundShapeURL; elModelAnimationURL.value = properties.animationURL; elModelAnimationPlaying.checked = properties.animationIsPlaying; @@ -331,7 +332,6 @@ elModelAnimationSettings.value = properties.animationSettings; elModelTextures.value = properties.textures; elModelOriginalTextures.value = properties.originalTextures; - elModelShapeType.value = properties.shapeType; } if (properties.type != "Text") { @@ -397,6 +397,8 @@ elZoneStageAltitude.value = properties.stageAltitude.toFixed(2); elZoneStageDay.value = properties.stageDay; elZoneStageHour.value = properties.stageHour; + elShapeType.value = properties.shapeType; + elCompoundShapeURL.value = properties.compoundShapeURL; } if (selected) { @@ -487,6 +489,7 @@ elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff')); elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL')); + elShapeType.addEventListener('change', createEmitTextPropertyUpdateFunction('shapeType')); elCompoundShapeURL.addEventListener('change', createEmitTextPropertyUpdateFunction('compoundShapeURL')); elModelAnimationURL.addEventListener('change', createEmitTextPropertyUpdateFunction('animationURL')); elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying')); @@ -494,7 +497,6 @@ elModelAnimationFrame.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFrameIndex')); elModelAnimationSettings.addEventListener('change', createEmitTextPropertyUpdateFunction('animationSettings')); elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures')); - elModelShapeType.addEventListener('change', createEmitTextPropertyUpdateFunction('shapeType')); elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text')); elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight')); @@ -774,7 +776,18 @@
-
+
+
Shape Type
+
+ +
+
+
Compound Shape URL
@@ -823,18 +836,6 @@
-
-
Shape Type
-
- -
-
- -
Text
diff --git a/examples/libraries/ToolTip.js b/examples/libraries/ToolTip.js index 2b0e125d4b..f6f14d7f2b 100644 --- a/examples/libraries/ToolTip.js +++ b/examples/libraries/ToolTip.js @@ -53,6 +53,7 @@ function Tooltip() { text += "ID: " + properties.id + "\n" if (properties.type == "Model") { text += "Model URL: " + properties.modelURL + "\n" + text += "Shape Type: " + properties.shapeType + "\n" text += "Compound Shape URL: " + properties.compoundShapeURL + "\n" text += "Animation URL: " + properties.animationURL + "\n" text += "Animation is playing: " + properties.animationIsPlaying + "\n" diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index 255cec4265..5c6c688f0d 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -52,6 +52,8 @@ EntityPropertyDialogBox = (function () { if (properties.type == "Model") { array.push({ label: "Model URL:", value: properties.modelURL }); index++; + array.push({ label: "Shape Type:", value: properties.shapeType }); + index++; array.push({ label: "Compound Shape URL:", value: properties.compoundShapeURL }); index++; array.push({ label: "Animation URL:", value: properties.animationURL }); @@ -284,6 +286,7 @@ EntityPropertyDialogBox = (function () { properties.locked = array[index++].value; if (properties.type == "Model") { properties.modelURL = array[index++].value; + properties.shapeType = array[index++].value; properties.compoundShapeURL = array[index++].value; properties.animationURL = array[index++].value; From 82a53c91398166be361ac2e1e20cbed5d520f84c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Apr 2015 16:53:39 +0200 Subject: [PATCH 282/401] Turn off all sections then turn on selected one This fixes the issue of properties present in a couple sections but not all that are going to only be displayed for the last section the are in that is being processed. --- examples/html/entityProperties.html | 48 ++++++++++------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 352ffebaa9..c01b2a6d10 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -95,6 +95,7 @@ }; function loaded() { + var allSections = []; var elID = document.getElementById("property-id"); var elType = document.getElementById("property-type"); var elLocked = document.getElementById("property-locked"); @@ -146,11 +147,13 @@ var elUserData = document.getElementById("property-user-data"); var elBoxSections = document.querySelectorAll(".box-section"); + allSections.push(elBoxSections); var elBoxColorRed = document.getElementById("property-box-red"); var elBoxColorGreen = document.getElementById("property-box-green"); var elBoxColorBlue = document.getElementById("property-box-blue"); var elLightSections = document.querySelectorAll(".light-section"); + allSections.push(elLightSections); var elLightSpotLight = document.getElementById("property-light-spot-light"); var elLightColorRed = document.getElementById("property-light-color-red"); var elLightColorGreen = document.getElementById("property-light-color-green"); @@ -161,6 +164,7 @@ var elLightCutoff = document.getElementById("property-light-cutoff"); var elModelSections = document.querySelectorAll(".model-section"); + allSections.push(elModelSections); var elModelURL = document.getElementById("property-model-url"); var elShapeType = document.getElementById("property-shape-type"); var elCompoundShapeURL = document.getElementById("property-compound-shape-url"); @@ -173,6 +177,7 @@ var elModelOriginalTextures = document.getElementById("property-model-original-textures"); var elTextSections = document.querySelectorAll(".text-section"); + allSections.push(elTextSections); var elTextText = document.getElementById("property-text-text"); var elTextLineHeight = document.getElementById("property-text-line-height"); var elTextTextColorRed = document.getElementById("property-text-text-color-red"); @@ -183,6 +188,7 @@ var elTextBackgroundColorBlue = document.getElementById("property-text-background-color-blue"); var elZoneSections = document.querySelectorAll(".zone-section"); + allSections.push(elZoneSections); var elZoneStageSunModelEnabled = document.getElementById("property-zone-stage-sun-model-enabled"); var elZoneKeyLightColorRed = document.getElementById("property-zone-key-light-color-red"); var elZoneKeyLightColorGreen = document.getElementById("property-zone-key-light-color-green"); @@ -299,11 +305,13 @@ elScriptURL.value = properties.script; elUserData.value = properties.userData; - if (properties.type != "Box") { - for (var i = 0; i < elBoxSections.length; i++) { - elBoxSections[i].style.display = 'none'; + for (var i = 0; i < allSections.length; i++) { + for (var j = 0; j < allSections[i].length; j++) { + allSections[i][j].style.display = 'none'; } - } else { + } + + if (properties.type == "Box") { for (var i = 0; i < elBoxSections.length; i++) { elBoxSections[i].style.display = 'block'; } @@ -311,13 +319,7 @@ elBoxColorRed.value = properties.color.red; elBoxColorGreen.value = properties.color.green; elBoxColorBlue.value = properties.color.blue; - } - - if (properties.type != "Model") { - for (var i = 0; i < elModelSections.length; i++) { - elModelSections[i].style.display = 'none'; - } - } else { + } else if (properties.type == "Model") { for (var i = 0; i < elModelSections.length; i++) { elModelSections[i].style.display = 'block'; } @@ -332,13 +334,7 @@ elModelAnimationSettings.value = properties.animationSettings; elModelTextures.value = properties.textures; elModelOriginalTextures.value = properties.originalTextures; - } - - if (properties.type != "Text") { - for (var i = 0; i < elTextSections.length; i++) { - elTextSections[i].style.display = 'none'; - } - } else { + } else if (properties.type == "Text") { for (var i = 0; i < elTextSections.length; i++) { elTextSections[i].style.display = 'block'; } @@ -351,13 +347,7 @@ elTextBackgroundColorRed.value = properties.backgroundColor.red; elTextBackgroundColorGreen.value = properties.backgroundColor.green; elTextBackgroundColorBlue.value = properties.backgroundColor.blue; - } - - if (properties.type != "Light") { - for (var i = 0; i < elLightSections.length; i++) { - elLightSections[i].style.display = 'none'; - } - } else { + } else if (properties.type == "Light") { for (var i = 0; i < elLightSections.length; i++) { elLightSections[i].style.display = 'block'; } @@ -371,13 +361,7 @@ elLightIntensity.value = properties.intensity; elLightExponent.value = properties.exponent; elLightCutoff.value = properties.cutoff; - } - - if (properties.type != "Zone") { - for (var i = 0; i < elZoneSections.length; i++) { - elZoneSections[i].style.display = 'none'; - } - } else { + } else if (properties.type == "Zone") { for (var i = 0; i < elZoneSections.length; i++) { elZoneSections[i].style.display = 'block'; } From 6a48010c0b3ccd39e6d2aaff038a6eea4b75a0c7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 24 Apr 2015 09:01:12 -0700 Subject: [PATCH 283/401] Fix new zone overlays not moving --- examples/libraries/zoneOverlayManager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/libraries/zoneOverlayManager.js b/examples/libraries/zoneOverlayManager.js index 9898b888fa..aac3af119b 100644 --- a/examples/libraries/zoneOverlayManager.js +++ b/examples/libraries/zoneOverlayManager.js @@ -105,6 +105,7 @@ ZoneOverlayManager = function(isEntityFunc, entityAddedFunc, entityRemovedFunc, if (entityID.id in entityOverlays) { releaseOverlay(entityOverlays[entityID.id].outline); releaseOverlay(entityOverlays[entityID.id].solid); + delete entityIDs[entityID.id]; delete entityOverlays[entityID.id]; } } From 6d151ee3ed305278585e518c5a556126bd9f3067 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 09:29:05 -0700 Subject: [PATCH 284/401] try a different way of identifying when to claim simulation ownership of a moving entity --- libraries/physics/src/EntityMotionState.cpp | 18 +++++++++++++----- libraries/physics/src/PhysicsEngine.cpp | 5 ++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 0f4bf05fb4..3c424c7db9 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -108,11 +108,19 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { getVelocity(v); _entity->setVelocity(v); - getAngularVelocity(v); + glm::vec3 av; + getAngularVelocity(av); _entity->setAngularVelocity(v); _entity->setLastSimulated(usecTimestampNow()); + bool isStill = (v == vec3(0.0f)) && (av == vec3(0.0f)); + + if (_entity->getSimulatorID().isNull() && !isStill) { + // object is moving and has no owner. attempt to claim simulation ownership. + _entity->setShouldClaimSimulationOwnership(true); + } + _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; EntityMotionState::enqueueOutgoingEntity(_entity); @@ -286,10 +294,10 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); - if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { - // the entity is moving and no node has claimed simulation ownership. try to claim it. - setShouldClaimSimulationOwnership(true); - } + // if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { + // // the entity is moving and no node has claimed simulation ownership. try to claim it. + // setShouldClaimSimulationOwnership(true); + // } if (getShouldClaimSimulationOwnership()) { // _entity->setSimulatorID(myNodeID); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 9d50b71514..5a86f8552e 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -370,9 +370,8 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) { - if (!objectA || !objectB) { - return; - } + assert(objectA); + assert(objectB); auto nodeList = DependencyManager::get(); QUuid myNodeID = nodeList->getSessionUUID(); From 6fdbce9ee3fa609c7ddee47c8d9f0d3afa376f7d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 09:29:57 -0700 Subject: [PATCH 285/401] oops --- libraries/physics/src/EntityMotionState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 3c424c7db9..37a1732ece 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -118,7 +118,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (_entity->getSimulatorID().isNull() && !isStill) { // object is moving and has no owner. attempt to claim simulation ownership. - _entity->setShouldClaimSimulationOwnership(true); + setShouldClaimSimulationOwnership(true); } _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; From 4127ec8019539a95868663748ff952c87938bd0a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 24 Apr 2015 09:42:59 -0700 Subject: [PATCH 286/401] Add checkboxes.html --- examples/checkboxes.html | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 examples/checkboxes.html diff --git a/examples/checkboxes.html b/examples/checkboxes.html new file mode 100644 index 0000000000..7c919bfd2d --- /dev/null +++ b/examples/checkboxes.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + +
Checkbox 2
Checkbox 3
Checkbox 4
+ +
+ +
From e2b60d35f040d84dd7c5bb980c73ede0f146ffb8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Apr 2015 18:50:03 +0200 Subject: [PATCH 287/401] Generate touchEndEvent if last event was more than 50 ms ago --- examples/look.js | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/examples/look.js b/examples/look.js index 6bba57e3ad..773a4ff73b 100644 --- a/examples/look.js +++ b/examples/look.js @@ -31,7 +31,9 @@ var yawFromTouch = 0; var pitchFromTouch = 0; // Touch Data +var TIME_BEFORE_GENERATED_END_TOUCH_EVENT = 50; // ms var startedTouching = false; +var lastTouchEvent = 0; var lastMouseX = 0; var lastMouseY = 0; var yawFromMouse = 0; @@ -80,11 +82,17 @@ function touchBeginEvent(event) { yawFromTouch = 0; pitchFromTouch = 0; startedTouching = true; + var d = new Date(); + lastTouchEvent = d.getTime(); } function touchEndEvent(event) { if (wantDebugging) { - print("touchEndEvent event.x,y=" + event.x + ", " + event.y); + if (event) { + print("touchEndEvent event.x,y=" + event.x + ", " + event.y); + } else { + print("touchEndEvent generated"); + } } startedTouching = false; } @@ -96,23 +104,31 @@ function touchUpdateEvent(event) { } if (!startedTouching) { - // handle Qt 5.4.x bug where we get touch update without a touch begin event - startedTouching = true; - lastTouchX = event.x; - lastTouchY = event.y; + // handle Qt 5.4.x bug where we get touch update without a touch begin event + touchBeginEvent(event); + return; } yawFromTouch += ((event.x - lastTouchX) * TOUCH_YAW_SCALE * FIXED_TOUCH_TIMESTEP); pitchFromTouch += ((event.y - lastTouchY) * TOUCH_PITCH_SCALE * FIXED_TOUCH_TIMESTEP); lastTouchX = event.x; lastTouchY = event.y; -} + var d = new Date(); + lastTouchEvent = d.getTime();} function update(deltaTime) { if (wantDebugging) { print("update()..."); } + + if(startedTouching) { + var d = new Date(); + var sinceLastTouch = d.getTime() - lastTouchEvent; + if (sinceLastTouch > TIME_BEFORE_GENERATED_END_TOUCH_EVENT) { + touchEndEvent(); + } + } if (yawFromTouch != 0 || yawFromMouse != 0) { var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollRadians(0, yawFromTouch + yawFromMouse, 0)); From fb5a0c8b010acc7d587f31519956743ecc996abf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Apr 2015 18:50:45 +0200 Subject: [PATCH 288/401] Only send touchUpdateEvent if it is one ie. not for touchBeginEvent --- interface/src/Application.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1df771f127..285bd11952 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1492,9 +1492,11 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { } void Application::touchUpdateEvent(QTouchEvent* event) { - TouchEvent thisEvent(*event, _lastTouchEvent); - _controllerScriptingInterface.emitTouchUpdateEvent(thisEvent); // send events to any registered scripts - _lastTouchEvent = thisEvent; + if (event->type() == QEvent::TouchUpdate) { + TouchEvent thisEvent(*event, _lastTouchEvent); + _controllerScriptingInterface.emitTouchUpdateEvent(thisEvent); // send events to any registered scripts + _lastTouchEvent = thisEvent; + } // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface.isTouchCaptured()) { From 80d3f35b2eae56a0f6a5260a0ed15ccdc05dadc0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 24 Apr 2015 09:57:22 -0700 Subject: [PATCH 289/401] Controller disabled when not in physics engine --- .../physics/src/DynamicCharacterController.cpp | 16 ++++++++++------ .../physics/src/DynamicCharacterController.h | 6 +++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/physics/src/DynamicCharacterController.cpp b/libraries/physics/src/DynamicCharacterController.cpp index 46ff2e524e..fa1a2d42d1 100644 --- a/libraries/physics/src/DynamicCharacterController.cpp +++ b/libraries/physics/src/DynamicCharacterController.cpp @@ -43,8 +43,8 @@ protected: DynamicCharacterController::DynamicCharacterController(AvatarData* avatarData) { _halfHeight = 1.0f; - _shape = NULL; - _rigidBody = NULL; + _shape = nullptr; + _rigidBody = nullptr; assert(avatarData); _avatarData = avatarData; @@ -257,6 +257,10 @@ void DynamicCharacterController::setEnabled(bool enabled) { } } +bool DynamicCharacterController::isEnabled() const { + return _enabled && _dynamicsWorld; +} + void DynamicCharacterController::setDynamicsWorld(btDynamicsWorld* world) { if (_dynamicsWorld != world) { if (_dynamicsWorld) { @@ -264,7 +268,7 @@ void DynamicCharacterController::setDynamicsWorld(btDynamicsWorld* world) { _dynamicsWorld->removeRigidBody(_rigidBody); _dynamicsWorld->removeAction(this); } - _dynamicsWorld = NULL; + _dynamicsWorld = nullptr; } if (world && _rigidBody) { _dynamicsWorld = world; @@ -294,9 +298,9 @@ void DynamicCharacterController::updateShapeIfNecessary() { _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; // delete shape and RigidBody delete _rigidBody; - _rigidBody = NULL; + _rigidBody = nullptr; delete _shape; - _shape = NULL; + _shape = nullptr; // compute new dimensions from avatar's bounding box float x = _boxScale.x; @@ -316,7 +320,7 @@ void DynamicCharacterController::updateShapeIfNecessary() { // create new body float mass = 1.0f; btVector3 inertia(1.0f, 1.0f, 1.0f); - _rigidBody = new btRigidBody(mass, NULL, _shape, inertia); + _rigidBody = new btRigidBody(mass, nullptr, _shape, inertia); _rigidBody->setSleepingThresholds (0.0f, 0.0f); _rigidBody->setAngularFactor (0.0f); _rigidBody->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), diff --git a/libraries/physics/src/DynamicCharacterController.h b/libraries/physics/src/DynamicCharacterController.h index f98343c49b..bd71a8bcdc 100644 --- a/libraries/physics/src/DynamicCharacterController.h +++ b/libraries/physics/src/DynamicCharacterController.h @@ -30,7 +30,7 @@ protected: glm::vec3 _shapeLocalOffset; glm::vec3 _boxScale; // used to compute capsule shape - AvatarData* _avatarData = NULL; + AvatarData* _avatarData = nullptr; bool _enabled; bool _isOnGround; @@ -41,7 +41,7 @@ protected: quint64 _jumpToHoverStart; uint32_t _pendingFlags; - btDynamicsWorld* _dynamicsWorld = NULL; + btDynamicsWorld* _dynamicsWorld = nullptr; btScalar _jumpSpeed; @@ -78,7 +78,7 @@ public: bool needsRemoval() const; bool needsAddition() const; void setEnabled(bool enabled); - bool isEnabled() const { return _enabled; } + bool isEnabled() const; void setDynamicsWorld(btDynamicsWorld* world); void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); From 53577107de006332703a562ff77eea6268ddccaa Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Apr 2015 19:06:46 +0200 Subject: [PATCH 290/401] Formatting --- examples/look.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/look.js b/examples/look.js index 773a4ff73b..7adcd054c2 100644 --- a/examples/look.js +++ b/examples/look.js @@ -114,7 +114,8 @@ function touchUpdateEvent(event) { lastTouchX = event.x; lastTouchY = event.y; var d = new Date(); - lastTouchEvent = d.getTime();} + lastTouchEvent = d.getTime(); +} function update(deltaTime) { @@ -122,7 +123,7 @@ function update(deltaTime) { print("update()..."); } - if(startedTouching) { + if (startedTouching) { var d = new Date(); var sinceLastTouch = d.getTime() - lastTouchEvent; if (sinceLastTouch > TIME_BEFORE_GENERATED_END_TOUCH_EVENT) { From 1b84be6e10b0796cabce7395dda285d74a49c366 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 10:55:43 -0700 Subject: [PATCH 291/401] attempting to have visual indicator of simulatorID --- .../entities-renderer/src/EntityTreeRenderer.cpp | 16 ++++++++++++++++ .../src/RenderableModelEntityItem.cpp | 15 ++++++++++++++- libraries/entities/src/EntityTree.cpp | 16 ++++++++++++---- libraries/physics/src/EntityMotionState.cpp | 2 +- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index dde13552f3..fbfa882494 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -677,10 +677,26 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) if (bigEnoughToRender) { renderProxies(entityItem, args); + + // XXX + // auto nodeList = DependencyManager::get(); + // const QUuid& myNodeID = nodeList->getSessionUUID(); + // XXX + + Glower* glower = NULL; if (entityItem->getGlowLevel() > 0.0f) { glower = new Glower(entityItem->getGlowLevel()); } + + // XXX glow things we are simulating + // if (entityItem->getSimulatorID() == myNodeID) { + // if (glower) delete glower; + // glower = new Glower(); + // } + // XXX glow things we are simulating + + entityItem->render(args); args->_itemsRendered++; if (glower) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 8ca6562505..1bdfa7bd1a 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -118,13 +118,26 @@ void RenderableModelEntityItem::render(RenderArgs* args) { glm::vec3 position = getPosition(); glm::vec3 dimensions = getDimensions(); float size = glm::length(dimensions); + + // XXX + auto nodeList = DependencyManager::get(); + const QUuid& myNodeID = nodeList->getSessionUUID(); + // XXX - if (drawAsModel) { + if (drawAsModel + && getSimulatorID() != myNodeID + ) { remapTextures(); glPushMatrix(); { float alpha = getLocalRenderAlpha(); + // XXX + // if (getSimulatorID() == myNodeID) { + // alpha = 1.0; + // } + // XXX + if (!_model || _needsModelReload) { // TODO: this getModel() appears to be about 3% of model render time. We should optimize PerformanceTimer perfTimer("getModel"); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 5b15aa26b4..360c783d34 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -140,16 +140,24 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro // A Node is trying to take ownership of the simulation of this entity from another Node. Only allow this // if ownership hasn't recently changed. if (usecTimestampNow() - entity->getSimulatorIDChangedTime() < SIMULATOR_CHANGE_LOCKOUT_PERIOD) { - qCDebug(entities) << "simulator_change_lockout_period:" - << entity->getSimulatorID() << "to" << properties.getSimulatorID(); + + // XXX + // qCDebug(entities) << "simulator_change_lockout_period:" + // << entity->getSimulatorID() << "to" << properties.getSimulatorID(); + // XXX + // squash the physics-related changes. properties.setSimulatorIDChanged(false); properties.setPositionChanged(false); properties.setVelocityChanged(false); properties.setAccelerationChanged(false); - } else { - qCDebug(entities) << "allowing simulatorID change"; + } + + // else { + // qCDebug(entities) << "allowing simulatorID change"; + // } + } QString entityScriptBefore = entity->getScript(); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 37a1732ece..10d919ba2f 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -306,7 +306,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the entity has stopped. give up "simulator" status // _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); + // properties.setSimulatorID(QUuid()); } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. From b40e78311b8f8e8ae5ecff673262c783aa07e528 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 11:00:06 -0700 Subject: [PATCH 292/401] disable hack to notice that the server is sending the same thing repeatedly --- libraries/entities/src/EntityItem.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 6c09569037..4c553201f7 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1098,7 +1098,7 @@ void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { } void EntityItem::updatePosition(const glm::vec3& value) { - if (value == _previousPositionFromServer) { + if (false && value == _previousPositionFromServer) { _position = value; } else if (glm::distance(_position, value) > MIN_POSITION_DELTA) { _position = value; @@ -1120,7 +1120,7 @@ void EntityItem::updateDimensions(const glm::vec3& value) { } void EntityItem::updateRotation(const glm::quat& rotation) { - if (rotation == _previousRotationFromServer) { + if (false && rotation == _previousRotationFromServer) { _rotation = rotation; } else if (glm::abs(glm::dot(_rotation, rotation)) < MIN_ALIGNMENT_DOT) { _rotation = rotation; @@ -1159,7 +1159,7 @@ void EntityItem::updateVelocityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateVelocity(const glm::vec3& value) { - if (value == _previousVelocityFromServer) { + if (false && value == _previousVelocityFromServer) { if (glm::length(value) < MIN_VELOCITY_DELTA) { _velocity = ENTITY_ITEM_ZERO_VEC3; } else { @@ -1189,7 +1189,7 @@ void EntityItem::updateGravityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateGravity(const glm::vec3& value) { - if (value == _previousGravityFromServer) { + if (false && value == _previousGravityFromServer) { _gravity = value; } else if (glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) { _gravity = value; @@ -1199,7 +1199,7 @@ void EntityItem::updateGravity(const glm::vec3& value) { } void EntityItem::updateAcceleration(const glm::vec3& value) { - if (value == _previousAccelerationFromServer) { + if (false && value == _previousAccelerationFromServer) { _acceleration = value; } else if (glm::distance(_acceleration, value) > MIN_ACCELERATION_DELTA) { _acceleration = value; @@ -1209,7 +1209,7 @@ void EntityItem::updateAcceleration(const glm::vec3& value) { } void EntityItem::updateAngularVelocity(const glm::vec3& value) { - if (value == _previousAngularVelocityFromServer) { + if (false && value == _previousAngularVelocityFromServer) { if (glm::length(value) < MIN_SPIN_DELTA) { _angularVelocity = ENTITY_ITEM_ZERO_VEC3; } else { From 926694517f432864040f842108e20ca25cdd0085 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 11:07:45 -0700 Subject: [PATCH 293/401] sync --- libraries/entities/src/EntityTree.cpp | 16 ++++------------ libraries/physics/src/EntityMotionState.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 360c783d34..5b15aa26b4 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -140,24 +140,16 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro // A Node is trying to take ownership of the simulation of this entity from another Node. Only allow this // if ownership hasn't recently changed. if (usecTimestampNow() - entity->getSimulatorIDChangedTime() < SIMULATOR_CHANGE_LOCKOUT_PERIOD) { - - // XXX - // qCDebug(entities) << "simulator_change_lockout_period:" - // << entity->getSimulatorID() << "to" << properties.getSimulatorID(); - // XXX - + qCDebug(entities) << "simulator_change_lockout_period:" + << entity->getSimulatorID() << "to" << properties.getSimulatorID(); // squash the physics-related changes. properties.setSimulatorIDChanged(false); properties.setPositionChanged(false); properties.setVelocityChanged(false); properties.setAccelerationChanged(false); - + } else { + qCDebug(entities) << "allowing simulatorID change"; } - - // else { - // qCDebug(entities) << "allowing simulatorID change"; - // } - } QString entityScriptBefore = entity->getScript(); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 10d919ba2f..4fab75384e 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -118,7 +118,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (_entity->getSimulatorID().isNull() && !isStill) { // object is moving and has no owner. attempt to claim simulation ownership. - setShouldClaimSimulationOwnership(true); + // setShouldClaimSimulationOwnership(true); } _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; @@ -211,7 +211,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& simulatorID = _entity->getSimulatorID(); - if (simulatorID != myNodeID && !simulatorID.isNull()) { + if (simulatorID != myNodeID /* && !simulatorID.isNull() */) { // some other Node owns the simulating of this, so don't broadcast the results of local simulation. return false; } @@ -305,8 +305,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ setShouldClaimSimulationOwnership(false); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the entity has stopped. give up "simulator" status - // _entity->setSimulatorID(QUuid()); - // properties.setSimulatorID(QUuid()); + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); } // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. From a27f8f3f10ac2e1dbb91d63713bc7813fa4e1a87 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 11:28:44 -0700 Subject: [PATCH 294/401] sync --- libraries/entities/src/EntityItem.cpp | 2 ++ libraries/physics/src/EntityMotionState.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4c553201f7..d39e3a9e5c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -314,6 +314,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef glm::vec3 savePosition = _position; glm::quat saveRotation = _rotation; glm::vec3 saveVelocity = _velocity; + glm::vec3 saveAngularVelocity = _angularVelocity; glm::vec3 saveGravity = _gravity; glm::vec3 saveAcceleration = _acceleration; @@ -616,6 +617,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef _position = savePosition; _rotation = saveRotation; _velocity = saveVelocity; + _angularVelocity = saveAngularVelocity; _gravity = saveGravity; _acceleration = saveAcceleration; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 4fab75384e..0ebf3c0739 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -211,7 +211,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& simulatorID = _entity->getSimulatorID(); - if (simulatorID != myNodeID /* && !simulatorID.isNull() */) { + if (simulatorID != myNodeID && !simulatorID.isNull()) { // some other Node owns the simulating of this, so don't broadcast the results of local simulation. return false; } @@ -300,7 +300,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // } if (getShouldClaimSimulationOwnership()) { - // _entity->setSimulatorID(myNodeID); + _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); setShouldClaimSimulationOwnership(false); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { From 37928dcd6d83276b1b70d6cfbd90c86df06155eb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 24 Apr 2015 11:30:18 -0700 Subject: [PATCH 295/401] fix default avatars on first run --- interface/src/avatar/MyAvatar.cpp | 33 +++++++++++++++++++----------- libraries/avatars/src/AvatarData.h | 4 ++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5adc818258..17f361e6a8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -683,12 +683,12 @@ void MyAvatar::loadData() { _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();; - + _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(); + _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString(); + if (isOldSettings) { bool assumeFullAvatar = _headURLFromPreferences.isEmpty(); _useFullAvatar = assumeFullAvatar; @@ -706,13 +706,22 @@ void MyAvatar::loadData() { } else { _fullAvatarURLFromPreferences = DEFAULT_FULL_AVATAR_MODEL_URL; - _skeletonURLFromPreferences = settings.value("skeletonModelURL").toUrl(); + _skeletonURLFromPreferences = settings.value("skeletonModelURL", DEFAULT_BODY_MODEL_URL).toUrl(); - QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); - QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); - - _headModelName = headFST["name"].toString(); - _bodyModelName = bodyFST["name"].toString(); + 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"; } } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 410b945f1d..58e9c42c3c 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -105,6 +105,10 @@ const QUrl DEFAULT_HEAD_MODEL_URL = QUrl("http://public.highfidelity.io/models/h 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"); +const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default"); + // 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). From df591f9ad74aac9de9b1ebe6d237f8fe2b988fdf Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 24 Apr 2015 11:49:33 -0700 Subject: [PATCH 296/401] Set style of webview --- interface/src/scripting/WebWindowClass.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index 1c9fced619..07188e62b6 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "Application.h" #include "ui/DataWebPage.h" @@ -46,6 +47,7 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid dockWidget->setFeatures(QDockWidget::DockWidgetMovable); _webView = new QWebView(dockWidget); + _webView->setStyle(QStyleFactory::create("fusion")); addEventBridgeToWindowObject(); dockWidget->setWidget(_webView); @@ -64,6 +66,7 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid dialogWidget->setLayout(layout); _webView = new QWebView(dialogWidget); + _webView->setStyle(QStyleFactory::create("fusion")); layout->addWidget(_webView); From a141ebbf934373ffcf245d2f2e70fe002b9eff47 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 24 Apr 2015 12:49:41 -0700 Subject: [PATCH 297/401] Log Faceshift FPS after a reset --- interface/src/devices/Faceshift.cpp | 28 +++++++++++++++++++++++++++- interface/src/devices/Faceshift.h | 7 ++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 4768571bd2..bef97fc38a 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -30,9 +31,14 @@ const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost"; const quint16 FACESHIFT_PORT = 33433; const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; +const int FPS_TIMER_DELAY = 2000; // ms +const int FPS_TIMER_DURATION = 2000; // ms + Faceshift::Faceshift() : _eyeDeflection("faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION), - _hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME) + _hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME), + _isCalculatingFPS(false), + _frameCount(0) { #ifdef HAVE_FACESHIFT connect(&_tcpSocket, SIGNAL(connected()), SLOT(noteConnected())); @@ -81,6 +87,12 @@ void Faceshift::reset() { string message; fsBinaryStream::encode_message(message, fsMsgCalibrateNeutral()); send(message); + + // Log camera FPS after a reset + if (!_isCalculatingFPS) { + QTimer::singleShot(FPS_TIMER_DELAY, this, SLOT(startFPSTimer())); + _isCalculatingFPS = true; + } } _longTermAverageInitialized = false; } @@ -283,6 +295,10 @@ void Faceshift::receive(const QByteArray& buffer) { } } #endif + // Count frames if timing + if (_isCalculatingFPS) { + _frameCount++; + } } void Faceshift::setEyeDeflection(float faceshiftEyeDeflection) { @@ -292,3 +308,13 @@ void Faceshift::setEyeDeflection(float faceshiftEyeDeflection) { void Faceshift::setHostname(const QString& hostname) { _hostname.set(hostname); } + +void Faceshift::startFPSTimer() { + _frameCount = 0; + QTimer::singleShot(FPS_TIMER_DURATION, this, SLOT(finishFPSTimer())); +} + +void Faceshift::finishFPSTimer() { + qCDebug(interfaceapp) << "Faceshift: FPS =" << (float)_frameCount / ((float)FPS_TIMER_DURATION / 1000.0f); + _isCalculatingFPS = false; +} diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index f224448b8e..18d88e6fe9 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -95,7 +95,9 @@ private slots: void noteError(QAbstractSocket::SocketError error); void readPendingDatagrams(); void readFromSocket(); - + void startFPSTimer(); + void finishFPSTimer(); + private: Faceshift(); virtual ~Faceshift() {} @@ -152,6 +154,9 @@ private: int _mouthSmileRightIndex = 29; int _jawOpenIndex = 21; + + bool _isCalculatingFPS; + int _frameCount; }; #endif // hifi_Faceshift_h From 1ff8c67576aa28d0443ef825c58d7f0f5dbacd35 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 24 Apr 2015 12:54:11 -0700 Subject: [PATCH 298/401] More work on menus and some code cleanup --- interface/resources/qml/HifiAction.qml | 28 +- interface/resources/qml/HifiMenu.qml | 521 +++++++----------- interface/resources/qml/MarketplaceDialog.qml | 10 +- interface/resources/qml/MessageDialog.qml | 28 +- interface/resources/qml/RootMenu.qml | 8 +- interface/resources/qml/TestRoot.qml | 18 +- interface/resources/qml/controls/Dialog.qml | 2 + .../resources/qml/controls/FontAwesome.qml | 2 +- .../resources/qml/styles/ButtonStyle.qml | 8 +- .../resources/qml/styles/HifiPalette.qml | 2 +- .../resources/qml/styles/MenuButtonStyle.qml | 8 +- interface/src/Application.cpp | 18 +- interface/src/MainWindow.cpp | 6 +- interface/src/Menu.cpp | 165 +++--- .../src/scripting/MenuScriptingInterface.cpp | 48 +- .../scripting/WindowScriptingInterface.cpp | 13 +- interface/src/ui/ApplicationOverlay.cpp | 2 +- libraries/shared/src/PathUtils.cpp | 12 +- libraries/ui/src/HifiMenu.cpp | 40 +- libraries/ui/src/HifiMenu.h | 10 +- tests/ui/main.qml | 2 +- 21 files changed, 438 insertions(+), 513 deletions(-) diff --git a/interface/resources/qml/HifiAction.qml b/interface/resources/qml/HifiAction.qml index 8e6e7d59b4..0cecff91d7 100644 --- a/interface/resources/qml/HifiAction.qml +++ b/interface/resources/qml/HifiAction.qml @@ -2,19 +2,19 @@ import QtQuick 2.4 import QtQuick.Controls 1.3 Action { - property string name - objectName: name + "HifiAction" - text: qsTr(name) - - signal triggeredByName(string name); - signal toggledByName(string name); - - onTriggered: { - triggeredByName(name); - } - - onToggled: { - toggledByName(name, checked); - } + property string name + objectName: name + "HifiAction" + text: qsTr(name) + + signal triggeredByName(string name); + signal toggledByName(string name); + + onTriggered: { + triggeredByName(name); + } + + onToggled: { + toggledByName(name, checked); + } } diff --git a/interface/resources/qml/HifiMenu.qml b/interface/resources/qml/HifiMenu.qml index 254ae32520..d86821601a 100644 --- a/interface/resources/qml/HifiMenu.qml +++ b/interface/resources/qml/HifiMenu.qml @@ -6,19 +6,20 @@ import "controls" import "styles" Hifi.HifiMenu { - id: root - anchors.fill: parent - objectName: "HifiMenu" + id: root + anchors.fill: parent + objectName: "HifiMenu" enabled: false opacity: 0.0 property int animationDuration: 200 HifiPalette { id: hifiPalette } + z: 10000 onEnabledChanged: { - if (enabled && columns.length == 0) { - pushColumn(rootMenu.items); - } - opacity = enabled ? 1.0 : 0.0 + if (enabled && columns.length == 0) { + pushColumn(rootMenu.items); + } + opacity = enabled ? 1.0 : 0.0 if (enabled) { forceActiveFocus() } @@ -37,355 +38,235 @@ Hifi.HifiMenu { } onVisibleChanged: { - if (!visible) reset(); + if (!visible) reset(); } property var menu: Menu {} property var models: [] - property var columns: [] + property var columns: [] property var itemBuilder: Component { - Text { - SystemPalette { id: sp; colorGroup: SystemPalette.Active } - id: thisText - x: 32 - property var source - property var root - property var listViewIndex - property var listView - text: typedText() - height: implicitHeight - width: implicitWidth - color: source.enabled ? "black" : "gray" - - onImplicitWidthChanged: { - if (listView) { - listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64); - listView.recalculateSize(); - } - } + Text { + SystemPalette { id: sp; colorGroup: SystemPalette.Active } + id: thisText + x: 32 + property var source + property var root + property var listViewIndex + property var listView + text: typedText() + height: implicitHeight + width: implicitWidth + color: source.enabled ? "black" : "gray" + + onImplicitWidthChanged: { + if (listView) { + listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64); + listView.recalculateSize(); + } + } - FontAwesome { - visible: source.type == 1 && source.checkable - x: -32 - text: (source.type == 1 && source.checked) ? "\uF05D" : "\uF10C" - } - - FontAwesome { - visible: source.type == 2 - x: listView.width - 64 - text: "\uF0DA" - } - + FontAwesome { + visible: source.type == 1 && source.checkable + x: -32 + text: (source.type == 1 && source.checked) ? "\uF05D" : "\uF10C" + } + + FontAwesome { + visible: source.type == 2 + x: listView.width - 64 + text: "\uF0DA" + } + - function typedText() { - switch(source.type) { - case 2: - return source.title; - case 1: - return source.text; - case 0: - return "-----" - } - } - - MouseArea { - id: mouseArea - acceptedButtons: Qt.LeftButton + function typedText() { + switch(source.type) { + case 2: + return source.title; + case 1: + return source.text; + case 0: + return "-----" + } + } + + MouseArea { + id: mouseArea + acceptedButtons: Qt.LeftButton anchors.bottom: parent.bottom anchors.bottomMargin: 0 anchors.top: parent.top anchors.topMargin: 0 width: listView.width - onClicked: { - listView.currentIndex = listViewIndex - parent.root.selectItem(parent.source); - } - } - } + onClicked: { + listView.currentIndex = listViewIndex + parent.root.selectItem(parent.source); + } + } + } } - + property var menuBuilder: Component { - Border { - SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } - x: root.models.length * 60; + Border { + SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } + x: root.models.length == 1 ? + (root.width / 2 - width / 2) : + root.columns[root.models.length - 2].x + 60; anchors.verticalCenter: parent.verticalCenter - border.color: hifiPalette.hifiBlue - color: sysPalette.window + border.color: hifiPalette.hifiBlue + color: sysPalette.window - ListView { - spacing: 6 - property int outerMargin: 8 - property real minWidth: 0 - anchors.fill: parent - anchors.margins: outerMargin - id: listView - height: root.height - currentIndex: -1 + ListView { + spacing: 6 + property int outerMargin: 8 + property real minWidth: 0 + anchors.fill: parent + anchors.margins: outerMargin + id: listView + height: root.height + currentIndex: -1 - onCountChanged: { - recalculateSize() - } - - function recalculateSize() { - var newHeight = 0 - var newWidth = minWidth; - for (var i = 0; i < children.length; ++i) { - var item = children[i]; - newHeight += item.height - } - parent.height = newHeight + outerMargin * 2; - parent.width = newWidth + outerMargin * 2 - } - - highlight: Rectangle { - width: listView.minWidth; height: 32 - color: sysPalette.highlight - y: (listView.currentItem) ? listView.currentItem.y : 0; - Behavior on y { - NumberAnimation { - duration: 100 - easing.type: Easing.InOutQuint - } - } - } - + onCountChanged: { + recalculateSize() + } + + function recalculateSize() { + var newHeight = 0 + var newWidth = minWidth; + for (var i = 0; i < children.length; ++i) { + var item = children[i]; + newHeight += item.height + } + parent.height = newHeight + outerMargin * 2; + parent.width = newWidth + outerMargin * 2 + } + + highlight: Rectangle { + width: listView.minWidth; height: 32 + color: sysPalette.highlight + y: (listView.currentItem) ? listView.currentItem.y : 0; + x: 32 + Behavior on y { + NumberAnimation { + duration: 100 + easing.type: Easing.InOutQuint + } + } + } + - property int columnIndex: root.models.length - 1 - model: root.models[columnIndex] - delegate: Loader { - id: loader - sourceComponent: root.itemBuilder - Binding { - target: loader.item - property: "root" - value: root - when: loader.status == Loader.Ready - } - Binding { - target: loader.item - property: "source" - value: modelData - when: loader.status == Loader.Ready - } - Binding { - target: loader.item - property: "listViewIndex" - value: index - when: loader.status == Loader.Ready - } - Binding { - target: loader.item - property: "listView" - value: listView - when: loader.status == Loader.Ready - } - } + property int columnIndex: root.models.length - 1 + model: root.models[columnIndex] + delegate: Loader { + id: loader + sourceComponent: root.itemBuilder + Binding { + target: loader.item + property: "root" + value: root + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "source" + value: modelData + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "listViewIndex" + value: index + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "listView" + value: listView + when: loader.status == Loader.Ready + } + } - } - - } + } + + } } function lastColumn() { - return columns[root.columns.length - 1]; + return columns[root.columns.length - 1]; } - function pushColumn(items) { - models.push(items) - if (columns.length) { - var oldColumn = lastColumn(); - oldColumn.enabled = false; - oldColumn.opacity = 0.5; - } - var newColumn = menuBuilder.createObject(root); - columns.push(newColumn); - newColumn.forceActiveFocus(); - } + function pushColumn(items) { + models.push(items) + if (columns.length) { + var oldColumn = lastColumn(); + oldColumn.enabled = false; + oldColumn.opacity = 0.5; + } + var newColumn = menuBuilder.createObject(root); + columns.push(newColumn); + newColumn.forceActiveFocus(); + } - function popColumn() { - if (columns.length > 0) { - var curColumn = columns.pop(); - console.log(curColumn); - curColumn.visible = false; - curColumn.destroy(); - models.pop(); - } - - if (columns.length == 0) { - enabled = false; - return; - } + function popColumn() { + if (columns.length > 0) { + var curColumn = columns.pop(); + console.log(curColumn); + curColumn.visible = false; + curColumn.destroy(); + models.pop(); + } + + if (columns.length == 0) { + enabled = false; + return; + } - curColumn = lastColumn(); - curColumn.enabled = true; - curColumn.opacity = 1.0; - curColumn.forceActiveFocus(); + curColumn = lastColumn(); + curColumn.enabled = true; + curColumn.opacity = 1.0; + curColumn.forceActiveFocus(); } - function selectItem(source) { - switch (source.type) { - case 2: - pushColumn(source.items) - break; - case 1: - source.trigger() - enabled = false - break; - case 0: - break; - } - } - - function reset() { - while (columns.length > 0) { - popColumn(); - } - } + function selectItem(source) { + switch (source.type) { + case 2: + pushColumn(source.items) + break; + case 1: + source.trigger() + enabled = false + break; + case 0: + break; + } + } + + function reset() { + while (columns.length > 0) { + popColumn(); + } + } - /* - HifiMenu { - id: rootMenu - Menu { - id: menu - Menu { - title: "File" - MenuItem { - action: HifiAction { - name: rootMenu.login - } - } - MenuItem { - action: HifiAction { - name: "Test" - checkable: true - } - } - MenuItem { - action: HifiAction { - name: rootMenu.quit - } - } - } - Menu { - title: "Edit" - MenuItem { - action: HifiAction { - text: "Copy" - shortcut: StandardKey.Copy - } - } - MenuItem { - action: HifiAction { - text: "Cut" - shortcut: StandardKey.Cut - } - } - MenuItem { - action: HifiAction { - text: "Paste" - shortcut: StandardKey.Paste - } - } - MenuItem { - action: HifiAction { - text: "Undo" - shortcut: StandardKey.Undo - } - } - MenuItem { - action: HifiAction { - text: "Redo" - shortcut: StandardKey.Redo - } - } - MenuItem { - action: HifiAction { - name: rootMenu.attachments - } - } - MenuItem { - action: HifiAction { - name: rootMenu.animations - } - } - } - - Menu { - title: "Scripts" - MenuItem { - action: HifiAction { - name: rootMenu.scriptEditor - } - } - MenuItem { - action: HifiAction { - name: rootMenu.loadScript - } - } - MenuItem { - action: HifiAction { - name: rootMenu.loadScriptURL - } - } - MenuItem { - action: HifiAction { - name: rootMenu.stopAllScripts - } - } - MenuItem { - action: HifiAction { - name: rootMenu.reloadAllScripts - } - } - MenuItem { - action: HifiAction { - name: rootMenu.runningScripts - } - } - } - Menu { - title: "Location" - MenuItem { - action: HifiAction { - name: rootMenu.addressBar - } - } - MenuItem { - action: HifiAction { - name: rootMenu.copyAddress - } - } - MenuItem { - action: HifiAction { - name: rootMenu.copyPath - } - } - } - } - } - */ - Keys.onPressed: { - switch (event.key) { - case Qt.Key_Escape: - root.popColumn() + switch (event.key) { + case Qt.Key_Escape: + root.popColumn() event.accepted = true; - } + } } - MouseArea { - anchors.fill: parent - id: mouseArea - acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: { + MouseArea { + anchors.fill: parent + id: mouseArea + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: { if (mouse.button == Qt.RightButton) { - root.popColumn(); + root.popColumn(); } else { - root.enabled = false; - } - } - } + root.enabled = false; + } + } + } } diff --git a/interface/resources/qml/MarketplaceDialog.qml b/interface/resources/qml/MarketplaceDialog.qml index fe192179eb..58bb3e6183 100644 --- a/interface/resources/qml/MarketplaceDialog.qml +++ b/interface/resources/qml/MarketplaceDialog.qml @@ -14,7 +14,7 @@ Dialog { resizable: true MarketplaceDialog { - id: marketplaceDialog + id: marketplaceDialog } Item { @@ -33,13 +33,13 @@ Dialog { url: "https://metaverse.highfidelity.com/marketplace" anchors.fill: parent onNavigationRequested: { - console.log(request.url) + console.log(request.url) if (!marketplaceDialog.navigationRequested(request.url)) { - console.log("Application absorbed the request") + console.log("Application absorbed the request") request.action = WebView.IgnoreRequest; - return; + return; } - console.log("Application passed on the request") + console.log("Application passed on the request") request.action = WebView.AcceptRequest; return; } diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml index eaf304b16a..26fd30db27 100644 --- a/interface/resources/qml/MessageDialog.qml +++ b/interface/resources/qml/MessageDialog.qml @@ -71,13 +71,13 @@ Dialog { onEnabledChanged: { if (enabled) { - content.forceActiveFocus(); + content.forceActiveFocus(); } } Hifi.MessageDialog { - id: content - clip: true + id: content + clip: true anchors.fill: parent anchors.topMargin: parent.topMargin + root.outerSpacing anchors.leftMargin: parent.margins + root.outerSpacing @@ -88,16 +88,16 @@ Dialog { property real buttonsRowImplicitWidth: Screen.pixelDensity * 50 Keys.onPressed: { - console.log("Key press at content") + console.log("Key press at content") event.accepted = true if (event.modifiers === Qt.ControlModifier) switch (event.key) { case Qt.Key_A: - console.log("Select All") + console.log("Select All") detailedText.selectAll() break case Qt.Key_C: - console.log("Copy") + console.log("Copy") detailedText.copy() break case Qt.Key_Period: @@ -107,12 +107,12 @@ Dialog { } else switch (event.key) { case Qt.Key_Escape: case Qt.Key_Back: - console.log("Rejecting") + console.log("Rejecting") reject() break case Qt.Key_Enter: case Qt.Key_Return: - console.log("Accepting") + console.log("Accepting") accept() break } @@ -123,18 +123,18 @@ Dialog { Component.onCompleted: { root.title = title } - + onTitleChanged: { - root.title = title + root.title = title } - + Column { id: contentColumn spacing: root.outerSpacing anchors { - top: parent.top - left: parent.left - right: parent.right + top: parent.top + left: parent.left + right: parent.right } Item { diff --git a/interface/resources/qml/RootMenu.qml b/interface/resources/qml/RootMenu.qml index dc2e36f89a..b8c81a6589 100644 --- a/interface/resources/qml/RootMenu.qml +++ b/interface/resources/qml/RootMenu.qml @@ -2,8 +2,8 @@ import QtQuick 2.4 import QtQuick.Controls 1.3 Item { - Menu { - id: root - objectName: "rootMenu" - } + Menu { + id: root + objectName: "rootMenu" + } } diff --git a/interface/resources/qml/TestRoot.qml b/interface/resources/qml/TestRoot.qml index 0b0f890361..80f8c900e3 100644 --- a/interface/resources/qml/TestRoot.qml +++ b/interface/resources/qml/TestRoot.qml @@ -10,17 +10,17 @@ Root { anchors.fill: parent onWidthChanged: { - console.log("Root width: " + width) - } - onHeightChanged: { - console.log("Root height: " + height) - } + console.log("Root width: " + width) + } + onHeightChanged: { + console.log("Root height: " + height) + } Component.onCompleted: { - console.log("Completed root") - root.forceActiveFocus() + console.log("Completed root") + root.forceActiveFocus() } - + Button { id: messageBox anchors.right: createDialog.left @@ -48,7 +48,7 @@ Root { } Keys.onPressed: { - console.log(event.key); + console.log(event.key); } } diff --git a/interface/resources/qml/controls/Dialog.qml b/interface/resources/qml/controls/Dialog.qml index 109889f738..07162ad1d8 100644 --- a/interface/resources/qml/controls/Dialog.qml +++ b/interface/resources/qml/controls/Dialog.qml @@ -16,6 +16,8 @@ Item { HifiPalette { id: hifiPalette } SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } + x: parent ? parent.width / 2 - width / 2 : 0 + y: parent ? parent.height / 2 - height / 2 : 0 property int animationDuration: 400 property bool destroyOnInvisible: false diff --git a/interface/resources/qml/controls/FontAwesome.qml b/interface/resources/qml/controls/FontAwesome.qml index 16fd4a6ecc..e975c0342b 100644 --- a/interface/resources/qml/controls/FontAwesome.qml +++ b/interface/resources/qml/controls/FontAwesome.qml @@ -7,7 +7,7 @@ Text { FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; } property int size: 32 width: size - height: size + height: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter font.family: iconFont.name diff --git a/interface/resources/qml/styles/ButtonStyle.qml b/interface/resources/qml/styles/ButtonStyle.qml index caf366364a..8d866390a0 100644 --- a/interface/resources/qml/styles/ButtonStyle.qml +++ b/interface/resources/qml/styles/ButtonStyle.qml @@ -2,15 +2,15 @@ import QtQuick 2.4 as Original import QtQuick.Controls.Styles 1.3 as OriginalStyles import "." import "../controls" - + OriginalStyles.ButtonStyle { - Original.SystemPalette { id: myPalette; colorGroup: Original.SystemPalette.Active } - padding { + Original.SystemPalette { id: myPalette; colorGroup: Original.SystemPalette.Active } + padding { top: 8 left: 12 right: 12 bottom: 8 - } + } background: Border { anchors.fill: parent } diff --git a/interface/resources/qml/styles/HifiPalette.qml b/interface/resources/qml/styles/HifiPalette.qml index 641d533e3d..46ef0ef14e 100644 --- a/interface/resources/qml/styles/HifiPalette.qml +++ b/interface/resources/qml/styles/HifiPalette.qml @@ -1,5 +1,5 @@ import QtQuick 2.4 QtObject { - property string hifiBlue: "#0e7077" + property string hifiBlue: "#0e7077" } \ No newline at end of file diff --git a/interface/resources/qml/styles/MenuButtonStyle.qml b/interface/resources/qml/styles/MenuButtonStyle.qml index f30ade3d33..fd21e88d86 100644 --- a/interface/resources/qml/styles/MenuButtonStyle.qml +++ b/interface/resources/qml/styles/MenuButtonStyle.qml @@ -2,15 +2,15 @@ import QtQuick 2.4 import QtQuick.Controls.Styles 1.3 import "../controls" import "." - + ButtonStyle { - HifiPalette { id: hifiPalette } - padding { + HifiPalette { id: hifiPalette } + padding { top: 2 left: 4 right: 4 bottom: 2 - } + } background: Item {} label: Text { renderType: Text.NativeRendering diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d281282fc8..8df8009b95 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1079,12 +1079,12 @@ bool Application::eventFilter(QObject* object, QEvent* event) { return false; } -static bool _altPressed; -static bool _ctrlPressed; +static bool altPressed; +static bool ctrlPressed; void Application::keyPressEvent(QKeyEvent* event) { - _altPressed = event->key() == Qt::Key_Alt; - _ctrlPressed = event->key() == Qt::Key_Control; + altPressed = event->key() == Qt::Key_Alt; + ctrlPressed = event->key() == Qt::Key_Control; _keysPressed.insert(event->key()); _controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts @@ -1336,15 +1336,13 @@ void Application::keyPressEvent(QKeyEvent* event) { } void Application::keyReleaseEvent(QKeyEvent* event) { - if (event->key() == Qt::Key_Alt && _altPressed) { + if (event->key() == Qt::Key_Alt && altPressed && _window->isActiveWindow()) { Menu::toggle(); } - if (event->key() == Qt::Key_Control && _ctrlPressed) { - auto offscreenUi = DependencyManager::get(); - auto rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); - QMetaObject::invokeMethod(rootMenu, "popup"); + if (event->key() == Qt::Key_Control && ctrlPressed && _window->isActiveWindow()) { + Menu::toggle(); } - _ctrlPressed = event->key() == Qt::Key_Control; + ctrlPressed = altPressed = false; _keysPressed.remove(event->key()); diff --git a/interface/src/MainWindow.cpp b/interface/src/MainWindow.cpp index f60716dc48..7e8d46f5ee 100644 --- a/interface/src/MainWindow.cpp +++ b/interface/src/MainWindow.cpp @@ -94,9 +94,9 @@ void MainWindow::changeEvent(QEvent* event) { emit windowShown(true); } - if (isFullScreen() != Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) { - Menu::getInstance()->setIsOptionChecked(MenuOption::Fullscreen, isFullScreen()); - } + //if (isFullScreen() != Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) { + // Menu::getInstance()->setIsOptionChecked(MenuOption::Fullscreen, isFullScreen()); + //} } else if (event->type() == QEvent::ActivationChange) { if (isActiveWindow()) { emit windowShown(true); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 029c150884..8c45f583f1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -45,13 +45,12 @@ #include "Util.h" // Proxy object to simplify porting over -HifiAction::HifiAction(const QString & menuOption) : _menuOption(menuOption) { +HifiAction::HifiAction(const QString& menuOption) : _menuOption(menuOption) { } -//void HifiAction::setCheckable(bool) { -// Menu::getInstance()->set -// qFatal("Not implemented"); -//} +void HifiAction::setCheckable(bool checkable) { + Menu::getInstance()->setCheckable(_menuOption, checkable); +} void HifiAction::setChecked(bool checked) { Menu::getInstance()->setChecked(_menuOption, checked); @@ -65,7 +64,7 @@ QString HifiAction::shortcut() const { return Menu::getInstance()->getItemShortcut(_menuOption); } -void HifiAction::setText(const QString & text) { +void HifiAction::setText(const QString& text) { Menu::getInstance()->setItemText(_menuOption, text); } @@ -101,7 +100,7 @@ Menu* Menu::getInstance() { return _instance; } -Menu::Menu(QQuickItem * parent) : HifiMenu(parent) { +Menu::Menu(QQuickItem* parent) : HifiMenu(parent) { } void Menu::init() { @@ -125,12 +124,15 @@ void Menu::init() { #endif { +#if 0 static const QString SCRIPTS_MENU{ "Scripts" }; - addMenu(FILE_MENU, SCRIPTS_MENU); + addMenu(FILE_MENU, LOCATION_MENU); +#else + static const QString SCRIPTS_MENU{ FILE_MENU }; + addSeparator(FILE_MENU, "Scripts"); +#endif //Qt::CTRL | Qt::Key_O - addItem(SCRIPTS_MENU, MenuOption::LoadScript, [=] { - qApp->loadDialog(); - }); + addItem(SCRIPTS_MENU, MenuOption::LoadScript, qApp, SLOT(loadDialog())); //Qt::CTRL | Qt::SHIFT | Qt::Key_O addItem(SCRIPTS_MENU, MenuOption::LoadScriptURL, [=] { qApp->loadScriptURLDialog(); @@ -149,9 +151,15 @@ void Menu::init() { } { +#if 0 static const QString LOCATION_MENU{ "Location" }; addMenu(FILE_MENU, LOCATION_MENU); +#else + addSeparator(FILE_MENU, "Location"); + static const QString LOCATION_MENU{ FILE_MENU }; +#endif qApp->getBookmarks()->setupMenus(LOCATION_MENU); + //Qt::CTRL | Qt::Key_L addItem(LOCATION_MENU, MenuOption::AddressBar, [=] { auto dialogsManager = DependencyManager::get(); @@ -178,16 +186,15 @@ void Menu::init() { { static const QString EDIT_MENU{ "Edit" }; addMenu(ROOT_MENU, EDIT_MENU); -#if 0 - QUndoStack* undoStack = qApp->getUndoStack(); - QAction* undoAction = undoStack->createUndoAction(editMenu); - undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); - addActionToQMenuAndActionHash(editMenu, undoAction); - QAction* redoAction = undoStack->createRedoAction(editMenu); - redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); - addActionToQMenuAndActionHash(editMenu, redoAction); -#endif + QUndoStack* undoStack = qApp->getUndoStack(); + QAction* undoAction = undoStack->createUndoAction(this); + //undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); + addItem(EDIT_MENU, undoAction->text(), undoAction, SLOT(trigger())); + + QAction* redoAction = undoStack->createRedoAction(this); + //redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); + addItem(EDIT_MENU, redoAction->text(), redoAction, SLOT(trigger())); // Qt::CTRL | Qt::Key_Comma // QAction::PreferencesRole @@ -231,23 +238,20 @@ void Menu::init() { // FIXME group addCheckableItem(VIZ_MENU, MenuOption::VisibleToEveryone, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, - [=](bool) { discoverabilityManager->setVisibility(); }); + discoverabilityManager.data(), SLOT(setVisibility())); addCheckableItem(VIZ_MENU, MenuOption::VisibleToFriends, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, - [=](bool) { discoverabilityManager->setVisibility(); }); - addCheckableItem(VIZ_MENU, MenuOption::VisibleToNoOne, + discoverabilityManager.data(), SLOT(setVisibility())); + addCheckableItem(VIZ_MENU, MenuOption::VisibleToNoOne, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, - [=](bool) { discoverabilityManager->setVisibility(); }); - + discoverabilityManager.data(), SLOT(setVisibility())); connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged); - } //Qt::CTRL | Qt::ALT | Qt::Key_T, - addItem(TOOLS_MENU, MenuOption::ToolWindow, [=] { -// dialogsManager->toggleToolWindow(); - }); + addItem(TOOLS_MENU, MenuOption::ToolWindow, + dialogsManager.data(), SLOT(toggleToolWindow())); //Qt::CTRL | Qt::ALT | Qt::Key_J, addItem(TOOLS_MENU, MenuOption::Console, [=] { @@ -297,12 +301,10 @@ void Menu::init() { addCheckableItem(AVATAR_MENU, MenuOption::NamesAboveHeads, true); addCheckableItem(AVATAR_MENU, MenuOption::GlowWhenSpeaking, true); addCheckableItem(AVATAR_MENU, MenuOption::BlueSpeechSphere, true); - addCheckableItem(AVATAR_MENU, MenuOption::EnableCharacterController, true, [=](bool) { - avatar->updateMotionBehavior(); - }); - addCheckableItem(AVATAR_MENU, MenuOption::ShiftHipsForIdleAnimations, false, [=](bool) { - avatar->updateMotionBehavior(); - }); + addCheckableItem(AVATAR_MENU, MenuOption::EnableCharacterController, true, + avatar, SLOT(updateMotionBehavior())); + addCheckableItem(AVATAR_MENU, MenuOption::ShiftHipsForIdleAnimations, false, + avatar, SLOT(updateMotionBehavior())); } { @@ -311,32 +313,28 @@ void Menu::init() { // Mac Qt::CTRL | Qt::META | Qt::Key_F, // Win32/Linux Qt::CTRL | Qt::Key_F, - addCheckableItem(VIEW_MENU, MenuOption::Fullscreen, false, [=](bool checked) { -// qApp->setFullscreen(checked); - }); + addCheckableItem(VIEW_MENU, MenuOption::Fullscreen, false); + connectCheckable(MenuOption::Fullscreen, qApp, SLOT(setFullscreen(bool))); // QML Qt::Key_P, - addCheckableItem(VIEW_MENU, MenuOption::FirstPerson, true, [=](bool checked) { -// qApp->cameraMenuChanged(); - }); + addCheckableItem(VIEW_MENU, MenuOption::FirstPerson, true, + qApp, SLOT(cameraMenuChanged())); //QML Qt::SHIFT | Qt::Key_H, - addCheckableItem(VIEW_MENU, MenuOption::Mirror, true); - + addCheckableItem(VIEW_MENU, MenuOption::Mirror, true, + qApp, SLOT(cameraMenuChanged())); // QML Qt::Key_H, - addCheckableItem(VIEW_MENU, MenuOption::FullscreenMirror, true, [=](bool checked) { -// qApp->cameraMenuChanged(); - }); + addCheckableItem(VIEW_MENU, MenuOption::FullscreenMirror, false, + qApp, SLOT(cameraMenuChanged())); + // Mac Qt::META | Qt::Key_H, // Win32/Linux Qt::CTRL | Qt::Key_H, addCheckableItem(VIEW_MENU, MenuOption::HMDTools, false, [=](bool checked) { dialogsManager->hmdTools(checked); }); - addCheckableItem(VIEW_MENU, MenuOption::EnableVRMode, false, [=](bool checked) { -// qApp->setEnableVRMode(checked); - }); - addCheckableItem(VIEW_MENU, MenuOption::Enable3DTVMode, false, [=](bool checked) { -// qApp->setEnable3DTVMode(checked); - }); + addCheckableItem(VIEW_MENU, MenuOption::EnableVRMode, false); + connectCheckable(MenuOption::EnableVRMode, qApp, SLOT(setEnableVRMode(bool))); + addCheckableItem(VIEW_MENU, MenuOption::Enable3DTVMode, false); + connectCheckable(MenuOption::Enable3DTVMode, qApp, SLOT(setEnable3DTVMode(bool))); { static const QString BORDER_MENU{ "Server Borders" }; @@ -362,7 +360,6 @@ void Menu::init() { dialogsManager->octreeStatsDetails(); }); } - { static const QString DEV_MENU{ "Developer" }; @@ -561,25 +558,19 @@ void Menu::init() { static const QString AUDIO_MENU{ "Audio" }; addMenu(DEV_MENU, AUDIO_MENU); auto audioIO = DependencyManager::get(); - addCheckableItem(AUDIO_MENU, MenuOption::AudioNoiseReduction, true, [=](bool checked) { - audioIO->toggleAudioNoiseReduction(); - }); - addCheckableItem(AUDIO_MENU, MenuOption::EchoServerAudio, false, [=](bool checked) { - audioIO->toggleServerEcho(); - }); - addCheckableItem(AUDIO_MENU, MenuOption::EchoLocalAudio, false, [=](bool checked) { - audioIO->toggleLocalEcho(); - }); - addCheckableItem(AUDIO_MENU, MenuOption::StereoAudio, false, [=](bool checked) { - audioIO->toggleStereoInput(); - }); + addCheckableItem(AUDIO_MENU, MenuOption::AudioNoiseReduction, true, + audioIO.data(), SLOT(toggleAudioNoiseReduction())); + addCheckableItem(AUDIO_MENU, MenuOption::EchoServerAudio, false, + audioIO.data(), SLOT(toggleServerEcho())); + addCheckableItem(AUDIO_MENU, MenuOption::EchoLocalAudio, false, + audioIO.data(), SLOT(toggleLocalEcho())); + addCheckableItem(AUDIO_MENU, MenuOption::StereoAudio, false, + audioIO.data(), SLOT(toggleStereoInput())); // Qt::CTRL | Qt::Key_M, - addCheckableItem(AUDIO_MENU, MenuOption::MuteAudio, false, [=](bool checked) { - audioIO->toggleMute(); - }); - addCheckableItem(AUDIO_MENU, MenuOption::MuteEnvironment, false, [=](bool checked) { - audioIO->sendMuteEnvironmentPacket(); - }); + addCheckableItem(AUDIO_MENU, MenuOption::MuteAudio, false, + audioIO.data(), SLOT(toggleMute())); + addCheckableItem(AUDIO_MENU, MenuOption::MuteEnvironment, false, + audioIO.data(), SLOT(sendMuteEnvironmentPacket())); { static const QString SCOPE_MENU{ "Audio Scope" }; addMenu(AUDIO_MENU, SCOPE_MENU); @@ -637,6 +628,37 @@ void Menu::loadSettings() { void Menu::saveSettings() { // scanMenuBar(&Menu::saveAction); } + +void Menu::addMenuItem(const MenuItemProperties& properties) { + if (QThread::currentThread() != Application::getInstance()->getMainThread()) { + Application::getInstance()->postLambdaEvent([=]{ + addMenuItem(properties); + }); + return; + } + // Shortcut key items: in order of priority + //QString shortcutKey; + //KeyEvent shortcutKeyEvent; + //QKeySequence shortcutKeySequence; // this is what we actually use, it's set from one of the above + + //// location related items: in order of priority + //int position; + //QString beforeItem; + //QString afterItem; + + if (properties.isSeparator) { + addSeparator(properties.menuName, properties.menuItemName); + return; + } + addItem(properties.menuName, properties.menuItemName); + if (properties.isCheckable) { + setCheckable(properties.menuItemName); + if (properties.isChecked) { + setChecked(properties.menuItemName); + } + } + } + #if 0 void Menu::loadAction(Settings& settings, QAction& action) { @@ -688,4 +710,5 @@ void Menu::addDisabledActionAndSeparator(QMenu* destinationMenu, const QString& } } + #endif diff --git a/interface/src/scripting/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index 277c611f04..823bb9f8d0 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -28,72 +28,50 @@ void MenuScriptingInterface::menuItemTriggered() { } void MenuScriptingInterface::addMenu(const QString& menu) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenu", Q_ARG(const QString&, menu)); + Menu::getInstance()->addMenu("", menu); } void MenuScriptingInterface::removeMenu(const QString& menu) { - QMetaObject::invokeMethod(Menu::getInstance(), "removeMenu", Q_ARG(const QString&, menu)); + Menu::getInstance()->removeMenu(menu); } bool MenuScriptingInterface::menuExists(const QString& menu) { - bool result; - QMetaObject::invokeMethod(Menu::getInstance(), "menuExists", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, result), - Q_ARG(const QString&, menu)); - return result; + return Menu::getInstance()->menuExists(menu); } void MenuScriptingInterface::addSeparator(const QString& menuName, const QString& separatorName) { - QMetaObject::invokeMethod(Menu::getInstance(), "addSeparator", - Q_ARG(const QString&, menuName), - Q_ARG(const QString&, separatorName)); + Menu::getInstance()->addSeparator(menuName, separatorName); } void MenuScriptingInterface::removeSeparator(const QString& menuName, const QString& separatorName) { - QMetaObject::invokeMethod(Menu::getInstance(), "removeSeparator", - Q_ARG(const QString&, menuName), - Q_ARG(const QString&, separatorName)); + Menu::getInstance()->removeSeparator(menuName, separatorName); } void MenuScriptingInterface::addMenuItem(const MenuItemProperties& properties) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); + Menu::getInstance()->addMenuItem(properties); } void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey) { - MenuItemProperties properties(menu, menuitem, shortcutKey); - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); + Menu::getInstance()->addItem(menu, menuitem); + Menu::getInstance()->setItemShortcut(menuitem, shortcutKey); } void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem) { - MenuItemProperties properties(menu, menuitem); - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); + Menu::getInstance()->addItem(menu, menuitem); } void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& menuitem) { - QMetaObject::invokeMethod(Menu::getInstance(), "removeMenuItem", - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem)); + Menu::getInstance()->removeItem(menuitem); }; bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString& menuitem) { - bool result; - QMetaObject::invokeMethod(Menu::getInstance(), "menuItemExists", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, result), - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem)); - return result; + return Menu::getInstance()->itemExists(menu, menuitem); } bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { - bool result; - QMetaObject::invokeMethod(Menu::getInstance(), "isOptionChecked", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, result), - Q_ARG(const QString&, menuOption)); - return result; + return Menu::getInstance()->isChecked(menuOption); } void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool isChecked) { - QMetaObject::invokeMethod(Menu::getInstance(), "setIsOptionChecked", Qt::BlockingQueuedConnection, - Q_ARG(const QString&, menuOption), - Q_ARG(bool, isChecked)); + Menu::getInstance()->setChecked(menuOption, isChecked); } diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 46ca0c160f..5e747f216d 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -45,13 +45,18 @@ QScriptValue WindowScriptingInterface::hasFocus() { } void WindowScriptingInterface::setFocus() { - auto window = Application::getInstance()->getWindow(); - window->activateWindow(); - window->setFocus(); + Application::getInstance()->postLambdaEvent([] { + auto window = Application::getInstance()->getWindow(); + window->activateWindow(); + window->setFocus(); + }); } void WindowScriptingInterface::raiseMainWindow() { -// Application::getInstance()->getWindow()->raise(); + // It's forbidden to call raise() from another thread. + Application::getInstance()->postLambdaEvent([] { + Application::getInstance()->getWindow()->raise(); + }); } void WindowScriptingInterface::setCursorVisible(bool visible) { diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 2a8f01aafc..7940a06993 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -323,7 +323,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { //Render magnifier, but dont show border for mouse magnifier glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(), _reticlePosition[MOUSE].y())); - with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { + with_each_texture(_overlays.getTexture(), 0, [&] { renderMagnifier(projection, _magSizeMult[i], i != MOUSE); }); } diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index bf846c0bf2..47e5659c60 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -14,16 +14,26 @@ #include #include #include - +#include #include "PathUtils.h" QString& PathUtils::resourcesPath() { +#ifdef DEBUG + static QString staticResourcePath; + if (staticResourcePath.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + staticResourcePath = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; + } +#else #ifdef Q_OS_MAC static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/"; #else static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/"; #endif +#endif + return staticResourcePath; } diff --git a/libraries/ui/src/HifiMenu.cpp b/libraries/ui/src/HifiMenu.cpp index 0c488e05a3..27517f99d7 100644 --- a/libraries/ui/src/HifiMenu.cpp +++ b/libraries/ui/src/HifiMenu.cpp @@ -45,7 +45,7 @@ void HifiMenu::setTriggerAction(const QString & name, std::function f) { QObject* addMenu(QObject* parent, const QString & text) { // FIXME add more checking here to ensure no name conflicts QVariant returnedValue; - QMetaObject::invokeMethod(parent, "addMenu", + QMetaObject::invokeMethod(parent, "addMenu", Qt::DirectConnection, Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, text)); QObject* result = returnedValue.value(); @@ -59,7 +59,7 @@ class QQuickMenuItem; QObject* addItem(QObject* parent, const QString& text) { // FIXME add more checking here to ensure no name conflicts QQuickMenuItem* returnedValue{ nullptr }; - bool invokeResult = QMetaObject::invokeMethod(parent, "addItem", + bool invokeResult = QMetaObject::invokeMethod(parent, "addItem", Qt::DirectConnection, Q_RETURN_ARG(QQuickMenuItem*, returnedValue), Q_ARG(QString, text)); Q_ASSERT(invokeResult); @@ -104,9 +104,11 @@ bool HifiMenu::menuExists(const QString& menuName) const { } void HifiMenu::addSeparator(const QString& parentMenu, const QString& separatorName) { - // FIXME 'add sep' -// addMenu(parentMenu, separatorName); -// setEnabled() + QObject * parent = findMenuObject(parentMenu); + bool invokeResult = QMetaObject::invokeMethod(parent, "addSeparator", Qt::DirectConnection); + Q_ASSERT(invokeResult); + addItem(parentMenu, separatorName); + enableItem(separatorName, false); } void HifiMenu::removeSeparator(const QString& parentMenu, const QString& separatorName) { @@ -132,6 +134,11 @@ void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption, s addItem(parentMenu, menuOption); } +void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption, QObject* receiver, const char* slot) { + addItem(parentMenu, menuOption); + connectItem(menuOption, receiver, slot); +} + void HifiMenu::removeItem(const QString& menuOption) { removeMenu(menuOption); } @@ -170,8 +177,10 @@ void HifiMenu::setChecked(const QString& menuOption, bool isChecked) { warn(menuOption); return; } - menuItem->setProperty("checked", QVariant::fromValue(isChecked)); - Q_ASSERT(menuItem->property("checked").toBool() == isChecked); + if (menuItem->property("checked").toBool() != isChecked) { + menuItem->setProperty("checked", QVariant::fromValue(isChecked)); + Q_ASSERT(menuItem->property("checked").toBool() == isChecked); + } } void HifiMenu::setCheckable(const QString& menuOption, bool checkable) { @@ -185,7 +194,7 @@ void HifiMenu::setCheckable(const QString& menuOption, bool checkable) { Q_ASSERT(menuItem->property("checkable").toBool() == checkable); } -void HifiMenu::setItemText(const QString& menuOption, const QString & text) { +void HifiMenu::setItemText(const QString& menuOption, const QString& text) { QObject* menuItem = findMenuObject(menuOption); if (!menuItem) { warn(menuOption); @@ -253,3 +262,18 @@ QString HifiMenu::getItemShortcut(const QString& menuOption) { } return QString(); } + +void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, QObject* receiver, const char* slot) { + addCheckableItem(parentMenu, menuOption, checked); + connectItem(menuOption, receiver, slot); +} + +void HifiMenu::connectCheckable(const QString& menuOption, QObject* receiver, const char* slot) { + QObject* result = findMenuObject(menuOption); + connect(result, SIGNAL(toggled(bool)), receiver, slot); +} + +void HifiMenu::connectItem(const QString& menuOption, QObject* receiver, const char* slot) { + QObject* result = findMenuObject(menuOption); + connect(result, SIGNAL(triggered()), receiver, slot); +} diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/HifiMenu.h index 299a927bc9..c89c91b028 100644 --- a/libraries/ui/src/HifiMenu.h +++ b/libraries/ui/src/HifiMenu.h @@ -37,9 +37,13 @@ public: void addItem(const QString& parentMenu, const QString& menuOption); void addItem(const QString& parentMenu, const QString& menuOption, std::function f); + void addItem(const QString& parentMenu, const QString& menuOption, QObject* receiver, const char* slot); void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked = false); void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f); + void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, QObject* receiver, const char* slot); + void connectCheckable(const QString& menuOption, QObject* receiver, const char* slot); + void connectItem(const QString& menuOption, QObject* receiver, const char* slot); void removeItem(const QString& menuitem); bool itemExists(const QString& menuName, const QString& menuitem) const; @@ -48,15 +52,15 @@ public: bool isChecked(const QString& menuOption) const; void setChecked(const QString& menuOption, bool checked = true); void setCheckable(const QString& menuOption, bool checkable = true); - void setExclusiveGroup(const QString& menuOption, const QString & groupName); + void setExclusiveGroup(const QString& menuOption, const QString& groupName); void setItemText(const QString& menuOption, const QString& text); void setItemVisible(const QString& menuOption, bool visible = true); bool isItemVisible(const QString& menuOption); - void setItemShortcut(const QString& menuOption, const QString & shortcut); + void setItemShortcut(const QString& menuOption, const QString& shortcut); QString getItemShortcut(const QString& menuOption); - void setRootMenu(QObject * rootMenu); + void setRootMenu(QObject* rootMenu); private slots: void onTriggeredByName(const QString& name); diff --git a/tests/ui/main.qml b/tests/ui/main.qml index 89dac3d1af..168b9fb291 100644 --- a/tests/ui/main.qml +++ b/tests/ui/main.qml @@ -47,7 +47,7 @@ import "qml" //import "/Users/bdavis/Git/hifi/interface/resources/qml" Item { - anchors.fill: parent + anchors.fill: parent visible: true //title: "Qt Quick Controls Gallery" From 902e84c7118d81f3d9502aa09bdebc3c9d2dc883 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 13:10:38 -0700 Subject: [PATCH 299/401] sync --- libraries/physics/src/EntityMotionState.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 0ebf3c0739..cff3000868 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -211,7 +211,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& simulatorID = _entity->getSimulatorID(); - if (simulatorID != myNodeID && !simulatorID.isNull()) { + if (simulatorID != myNodeID /* && !simulatorID.isNull() */) { // some other Node owns the simulating of this, so don't broadcast the results of local simulation. return false; } @@ -300,12 +300,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // } if (getShouldClaimSimulationOwnership()) { - _entity->setSimulatorID(myNodeID); + // _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); setShouldClaimSimulationOwnership(false); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the entity has stopped. give up "simulator" status - _entity->setSimulatorID(QUuid()); + // _entity->setSimulatorID(QUuid()); properties.setSimulatorID(QUuid()); } From a4f03f8b1cdf74fe7223d3c378d07a68f628a0b6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Apr 2015 22:16:21 +0200 Subject: [PATCH 300/401] Zones use avatar position not view frustum --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index dde13552f3..c744ec0165 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -643,7 +643,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) // NOTE: Zone Entities are a special case we handle here... Zones don't render // like other entity types. So we will skip the normal rendering tests if (entityItem->getType() == EntityTypes::Zone) { - if (entityItem->contains(args->_viewFrustum->getPosition())) { + if (entityItem->contains(_viewState->getAvatarPosition())) { float entityVolumeEstimate = entityItem->getVolumeEstimate(); if (entityVolumeEstimate < _bestZoneVolume) { _bestZoneVolume = entityVolumeEstimate; From 99a6e1f86c0f7d1498130c2f9dcae2d71a16b19c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 24 Apr 2015 13:21:21 -0700 Subject: [PATCH 301/401] Breaking up offscreen UI work --- interface/CMakeLists.txt | 2 +- .../resources/fonts/fontawesome-webfont.ttf | Bin 0 -> 122092 bytes interface/resources/qml/AddressBarDialog.qml | 11 +- interface/resources/qml/Browser.qml | 21 +- interface/resources/qml/CustomButton.qml | 23 -- interface/resources/qml/CustomTextArea.qml | 10 - interface/resources/qml/HifiAction.qml | 20 + interface/resources/qml/HifiMenu.qml | 272 +++++++++++++ interface/resources/qml/Icon.qml | 8 - interface/resources/qml/LoginDialog.qml | 30 +- interface/resources/qml/MarketplaceDialog.qml | 50 +++ interface/resources/qml/MessageDialog.qml | 359 ++++++++++++++++++ interface/resources/qml/Palettes.qml | 86 ----- interface/resources/qml/Root.qml | 5 +- interface/resources/qml/RootMenu.qml | 9 + interface/resources/qml/TestDialog.qml | 22 +- interface/resources/qml/TestRoot.qml | 29 +- interface/resources/qml/componentCreation.js | 29 -- interface/resources/qml/controls/Button.qml | 10 + .../{CustomDialog.qml => controls/Dialog.qml} | 241 +++++++----- .../resources/qml/controls/FontAwesome.qml | 16 + .../IconButton.qml} | 0 .../resources/qml/controls/MenuButton.qml | 5 + interface/resources/qml/controls/README.md | 2 + .../{CustomTextEdit.qml => controls/Text.qml} | 4 +- .../{CustomText.qml => controls/TextArea.qml} | 4 +- interface/resources/qml/controls/TextEdit.qml | 7 + .../TextInput.qml} | 4 +- interface/resources/qml/hifiConstants.js | 4 - interface/resources/qml/images/critical.png | Bin 0 -> 253 bytes .../resources/qml/images/information.png | Bin 0 -> 254 bytes interface/resources/qml/images/question.png | Bin 0 -> 257 bytes interface/resources/qml/images/warning.png | Bin 0 -> 224 bytes .../{CustomBorder.qml => styles/Border.qml} | 1 - .../resources/qml/styles/ButtonStyle.qml | 24 ++ .../resources/qml/styles/HifiPalette.qml | 5 + .../resources/qml/styles/IconButtonStyle.qml | 15 + .../resources/qml/styles/MenuButtonStyle.qml | 22 ++ interface/src/Application.cpp | 35 +- interface/src/Application.h | 3 + interface/src/ui/ApplicationOverlay.cpp | 2 +- .../render-utils/src/OffscreenQmlDialog.h | 56 --- libraries/shared/src/PathUtils.cpp | 12 +- libraries/ui/CMakeLists.txt | 12 + libraries/ui/src/HifiMenu.cpp | 279 ++++++++++++++ libraries/ui/src/HifiMenu.h | 83 ++++ libraries/ui/src/MessageDialog.cpp | 142 +++++++ libraries/ui/src/MessageDialog.h | 98 +++++ .../src/OffscreenQmlDialog.cpp | 24 ++ libraries/ui/src/OffscreenQmlDialog.h | 104 +++++ .../{render-utils => ui}/src/OffscreenUi.cpp | 108 ++++-- .../{render-utils => ui}/src/OffscreenUi.h | 97 ++++- tests/render-utils/src/main.cpp | 93 +---- tests/ui/CMakeLists.txt | 15 + tests/ui/main.qml | 161 ++++++++ tests/ui/qml/ButtonPage.qml | 128 +++++++ tests/ui/qml/InputPage.qml | 114 ++++++ tests/ui/qml/ProgressPage.qml | 90 +++++ tests/ui/qml/UI.js | 45 +++ tests/ui/src/main.cpp | 336 ++++++++++++++++ 60 files changed, 2847 insertions(+), 540 deletions(-) create mode 100644 interface/resources/fonts/fontawesome-webfont.ttf delete mode 100644 interface/resources/qml/CustomButton.qml delete mode 100644 interface/resources/qml/CustomTextArea.qml create mode 100644 interface/resources/qml/HifiAction.qml create mode 100644 interface/resources/qml/HifiMenu.qml delete mode 100644 interface/resources/qml/Icon.qml create mode 100644 interface/resources/qml/MarketplaceDialog.qml create mode 100644 interface/resources/qml/MessageDialog.qml create mode 100644 interface/resources/qml/RootMenu.qml delete mode 100644 interface/resources/qml/componentCreation.js create mode 100644 interface/resources/qml/controls/Button.qml rename interface/resources/qml/{CustomDialog.qml => controls/Dialog.qml} (55%) create mode 100644 interface/resources/qml/controls/FontAwesome.qml rename interface/resources/qml/{IconControl.qml => controls/IconButton.qml} (100%) create mode 100644 interface/resources/qml/controls/MenuButton.qml create mode 100644 interface/resources/qml/controls/README.md rename interface/resources/qml/{CustomTextEdit.qml => controls/Text.qml} (54%) rename interface/resources/qml/{CustomText.qml => controls/TextArea.qml} (52%) create mode 100644 interface/resources/qml/controls/TextEdit.qml rename interface/resources/qml/{CustomTextInput.qml => controls/TextInput.qml} (90%) delete mode 100644 interface/resources/qml/hifiConstants.js create mode 100644 interface/resources/qml/images/critical.png create mode 100644 interface/resources/qml/images/information.png create mode 100644 interface/resources/qml/images/question.png create mode 100644 interface/resources/qml/images/warning.png rename interface/resources/qml/{CustomBorder.qml => styles/Border.qml} (99%) create mode 100644 interface/resources/qml/styles/ButtonStyle.qml create mode 100644 interface/resources/qml/styles/HifiPalette.qml create mode 100644 interface/resources/qml/styles/IconButtonStyle.qml create mode 100644 interface/resources/qml/styles/MenuButtonStyle.qml delete mode 100644 libraries/render-utils/src/OffscreenQmlDialog.h create mode 100644 libraries/ui/CMakeLists.txt create mode 100644 libraries/ui/src/HifiMenu.cpp create mode 100644 libraries/ui/src/HifiMenu.h create mode 100644 libraries/ui/src/MessageDialog.cpp create mode 100644 libraries/ui/src/MessageDialog.h rename libraries/{render-utils => ui}/src/OffscreenQmlDialog.cpp (55%) create mode 100644 libraries/ui/src/OffscreenQmlDialog.h rename libraries/{render-utils => ui}/src/OffscreenUi.cpp (83%) rename libraries/{render-utils => ui}/src/OffscreenUi.h (52%) create mode 100644 tests/ui/CMakeLists.txt create mode 100644 tests/ui/main.qml create mode 100644 tests/ui/qml/ButtonPage.qml create mode 100644 tests/ui/qml/InputPage.qml create mode 100644 tests/ui/qml/ProgressPage.qml create mode 100644 tests/ui/qml/UI.js create mode 100644 tests/ui/src/main.cpp diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 7688036c94..b4e0e3a244 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -128,7 +128,7 @@ target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES}) # link required hifi libraries link_hifi_libraries(shared octree environment gpu model fbx networking entities avatars audio audio-client animation script-engine physics - render-utils entities-renderer) + render-utils entities-renderer ui) add_dependency_external_projects(sdl2) diff --git a/interface/resources/fonts/fontawesome-webfont.ttf b/interface/resources/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ed9372f8ea0fbaa04f42630a48887e4b38945345 GIT binary patch literal 122092 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
p=`O<~2naWuyTk|m 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 literal 0 HcmV?d00001 diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index ec1480928a..d12737081e 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -1,10 +1,9 @@ import Hifi 1.0 import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Controls.Styles 1.3 +import "controls" +import "styles" -CustomDialog { +Dialog { title: "Go to..." objectName: "AddressBarDialog" height: 128 @@ -36,14 +35,14 @@ CustomDialog { anchors.margins: parent.margins anchors.topMargin: parent.topMargin - CustomBorder { + Border { height: 64 anchors.left: parent.left anchors.leftMargin: 0 anchors.right: goButton.left anchors.rightMargin: 8 anchors.verticalCenter: parent.verticalCenter - CustomTextInput { + TextInput { id: addressLine anchors.fill: parent helperText: "domain, location, @user, /x,y,z" diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index d7e08fbd97..a439f9114c 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -1,12 +1,10 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Dialogs 1.2 -import QtQuick.Controls.Styles 1.3 import QtWebKit 3.0 +import "controls" -CustomDialog { - title: "Test Dlg" +Dialog { + title: "Browser Window" id: testDialog objectName: "Browser" width: 1280 @@ -18,7 +16,6 @@ CustomDialog { anchors.fill: parent anchors.margins: parent.margins anchors.topMargin: parent.topMargin - ScrollView { anchors.fill: parent @@ -30,16 +27,4 @@ CustomDialog { } } - - } - - -/* - -// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property - -MouseArea { - anchors.fill: parent -} -*/ diff --git a/interface/resources/qml/CustomButton.qml b/interface/resources/qml/CustomButton.qml deleted file mode 100644 index ce57d7ce5e..0000000000 --- a/interface/resources/qml/CustomButton.qml +++ /dev/null @@ -1,23 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.3 -import QtQuick.Window 2.2 -import QtQuick.Controls.Styles 1.3 - -Button { - SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - text: "Text" - width: 128 - height: 64 - style: ButtonStyle { - background: CustomBorder { - anchors.fill: parent - } - label: CustomText { - renderType: Text.NativeRendering - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - text: control.text - color: control.enabled ? myPalette.text : myPalette.dark - } - } -} diff --git a/interface/resources/qml/CustomTextArea.qml b/interface/resources/qml/CustomTextArea.qml deleted file mode 100644 index cf3308e2b7..0000000000 --- a/interface/resources/qml/CustomTextArea.qml +++ /dev/null @@ -1,10 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 - -TextArea { - font.family: "Helvetica" - font.pointSize: 18 - backgroundVisible: false - readOnly: true -} - diff --git a/interface/resources/qml/HifiAction.qml b/interface/resources/qml/HifiAction.qml new file mode 100644 index 0000000000..0cecff91d7 --- /dev/null +++ b/interface/resources/qml/HifiAction.qml @@ -0,0 +1,20 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.3 + +Action { + property string name + objectName: name + "HifiAction" + text: qsTr(name) + + signal triggeredByName(string name); + signal toggledByName(string name); + + onTriggered: { + triggeredByName(name); + } + + onToggled: { + toggledByName(name, checked); + } +} + diff --git a/interface/resources/qml/HifiMenu.qml b/interface/resources/qml/HifiMenu.qml new file mode 100644 index 0000000000..d86821601a --- /dev/null +++ b/interface/resources/qml/HifiMenu.qml @@ -0,0 +1,272 @@ +import Hifi 1.0 as Hifi +import QtQuick 2.4 +import QtQuick.Controls 1.3 +import QtQuick.Controls.Styles 1.3 +import "controls" +import "styles" + +Hifi.HifiMenu { + id: root + anchors.fill: parent + objectName: "HifiMenu" + enabled: false + opacity: 0.0 + property int animationDuration: 200 + HifiPalette { id: hifiPalette } + z: 10000 + + onEnabledChanged: { + if (enabled && columns.length == 0) { + pushColumn(rootMenu.items); + } + opacity = enabled ? 1.0 : 0.0 + if (enabled) { + forceActiveFocus() + } + } + + // The actual animator + Behavior on opacity { + NumberAnimation { + duration: root.animationDuration + easing.type: Easing.InOutBounce + } + } + + onOpacityChanged: { + visible = (opacity != 0.0); + } + + onVisibleChanged: { + if (!visible) reset(); + } + + + property var menu: Menu {} + property var models: [] + property var columns: [] + property var itemBuilder: Component { + Text { + SystemPalette { id: sp; colorGroup: SystemPalette.Active } + id: thisText + x: 32 + property var source + property var root + property var listViewIndex + property var listView + text: typedText() + height: implicitHeight + width: implicitWidth + color: source.enabled ? "black" : "gray" + + onImplicitWidthChanged: { + if (listView) { + listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64); + listView.recalculateSize(); + } + } + + FontAwesome { + visible: source.type == 1 && source.checkable + x: -32 + text: (source.type == 1 && source.checked) ? "\uF05D" : "\uF10C" + } + + FontAwesome { + visible: source.type == 2 + x: listView.width - 64 + text: "\uF0DA" + } + + + function typedText() { + switch(source.type) { + case 2: + return source.title; + case 1: + return source.text; + case 0: + return "-----" + } + } + + MouseArea { + id: mouseArea + acceptedButtons: Qt.LeftButton + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: parent.top + anchors.topMargin: 0 + width: listView.width + onClicked: { + listView.currentIndex = listViewIndex + parent.root.selectItem(parent.source); + } + } + } + } + + + property var menuBuilder: Component { + Border { + SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } + x: root.models.length == 1 ? + (root.width / 2 - width / 2) : + root.columns[root.models.length - 2].x + 60; + anchors.verticalCenter: parent.verticalCenter + border.color: hifiPalette.hifiBlue + color: sysPalette.window + + ListView { + spacing: 6 + property int outerMargin: 8 + property real minWidth: 0 + anchors.fill: parent + anchors.margins: outerMargin + id: listView + height: root.height + currentIndex: -1 + + onCountChanged: { + recalculateSize() + } + + function recalculateSize() { + var newHeight = 0 + var newWidth = minWidth; + for (var i = 0; i < children.length; ++i) { + var item = children[i]; + newHeight += item.height + } + parent.height = newHeight + outerMargin * 2; + parent.width = newWidth + outerMargin * 2 + } + + highlight: Rectangle { + width: listView.minWidth; height: 32 + color: sysPalette.highlight + y: (listView.currentItem) ? listView.currentItem.y : 0; + x: 32 + Behavior on y { + NumberAnimation { + duration: 100 + easing.type: Easing.InOutQuint + } + } + } + + + property int columnIndex: root.models.length - 1 + model: root.models[columnIndex] + delegate: Loader { + id: loader + sourceComponent: root.itemBuilder + Binding { + target: loader.item + property: "root" + value: root + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "source" + value: modelData + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "listViewIndex" + value: index + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "listView" + value: listView + when: loader.status == Loader.Ready + } + } + + } + + } + } + + + function lastColumn() { + return columns[root.columns.length - 1]; + } + + function pushColumn(items) { + models.push(items) + if (columns.length) { + var oldColumn = lastColumn(); + oldColumn.enabled = false; + oldColumn.opacity = 0.5; + } + var newColumn = menuBuilder.createObject(root); + columns.push(newColumn); + newColumn.forceActiveFocus(); + } + + function popColumn() { + if (columns.length > 0) { + var curColumn = columns.pop(); + console.log(curColumn); + curColumn.visible = false; + curColumn.destroy(); + models.pop(); + } + + if (columns.length == 0) { + enabled = false; + return; + } + + curColumn = lastColumn(); + curColumn.enabled = true; + curColumn.opacity = 1.0; + curColumn.forceActiveFocus(); + } + + function selectItem(source) { + switch (source.type) { + case 2: + pushColumn(source.items) + break; + case 1: + source.trigger() + enabled = false + break; + case 0: + break; + } + } + + function reset() { + while (columns.length > 0) { + popColumn(); + } + } + + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Escape: + root.popColumn() + event.accepted = true; + } + } + + MouseArea { + anchors.fill: parent + id: mouseArea + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: { + if (mouse.button == Qt.RightButton) { + root.popColumn(); + } else { + root.enabled = false; + } + } + } +} diff --git a/interface/resources/qml/Icon.qml b/interface/resources/qml/Icon.qml deleted file mode 100644 index 0d60afb2b7..0000000000 --- a/interface/resources/qml/Icon.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick 1.0 - -Image { -id: icon -width: 64 -height: 64 -source: "file.svg" -} \ No newline at end of file diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index be69b65ef7..b3b926bbe3 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -1,12 +1,12 @@ import Hifi 1.0 import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 import QtQuick.Controls.Styles 1.3 -import "hifiConstants.js" as HifiConstants +import "controls" +import "styles" -CustomDialog { +Dialog { title: "Login" + HifiPalette { id: hifiPalette } SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } objectName: "LoginDialog" height: 512 @@ -50,11 +50,11 @@ CustomDialog { source: "../images/hifi-logo.svg" } - CustomBorder { + Border { width: 304 height: 64 anchors.horizontalCenter: parent.horizontalCenter - CustomTextInput { + TextInput { id: username anchors.fill: parent helperText: "Username or Email" @@ -67,11 +67,11 @@ CustomDialog { } } - CustomBorder { + Border { width: 304 height: 64 anchors.horizontalCenter: parent.horizontalCenter - CustomTextInput { + TextInput { id: password anchors.fill: parent echoMode: TextInput.Password @@ -94,7 +94,7 @@ CustomDialog { } } - CustomText { + Text { anchors.horizontalCenter: parent.horizontalCenter textFormat: Text.StyledText width: parent.width @@ -117,7 +117,7 @@ CustomDialog { width: 192 height: 64 anchors.horizontalCenter: parent.horizontalCenter - color: HifiConstants.color + color: hifiPalette.hifiBlue border.width: 0 radius: 10 @@ -142,7 +142,7 @@ CustomDialog { width: 32 source: "../images/login.svg" } - CustomText { + Text { text: "Login" color: "white" width: 64 @@ -152,7 +152,7 @@ CustomDialog { } - CustomText { + Text { width: parent.width height: 24 horizontalAlignment: Text.AlignHCenter @@ -160,7 +160,7 @@ CustomDialog { text:"Create Account" font.pointSize: 12 font.bold: true - color: HifiConstants.color + color: hifiPalette.hifiBlue MouseArea { anchors.fill: parent @@ -170,14 +170,14 @@ CustomDialog { } } - CustomText { + Text { width: parent.width height: 24 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pointSize: 12 text: "Recover Password" - color: HifiConstants.color + color: hifiPalette.hifiBlue MouseArea { anchors.fill: parent diff --git a/interface/resources/qml/MarketplaceDialog.qml b/interface/resources/qml/MarketplaceDialog.qml new file mode 100644 index 0000000000..58bb3e6183 --- /dev/null +++ b/interface/resources/qml/MarketplaceDialog.qml @@ -0,0 +1,50 @@ +import Hifi 1.0 +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.3 +import QtWebKit 3.0 +import "controls" + +Dialog { + title: "Test Dlg" + id: testDialog + objectName: "Browser" + width: 720 + height: 720 + resizable: true + + MarketplaceDialog { + id: marketplaceDialog + } + + Item { + id: clientArea + // The client area + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + + + ScrollView { + anchors.fill: parent + WebView { + objectName: "WebView" + id: webview + url: "https://metaverse.highfidelity.com/marketplace" + anchors.fill: parent + onNavigationRequested: { + console.log(request.url) + if (!marketplaceDialog.navigationRequested(request.url)) { + console.log("Application absorbed the request") + request.action = WebView.IgnoreRequest; + return; + } + console.log("Application passed on the request") + request.action = WebView.AcceptRequest; + return; + } + } + } + + } +} diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml new file mode 100644 index 0000000000..26fd30db27 --- /dev/null +++ b/interface/resources/qml/MessageDialog.qml @@ -0,0 +1,359 @@ +/***************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick.Dialogs module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +*****************************************************************************/ + +import Hifi 1.0 as Hifi +import QtQuick 2.2 +import QtQuick.Controls 1.2 +import QtQuick.Dialogs 1.2 +import "controls" + +Dialog { + id: root + property real spacing: 8 + property real outerSpacing: 16 + + destroyOnCloseButton: true + destroyOnInvisible: true + implicitHeight: content.implicitHeight + outerSpacing * 2 + 48 + implicitWidth: Math.min(200, Math.max(mainText.implicitWidth, content.buttonsRowImplicitWidth) + outerSpacing * 2); + + onImplicitHeightChanged: root.height = implicitHeight + onImplicitWidthChanged: root.width = implicitWidth + + SystemPalette { id: palette } + + function calculateImplicitWidth() { + if (buttons.visibleChildren.length < 2) + return; + var calcWidth = 0; + for (var i = 0; i < buttons.visibleChildren.length; ++i) { + calcWidth += Math.max(100, buttons.visibleChildren[i].implicitWidth) + root.spacing + } + content.buttonsRowImplicitWidth = outerSpacing + calcWidth + 48 + } + + onEnabledChanged: { + if (enabled) { + content.forceActiveFocus(); + } + } + + Hifi.MessageDialog { + id: content + clip: true + anchors.fill: parent + anchors.topMargin: parent.topMargin + root.outerSpacing + anchors.leftMargin: parent.margins + root.outerSpacing + anchors.rightMargin: parent.margins + root.outerSpacing + anchors.bottomMargin: parent.margins + root.outerSpacing + implicitHeight: contentColumn.implicitHeight + outerSpacing * 2 + implicitWidth: Math.max(mainText.implicitWidth, buttonsRowImplicitWidth); + property real buttonsRowImplicitWidth: Screen.pixelDensity * 50 + + Keys.onPressed: { + console.log("Key press at content") + event.accepted = true + if (event.modifiers === Qt.ControlModifier) + switch (event.key) { + case Qt.Key_A: + console.log("Select All") + detailedText.selectAll() + break + case Qt.Key_C: + console.log("Copy") + detailedText.copy() + break + case Qt.Key_Period: + if (Qt.platform.os === "osx") + reject() + break + } else switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + console.log("Rejecting") + reject() + break + case Qt.Key_Enter: + case Qt.Key_Return: + console.log("Accepting") + accept() + break + } + } + + onImplicitWidthChanged: root.width = implicitWidth + + Component.onCompleted: { + root.title = title + } + + onTitleChanged: { + root.title = title + } + + Column { + id: contentColumn + spacing: root.outerSpacing + anchors { + top: parent.top + left: parent.left + right: parent.right + } + + Item { + width: parent.width + height: Math.max(icon.height, mainText.height + informativeText.height + root.spacing) + Image { + id: icon + source: content.standardIconSource + } + + Text { + id: mainText + anchors { + left: icon.right + leftMargin: root.spacing + right: parent.right + } + text: content.text + font.pointSize: 14 + font.weight: Font.Bold + wrapMode: Text.WordWrap + } + + Text { + id: informativeText + anchors { + left: icon.right + right: parent.right + top: mainText.bottom + leftMargin: root.spacing + topMargin: root.spacing + } + text: content.informativeText + font.pointSize: 14 + wrapMode: Text.WordWrap + } + } + + + Flow { + id: buttons + spacing: root.spacing + layoutDirection: Qt.RightToLeft + width: parent.width + Button { + id: okButton + text: qsTr("OK") + onClicked: content.click(StandardButton.Ok) + visible: content.standardButtons & StandardButton.Ok + } + Button { + id: openButton + text: qsTr("Open") + onClicked: content.click(StandardButton.Open) + visible: content.standardButtons & StandardButton.Open + } + Button { + id: saveButton + text: qsTr("Save") + onClicked: content.click(StandardButton.Save) + visible: content.standardButtons & StandardButton.Save + } + Button { + id: saveAllButton + text: qsTr("Save All") + onClicked: content.click(StandardButton.SaveAll) + visible: content.standardButtons & StandardButton.SaveAll + } + Button { + id: retryButton + text: qsTr("Retry") + onClicked: content.click(StandardButton.Retry) + visible: content.standardButtons & StandardButton.Retry + } + Button { + id: ignoreButton + text: qsTr("Ignore") + onClicked: content.click(StandardButton.Ignore) + visible: content.standardButtons & StandardButton.Ignore + } + Button { + id: applyButton + text: qsTr("Apply") + onClicked: content.click(StandardButton.Apply) + visible: content.standardButtons & StandardButton.Apply + } + Button { + id: yesButton + text: qsTr("Yes") + onClicked: content.click(StandardButton.Yes) + visible: content.standardButtons & StandardButton.Yes + } + Button { + id: yesAllButton + text: qsTr("Yes to All") + onClicked: content.click(StandardButton.YesToAll) + visible: content.standardButtons & StandardButton.YesToAll + } + Button { + id: noButton + text: qsTr("No") + onClicked: content.click(StandardButton.No) + visible: content.standardButtons & StandardButton.No + } + Button { + id: noAllButton + text: qsTr("No to All") + onClicked: content.click(StandardButton.NoToAll) + visible: content.standardButtons & StandardButton.NoToAll + } + Button { + id: discardButton + text: qsTr("Discard") + onClicked: content.click(StandardButton.Discard) + visible: content.standardButtons & StandardButton.Discard + } + Button { + id: resetButton + text: qsTr("Reset") + onClicked: content.click(StandardButton.Reset) + visible: content.standardButtons & StandardButton.Reset + } + Button { + id: restoreDefaultsButton + text: qsTr("Restore Defaults") + onClicked: content.click(StandardButton.RestoreDefaults) + visible: content.standardButtons & StandardButton.RestoreDefaults + } + Button { + id: cancelButton + text: qsTr("Cancel") + onClicked: content.click(StandardButton.Cancel) + visible: content.standardButtons & StandardButton.Cancel + } + Button { + id: abortButton + text: qsTr("Abort") + onClicked: content.click(StandardButton.Abort) + visible: content.standardButtons & StandardButton.Abort + } + Button { + id: closeButton + text: qsTr("Close") + onClicked: content.click(StandardButton.Close) + visible: content.standardButtons & StandardButton.Close + } + Button { + id: moreButton + text: qsTr("Show Details...") + onClicked: content.state = (content.state === "" ? "expanded" : "") + visible: content.detailedText.length > 0 + } + Button { + id: helpButton + text: qsTr("Help") + onClicked: content.click(StandardButton.Help) + visible: content.standardButtons & StandardButton.Help + } + onVisibleChildrenChanged: root.calculateImplicitWidth() + } + } + + Item { + id: details + width: parent.width + implicitHeight: detailedText.implicitHeight + root.spacing + height: 0 + clip: true + + anchors { + left: parent.left + right: parent.right + top: contentColumn.bottom + topMargin: root.spacing + leftMargin: root.outerSpacing + rightMargin: root.outerSpacing + } + + Flickable { + id: flickable + contentHeight: detailedText.height + anchors.fill: parent + anchors.topMargin: root.spacing + anchors.bottomMargin: root.outerSpacing + TextEdit { + id: detailedText + text: content.detailedText + width: details.width + wrapMode: Text.WordWrap + readOnly: true + selectByMouse: true + } + } + } + + states: [ + State { + name: "expanded" + PropertyChanges { + target: details + height: root.height - contentColumn.height - root.spacing - root.outerSpacing + } + PropertyChanges { + target: content + implicitHeight: contentColumn.implicitHeight + root.spacing * 2 + + detailedText.implicitHeight + root.outerSpacing * 2 + } + PropertyChanges { + target: moreButton + text: qsTr("Hide Details") + } + } + ] + +/* + Rectangle { + + } + Component.onCompleted: calculateImplicitWidth() + */ + } +} diff --git a/interface/resources/qml/Palettes.qml b/interface/resources/qml/Palettes.qml index c4b0953df7..2bdf6eba8b 100644 --- a/interface/resources/qml/Palettes.qml +++ b/interface/resources/qml/Palettes.qml @@ -1,8 +1,5 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Dialogs 1.2 -import QtQuick.Controls.Styles 1.3 Rectangle { color: "teal" @@ -150,87 +147,4 @@ Rectangle { Rectangle { height: parent.height; width: 16; color: spd.highlightedText} } } - - -/* - CustomDialog { - title: "Test Dlg" - anchors.fill: parent - - Rectangle { - property int d: 100 - id: square - objectName: "testRect" - width: d - height: d - anchors.centerIn: parent - color: "red" - NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } - } - - - CustomTextEdit { - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.right: parent.right - anchors.rightMargin: 12 - clip: true - text: "test edit" - anchors.top: parent.top - anchors.topMargin: parent.titleSize + 12 - } - - CustomButton { - x: 128 - y: 192 - anchors.bottom: parent.bottom - anchors.bottomMargin: 12 - anchors.right: parent.right - anchors.rightMargin: 12 - onClicked: { - console.log("Click"); - if (square.visible) { - square.visible = false - } else { - square.visible = true - } - } - } - - CustomButton { - id: customButton2 - y: 192 - text: "Close" - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.bottom: parent.bottom - anchors.bottomMargin: 12 - onClicked: { - onClicked: testDialog.x == 0 ? testDialog.x = 200 : testDialog.x = 0 - } - } - - Keys.onPressed: { - console.log("Key " + event.key); - switch (event.key) { - case Qt.Key_Q: - if (Qt.ControlModifier == event.modifiers) { - event.accepted = true; - break; - } - } - } - } -*/ - } - - -/* - -// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property - -MouseArea { - anchors.fill: parent -} -*/ diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index 9422ef123d..b2db7d18bf 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -1,9 +1,10 @@ import Hifi 1.0 import QtQuick 2.3 +// This is our primary 'window' object to which all dialogs and controls will +// be childed. Root { id: root - width: 1280 - height: 720 + anchors.fill: parent } diff --git a/interface/resources/qml/RootMenu.qml b/interface/resources/qml/RootMenu.qml new file mode 100644 index 0000000000..b8c81a6589 --- /dev/null +++ b/interface/resources/qml/RootMenu.qml @@ -0,0 +1,9 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.3 + +Item { + Menu { + id: root + objectName: "rootMenu" + } +} diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml index 1fe8676bc6..15bd790c22 100644 --- a/interface/resources/qml/TestDialog.qml +++ b/interface/resources/qml/TestDialog.qml @@ -1,10 +1,9 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Dialogs 1.2 import QtQuick.Controls.Styles 1.3 +import "controls" -CustomDialog { +Dialog { title: "Test Dialog" id: testDialog objectName: "TestDialog" @@ -37,7 +36,7 @@ CustomDialog { } - CustomTextEdit { + TextEdit { id: edit anchors.left: parent.left anchors.leftMargin: 12 @@ -49,7 +48,7 @@ CustomDialog { anchors.topMargin: 12 } - CustomButton { + Button { x: 128 y: 192 text: "Test" @@ -68,7 +67,7 @@ CustomDialog { } } - CustomButton { + Button { id: customButton2 y: 192 text: "Move" @@ -92,15 +91,4 @@ CustomDialog { } } } - } - - -/* - -// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property - -MouseArea { - anchors.fill: parent -} -*/ diff --git a/interface/resources/qml/TestRoot.qml b/interface/resources/qml/TestRoot.qml index 158c0b7a54..80f8c900e3 100644 --- a/interface/resources/qml/TestRoot.qml +++ b/interface/resources/qml/TestRoot.qml @@ -1,12 +1,27 @@ import Hifi 1.0 import QtQuick 2.3 +import QtQuick.Controls 1.3 +// Import local folder last so that our own control customizations override +// the built in ones +import "controls" Root { id: root - width: 1280 - height: 720 + anchors.fill: parent - CustomButton { + onWidthChanged: { + console.log("Root width: " + width) + } + onHeightChanged: { + console.log("Root height: " + height) + } + + Component.onCompleted: { + console.log("Completed root") + root.forceActiveFocus() + } + + Button { id: messageBox anchors.right: createDialog.left anchors.rightMargin: 24 @@ -20,7 +35,7 @@ Root { } } - CustomButton { + Button { id: createDialog anchors.right: parent.right anchors.rightMargin: 24 @@ -28,8 +43,12 @@ Root { anchors.bottomMargin: 24 text: "Create" onClicked: { - root.loadChild("TestDialog.qml"); + root.loadChild("MenuTest.qml"); } } + + Keys.onPressed: { + console.log(event.key); + } } diff --git a/interface/resources/qml/componentCreation.js b/interface/resources/qml/componentCreation.js deleted file mode 100644 index 15a828d6f8..0000000000 --- a/interface/resources/qml/componentCreation.js +++ /dev/null @@ -1,29 +0,0 @@ -var component; -var instance; -var parent; - -function createObject(parentObject, url) { - parent = parentObject; - component = Qt.createComponent(url); - if (component.status == Component.Ready) - finishCreation(); - else - component.statusChanged.connect(finishCreation); -} - -function finishCreation() { - if (component.status == Component.Ready) { - instance = component.createObject(parent, {"x": 100, "y": 100}); - if (instance == null) { - // Error Handling - console.log("Error creating object"); - } else { - instance.enabled = true - } - } else if (component.status == Component.Error) { - // Error Handling - console.log("Error loading component:", component.errorString()); - } else { - console.log("Unknown component status: " + component.status); - } -} \ No newline at end of file diff --git a/interface/resources/qml/controls/Button.qml b/interface/resources/qml/controls/Button.qml new file mode 100644 index 0000000000..215e0542f7 --- /dev/null +++ b/interface/resources/qml/controls/Button.qml @@ -0,0 +1,10 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 as Original +import QtQuick.Controls.Styles 1.3 +import "." +import "../styles" + +Original.Button { + style: ButtonStyle { + } +} diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/controls/Dialog.qml similarity index 55% rename from interface/resources/qml/CustomDialog.qml rename to interface/resources/qml/controls/Dialog.qml index 1e0351af4f..07162ad1d8 100644 --- a/interface/resources/qml/CustomDialog.qml +++ b/interface/resources/qml/controls/Dialog.qml @@ -1,40 +1,79 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtQuick.Window 2.2 -import QtQuick.Dialogs 1.2 -import QtQuick.Controls.Styles 1.3 -import "hifiConstants.js" as HifiConstants +import "." +import "../styles" +/* + * FIXME Need to create a client property here so that objects can be + * placed in it without having to think about positioning within the outer + * window. + * + * Examine the QML ApplicationWindow.qml source for how it does this + * + */ Item { - SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - id: dialog - width: 256 - height: 256 - scale: 0.0 - enabled: false + id: root + + HifiPalette { id: hifiPalette } + SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } + x: parent ? parent.width / 2 - width / 2 : 0 + y: parent ? parent.height / 2 - height / 2 : 0 + property int animationDuration: 400 property bool destroyOnInvisible: false property bool destroyOnCloseButton: true property bool resizable: false property int minX: 256 property int minY: 256 + property int topMargin: root.height - clientBorder.height + 8 + property int margins: 8 + property string title + property int titleSize: titleBorder.height + 12 + property string frameColor: hifiPalette.hifiBlue + property string backgroundColor: sysPalette.window + property string headerBackgroundColor: sysPalette.dark clip: true + + /* + * Support for animating the dialog in and out. + */ + enabled: false + scale: 0.0 + // The offscreen UI will enable an object, rather than manipulating it's + // visibility, so that we can do animations in both directions. Because + // visibility and enabled are boolean flags, they cannot be animated. So when + // enabled is change, we modify a property that can be animated, like scale or + // opacity. onEnabledChanged: { scale = enabled ? 1.0 : 0.0 } - + + // The actual animator + Behavior on scale { + NumberAnimation { + duration: root.animationDuration + easing.type: Easing.InOutBounce + } + } + + // We remove any load the dialog might have on the QML by toggling it's + // visibility based on the state of the animated property onScaleChanged: { visible = (scale != 0.0); } + // Some dialogs should be destroyed when they become invisible, so handle that onVisibleChanged: { if (!visible && destroyOnInvisible) { - console.log("Destroying closed component"); destroy(); } } + // our close function performs the same way as the OffscreenUI class: + // don't do anything but manipulate the enabled flag and let the other + // mechanisms decide if the window should be destoryed after the close + // animation completes function close() { if (destroyOnCloseButton) { destroyOnInvisible = true @@ -42,102 +81,14 @@ Item { enabled = false; } + /* + * Resize support + */ function deltaSize(dx, dy) { width = Math.max(width + dx, minX) height = Math.max(height + dy, minY) } - Behavior on scale { - NumberAnimation { - //This specifies how long the animation takes - duration: dialog.animationDuration - //This selects an easing curve to interpolate with, the default is Easing.Linear - easing.type: Easing.InOutBounce - } - } - - property int topMargin: dialog.height - clientBorder.height + 8 - property int margins: 8 - property string title - property int titleSize: titleBorder.height + 12 - property string frameColor: HifiConstants.color - property string backgroundColor: myPalette.window - property string headerBackgroundColor: myPalette.dark - - CustomBorder { - id: windowBorder - anchors.fill: parent - border.color: dialog.frameColor - color: dialog.backgroundColor - - CustomBorder { - id: titleBorder - height: 48 - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - border.color: dialog.frameColor - color: dialog.headerBackgroundColor - - CustomText { - id: titleText - color: "white" - text: dialog.title - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - anchors.fill: parent - } - - MouseArea { - id: titleDrag - anchors.right: closeButton.left - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.top: parent.top - anchors.rightMargin: 4 - drag { - target: dialog - minimumX: 0 - minimumY: 0 - maximumX: dialog.parent ? dialog.parent.width - dialog.width : 0 - maximumY: dialog.parent ? dialog.parent.height - dialog.height : 0 - } - } - Image { - id: closeButton - x: 360 - height: 16 - anchors.verticalCenter: parent.verticalCenter - width: 16 - anchors.right: parent.right - anchors.rightMargin: 12 - source: "../styles/close.svg" - MouseArea { - anchors.fill: parent - onClicked: { - dialog.close(); - } - } - } - } // header border - - CustomBorder { - id: clientBorder - border.color: dialog.frameColor - color: "#00000000" - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: titleBorder.bottom - anchors.topMargin: -titleBorder.border.width - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - clip: true - } // client border - } // window border - MouseArea { id: sizeDrag property int startX @@ -152,11 +103,91 @@ Item { startY = mouseY } onPositionChanged: { - if (pressed && dialog.resizable) { - dialog.deltaSize((mouseX - startX), (mouseY - startY)) + if (pressed && root.resizable) { + root.deltaSize((mouseX - startX), (mouseY - startY)) startX = mouseX startY = mouseY } } } + + /* + * Window decorations, with a title bar and frames + */ + Border { + id: windowBorder + anchors.fill: parent + border.color: root.frameColor + color: root.backgroundColor + + Border { + id: titleBorder + height: 48 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + border.color: root.frameColor + color: root.headerBackgroundColor + + Text { + id: titleText + // FIXME move all constant colors to our own palette class HifiPalette + color: "white" + text: root.title + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + } + + MouseArea { + id: titleDrag + anchors.right: closeButton.left + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.top: parent.top + anchors.rightMargin: 4 + drag { + target: root + minimumX: 0 + minimumY: 0 + maximumX: root.parent ? root.parent.width - root.width : 0 + maximumY: root.parent ? root.parent.height - root.height : 0 + } + } + Image { + id: closeButton + x: 360 + height: 16 + anchors.verticalCenter: parent.verticalCenter + width: 16 + anchors.right: parent.right + anchors.rightMargin: 12 + source: "../../styles/close.svg" + MouseArea { + anchors.fill: parent + onClicked: { + root.close(); + } + } + } + } // header border + + Border { + id: clientBorder + border.color: root.frameColor + // FIXME move all constant colors to our own palette class HifiPalette + color: "#00000000" + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: titleBorder.bottom + anchors.topMargin: -titleBorder.border.width + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + clip: true + } // client border + } // window border + } diff --git a/interface/resources/qml/controls/FontAwesome.qml b/interface/resources/qml/controls/FontAwesome.qml new file mode 100644 index 0000000000..e975c0342b --- /dev/null +++ b/interface/resources/qml/controls/FontAwesome.qml @@ -0,0 +1,16 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 +import QtQuick.Controls.Styles 1.3 + +Text { + id: root + FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; } + property int size: 32 + width: size + height: size + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + font.family: iconFont.name + font.pointSize: 18 +} + diff --git a/interface/resources/qml/IconControl.qml b/interface/resources/qml/controls/IconButton.qml similarity index 100% rename from interface/resources/qml/IconControl.qml rename to interface/resources/qml/controls/IconButton.qml diff --git a/interface/resources/qml/controls/MenuButton.qml b/interface/resources/qml/controls/MenuButton.qml new file mode 100644 index 0000000000..740995a199 --- /dev/null +++ b/interface/resources/qml/controls/MenuButton.qml @@ -0,0 +1,5 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 as Original +import "../styles" +import "../controls" + diff --git a/interface/resources/qml/controls/README.md b/interface/resources/qml/controls/README.md new file mode 100644 index 0000000000..7f05f32a63 --- /dev/null +++ b/interface/resources/qml/controls/README.md @@ -0,0 +1,2 @@ +These are our own custom controls with the same names as existing controls, but +customized for readability / usability in VR. diff --git a/interface/resources/qml/CustomTextEdit.qml b/interface/resources/qml/controls/Text.qml similarity index 54% rename from interface/resources/qml/CustomTextEdit.qml rename to interface/resources/qml/controls/Text.qml index 0602bbc150..a9c19e70b4 100644 --- a/interface/resources/qml/CustomTextEdit.qml +++ b/interface/resources/qml/controls/Text.qml @@ -1,6 +1,6 @@ -import QtQuick 2.3 +import QtQuick 2.3 as Original -TextEdit { +Original.Text { font.family: "Helvetica" font.pointSize: 18 } diff --git a/interface/resources/qml/CustomText.qml b/interface/resources/qml/controls/TextArea.qml similarity index 52% rename from interface/resources/qml/CustomText.qml rename to interface/resources/qml/controls/TextArea.qml index 83229b783e..dfa177bcb6 100644 --- a/interface/resources/qml/CustomText.qml +++ b/interface/resources/qml/controls/TextArea.qml @@ -1,6 +1,6 @@ -import QtQuick 2.3 +import QtQuick 2.3 as Original -Text { +Original.TextArea { font.family: "Helvetica" font.pointSize: 18 } diff --git a/interface/resources/qml/controls/TextEdit.qml b/interface/resources/qml/controls/TextEdit.qml new file mode 100644 index 0000000000..28551bb171 --- /dev/null +++ b/interface/resources/qml/controls/TextEdit.qml @@ -0,0 +1,7 @@ +import QtQuick 2.3 as Original + +Original.TextEdit { + font.family: "Helvetica" + font.pointSize: 18 +} + diff --git a/interface/resources/qml/CustomTextInput.qml b/interface/resources/qml/controls/TextInput.qml similarity index 90% rename from interface/resources/qml/CustomTextInput.qml rename to interface/resources/qml/controls/TextInput.qml index a706187376..8ce3d85d81 100644 --- a/interface/resources/qml/CustomTextInput.qml +++ b/interface/resources/qml/controls/TextInput.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 1.2 TextInput { SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - property string helperText: "" + property string helperText font.family: "Helvetica" font.pointSize: 18 width: 256 @@ -24,7 +24,7 @@ TextInput { id: helperText anchors.fill: parent font.pointSize: parent.font.pointSize - font.family: "Helvetica" + font.family: parent.font.family verticalAlignment: TextInput.AlignVCenter text: parent.helperText color: myPalette.dark diff --git a/interface/resources/qml/hifiConstants.js b/interface/resources/qml/hifiConstants.js deleted file mode 100644 index 860226c963..0000000000 --- a/interface/resources/qml/hifiConstants.js +++ /dev/null @@ -1,4 +0,0 @@ -var color = "#0e7077" -var Colors = { - hifiBlue: "#0e7077" -} diff --git a/interface/resources/qml/images/critical.png b/interface/resources/qml/images/critical.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9c5aebf453dd92dba60c48f060b34f0087e02c GIT binary patch literal 253 zcmVkNDWE^AyB8@ZEC00000NkvXXu0mjf DKfYr$ literal 0 HcmV?d00001 diff --git a/interface/resources/qml/images/information.png b/interface/resources/qml/images/information.png new file mode 100644 index 0000000000000000000000000000000000000000..0a2eb87d108d2a24b71559998627570a252ebe69 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8`~f~8uBj!u3?T4-=FFM@ z|NrludHNay0|R48kY6x^!?PP{3=9l&JzX3_G|sP`c#-$80*{Mh+yV`sgwlqP>#QC( z>X#+u7`Xm@Q`=BsWqr<)MUc^=nfrazYu@_ss|q3QYrOu5+ux47bKp#oZChf4k#&aW z_6qNdiK4+zLkc4MIa@Ri#52@3K4zcMoZ;%Na4X>suaM`rgBP8<|7A}r*;L-N)XQ^~ z*Qd}2Q;+ng3Z7t^78=O>`qh(QX^u+vLUu-L1y=d3FMU5VRZj!?kipZ{&t;ucLK6Te CT3=!S literal 0 HcmV?d00001 diff --git a/interface/resources/qml/images/question.png b/interface/resources/qml/images/question.png new file mode 100644 index 0000000000000000000000000000000000000000..2dd92fd7915a09de670b8b6022ddcf02d4cc90e1 GIT binary patch literal 257 zcmV+c0sj7pP)NklQ}7)nBez2^$+jK{Nw%L3xK4m{g6jm}2|@>7z7zk+b}w*O&>f9X*ioevByCmJtfv0xgg* zX&;ac>>nrw_75mp9NLlK=){M}g!K&|3b4W-F*J23VSVK);JN=%IJYXN$un1x$~;9b a#PS7=(1SoC6O>K>0000a literal 0 HcmV?d00001 diff --git a/interface/resources/qml/CustomBorder.qml b/interface/resources/qml/styles/Border.qml similarity index 99% rename from interface/resources/qml/CustomBorder.qml rename to interface/resources/qml/styles/Border.qml index 1bb30d1ebc..7d38e7d277 100644 --- a/interface/resources/qml/CustomBorder.qml +++ b/interface/resources/qml/styles/Border.qml @@ -1,6 +1,5 @@ import QtQuick 2.3 - Rectangle { SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } property int margin: 5 diff --git a/interface/resources/qml/styles/ButtonStyle.qml b/interface/resources/qml/styles/ButtonStyle.qml new file mode 100644 index 0000000000..8d866390a0 --- /dev/null +++ b/interface/resources/qml/styles/ButtonStyle.qml @@ -0,0 +1,24 @@ +import QtQuick 2.4 as Original +import QtQuick.Controls.Styles 1.3 as OriginalStyles +import "." +import "../controls" + +OriginalStyles.ButtonStyle { + Original.SystemPalette { id: myPalette; colorGroup: Original.SystemPalette.Active } + padding { + top: 8 + left: 12 + right: 12 + bottom: 8 + } + background: Border { + anchors.fill: parent + } + label: Text { + renderType: Original.Text.NativeRendering + verticalAlignment: Original.Text.AlignVCenter + horizontalAlignment: Original.Text.AlignHCenter + text: control.text + color: control.enabled ? myPalette.text : myPalette.dark + } +} diff --git a/interface/resources/qml/styles/HifiPalette.qml b/interface/resources/qml/styles/HifiPalette.qml new file mode 100644 index 0000000000..46ef0ef14e --- /dev/null +++ b/interface/resources/qml/styles/HifiPalette.qml @@ -0,0 +1,5 @@ +import QtQuick 2.4 + +QtObject { + property string hifiBlue: "#0e7077" +} \ No newline at end of file diff --git a/interface/resources/qml/styles/IconButtonStyle.qml b/interface/resources/qml/styles/IconButtonStyle.qml new file mode 100644 index 0000000000..b341e5d6dd --- /dev/null +++ b/interface/resources/qml/styles/IconButtonStyle.qml @@ -0,0 +1,15 @@ +ButtonStyle { + background: Item { anchors.fill: parent } + label: Text { + id: icon + width: height + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + font.family: iconFont.name + font.pointSize: 18 + property alias unicode: icon.text + FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; } + text: control.text + color: control.enabled ? "white" : "dimgray" + } +} diff --git a/interface/resources/qml/styles/MenuButtonStyle.qml b/interface/resources/qml/styles/MenuButtonStyle.qml new file mode 100644 index 0000000000..fd21e88d86 --- /dev/null +++ b/interface/resources/qml/styles/MenuButtonStyle.qml @@ -0,0 +1,22 @@ +import QtQuick 2.4 +import QtQuick.Controls.Styles 1.3 +import "../controls" +import "." + +ButtonStyle { + HifiPalette { id: hifiPalette } + padding { + top: 2 + left: 4 + right: 4 + bottom: 2 + } + background: Item {} + label: Text { + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.text + color: control.enabled ? "yellow" : "brown" + } +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9ae54ac83e..5a8b3ecee9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -144,6 +144,23 @@ extern "C" { } #endif +enum CustomEventTypes { + Lambda = QEvent::User + 1 +}; + +class LambdaEvent : public QEvent { + std::function _fun; +public: + LambdaEvent(const std::function & fun) : + QEvent(static_cast(Lambda)), _fun(fun) { + } + LambdaEvent(std::function && fun) : + QEvent(static_cast(Lambda)), _fun(fun) { + } + void call() { _fun(); } +}; + + using namespace std; // Starfield information @@ -707,6 +724,13 @@ void Application::initializeGL() { initDisplay(); qCDebug(interfaceapp, "Initialized Display."); + // The UI can't be created until the primary OpenGL + // context is created, because it needs to share + // texture resources + initializeUi(); + qCDebug(interfaceapp, "Initialized Offscreen UI."); + _glWidget->makeCurrent(); + init(); qCDebug(interfaceapp, "init() complete."); @@ -735,17 +759,13 @@ void Application::initializeGL() { // update before the first render update(1.0f / _fps); - // The UI can't be created until the primary OpenGL - // context is created, because it needs to share - // texture resources - initializeUi(); - InfoView::showFirstTime(INFO_HELP_PATH); } void Application::initializeUi() { AddressBarDialog::registerType(); LoginDialog::registerType(); + MessageDialog::registerType(); auto offscreenUi = DependencyManager::get(); offscreenUi->create(_glWidget->context()->contextHandle()); @@ -753,6 +773,7 @@ void Application::initializeUi() { offscreenUi->setProxyWindow(_window->windowHandle()); offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); offscreenUi->load("Root.qml"); + offscreenUi->load("RootMenu.qml"); offscreenUi->setMouseTranslator([this](const QPointF& p){ if (OculusManager::isConnected()) { glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p)); @@ -964,6 +985,10 @@ bool Application::importSVOFromURL(const QString& urlString) { bool Application::event(QEvent* event) { switch (event->type()) { + case Lambda: + ((LambdaEvent*)event)->call(); + return true; + case QEvent::MouseMove: mouseMoveEvent((QMouseEvent*)event); return true; diff --git a/interface/src/Application.h b/interface/src/Application.h index 89de18dde5..688cf23876 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -147,6 +148,8 @@ public: Application(int& argc, char** argv, QElapsedTimer &startup_time); ~Application(); + void postLambdaEvent(std::function f); + void loadScripts(); QString getPreviousScriptLocation(); void setPreviousScriptLocation(const QString& previousScriptLocation); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 2a8f01aafc..7940a06993 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -323,7 +323,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { //Render magnifier, but dont show border for mouse magnifier glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(), _reticlePosition[MOUSE].y())); - with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { + with_each_texture(_overlays.getTexture(), 0, [&] { renderMagnifier(projection, _magSizeMult[i], i != MOUSE); }); } diff --git a/libraries/render-utils/src/OffscreenQmlDialog.h b/libraries/render-utils/src/OffscreenQmlDialog.h deleted file mode 100644 index eca82261c0..0000000000 --- a/libraries/render-utils/src/OffscreenQmlDialog.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// OffscreenQmlDialog.h -// -// Created by Bradley Austin Davis on 2015/04/14 -// Copyright 2015 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 -// - -#pragma once -#ifndef hifi_OffscreenQmlDialog_h -#define hifi_OffscreenQmlDialog_h - -#include -#include "OffscreenUi.h" - -#define QML_DIALOG_DECL \ -private: \ - static const QString NAME; \ - static const QUrl QML; \ -public: \ - static void registerType(); \ - static void show(); \ - static void toggle(); \ -private: - -#define QML_DIALOG_DEF(x) \ - const QUrl x::QML = QUrl(#x ".qml"); \ - const QString x::NAME = #x; \ - \ - void x::registerType() { \ - qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ - } \ - \ - void x::show() { \ - auto offscreenUi = DependencyManager::get(); \ - offscreenUi->show(QML, NAME); \ - } \ - \ - void x::toggle() { \ - auto offscreenUi = DependencyManager::get(); \ - offscreenUi->toggle(QML, NAME); \ - } - -class OffscreenQmlDialog : public QQuickItem -{ - Q_OBJECT -public: - OffscreenQmlDialog(QQuickItem* parent = nullptr); - -protected: - void hide(); -}; - -#endif diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index bf846c0bf2..47e5659c60 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -14,16 +14,26 @@ #include #include #include - +#include #include "PathUtils.h" QString& PathUtils::resourcesPath() { +#ifdef DEBUG + static QString staticResourcePath; + if (staticResourcePath.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + staticResourcePath = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; + } +#else #ifdef Q_OS_MAC static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/"; #else static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/"; #endif +#endif + return staticResourcePath; } diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt new file mode 100644 index 0000000000..36a0a1a846 --- /dev/null +++ b/libraries/ui/CMakeLists.txt @@ -0,0 +1,12 @@ +set(TARGET_NAME ui) + +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(OpenGL Network Qml Quick Script) + +link_hifi_libraries(render-utils shared) + +add_dependency_external_projects(glm) +find_package(GLM REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + + diff --git a/libraries/ui/src/HifiMenu.cpp b/libraries/ui/src/HifiMenu.cpp new file mode 100644 index 0000000000..27517f99d7 --- /dev/null +++ b/libraries/ui/src/HifiMenu.cpp @@ -0,0 +1,279 @@ +#include "HifiMenu.h" +#include + +// FIXME can this be made a class member? +static const QString MENU_SUFFIX{ "__Menu" }; + +HIFI_QML_DEF_LAMBDA(HifiMenu, [=](QQmlContext* context, QObject* newItem) { + auto offscreenUi = DependencyManager::get(); + QObject * rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); + Q_ASSERT(rootMenu); + static_cast(newItem)->setRootMenu(rootMenu); + context->setContextProperty("rootMenu", rootMenu); +}); + +HifiMenu::HifiMenu(QQuickItem* parent) : QQuickItem(parent), _triggerMapper(this), _toggleMapper(this) { + this->setEnabled(false); + connect(&_triggerMapper, SIGNAL(mapped(QString)), this, SLOT(onTriggeredByName(const QString &))); + connect(&_toggleMapper, SIGNAL(mapped(QString)), this, SLOT(onToggledByName(const QString &))); +} + +void HifiMenu::onTriggeredByName(const QString & name) { + qDebug() << name << " triggered"; + if (_triggerActions.count(name)) { + _triggerActions[name](); + } +} + +void HifiMenu::onToggledByName(const QString & name) { + qDebug() << name << " toggled"; + if (_toggleActions.count(name)) { + QObject* menu = findMenuObject(name); + bool checked = menu->property("checked").toBool(); + _toggleActions[name](checked); + } +} + +void HifiMenu::setToggleAction(const QString & name, std::function f) { + _toggleActions[name] = f; +} + +void HifiMenu::setTriggerAction(const QString & name, std::function f) { + _triggerActions[name] = f; +} + +QObject* addMenu(QObject* parent, const QString & text) { + // FIXME add more checking here to ensure no name conflicts + QVariant returnedValue; + QMetaObject::invokeMethod(parent, "addMenu", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, returnedValue), + Q_ARG(QVariant, text)); + QObject* result = returnedValue.value(); + if (result) { + result->setObjectName(text + MENU_SUFFIX); + } + return result; +} + +class QQuickMenuItem; +QObject* addItem(QObject* parent, const QString& text) { + // FIXME add more checking here to ensure no name conflicts + QQuickMenuItem* returnedValue{ nullptr }; + bool invokeResult = QMetaObject::invokeMethod(parent, "addItem", Qt::DirectConnection, + Q_RETURN_ARG(QQuickMenuItem*, returnedValue), + Q_ARG(QString, text)); + Q_ASSERT(invokeResult); + QObject* result = reinterpret_cast(returnedValue); + return result; +} + +const QObject* HifiMenu::findMenuObject(const QString & menuOption) const { + if (menuOption.isEmpty()) { + return _rootMenu; + } + const QObject* result = _rootMenu->findChild(menuOption + MENU_SUFFIX); + return result; +} + +QObject* HifiMenu::findMenuObject(const QString & menuOption) { + if (menuOption.isEmpty()) { + return _rootMenu; + } + QObject* result = _rootMenu->findChild(menuOption + MENU_SUFFIX); + return result; +} + +void HifiMenu::addMenu(const QString & parentMenu, const QString & menuOption) { + QObject* parent = findMenuObject(parentMenu); + QObject* result = ::addMenu(parent, menuOption); + Q_ASSERT(result); + result->setObjectName(menuOption + MENU_SUFFIX); + Q_ASSERT(findMenuObject(menuOption)); +} + +void HifiMenu::removeMenu(const QString& menuName) { + QObject* menu = findMenuObject(menuName); + Q_ASSERT(menu); + Q_ASSERT(menu != _rootMenu); + QMetaObject::invokeMethod(menu->parent(), "removeItem", + Q_ARG(QVariant, QVariant::fromValue(menu))); +} + +bool HifiMenu::menuExists(const QString& menuName) const { + return findMenuObject(menuName); +} + +void HifiMenu::addSeparator(const QString& parentMenu, const QString& separatorName) { + QObject * parent = findMenuObject(parentMenu); + bool invokeResult = QMetaObject::invokeMethod(parent, "addSeparator", Qt::DirectConnection); + Q_ASSERT(invokeResult); + addItem(parentMenu, separatorName); + enableItem(separatorName, false); +} + +void HifiMenu::removeSeparator(const QString& parentMenu, const QString& separatorName) { +} + +void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption) { + QObject* parent = findMenuObject(parentMenu); + Q_ASSERT(parent); + QObject* result = ::addItem(parent, menuOption); + Q_ASSERT(result); + result->setObjectName(menuOption + MENU_SUFFIX); + Q_ASSERT(findMenuObject(menuOption)); + + _triggerMapper.setMapping(result, menuOption); + connect(result, SIGNAL(triggered()), &_triggerMapper, SLOT(map())); + + _toggleMapper.setMapping(result, menuOption); + connect(result, SIGNAL(toggled(bool)), &_toggleMapper, SLOT(map())); +} + +void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption, std::function f) { + setTriggerAction(menuOption, f); + addItem(parentMenu, menuOption); +} + +void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption, QObject* receiver, const char* slot) { + addItem(parentMenu, menuOption); + connectItem(menuOption, receiver, slot); +} + +void HifiMenu::removeItem(const QString& menuOption) { + removeMenu(menuOption); +} + +bool HifiMenu::itemExists(const QString& menuName, const QString& menuitem) const { + return findMenuObject(menuName); +} + +void HifiMenu::triggerItem(const QString& menuOption) { + QObject* menuItem = findMenuObject(menuOption); + Q_ASSERT(menuItem); + Q_ASSERT(menuItem != _rootMenu); + QMetaObject::invokeMethod(menuItem, "trigger"); +} + +QHash warned; +void warn(const QString & menuOption) { + if (!warned.contains(menuOption)) { + warned[menuOption] = menuOption; + qWarning() << "No menu item: " << menuOption; + } +} + +bool HifiMenu::isChecked(const QString& menuOption) const { + const QObject* menuItem = findMenuObject(menuOption); + if (!menuItem) { + warn(menuOption); + return false; + } + return menuItem->property("checked").toBool(); +} + +void HifiMenu::setChecked(const QString& menuOption, bool isChecked) { + QObject* menuItem = findMenuObject(menuOption); + if (!menuItem) { + warn(menuOption); + return; + } + if (menuItem->property("checked").toBool() != isChecked) { + menuItem->setProperty("checked", QVariant::fromValue(isChecked)); + Q_ASSERT(menuItem->property("checked").toBool() == isChecked); + } +} + +void HifiMenu::setCheckable(const QString& menuOption, bool checkable) { + QObject* menuItem = findMenuObject(menuOption); + if (!menuItem) { + warn(menuOption); + return; + } + + menuItem->setProperty("checkable", QVariant::fromValue(checkable)); + Q_ASSERT(menuItem->property("checkable").toBool() == checkable); +} + +void HifiMenu::setItemText(const QString& menuOption, const QString& text) { + QObject* menuItem = findMenuObject(menuOption); + if (!menuItem) { + warn(menuOption); + return; + } + if (menuItem->property("type").toInt() == 2) { + menuItem->setProperty("title", QVariant::fromValue(text)); + } else { + menuItem->setProperty("text", QVariant::fromValue(text)); + } +} + +void HifiMenu::setRootMenu(QObject* rootMenu) { + _rootMenu = rootMenu; +} + +void HifiMenu::enableItem(const QString & menuOption, bool enabled) { + QObject* menuItem = findMenuObject(menuOption); + if (!menuItem) { + warn(menuOption); + return; + } + menuItem->setProperty("enabled", QVariant::fromValue(enabled)); +} + +void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked) { + addItem(parentMenu, menuOption); + setCheckable(menuOption); + if (checked) { + setChecked(menuOption, checked); + } +} + +void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f) { + setToggleAction(menuOption, f); + addCheckableItem(parentMenu, menuOption, checked); +} + +void HifiMenu::setItemVisible(const QString& menuOption, bool visible) { + QObject* result = findMenuObject(menuOption); + if (result) { + result->setProperty("visible", visible); + } +} + +bool HifiMenu::isItemVisible(const QString& menuOption) { + QObject* result = findMenuObject(menuOption); + if (result) { + return result->property("visible").toBool(); + } + return false; +} + +void HifiMenu::setItemShortcut(const QString& menuOption, const QString& shortcut) { + QObject* result = findMenuObject(menuOption); + if (result) { + result->setProperty("shortcut", shortcut); + } +} + +QString HifiMenu::getItemShortcut(const QString& menuOption) { + QObject* result = findMenuObject(menuOption); + if (result) { + return result->property("shortcut").toString(); + } + return QString(); +} + +void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, QObject* receiver, const char* slot) { + addCheckableItem(parentMenu, menuOption, checked); + connectItem(menuOption, receiver, slot); +} + +void HifiMenu::connectCheckable(const QString& menuOption, QObject* receiver, const char* slot) { + QObject* result = findMenuObject(menuOption); + connect(result, SIGNAL(toggled(bool)), receiver, slot); +} + +void HifiMenu::connectItem(const QString& menuOption, QObject* receiver, const char* slot) { + QObject* result = findMenuObject(menuOption); + connect(result, SIGNAL(triggered()), receiver, slot); +} diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/HifiMenu.h new file mode 100644 index 0000000000..c89c91b028 --- /dev/null +++ b/libraries/ui/src/HifiMenu.h @@ -0,0 +1,83 @@ +// +// MenuConstants.h +// +// Created by Bradley Austin Davis on 2015/04/21 +// Copyright 2015 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 +// + +#pragma once +#ifndef hifi_MenuContants_h +#define hifi_MenuConstants_h + +#include +#include +#include +#include +#include "OffscreenUi.h" + +class HifiMenu : public QQuickItem { + Q_OBJECT + HIFI_QML_DECL_LAMBDA + +public: + HifiMenu(QQuickItem* parent = nullptr); + + void setToggleAction(const QString& name, std::function f); + void setTriggerAction(const QString& name, std::function f); + + void addMenu(const QString& parentMenu, const QString& menuOption); + void removeMenu(const QString& menuName); + bool menuExists(const QString& menuName) const; + + void addSeparator(const QString& menuName, const QString& separatorName); + void removeSeparator(const QString& menuName, const QString& separatorName); + + void addItem(const QString& parentMenu, const QString& menuOption); + void addItem(const QString& parentMenu, const QString& menuOption, std::function f); + void addItem(const QString& parentMenu, const QString& menuOption, QObject* receiver, const char* slot); + + void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked = false); + void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f); + void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, QObject* receiver, const char* slot); + void connectCheckable(const QString& menuOption, QObject* receiver, const char* slot); + void connectItem(const QString& menuOption, QObject* receiver, const char* slot); + + void removeItem(const QString& menuitem); + bool itemExists(const QString& menuName, const QString& menuitem) const; + void triggerItem(const QString& menuOption); + void enableItem(const QString& menuOption, bool enabled = true); + bool isChecked(const QString& menuOption) const; + void setChecked(const QString& menuOption, bool checked = true); + void setCheckable(const QString& menuOption, bool checkable = true); + void setExclusiveGroup(const QString& menuOption, const QString& groupName); + void setItemText(const QString& menuOption, const QString& text); + void setItemVisible(const QString& menuOption, bool visible = true); + bool isItemVisible(const QString& menuOption); + + void setItemShortcut(const QString& menuOption, const QString& shortcut); + QString getItemShortcut(const QString& menuOption); + + void setRootMenu(QObject* rootMenu); + +private slots: + void onTriggeredByName(const QString& name); + void onToggledByName(const QString& name); + +protected: + QHash> _triggerActions; + QHash> _toggleActions; + QObject* findMenuObject(const QString& name); + const QObject* findMenuObject(const QString& name) const; + QObject* _rootMenu{ nullptr }; + QSignalMapper _triggerMapper; + QSignalMapper _toggleMapper; +}; + +#endif // hifi_MenuConstants_h + + + + diff --git a/libraries/ui/src/MessageDialog.cpp b/libraries/ui/src/MessageDialog.cpp new file mode 100644 index 0000000000..c16f5653e5 --- /dev/null +++ b/libraries/ui/src/MessageDialog.cpp @@ -0,0 +1,142 @@ +// +// +// MessageDialog.cpp +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 "MessageDialog.h" + +QML_DIALOG_DEF(MessageDialog) + + +MessageDialog::MessageDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { + _buttons = StandardButtons(Ok | Cancel); +} + +MessageDialog::~MessageDialog() { +} + +QString MessageDialog::text() const { + return _text; +} + +QString MessageDialog::informativeText() const { + return _informativeText; +} + +QString MessageDialog::detailedText() const { + return _detailedText; +} + +MessageDialog::Icon MessageDialog::icon() const { + return _icon; +} + +void MessageDialog::setVisible(bool v) { + OffscreenQmlDialog::setVisible(v); +} + +void MessageDialog::setText(const QString &arg) { + if (arg != _text) { + _text = arg; + emit textChanged(); + } +} + +void MessageDialog::setInformativeText(const QString &arg) { + if (arg != _informativeText) { + _informativeText = arg; + emit informativeTextChanged(); + } +} + +void MessageDialog::setDetailedText(const QString &arg) { + if (arg != _detailedText) { + _detailedText = arg; + emit detailedTextChanged(); + } +} + +void MessageDialog::setIcon(MessageDialog::Icon icon) { + if (icon != _icon) { + _icon = icon; + emit iconChanged(); + } +} + +void MessageDialog::setStandardButtons(StandardButtons buttons) { + if (buttons != _buttons) { + _buttons = buttons; + emit standardButtonsChanged(); + } +} + +void MessageDialog::click(StandardButton button) { + click(static_cast(button), + static_cast( + QPlatformDialogHelper::buttonRole(static_cast(button)))); +} + +QUrl MessageDialog::standardIconSource() { + switch (icon()) { + case QMessageDialogOptions::Information: + return QUrl("images/information.png"); + break; + case QMessageDialogOptions::Warning: + return QUrl("images/warning.png"); + break; + case QMessageDialogOptions::Critical: + return QUrl("images/critical.png"); + break; + case QMessageDialogOptions::Question: + return QUrl("images/question.png"); + break; + default: + return QUrl(); + break; + } +} + +MessageDialog::StandardButtons MessageDialog::standardButtons() const { + return _buttons; +} + +MessageDialog::StandardButton MessageDialog::clickedButton() const { + return _clickedButton; +} + +void MessageDialog::click(StandardButton button, QPlatformDialogHelper::ButtonRole) { + _clickedButton = button; + if (_resultCallback) { + _resultCallback(QMessageBox::StandardButton(_clickedButton)); + } + hide(); +} + +void MessageDialog::accept() { + // enter key is treated like OK + if (_clickedButton == NoButton) + _clickedButton = Ok; + if (_resultCallback) { + _resultCallback(QMessageBox::StandardButton(_clickedButton)); + } + OffscreenQmlDialog::accept(); +} + +void MessageDialog::reject() { + // escape key is treated like cancel + if (_clickedButton == NoButton) + _clickedButton = Cancel; + if (_resultCallback) { + _resultCallback(QMessageBox::StandardButton(_clickedButton)); + } + OffscreenQmlDialog::reject(); +} + +void MessageDialog::setResultCallback(OffscreenUi::ButtonCallback callback) { + _resultCallback = callback; +} diff --git a/libraries/ui/src/MessageDialog.h b/libraries/ui/src/MessageDialog.h new file mode 100644 index 0000000000..8b5a895068 --- /dev/null +++ b/libraries/ui/src/MessageDialog.h @@ -0,0 +1,98 @@ +// +// MessageDialog.h +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 +// + +#pragma once +#ifndef hifi_MessageDialog_h +#define hifi_MessageDialog_h + +#include "OffscreenQmlDialog.h" +#include <5.4.1/QtGui/qpa/qplatformdialoghelper.h> + +class MessageDialog : public OffscreenQmlDialog +{ + Q_OBJECT + QML_DIALOG_DECL + +private: + Q_ENUMS(Icon) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QString informativeText READ informativeText WRITE setInformativeText NOTIFY informativeTextChanged) + Q_PROPERTY(QString detailedText READ detailedText WRITE setDetailedText NOTIFY detailedTextChanged) + Q_PROPERTY(Icon icon READ icon WRITE setIcon NOTIFY iconChanged) + Q_PROPERTY(QUrl standardIconSource READ standardIconSource NOTIFY iconChanged) + Q_PROPERTY(StandardButtons standardButtons READ standardButtons WRITE setStandardButtons NOTIFY standardButtonsChanged) + Q_PROPERTY(StandardButton clickedButton READ clickedButton NOTIFY buttonClicked) + +public: + enum Icon { + NoIcon = QMessageDialogOptions::NoIcon, + Information = QMessageDialogOptions::Information, + Warning = QMessageDialogOptions::Warning, + Critical = QMessageDialogOptions::Critical, + Question = QMessageDialogOptions::Question + }; + + + MessageDialog(QQuickItem *parent = 0); + virtual ~MessageDialog(); + + QString text() const; + QString informativeText() const; + QString detailedText() const; + Icon icon() const; + +public slots: + virtual void setVisible(bool v); + void setText(const QString &arg); + void setInformativeText(const QString &arg); + void setDetailedText(const QString &arg); + void setIcon(Icon icon); + void setStandardButtons(StandardButtons buttons); + void setResultCallback(OffscreenUi::ButtonCallback callback); + void click(StandardButton button); + QUrl standardIconSource(); + StandardButtons standardButtons() const; + StandardButton clickedButton() const; + +signals: + void textChanged(); + void informativeTextChanged(); + void detailedTextChanged(); + void iconChanged(); + void standardButtonsChanged(); + void buttonClicked(); + void discard(); + void help(); + void yes(); + void no(); + void apply(); + void reset(); + +protected slots: + virtual void click(StandardButton button, QPlatformDialogHelper::ButtonRole); + virtual void accept(); + virtual void reject(); + +private: + QString _title; + QString _text; + QString _informativeText; + QString _detailedText; + Icon _icon{ Information }; + StandardButtons _buttons; + StandardButton _clickedButton{ NoButton }; + OffscreenUi::ButtonCallback _resultCallback; +}; + +#endif // hifi_MessageDialog_h + + + + diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/ui/src/OffscreenQmlDialog.cpp similarity index 55% rename from libraries/render-utils/src/OffscreenQmlDialog.cpp rename to libraries/ui/src/OffscreenQmlDialog.cpp index d1e060245d..dbd621ad85 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.cpp +++ b/libraries/ui/src/OffscreenQmlDialog.cpp @@ -13,6 +13,30 @@ OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem* parent) : QQuickItem(parent) { } +OffscreenQmlDialog::~OffscreenQmlDialog() { +} + void OffscreenQmlDialog::hide() { static_cast(parent())->setEnabled(false); } + +QString OffscreenQmlDialog::title() const { + return _title; +} + +void OffscreenQmlDialog::setTitle(const QString &arg) { + if (arg != _title) { + _title = arg; + emit titleChanged(); + } +} + +void OffscreenQmlDialog::accept() { + hide(); + emit accepted(); +} + +void OffscreenQmlDialog::reject() { + hide(); + emit rejected(); +} diff --git a/libraries/ui/src/OffscreenQmlDialog.h b/libraries/ui/src/OffscreenQmlDialog.h new file mode 100644 index 0000000000..7b7c83ad65 --- /dev/null +++ b/libraries/ui/src/OffscreenQmlDialog.h @@ -0,0 +1,104 @@ +// +// OffscreenQmlDialog.h +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 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 +// + +#pragma once +#ifndef hifi_OffscreenQmlDialog_h +#define hifi_OffscreenQmlDialog_h + +#include +#include <5.4.1/QtGui/qpa/qplatformdialoghelper.h> + +#include "OffscreenUi.h" + +#define QML_DIALOG_DECL \ +private: \ + static const QString NAME; \ + static const QUrl QML; \ +public: \ + static void registerType(); \ + static void show(std::function f = [](QQmlContext*, QObject*) {}); \ + static void toggle(std::function f = [](QQmlContext*, QObject*) {}); \ +private: + +#define QML_DIALOG_DEF(x) \ + const QUrl x::QML = QUrl(#x ".qml"); \ + const QString x::NAME = #x; \ + \ + void x::registerType() { \ + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ + } \ + \ + void x::show(std::function f) { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->show(QML, NAME, f); \ + } \ + \ + void x::toggle(std::function f) { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->toggle(QML, NAME, f); \ + } + +class OffscreenQmlDialog : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + Q_ENUMS(StandardButton) + Q_FLAGS(StandardButtons) + +public: + OffscreenQmlDialog(QQuickItem* parent = nullptr); + virtual ~OffscreenQmlDialog(); + + enum StandardButton { + NoButton = QPlatformDialogHelper::NoButton, + Ok = QPlatformDialogHelper::Ok, + Save = QPlatformDialogHelper::Save, + SaveAll = QPlatformDialogHelper::SaveAll, + Open = QPlatformDialogHelper::Open, + Yes = QPlatformDialogHelper::Yes, + YesToAll = QPlatformDialogHelper::YesToAll, + No = QPlatformDialogHelper::No, + NoToAll = QPlatformDialogHelper::NoToAll, + Abort = QPlatformDialogHelper::Abort, + Retry = QPlatformDialogHelper::Retry, + Ignore = QPlatformDialogHelper::Ignore, + Close = QPlatformDialogHelper::Close, + Cancel = QPlatformDialogHelper::Cancel, + Discard = QPlatformDialogHelper::Discard, + Help = QPlatformDialogHelper::Help, + Apply = QPlatformDialogHelper::Apply, + Reset = QPlatformDialogHelper::Reset, + RestoreDefaults = QPlatformDialogHelper::RestoreDefaults, + NButtons + }; + Q_DECLARE_FLAGS(StandardButtons, StandardButton) + +protected: + void hide(); + virtual void accept(); + virtual void reject(); + +public: + QString title() const; + void setTitle(const QString &arg); + +signals: + void accepted(); + void rejected(); + void titleChanged(); + +private: + QString _title; + +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(OffscreenQmlDialog::StandardButtons) + +#endif diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp similarity index 83% rename from libraries/render-utils/src/OffscreenUi.cpp rename to libraries/ui/src/OffscreenUi.cpp index 837affab59..7b84bb763f 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -13,6 +13,11 @@ #include #include #include +#include "MessageDialog.h" + + +Q_DECLARE_LOGGING_CATEGORY(offscreenFocus) +Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus") // Time between receiving a request to render the offscreen UI actually triggering // the render. Could possibly be increased depending on the framerate we expect to @@ -92,10 +97,10 @@ void OffscreenUi::create(QOpenGLContext* shareContext) { #ifdef DEBUG connect(_quickWindow, &QQuickWindow::focusObjectChanged, [this]{ - qDebug() << "New focus item " << _quickWindow->focusObject(); + qCDebug(offscreenFocus) << "New focus item " << _quickWindow->focusObject(); }); connect(_quickWindow, &QQuickWindow::activeFocusItemChanged, [this] { - qDebug() << "New active focus item " << _quickWindow->activeFocusItem(); + qCDebug(offscreenFocus) << "New active focus item " << _quickWindow->activeFocusItem(); }); #endif @@ -117,36 +122,45 @@ void OffscreenUi::resize(const QSize& newSize) { qDebug() << "Offscreen UI resizing to " << newSize.width() << "x" << newSize.height() << " with pixel ratio " << pixelRatio; _fboCache.setSize(newSize * pixelRatio); + if (_quickWindow) { + _quickWindow->setGeometry(QRect(QPoint(), newSize)); + } + + _quickWindow->contentItem()->setSize(newSize); + // Update our members if (_rootItem) { _rootItem->setSize(newSize); } - if (_quickWindow) { - _quickWindow->setGeometry(QRect(QPoint(), newSize)); - } - doneCurrent(); } -QQmlContext* OffscreenUi::qmlContext() { - if (nullptr == _rootItem) { - return _qmlComponent->creationContext(); - } - return QQmlEngine::contextForObject(_rootItem); +QQuickItem* OffscreenUi::getRootItem() { + return _rootItem; } +//QQmlContext* OffscreenUi::qmlContext() { +// if (nullptr == _rootItem) { +// return _qmlComponent->creationContext(); +// } +// return QQmlEngine::contextForObject(_rootItem); +//} + void OffscreenUi::setBaseUrl(const QUrl& baseUrl) { _qmlEngine->setBaseUrl(baseUrl); } -void OffscreenUi::load(const QUrl& qmlSource, std::function f) { +void OffscreenUi::load(const QUrl& qmlSource, std::function f) { qDebug() << "Loading QML from URL " << qmlSource; _qmlComponent->loadUrl(qmlSource); - if (_qmlComponent->isLoading()) { - connect(_qmlComponent, &QQmlComponent::statusChanged, this, []{}); - } else { - finishQmlLoad(); + if (_qmlComponent->isLoading()) + connect(_qmlComponent, &QQmlComponent::statusChanged, this, + [this, f](QQmlComponent::Status){ + finishQmlLoad(f); + }); + else { + finishQmlLoad(f); } } @@ -163,8 +177,8 @@ void OffscreenUi::requestRender() { } } -void OffscreenUi::finishQmlLoad() { - disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad); +void OffscreenUi::finishQmlLoad(std::function f) { + disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, 0); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); foreach(const QQmlError &error, errorList) { @@ -173,7 +187,8 @@ void OffscreenUi::finishQmlLoad() { return; } - QObject* newObject = _qmlComponent->create(); + QQmlContext * newContext = new QQmlContext(_qmlEngine, qApp); + QObject* newObject = _qmlComponent->beginCreate(newContext); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); foreach(const QQmlError &error, errorList) @@ -184,9 +199,13 @@ void OffscreenUi::finishQmlLoad() { return; } + f(newContext, newObject); + _qmlComponent->completeCreate(); + QQuickItem* newItem = qobject_cast(newObject); if (!newItem) { qWarning("run: Not a QQuickItem"); + return; delete newObject; if (!_rootItem) { qFatal("Unable to find root QQuickItem"); @@ -197,18 +216,17 @@ void OffscreenUi::finishQmlLoad() { // Make sure we make items focusable (critical for // supporting keyboard shortcuts) newItem->setFlag(QQuickItem::ItemIsFocusScope, true); - if (!_rootItem) { // The root item is ready. Associate it with the window. _rootItem = newItem; _rootItem->setParentItem(_quickWindow->contentItem()); _rootItem->setSize(_quickWindow->renderTargetSize()); + _rootItem->forceActiveFocus(); } else { // Allow child windows to be destroyed from JS QQmlEngine::setObjectOwnership(newItem, QQmlEngine::JavaScriptOwnership); newItem->setParent(_rootItem); newItem->setParentItem(_rootItem); - newItem->setEnabled(true); } } @@ -390,54 +408,62 @@ void OffscreenUi::setProxyWindow(QWindow* window) { _renderControl->_renderWindow = window; } -void OffscreenUi::show(const QUrl& url, const QString& name) { +void OffscreenUi::show(const QUrl& url, const QString& name, std::function f) { QQuickItem* item = _rootItem->findChild(name); // First load? if (!item) { - load(url); - return; + load(url, f); + item = _rootItem->findChild(name); } item->setEnabled(true); } -void OffscreenUi::toggle(const QUrl& url, const QString& name) { +void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function f) { QQuickItem* item = _rootItem->findChild(name); // First load? if (!item) { - load(url); - return; + load(url, f); + item = _rootItem->findChild(name); } item->setEnabled(!item->isEnabled()); } void OffscreenUi::messageBox(const QString& title, const QString& text, + ButtonCallback callback, QMessageBox::Icon icon, - QMessageBox::StandardButtons buttons, - ButtonCallback f) { + QMessageBox::StandardButtons buttons) { + MessageDialog::show([=](QQmlContext*ctx, QObject*item) { + MessageDialog * pDialog = item->findChild(); + pDialog->setIcon((MessageDialog::Icon)icon); + pDialog->setTitle(title); + pDialog->setText(text); + pDialog->setStandardButtons(MessageDialog::StandardButtons((int)buttons)); + pDialog->setResultCallback(callback); + }); } void OffscreenUi::information(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons, - ButtonCallback callback) { - callback(QMessageBox::information(nullptr, title, text, buttons)); + ButtonCallback callback, + QMessageBox::StandardButtons buttons) { + messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Information, buttons); } void OffscreenUi::question(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons, - ButtonCallback callback) { - callback(QMessageBox::question(nullptr, title, text, buttons)); + ButtonCallback callback, + QMessageBox::StandardButtons buttons) { + messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Question, buttons); } void OffscreenUi::warning(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons, - ButtonCallback callback) { - callback(QMessageBox::warning(nullptr, title, text, buttons)); + ButtonCallback callback, + QMessageBox::StandardButtons buttons) { + messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Warning, buttons); } void OffscreenUi::critical(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons, - ButtonCallback callback) { - callback(QMessageBox::critical(nullptr, title, text, buttons)); + ButtonCallback callback, + QMessageBox::StandardButtons buttons) { + messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Critical, buttons); } diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h similarity index 52% rename from libraries/render-utils/src/OffscreenUi.h rename to libraries/ui/src/OffscreenUi.h index c64d0d833c..b58b4e59cb 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -32,6 +32,69 @@ #include "FboCache.h" #include +#define HIFI_QML_DECL \ +private: \ + static const QString NAME; \ + static const QUrl QML; \ +public: \ + static void registerType(); \ + static void show(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void toggle(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void load(std::function f = [](QQmlContext*, QQuickItem*) {}); \ +private: + +#define HIFI_QML_DECL_LAMBDA \ +protected: \ + static const QString NAME; \ + static const QUrl QML; \ +public: \ + static void registerType(); \ + static void show(); \ + static void toggle(); \ + static void load(); \ +private: + +#define HIFI_QML_DEF(x) \ + const QUrl x::QML = QUrl(#x ".qml"); \ + const QString x::NAME = #x; \ + \ + void x::registerType() { \ + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ + } \ + \ + void x::show(std::function f) { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->show(QML, NAME, f); \ + } \ + \ + void x::toggle(std::function f) { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->toggle(QML, NAME, f); \ + } \ + void x::load(std::function f) { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->load(QML, f); \ + } + +#define HIFI_QML_DEF_LAMBDA(x, f) \ + const QUrl x::QML = QUrl(#x ".qml"); \ + const QString x::NAME = #x; \ + \ + void x::registerType() { \ + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ + } \ + void x::show() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->show(QML, NAME, f); \ + } \ + void x::toggle() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->toggle(QML, NAME, f); \ + } \ + void x::load() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->load(QML, f); \ + } class OffscreenUi : public OffscreenGlCanvas, public Dependency { Q_OBJECT @@ -59,16 +122,16 @@ public: virtual ~OffscreenUi(); void create(QOpenGLContext* context); void resize(const QSize& size); - void load(const QUrl& qmlSource, std::function f = [](QQmlContext*) {}); - void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*) {}) { + void load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); + void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { load(QUrl(qmlSourceFile), f); } - void show(const QUrl& url, const QString& name); - void toggle(const QUrl& url, const QString& name); + void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); + void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); void setBaseUrl(const QUrl& baseUrl); void addImportPath(const QString& path); - QQmlContext* qmlContext(); - + //QQmlContext* getQmlContext(); + QQuickItem* getRootItem(); void pause(); void resume(); bool isPaused() const; @@ -86,31 +149,31 @@ public: static ButtonCallback NO_OP_CALLBACK; static void messageBox(const QString& title, const QString& text, + ButtonCallback f, QMessageBox::Icon icon, - QMessageBox::StandardButtons buttons, - ButtonCallback f); + QMessageBox::StandardButtons buttons); static void information(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok, - ButtonCallback callback = NO_OP_CALLBACK); + ButtonCallback callback = NO_OP_CALLBACK, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); static void question(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), - ButtonCallback callback = [](QMessageBox::StandardButton) {}); + ButtonCallback callback = NO_OP_CALLBACK, + QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No)); static void warning(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok, - ButtonCallback callback = [](QMessageBox::StandardButton) {}); + ButtonCallback callback = NO_OP_CALLBACK, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); static void critical(const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok, - ButtonCallback callback = [](QMessageBox::StandardButton) {}); + ButtonCallback callback = NO_OP_CALLBACK, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); protected: private slots: void updateQuick(); - void finishQmlLoad(); + void finishQmlLoad(std::function f); public slots: void requestUpdate(); diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 9d7363c241..5e45bf23a2 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -10,7 +10,6 @@ #include "TextRenderer.h" #include "MatrixStack.h" -#include "OffscreenUi.h" #include #include @@ -27,6 +26,7 @@ #include #include #include + #include #include #include @@ -80,6 +80,7 @@ const QString& getQmlDir() { } return dir; } + // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { Q_OBJECT @@ -88,24 +89,17 @@ class QTestWindow : public QWindow { QSize _size; TextRenderer* _textRenderer[4]; RateCounter fps; - int testQmlTexture{ 0 }; - //ProgramPtr _planeProgam; - //ShapeWrapperPtr _planeShape; protected: - void renderText(); - void renderQml(); private: void resizeWindow(const QSize& size) { _size = size; - DependencyManager::get()->resize(_size); } public: QTestWindow() { - DependencyManager::set(); setSurfaceType(QSurface::OpenGLSurface); QSurfaceFormat format; @@ -165,30 +159,10 @@ public: glClearColor(0.2f, 0.2f, 0.2f, 1); glDisable(GL_DEPTH_TEST); - auto offscreenUi = DependencyManager::get(); - offscreenUi->create(_context); - // FIXME, need to switch to a QWindow for mouse and keyboard input to work - offscreenUi->setProxyWindow(this); - // "#0e7077" + makeCurrent(); + setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); - - offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); - offscreenUi->load(QUrl("TestRoot.qml")); - offscreenUi->addImportPath(getQmlDir()); - offscreenUi->addImportPath("."); - - connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { - offscreenUi->lockTexture(textureId); - assert(!glGetError()); - GLuint oldTexture = testQmlTexture; - testQmlTexture = textureId; - if (oldTexture) { - offscreenUi->releaseTexture(oldTexture); - } - }); - installEventFilter(offscreenUi.data()); - offscreenUi->resume(); } virtual ~QTestWindow() { @@ -204,28 +178,6 @@ protected: void resizeEvent(QResizeEvent* ev) override { resizeWindow(ev->size()); } - - - void keyPressEvent(QKeyEvent* event) { - switch (event->key()) { - case Qt::Key_L: - if (event->modifiers() & Qt::CTRL) { - DependencyManager::get()->toggle(QString("TestDialog.qml"), "TestDialog"); - } - break; - } - QWindow::keyPressEvent(event); - } - - void moveEvent(QMoveEvent* event) { - static qreal oldPixelRatio = 0.0; - if (devicePixelRatio() != oldPixelRatio) { - oldPixelRatio = devicePixelRatio(); - resizeWindow(size()); - } - - QWindow::moveEvent(event); - } }; #ifndef SERIF_FONT_FAMILY @@ -282,39 +234,16 @@ void QTestWindow::renderText() { } } -void QTestWindow::renderQml() { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - if (testQmlTexture > 0) { - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, testQmlTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - glBegin(GL_QUADS); - { - glTexCoord2f(0, 0); - glVertex2f(-1, -1); - glTexCoord2f(0, 1); - glVertex2f(-1, 1); - glTexCoord2f(1, 1); - glVertex2f(1, 1); - glTexCoord2f(1, 0); - glVertex2f(1, -1); - } - glEnd(); -} - void QTestWindow::draw() { + if (!isVisible()) { + return; + } + makeCurrent(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); - //renderText(); - renderQml(); + renderText(); _context->swapBuffers(this); glFinish(); @@ -327,10 +256,8 @@ void QTestWindow::draw() { } int main(int argc, char** argv) { - QApplication app(argc, argv); - //QLoggingCategory::setFilterRules("qt.quick.mouse.debug = true"); + QGuiApplication app(argc, argv); QTestWindow window; - QTimer timer; timer.setInterval(1); app.connect(&timer, &QTimer::timeout, &app, [&] { diff --git a/tests/ui/CMakeLists.txt b/tests/ui/CMakeLists.txt new file mode 100644 index 0000000000..3ff8555fa2 --- /dev/null +++ b/tests/ui/CMakeLists.txt @@ -0,0 +1,15 @@ +set(TARGET_NAME ui-tests) + +setup_hifi_project(Widgets OpenGL Network Qml Quick Script) + +if (WIN32) + add_dependency_external_projects(glew) + find_package(GLEW REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} wsock32.lib opengl32.lib Winmm.lib) +endif() + +# link in the shared libraries +link_hifi_libraries(ui render-utils gpu shared) + +copy_dlls_beside_windows_executable() \ No newline at end of file diff --git a/tests/ui/main.qml b/tests/ui/main.qml new file mode 100644 index 0000000000..168b9fb291 --- /dev/null +++ b/tests/ui/main.qml @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Controls 1.2 +import "qml/UI.js" as UI +import "qml" +//import "/Users/bdavis/Git/hifi/interface/resources/qml" + +Item { + anchors.fill: parent + visible: true + //title: "Qt Quick Controls Gallery" + + MessageDialog { + id: aboutDialog + icon: StandardIcon.Information + title: "About" + text: "Qt Quick Controls Gallery" + informativeText: "This example demonstrates most of the available Qt Quick Controls." + } + + Action { + id: copyAction + text: "&Copy" + shortcut: StandardKey.Copy + iconName: "edit-copy" + enabled: (!!activeFocusItem && !!activeFocusItem["copy"]) + onTriggered: activeFocusItem.copy() + } + + Action { + id: cutAction + text: "Cu&t" + shortcut: StandardKey.Cut + iconName: "edit-cut" + enabled: (!!activeFocusItem && !!activeFocusItem["cut"]) + onTriggered: activeFocusItem.cut() + } + + Action { + id: pasteAction + text: "&Paste" + shortcut: StandardKey.Paste + iconName: "edit-paste" + enabled: (!!activeFocusItem && !!activeFocusItem["paste"]) + onTriggered: activeFocusItem.paste() + } + +// toolBar: ToolBar { +// RowLayout { +// anchors.fill: parent +// anchors.margins: spacing +// Label { +// text: UI.label +// } +// Item { Layout.fillWidth: true } +// CheckBox { +// id: enabler +// text: "Enabled" +// checked: true +// } +// } +// } + +// menuBar: MenuBar { +// Menu { +// title: "&File" +// MenuItem { +// text: "E&xit" +// shortcut: StandardKey.Quit +// onTriggered: Qt.quit() +// } +// } +// Menu { +// title: "&Edit" +// visible: tabView.currentIndex == 2 +// MenuItem { action: cutAction } +// MenuItem { action: copyAction } +// MenuItem { action: pasteAction } +// } +// Menu { +// title: "&Help" +// MenuItem { +// text: "About..." +// onTriggered: aboutDialog.open() +// } +// } +// } + + TabView { + id: tabView + + anchors.fill: parent + anchors.margins: UI.margin + tabPosition: UI.tabPosition + + Layout.minimumWidth: 360 + Layout.minimumHeight: 360 + Layout.preferredWidth: 480 + Layout.preferredHeight: 640 + + Tab { + title: "Buttons" + ButtonPage { + enabled: enabler.checked + } + } + Tab { + title: "Progress" + ProgressPage { + enabled: enabler.checked + } + } + Tab { + title: "Input" + InputPage { + enabled: enabler.checked + } + } + } +} diff --git a/tests/ui/qml/ButtonPage.qml b/tests/ui/qml/ButtonPage.qml new file mode 100644 index 0000000000..0ed7e2d6ad --- /dev/null +++ b/tests/ui/qml/ButtonPage.qml @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 + +ScrollView { + id: page + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + Item { + id: content + + width: Math.max(page.viewport.width, grid.implicitWidth + 2 * grid.rowSpacing) + height: Math.max(page.viewport.height, grid.implicitHeight + 2 * grid.columnSpacing) + + GridLayout { + id: grid + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: grid.rowSpacing + anchors.rightMargin: grid.rowSpacing + anchors.topMargin: grid.columnSpacing + + columns: page.width < page.height ? 1 : 2 + + GroupBox { + title: "Button" + Layout.fillWidth: true + Layout.columnSpan: grid.columns + RowLayout { + anchors.fill: parent + Button { text: "OK"; isDefault: true } + Button { text: "Cancel" } + Item { Layout.fillWidth: true } + Button { + text: "Attach" + menu: Menu { + MenuItem { text: "Image" } + MenuItem { text: "Document" } + } + } + } + } + + GroupBox { + title: "CheckBox" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + CheckBox { text: "E-mail"; checked: true } + CheckBox { text: "Calendar"; checked: true } + CheckBox { text: "Contacts" } + } + } + + GroupBox { + title: "RadioButton" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + ExclusiveGroup { id: radioGroup } + RadioButton { text: "Portrait"; exclusiveGroup: radioGroup } + RadioButton { text: "Landscape"; exclusiveGroup: radioGroup } + RadioButton { text: "Automatic"; exclusiveGroup: radioGroup; checked: true } + } + } + + GroupBox { + title: "Switch" + Layout.fillWidth: true + Layout.columnSpan: grid.columns + ColumnLayout { + anchors.fill: parent + RowLayout { + Label { text: "Wi-Fi"; Layout.fillWidth: true } + Switch { checked: true } + } + RowLayout { + Label { text: "Bluetooth"; Layout.fillWidth: true } + Switch { checked: false } + } + } + } + } + } +} diff --git a/tests/ui/qml/InputPage.qml b/tests/ui/qml/InputPage.qml new file mode 100644 index 0000000000..cb1878d023 --- /dev/null +++ b/tests/ui/qml/InputPage.qml @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 + +ScrollView { + id: page + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + Item { + id: content + + width: Math.max(page.viewport.width, column.implicitWidth + 2 * column.spacing) + height: Math.max(page.viewport.height, column.implicitHeight + 2 * column.spacing) + + ColumnLayout { + id: column + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: column.spacing + + GroupBox { + title: "TextField" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + TextField { placeholderText: "..."; Layout.fillWidth: true; z: 1 } + TextField { placeholderText: "Password"; echoMode: TextInput.Password; Layout.fillWidth: true } + } + } + + GroupBox { + title: "ComboBox" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + ComboBox { + model: Qt.fontFamilies() + Layout.fillWidth: true + } + ComboBox { + editable: true + model: ListModel { + id: listModel + ListElement { text: "Apple" } + ListElement { text: "Banana" } + ListElement { text: "Coconut" } + ListElement { text: "Orange" } + } + onAccepted: { + if (find(currentText) === -1) { + listModel.append({text: editText}) + currentIndex = find(editText) + } + } + Layout.fillWidth: true + } + } + } + + GroupBox { + title: "SpinBox" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + SpinBox { value: 99; Layout.fillWidth: true; z: 1 } + SpinBox { decimals: 2; Layout.fillWidth: true } + } + } + } + } +} diff --git a/tests/ui/qml/ProgressPage.qml b/tests/ui/qml/ProgressPage.qml new file mode 100644 index 0000000000..a1fa596f79 --- /dev/null +++ b/tests/ui/qml/ProgressPage.qml @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 + +ScrollView { + id: page + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + Item { + id: content + + width: Math.max(page.viewport.width, column.implicitWidth + 2 * column.spacing) + height: Math.max(page.viewport.height, column.implicitHeight + 2 * column.spacing) + + ColumnLayout { + id: column + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: column.spacing + + GroupBox { + title: "ProgressBar" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + ProgressBar { indeterminate: true; Layout.fillWidth: true } + ProgressBar { value: slider.value; Layout.fillWidth: true } + } + } + + GroupBox { + title: "Slider" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + Slider { id: slider; value: 0.5; Layout.fillWidth: true } + } + } + + GroupBox { + title: "BusyIndicator" + Layout.fillWidth: true + BusyIndicator { running: true } + } + } + } +} diff --git a/tests/ui/qml/UI.js b/tests/ui/qml/UI.js new file mode 100644 index 0000000000..0286ac56a6 --- /dev/null +++ b/tests/ui/qml/UI.js @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +.pragma library + +var margin = 2 +var tabPosition = Qt.TopEdge +var label = "" diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp new file mode 100644 index 0000000000..4189282de1 --- /dev/null +++ b/tests/ui/src/main.cpp @@ -0,0 +1,336 @@ +// +// main.cpp +// tests/render-utils/src +// +// 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 "OffscreenUi.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "MessageDialog.h" +#include "HifiMenu.h" + +class RateCounter { + std::vector times; + QElapsedTimer timer; +public: + RateCounter() { + timer.start(); + } + + void reset() { + times.clear(); + } + + unsigned int count() const { + return times.size() - 1; + } + + float elapsed() const { + if (times.size() < 1) { + return 0.0f; + } + float elapsed = *times.rbegin() - *times.begin(); + return elapsed; + } + + void increment() { + times.push_back(timer.elapsed() / 1000.0f); + } + + float rate() const { + if (elapsed() == 0.0f) { + return NAN; + } + return (float) count() / elapsed(); + } +}; + + +const QString & getQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/qml/")) + "/"; + qDebug() << "Qml Path: " << dir; + } + return dir; +} + +const QString & getTestQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; + qDebug() << "Qml Test Path: " << dir; + } + return dir; +} + +// Create a simple OpenGL window that renders text in various ways +class QTestWindow : public QWindow, private QOpenGLFunctions { + Q_OBJECT + + QOpenGLContext * _context{ nullptr }; + QSize _size; + bool _altPressed{ false }; + RateCounter fps; + QTimer _timer; + int testQmlTexture{ 0 }; + +public: + QObject * rootMenu; + + QTestWindow() { + _timer.setInterval(1); + connect(&_timer, &QTimer::timeout, [=] { + draw(); + }); + + DependencyManager::set(); + setSurfaceType(QSurface::OpenGLSurface); + + QSurfaceFormat format; + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + format.setVersion(4, 1); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + format.setOption(QSurfaceFormat::DebugContext); + + setFormat(format); + + _context = new QOpenGLContext; + _context->setFormat(format); + if (!_context->create()) { + qFatal("Could not create OpenGL context"); + } + + show(); + makeCurrent(); + initializeOpenGLFunctions(); + + { + QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + logger->initialize(); // initializes in the current context, i.e. ctx + logger->enableMessages(); + connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { + qDebug() << debugMessage; + }); + // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); + } + + qDebug() << (const char*)this->glGetString(GL_VERSION); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glClearColor(0.2f, 0.2f, 0.2f, 1); + glDisable(GL_DEPTH_TEST); + + MessageDialog::registerType(); + HifiMenu::registerType(); + + auto offscreenUi = DependencyManager::get(); + offscreenUi->create(_context); + connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { + offscreenUi->lockTexture(textureId); + assert(!glGetError()); + GLuint oldTexture = testQmlTexture; + testQmlTexture = textureId; + if (oldTexture) { + offscreenUi->releaseTexture(oldTexture); + } + }); + + makeCurrent(); + + offscreenUi->setProxyWindow(this); + setFramePosition(QPoint(-1000, 0)); + resize(QSize(800, 600)); + +#ifdef QML_CONTROL_GALLERY + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir())); + offscreenUi->load(QUrl("main.qml")); +#else + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); + offscreenUi->load(QUrl("TestRoot.qml")); + offscreenUi->load(QUrl("RootMenu.qml")); + HifiMenu::load(); + QObject* menuObject = offscreenUi->getRootItem()->findChild("HifiMenu"); + HifiMenu* menu = offscreenUi->getRootItem()->findChild(); + menu->addMenu("", "File"); + menu->addMenuItem("File", "Quit", []{ + QApplication::quit(); + }); + menu->addCheckableMenuItem("File", "Toggle", false, [](bool toggled) { + qDebug() << "Toggle is " << toggled; + }); + menu->addMenu("", "Edit"); + menu->addMenuItem("Edit", "Undo"); + menu->addMenuItem("Edit", "Redo"); + menu->addMenuItem("Edit", "Copy"); + menu->addMenuItem("Edit", "Cut"); + menu->addMenuItem("Edit", "Paste"); + menu->addMenu("", "Long Menu Name..."); +#endif + installEventFilter(offscreenUi.data()); + offscreenUi->resume(); + _timer.start(); + } + + virtual ~QTestWindow() { + DependencyManager::destroy(); + } + +private: + void draw() { + if (!isVisible()) { + return; + } + + makeCurrent(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); + + renderQml(); + + _context->swapBuffers(this); + glFinish(); + + fps.increment(); + if (fps.elapsed() >= 2.0f) { + qDebug() << "FPS: " << fps.rate(); + fps.reset(); + } + } + + void makeCurrent() { + _context->makeCurrent(this); + } + + void renderQml(); + + void resizeWindow(const QSize & size) { + _size = size; + DependencyManager::get()->resize(_size); + } + + +protected: + void resizeEvent(QResizeEvent * ev) override { + resizeWindow(ev->size()); + } + + + void keyPressEvent(QKeyEvent *event) { + _altPressed = Qt::Key_Alt == event->key(); + switch (event->key()) { + case Qt::Key_L: + if (event->modifiers() & Qt::CTRL) { + auto offscreenUi = DependencyManager::get(); + HifiMenu * menu = offscreenUi->findChild(); + menu->addMenuItem("", "Test 3"); + menu->addMenuItem("File", "Test 3"); + } + break; + case Qt::Key_K: + if (event->modifiers() & Qt::CTRL) { + OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){ + qDebug() << b; + }); + } + break; + case Qt::Key_J: + if (event->modifiers() & Qt::CTRL) { + auto offscreenUi = DependencyManager::get(); + rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); + QMetaObject::invokeMethod(rootMenu, "popup"); + } + break; + } + QWindow::keyPressEvent(event); + } + QQmlContext* menuContext{ nullptr }; + void keyReleaseEvent(QKeyEvent *event) { + if (_altPressed && Qt::Key_Alt == event->key()) { + HifiMenu::toggle(); + } + } + + void moveEvent(QMoveEvent *event) { + static qreal oldPixelRatio = 0.0; + if (devicePixelRatio() != oldPixelRatio) { + oldPixelRatio = devicePixelRatio(); + resizeWindow(size()); + } + QWindow::moveEvent(event); + } +}; + +void QTestWindow::renderQml() { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + if (testQmlTexture > 0) { + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, testQmlTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + glBegin(GL_QUADS); + { + glTexCoord2f(0, 0); + glVertex2f(-1, -1); + glTexCoord2f(0, 1); + glVertex2f(-1, 1); + glTexCoord2f(1, 1); + glVertex2f(1, 1); + glTexCoord2f(1, 0); + glVertex2f(1, -1); + } + glEnd(); +} + + +const char * LOG_FILTER_RULES = R"V0G0N( +*.debug=false +qt.quick.mouse.debug=false +)V0G0N"; + +int main(int argc, char** argv) { + QGuiApplication app(argc, argv); +// QLoggingCategory::setFilterRules(LOG_FILTER_RULES); + QTestWindow window; + app.exec(); + return 0; +} + +#include "main.moc" From 0a9398808f2e140f77e4d631fecf78c517e9aa42 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 24 Apr 2015 13:25:30 -0700 Subject: [PATCH 302/401] CR comments --- libraries/render-utils/src/OffscreenUi.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 837affab59..ac78317703 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -318,8 +318,6 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { case QEvent::KeyPress: case QEvent::KeyRelease: { event->ignore(); - //if (_quickWindow->activeFocusItem()) { - // _quickWindow->sendEvent(_quickWindow->activeFocusItem(), event); if (QCoreApplication::sendEvent(_quickWindow, event)) { return event->isAccepted(); } From c4395e75bb40f2d208ad63201e1436732cef8c7c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 22 Apr 2015 11:20:38 -0700 Subject: [PATCH 303/401] cleanup and comments --- interface/src/avatar/AvatarManager.h | 2 +- libraries/physics/src/DynamicCharacterController.cpp | 8 ++++---- libraries/physics/src/PhysicsEngine.cpp | 1 + libraries/physics/src/PhysicsEngine.h | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 4912fabd33..1a833c5106 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -59,7 +59,7 @@ private: AvatarSharedPointer newSharedAvatar(); - // virtual override + // virtual overrides AvatarHash::iterator erase(const AvatarHash::iterator& iterator); QVector _avatarFades; diff --git a/libraries/physics/src/DynamicCharacterController.cpp b/libraries/physics/src/DynamicCharacterController.cpp index 46ff2e524e..f05dc11c5c 100644 --- a/libraries/physics/src/DynamicCharacterController.cpp +++ b/libraries/physics/src/DynamicCharacterController.cpp @@ -96,7 +96,7 @@ void DynamicCharacterController::preStep(btCollisionWorld* collisionWorld) { } } -void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld,btScalar dt) { +void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { btVector3 actualVelocity = _rigidBody->getLinearVelocity(); btScalar actualSpeed = actualVelocity.length(); @@ -317,10 +317,10 @@ void DynamicCharacterController::updateShapeIfNecessary() { float mass = 1.0f; btVector3 inertia(1.0f, 1.0f, 1.0f); _rigidBody = new btRigidBody(mass, NULL, _shape, inertia); - _rigidBody->setSleepingThresholds (0.0f, 0.0f); - _rigidBody->setAngularFactor (0.0f); + _rigidBody->setSleepingThresholds(0.0f, 0.0f); + _rigidBody->setAngularFactor(0.0f); _rigidBody->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), - glmToBullet(_avatarData->getPosition()))); + glmToBullet(_avatarData->getPosition()))); if (_isHovering) { _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); } else { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 45f3c97e30..75bab97d38 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -15,6 +15,7 @@ #include "ShapeInfoUtil.h" #include "PhysicsHelpers.h" #include "ThreadSafeDynamicsWorld.h" +#include "PhysicsLogging.h" static uint32_t _numSubsteps; diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 148261c6d2..af140f0f24 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -39,8 +39,8 @@ public: ContactKey(void* a, void* b) : _a(a), _b(b) {} bool operator<(const ContactKey& other) const { return _a < other._a || (_a == other._a && _b < other._b); } bool operator==(const ContactKey& other) const { return _a == other._a && _b == other._b; } - void* _a; - void* _b; + void* _a; // EntityMotionState pointer + void* _b; // EntityMotionState pointer }; typedef std::map ContactMap; From 79cb55eabc98bf611d16ae479dc35d18df56b7db Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 23 Apr 2015 15:09:57 -0700 Subject: [PATCH 304/401] rename setJointStates() --> initJointStates() --- interface/src/avatar/SkeletonModel.cpp | 5 +++-- interface/src/avatar/SkeletonModel.h | 2 +- libraries/render-utils/src/Model.cpp | 6 +++--- libraries/render-utils/src/Model.h | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index dc5427ab48..08e3ece331 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -40,13 +40,14 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : _clampedFootPosition(0.0f), _headClipDistance(DEFAULT_NEAR_CLIP) { + assert(_owningAvatar); } SkeletonModel::~SkeletonModel() { } -void SkeletonModel::setJointStates(QVector states) { - Model::setJointStates(states); +void SkeletonModel::initJointStates(QVector states) { + Model::initJointStates(states); // Determine the default eye position for avatar scale = 1.0 int headJointIndex = _geometry->getFBXGeometry().headJointIndex; diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 298d74fb7a..e28988326a 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -28,7 +28,7 @@ public: SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL); ~SkeletonModel(); - void setJointStates(QVector states); + virtual void initJointStates(QVector states); void simulate(float deltaTime, bool fullUpdate = true); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 4bc69f1bea..78abd142bc 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -426,12 +426,12 @@ bool Model::updateGeometry() { _dilatedTextures.clear(); _geometry = geometry; _meshGroupsKnown = false; - setJointStates(newJointStates); + initJointStates(newJointStates); needToRebuild = true; } else if (_jointStates.isEmpty()) { const FBXGeometry& fbxGeometry = geometry->getFBXGeometry(); if (fbxGeometry.joints.size() > 0) { - setJointStates(createJointStates(fbxGeometry)); + initJointStates(createJointStates(fbxGeometry)); needToRebuild = true; } } else if (!geometry->isLoaded()) { @@ -469,7 +469,7 @@ bool Model::updateGeometry() { } // virtual -void Model::setJointStates(QVector states) { +void Model::initJointStates(QVector states) { _jointStates = states; initJointTransforms(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 1559e73e61..b91d2116f8 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -244,7 +244,7 @@ protected: // returns 'true' if needs fullUpdate after geometry change bool updateGeometry(); - virtual void setJointStates(QVector states); + virtual void initJointStates(QVector states); void setScaleInternal(const glm::vec3& scale); void scaleToFit(); From f09a67af6c1dfc98d7328b2e8ac3add52e6e5914 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 24 Apr 2015 09:32:54 -0700 Subject: [PATCH 305/401] don't need temp variable --- libraries/physics/src/EntityMotionState.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d1571fbcc5..64d1067668 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -189,9 +189,7 @@ float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const { } bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { - bool baseResult = this->ObjectMotionState::shouldSendUpdate(simulationFrame); - - if (!baseResult) { + if (!ObjectMotionState::shouldSendUpdate(simulationFrame)) { return false; } From 7cd9023e2339acd35b798ae6dba7a6c15f01122e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 24 Apr 2015 09:34:19 -0700 Subject: [PATCH 306/401] build Avatar shape on SkeletonModel load --- interface/src/Application.cpp | 1 - interface/src/avatar/Avatar.cpp | 17 +++++++++++++++++ interface/src/avatar/Avatar.h | 4 ++++ interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/avatar/MyAvatar.h | 3 ++- interface/src/avatar/SkeletonModel.cpp | 1 + 6 files changed, 25 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 285bd11952..485f616a6c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4389,7 +4389,6 @@ void Application::checkSkeleton() { _myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default"); } else { - _myAvatar->updateCharacterController(); _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); } } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 63dd884bc6..b3439317d8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1058,3 +1058,20 @@ void Avatar::setShowDisplayName(bool showDisplayName) { } +// virtual +void Avatar::rebuildSkeletonBody() { + /* TODO: implement this and remove override from MyAvatar (when we have AvatarMotionStates working) + if (_motionState) { + // compute localAABox + const CapsuleShape& capsule = _skeletonModel.getBoundingShape(); + float radius = capsule.getRadius(); + float height = 2.0f * (capsule.getHalfHeight() + radius); + glm::vec3 corner(-radius, -0.5f * height, -radius); + corner += _skeletonModel.getBoundingShapeOffset(); + glm::vec3 scale(2.0f * radius, height, 2.0f * radius); + //_characterController.setLocalBoundingBox(corner, scale); + _motionState->setBoundingBox(corner, scale); + } + */ +} + diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 032fe25c7d..a358e7e58d 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -162,6 +162,8 @@ public: // (otherwise floating point error will cause problems at large positions). void applyPositionDelta(const glm::vec3& delta); + virtual void rebuildSkeletonBody(); + signals: void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision); @@ -228,6 +230,8 @@ private: static int _jointConesID; int _voiceSphereID; + + //AvatarMotionState* _motionState = nullptr; }; #endif // hifi_Avatar_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5adc818258..95f5e3fe9f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1070,7 +1070,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { return Avatar::getPosition(); } -void MyAvatar::updateCharacterController() { +void MyAvatar::rebuildSkeletonBody() { // compute localAABox const CapsuleShape& capsule = _skeletonModel.getBoundingShape(); float radius = capsule.getRadius(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 886d8ad590..4746a40099 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -138,7 +138,6 @@ public: virtual glm::vec3 getSkeletonPosition() const; void updateLocalAABox(); DynamicCharacterController* getCharacterController() { return &_characterController; } - void updateCharacterController(); void clearJointAnimationPriorities(); @@ -192,6 +191,8 @@ public slots: void stopRecording(); void saveRecording(QString filename); void loadLastRecording(); + + virtual void rebuildSkeletonBody(); signals: void transformChanged(); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 08e3ece331..8c52c79ca0 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -84,6 +84,7 @@ void SkeletonModel::initJointStates(QVector states) { _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); _headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP); + _owningAvatar->rebuildSkeletonBody(); emit skeletonLoaded(); } From 6087a3e8a93b4e990c611711e28112a8b3e8c05c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 24 Apr 2015 13:40:02 -0700 Subject: [PATCH 307/401] Revert "Add checkboxes.html" This reverts commit 4127ec8019539a95868663748ff952c87938bd0a. --- examples/checkboxes.html | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 examples/checkboxes.html diff --git a/examples/checkboxes.html b/examples/checkboxes.html deleted file mode 100644 index 7c919bfd2d..0000000000 --- a/examples/checkboxes.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - -
Checkbox 2
Checkbox 3
Checkbox 4
- -
- -
From 547b0e5ee64ffd1f850cb71a70c97414b91e35c7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 24 Apr 2015 13:42:03 -0700 Subject: [PATCH 308/401] Update style of webview to only be set when 'fusion' exists --- interface/src/scripting/WebWindowClass.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index 07188e62b6..be36fe1989 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -47,7 +47,6 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid dockWidget->setFeatures(QDockWidget::DockWidgetMovable); _webView = new QWebView(dockWidget); - _webView->setStyle(QStyleFactory::create("fusion")); addEventBridgeToWindowObject(); dockWidget->setWidget(_webView); @@ -66,7 +65,6 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid dialogWidget->setLayout(layout); _webView = new QWebView(dialogWidget); - _webView->setStyle(QStyleFactory::create("fusion")); layout->addWidget(_webView); @@ -75,6 +73,11 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid _windowWidget = dialogWidget; } + auto style = QStyleFactory::create("fusion"); + if (style) { + _webView->setStyle(style); + } + _webView->setPage(new DataWebPage()); _webView->setUrl(url); From e33f3c9d00319836b8d444432435a033ba363dd4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 24 Apr 2015 13:42:56 -0700 Subject: [PATCH 309/401] Remove unnecessary #include --- interface/src/devices/Faceshift.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index bef97fc38a..a2c1cd693a 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -10,7 +10,6 @@ // #include -#include #include #include From ad85837b5aa8c8db6a00762ee3bb768db49c0538 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 13:44:34 -0700 Subject: [PATCH 310/401] sync --- libraries/entities/src/EntityItem.h | 3 ++- libraries/physics/src/EntityMotionState.cpp | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index fa6efd72a1..e726e5b11b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -54,7 +54,8 @@ public: DIRTY_MOTION_TYPE = 0x0010, DIRTY_SHAPE = 0x0020, DIRTY_LIFETIME = 0x0040, - DIRTY_UPDATEABLE = 0x0080 + DIRTY_UPDATEABLE = 0x0080, + DIRTY_TWEAK = 0x0100 }; DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index cff3000868..7bed5a72af 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -114,9 +114,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _entity->setLastSimulated(usecTimestampNow()); - bool isStill = (v == vec3(0.0f)) && (av == vec3(0.0f)); - - if (_entity->getSimulatorID().isNull() && !isStill) { + if (_entity->getSimulatorID().isNull() && isMoving()) { // object is moving and has no owner. attempt to claim simulation ownership. // setShouldClaimSimulationOwnership(true); } @@ -342,6 +340,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; #endif + qDebug() << "sending"; entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { #ifdef WANT_DEBUG From fea8d846184cb0e655fbb95ba3ed575feb496366 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 14:09:10 -0700 Subject: [PATCH 311/401] sync --- libraries/entities/src/EntityItem.cpp | 14 ++++++++------ libraries/physics/src/EntityMotionState.cpp | 17 +++++++++++------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d39e3a9e5c..07c7935556 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -620,6 +620,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef _angularVelocity = saveAngularVelocity; _gravity = saveGravity; _acceleration = saveAcceleration; + } else { + qDebug() << "accepting update"; } return bytesRead; @@ -1100,7 +1102,7 @@ void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { } void EntityItem::updatePosition(const glm::vec3& value) { - if (false && value == _previousPositionFromServer) { + if (/* false && */ value == _previousPositionFromServer) { _position = value; } else if (glm::distance(_position, value) > MIN_POSITION_DELTA) { _position = value; @@ -1122,7 +1124,7 @@ void EntityItem::updateDimensions(const glm::vec3& value) { } void EntityItem::updateRotation(const glm::quat& rotation) { - if (false && rotation == _previousRotationFromServer) { + if (/* false && */ rotation == _previousRotationFromServer) { _rotation = rotation; } else if (glm::abs(glm::dot(_rotation, rotation)) < MIN_ALIGNMENT_DOT) { _rotation = rotation; @@ -1161,7 +1163,7 @@ void EntityItem::updateVelocityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateVelocity(const glm::vec3& value) { - if (false && value == _previousVelocityFromServer) { + if (/* false && */ value == _previousVelocityFromServer) { if (glm::length(value) < MIN_VELOCITY_DELTA) { _velocity = ENTITY_ITEM_ZERO_VEC3; } else { @@ -1191,7 +1193,7 @@ void EntityItem::updateGravityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateGravity(const glm::vec3& value) { - if (false && value == _previousGravityFromServer) { + if (/* false && */ value == _previousGravityFromServer) { _gravity = value; } else if (glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) { _gravity = value; @@ -1201,7 +1203,7 @@ void EntityItem::updateGravity(const glm::vec3& value) { } void EntityItem::updateAcceleration(const glm::vec3& value) { - if (false && value == _previousAccelerationFromServer) { + if (/* false && */ value == _previousAccelerationFromServer) { _acceleration = value; } else if (glm::distance(_acceleration, value) > MIN_ACCELERATION_DELTA) { _acceleration = value; @@ -1211,7 +1213,7 @@ void EntityItem::updateAcceleration(const glm::vec3& value) { } void EntityItem::updateAngularVelocity(const glm::vec3& value) { - if (false && value == _previousAngularVelocityFromServer) { + if (/* false && */ value == _previousAngularVelocityFromServer) { if (glm::length(value) < MIN_SPIN_DELTA) { _angularVelocity = ENTITY_ITEM_ZERO_VEC3; } else { diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 7bed5a72af..dba4cfac79 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -195,16 +195,17 @@ float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const { } bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { - if (getShouldClaimSimulationOwnership()) { - return true; - } - bool baseResult = this->ObjectMotionState::shouldSendUpdate(simulationFrame); if (!baseResult) { return false; } + if (getShouldClaimSimulationOwnership()) { + qDebug() << "shouldSendUpdate due to claiming ownership"; + return true; + } + auto nodeList = DependencyManager::get(); const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& simulatorID = _entity->getSimulatorID(); @@ -303,7 +304,11 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ setShouldClaimSimulationOwnership(false); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the entity has stopped. give up "simulator" status - // _entity->setSimulatorID(QUuid()); + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); + } else if (simulatorID == myNodeID && !_body->isActive()) { + // it's not active. don't keep simulation ownership. + _entity->setSimulatorID(QUuid()); properties.setSimulatorID(QUuid()); } @@ -340,7 +345,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; #endif - qDebug() << "sending"; + qDebug() << "sending" << _body->isActive() << (_entity->getSimulatorID() == myNodeID); entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { #ifdef WANT_DEBUG From 6b53fefebe9124b3ca839da084786aaf56d7f6e3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 14:21:59 -0700 Subject: [PATCH 312/401] sync --- libraries/physics/src/PhysicsEngine.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 5a86f8552e..0909ded84b 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -391,6 +391,7 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const (a && a->getShouldClaimSimulationOwnership()) || (objectA == characterCollisionObject)) { if (bIsDynamic) { + qDebug() << "setShouldClaimSimulationOwnership(true) in doOwnershipInfection"; b->setShouldClaimSimulationOwnership(true); } } @@ -398,6 +399,7 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const (b && b->getShouldClaimSimulationOwnership()) || (objectB == characterCollisionObject)) { if (aIsDynamic) { + qDebug() << "setShouldClaimSimulationOwnership(true) in doOwnershipInfection"; a->setShouldClaimSimulationOwnership(true); } } @@ -576,12 +578,14 @@ void PhysicsEngine::bump(EntityItem* bumpEntity) { EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : NULL; if (entityA && entityB) { if (entityA == bumpEntity) { + qDebug() << "setShouldClaimSimulationOwnership(true) in bump"; entityMotionStateB->setShouldClaimSimulationOwnership(true); if (!objectB->isActive()) { objectB->setActivationState(ACTIVE_TAG); } } if (entityB == bumpEntity) { + qDebug() << "setShouldClaimSimulationOwnership(true) in bump"; entityMotionStateA->setShouldClaimSimulationOwnership(true); if (!objectA->isActive()) { objectA->setActivationState(ACTIVE_TAG); From ea250c037a2d53efdbbde452415fe4ebd204bf07 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 14:27:32 -0700 Subject: [PATCH 313/401] sync --- libraries/physics/src/PhysicsEngine.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 0909ded84b..235de7f172 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -391,7 +391,11 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const (a && a->getShouldClaimSimulationOwnership()) || (objectA == characterCollisionObject)) { if (bIsDynamic) { - qDebug() << "setShouldClaimSimulationOwnership(true) in doOwnershipInfection"; + qDebug() << "setShouldClaimSimulationOwnership(true) in doOwnershipInfection A" + << (aIsDynamic && entityA->getSimulatorID() == myNodeID) + << (a && a->getShouldClaimSimulationOwnership()) + << (objectA == characterCollisionObject); + b->setShouldClaimSimulationOwnership(true); } } @@ -399,7 +403,11 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const (b && b->getShouldClaimSimulationOwnership()) || (objectB == characterCollisionObject)) { if (aIsDynamic) { - qDebug() << "setShouldClaimSimulationOwnership(true) in doOwnershipInfection"; + qDebug() << "setShouldClaimSimulationOwnership(true) in doOwnershipInfection B" + << (bIsDynamic && entityB->getSimulatorID() == myNodeID) + << (b && b->getShouldClaimSimulationOwnership()) + << (objectB == characterCollisionObject); + a->setShouldClaimSimulationOwnership(true); } } From e7c6ee597a4c00287d3257109227c53b6899871c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 14:36:05 -0700 Subject: [PATCH 314/401] sync --- libraries/physics/src/PhysicsEngine.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 235de7f172..afb0e65a00 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -378,6 +378,8 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const const btCollisionObject* characterCollisionObject = _characterController ? _characterController->getCollisionObject() : NULL; + assert(!myNodeID.isNull()); + ObjectMotionState* a = static_cast(objectA->getUserPointer()); ObjectMotionState* b = static_cast(objectB->getUserPointer()); EntityItem* entityA = a ? a->getEntity() : NULL; @@ -387,24 +389,23 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const // collisions cause infectious spread of simulation-ownership. we also attempt to take // ownership of anything that collides with our avatar. - if ((aIsDynamic && entityA->getSimulatorID() == myNodeID) || - (a && a->getShouldClaimSimulationOwnership()) || + if ((aIsDynamic && (entityA->getSimulatorID() == myNodeID)) || + // (a && a->getShouldClaimSimulationOwnership()) || (objectA == characterCollisionObject)) { if (bIsDynamic) { qDebug() << "setShouldClaimSimulationOwnership(true) in doOwnershipInfection A" - << (aIsDynamic && entityA->getSimulatorID() == myNodeID) + << (aIsDynamic && (entityA->getSimulatorID() == myNodeID)) << (a && a->getShouldClaimSimulationOwnership()) << (objectA == characterCollisionObject); b->setShouldClaimSimulationOwnership(true); } - } - if ((bIsDynamic && entityB->getSimulatorID() == myNodeID) || - (b && b->getShouldClaimSimulationOwnership()) || + } else if ((bIsDynamic && (entityB->getSimulatorID() == myNodeID)) || + // (b && b->getShouldClaimSimulationOwnership()) || (objectB == characterCollisionObject)) { if (aIsDynamic) { qDebug() << "setShouldClaimSimulationOwnership(true) in doOwnershipInfection B" - << (bIsDynamic && entityB->getSimulatorID() == myNodeID) + << (bIsDynamic && (entityB->getSimulatorID() == myNodeID)) << (b && b->getShouldClaimSimulationOwnership()) << (objectB == characterCollisionObject); From 2a8fbeca3227434824abab7688324214927db217 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 14:43:39 -0700 Subject: [PATCH 315/401] sync --- libraries/physics/src/EntityMotionState.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 07f82aaa42..1ab3309934 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -67,7 +67,12 @@ public: quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } virtual EntityItem* getEntity() const { return _entity; } - virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } + virtual void setShouldClaimSimulationOwnership(bool value) { + if (value) { + qDebug() << "setShouldClaimSimulationOwnership to TRUE"; + } + _shouldClaimSimulationOwnership = value; + } virtual bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } protected: From 3ecf959b3e514e1a21a51b958f33cdb66b763ece Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 24 Apr 2015 14:50:37 -0700 Subject: [PATCH 316/401] removed cached copies of damping and restitution --- libraries/entities/src/EntityItem.cpp | 15 ++++++++++-- libraries/entities/src/EntityItem.h | 6 ++++- libraries/physics/src/EntityMotionState.cpp | 20 ++++++++-------- libraries/physics/src/EntityMotionState.h | 1 + libraries/physics/src/ObjectMotionState.cpp | 26 +++------------------ libraries/physics/src/ObjectMotionState.h | 18 ++++---------- libraries/physics/src/PhysicsEngine.cpp | 5 ++-- 7 files changed, 38 insertions(+), 53 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f968244ab3..54a00cdcb0 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -675,6 +675,17 @@ void EntityItem::setMass(float mass) { } } +const float DEFAULT_ENTITY_RESTITUTION = 0.5f; +const float DEFAULT_ENTITY_FRICTION = 0.5f; + +float EntityItem::getRestitution() const { + return DEFAULT_ENTITY_RESTITUTION; +} + +float EntityItem::getFriction() const { + return DEFAULT_ENTITY_FRICTION; +} + void EntityItem::simulate(const quint64& now) { if (_lastSimulated == 0) { _lastSimulated = now; @@ -1157,7 +1168,7 @@ void EntityItem::updateVelocity(const glm::vec3& value) { void EntityItem::updateDamping(float value) { if (fabsf(_damping - value) > MIN_DAMPING_DELTA) { _damping = glm::clamp(value, 0.0f, 1.0f); - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_MATERIAL; } } @@ -1188,7 +1199,7 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) { void EntityItem::updateAngularDamping(float value) { if (fabsf(_angularDamping - value) > MIN_DAMPING_DELTA) { _angularDamping = glm::clamp(value, 0.0f, 1.0f); - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_MATERIAL; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index fda8167564..d6f9a9506f 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -54,7 +54,8 @@ public: DIRTY_MOTION_TYPE = 0x0010, DIRTY_SHAPE = 0x0020, DIRTY_LIFETIME = 0x0040, - DIRTY_UPDATEABLE = 0x0080 + DIRTY_UPDATEABLE = 0x0080, + DIRTY_MATERIAL = 0x00100 }; DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly @@ -188,6 +189,9 @@ public: float getDamping() const { return _damping; } void setDamping(float value) { _damping = value; } + float getRestitution() const; + float getFriction() const; + // lifetime related properties. float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 64d1067668..f905b00ffa 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -143,15 +143,9 @@ void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { _sentStep = step; } - // TODO: entity support for friction and restitution - //_restitution = _entity->getRestitution(); - _body->setRestitution(_restitution); - //_friction = _entity->getFriction(); - _body->setFriction(_friction); - - _linearDamping = _entity->getDamping(); - _angularDamping = _entity->getAngularDamping(); - _body->setDamping(_linearDamping, _angularDamping); + if (flags & EntityItem::DIRTY_MATERIAL) { + updateMaterialProperties(); + } if (flags & EntityItem::DIRTY_MASS) { float mass = _entity->computeMass(); @@ -161,7 +155,13 @@ void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { _body->updateInertiaTensor(); } _body->activate(); -}; +} + +void EntityMotionState::updateMaterialProperties() { + _body->setRestitution(_entity->getRestitution()); + _body->setFriction(_entity->getFriction()); + _body->setDamping(fabsf(btMin(_entity->getDamping(), 1.0f)), fabsf(btMin(_entity->getAngularDamping(), 1.0f))); +} void EntityMotionState::updateObjectVelocities() { if (_body) { diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 07f82aaa42..e8a96428a0 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -51,6 +51,7 @@ public: // these relay incoming values to the RigidBody virtual void updateObjectEasy(uint32_t flags, uint32_t step); + virtual void updateMaterialProperties(); virtual void updateObjectVelocities(); virtual void computeShapeInfo(ShapeInfo& shapeInfo); diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 3d8e578056..96257950ff 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -43,10 +43,6 @@ void ObjectMotionState::setSimulationStep(uint32_t step) { } ObjectMotionState::ObjectMotionState() : - _friction(DEFAULT_FRICTION), - _restitution(DEFAULT_RESTITUTION), - _linearDamping(0.0f), - _angularDamping(0.0f), _motionType(MOTION_TYPE_STATIC), _body(NULL), _sentMoving(false), @@ -80,7 +76,7 @@ void ObjectMotionState::measureAcceleration() { // Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt // hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity()); - _measuredAcceleration = (velocity / powf(1.0f - _linearDamping, dt) - _lastVelocity) * invDt; + _measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt; _lastVelocity = velocity; } } @@ -90,22 +86,6 @@ void ObjectMotionState::resetMeasuredAcceleration() { _lastVelocity = bulletToGLM(_body->getLinearVelocity()); } -void ObjectMotionState::setFriction(float friction) { - _friction = btMax(btMin(fabsf(friction), MAX_FRICTION), 0.0f); -} - -void ObjectMotionState::setRestitution(float restitution) { - _restitution = btMax(btMin(fabsf(restitution), 1.0f), 0.0f); -} - -void ObjectMotionState::setLinearDamping(float damping) { - _linearDamping = btMax(btMin(fabsf(damping), 1.0f), 0.0f); -} - -void ObjectMotionState::setAngularDamping(float damping) { - _angularDamping = btMax(btMin(fabsf(damping), 1.0f), 0.0f); -} - void ObjectMotionState::setVelocity(const glm::vec3& velocity) const { _body->setLinearVelocity(glmToBullet(velocity)); } @@ -181,7 +161,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) { // compute position error if (glm::length2(_sentVelocity) > 0.0f) { _sentVelocity += _sentAcceleration * dt; - _sentVelocity *= powf(1.0f - _linearDamping, dt); + _sentVelocity *= powf(1.0f - _body->getLinearDamping(), dt); _sentPosition += dt * _sentVelocity; } @@ -206,7 +186,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) { if (glm::length2(_sentAngularVelocity) > 0.0f) { // compute rotation error - float attenuation = powf(1.0f - _angularDamping, dt); + float attenuation = powf(1.0f - _body->getAngularDamping(), dt); _sentAngularVelocity *= attenuation; // Bullet caps the effective rotation velocity inside its rotation integration step, therefore diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 9e0917a3ab..0f1d04d0bd 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -36,7 +36,7 @@ enum MotionStateType { // and re-added to the physics engine and "easy" which just updates the body properties. const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY | - EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP); + EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | EntityItem::DIRTY_MATERIAL); // These are the set of incoming flags that the PhysicsEngine needs to hear about: const uint32_t DIRTY_PHYSICS_FLAGS = HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS; @@ -69,6 +69,7 @@ public: // An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0; + virtual void updateMaterialProperties() = 0; virtual void updateObjectVelocities() = 0; MotionStateType getType() const { return _type; } @@ -77,11 +78,6 @@ public: virtual void computeShapeInfo(ShapeInfo& info) = 0; virtual float computeMass(const ShapeInfo& shapeInfo) const = 0; - void setFriction(float friction); - void setRestitution(float restitution); - void setLinearDamping(float damping); - void setAngularDamping(float damping); - void setVelocity(const glm::vec3& velocity) const; void setAngularVelocity(const glm::vec3& velocity) const; void setGravity(const glm::vec3& gravity) const; @@ -120,15 +116,9 @@ public: protected: void setRigidBody(btRigidBody* body); - MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN; + MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN; // type of MotionState - // TODO: move these materials properties outside of ObjectMotionState - float _friction; - float _restitution; - float _linearDamping; - float _angularDamping; - - MotionType _motionType; + MotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC btRigidBody* _body; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 75bab97d38..00ac807808 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -527,9 +527,8 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap } } body->setFlags(BT_DISABLE_WORLD_GRAVITY); - body->setRestitution(motionState->_restitution); - body->setFriction(motionState->_friction); - body->setDamping(motionState->_linearDamping, motionState->_angularDamping); + motionState->updateMaterialProperties(); + _dynamicsWorld->addRigidBody(body); motionState->resetMeasuredAcceleration(); } From 6e6793cbcc666c06db6e18a50153683f3a968937 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 15:18:02 -0700 Subject: [PATCH 317/401] remove debugging prints --- .../src/RenderableModelEntityItem.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 2 -- libraries/physics/src/EntityMotionState.cpp | 2 -- libraries/physics/src/EntityMotionState.h | 7 +------ libraries/physics/src/PhysicsEngine.cpp | 12 ------------ 5 files changed, 2 insertions(+), 23 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 1bdfa7bd1a..c4e12eb957 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -125,7 +125,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // XXX if (drawAsModel - && getSimulatorID() != myNodeID + && getSimulatorID() != myNodeID // XXX ) { remapTextures(); glPushMatrix(); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 07c7935556..8db68785d0 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -620,8 +620,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef _angularVelocity = saveAngularVelocity; _gravity = saveGravity; _acceleration = saveAcceleration; - } else { - qDebug() << "accepting update"; } return bytesRead; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index dba4cfac79..d0c362b852 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -202,7 +202,6 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { } if (getShouldClaimSimulationOwnership()) { - qDebug() << "shouldSendUpdate due to claiming ownership"; return true; } @@ -345,7 +344,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; #endif - qDebug() << "sending" << _body->isActive() << (_entity->getSimulatorID() == myNodeID); entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { #ifdef WANT_DEBUG diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 1ab3309934..07f82aaa42 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -67,12 +67,7 @@ public: quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } virtual EntityItem* getEntity() const { return _entity; } - virtual void setShouldClaimSimulationOwnership(bool value) { - if (value) { - qDebug() << "setShouldClaimSimulationOwnership to TRUE"; - } - _shouldClaimSimulationOwnership = value; - } + virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } virtual bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } protected: diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index afb0e65a00..6d0c9c878a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -393,22 +393,12 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const // (a && a->getShouldClaimSimulationOwnership()) || (objectA == characterCollisionObject)) { if (bIsDynamic) { - qDebug() << "setShouldClaimSimulationOwnership(true) in doOwnershipInfection A" - << (aIsDynamic && (entityA->getSimulatorID() == myNodeID)) - << (a && a->getShouldClaimSimulationOwnership()) - << (objectA == characterCollisionObject); - b->setShouldClaimSimulationOwnership(true); } } else if ((bIsDynamic && (entityB->getSimulatorID() == myNodeID)) || // (b && b->getShouldClaimSimulationOwnership()) || (objectB == characterCollisionObject)) { if (aIsDynamic) { - qDebug() << "setShouldClaimSimulationOwnership(true) in doOwnershipInfection B" - << (bIsDynamic && (entityB->getSimulatorID() == myNodeID)) - << (b && b->getShouldClaimSimulationOwnership()) - << (objectB == characterCollisionObject); - a->setShouldClaimSimulationOwnership(true); } } @@ -587,14 +577,12 @@ void PhysicsEngine::bump(EntityItem* bumpEntity) { EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : NULL; if (entityA && entityB) { if (entityA == bumpEntity) { - qDebug() << "setShouldClaimSimulationOwnership(true) in bump"; entityMotionStateB->setShouldClaimSimulationOwnership(true); if (!objectB->isActive()) { objectB->setActivationState(ACTIVE_TAG); } } if (entityB == bumpEntity) { - qDebug() << "setShouldClaimSimulationOwnership(true) in bump"; entityMotionStateA->setShouldClaimSimulationOwnership(true); if (!objectA->isActive()) { objectA->setActivationState(ACTIVE_TAG); From 08d60c6a017217d7df8f46eeae9df7796d4dc9cd Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 24 Apr 2015 14:54:38 -0700 Subject: [PATCH 318/401] Fixing message dialog --- interface/resources/qml/AddressBarDialog.qml | 16 ++ interface/resources/qml/HifiMenu.qml | 4 +- interface/resources/qml/MessageDialog.qml | 155 +++++++++---------- interface/resources/qml/Root.qml | 4 + interface/resources/qml/TestRoot.qml | 21 +-- interface/resources/qml/controls/Dialog.qml | 2 +- interface/src/Application.cpp | 6 + interface/src/ui/LoginDialog.cpp | 4 +- libraries/ui/src/MessageDialog.cpp | 19 ++- libraries/ui/src/MessageDialog.h | 28 ++-- libraries/ui/src/OffscreenQmlDialog.h | 40 ++--- libraries/ui/src/OffscreenUi.cpp | 74 +++++---- libraries/ui/src/OffscreenUi.h | 20 +-- tests/ui/src/main.cpp | 18 +-- 14 files changed, 221 insertions(+), 190 deletions(-) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index d12737081e..8a2bc3e2b4 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -48,6 +48,7 @@ Dialog { helperText: "domain, location, @user, /x,y,z" anchors.margins: 8 onAccepted: { + event.accepted addressBarDialog.loadAddress(addressLine.text) } } @@ -71,5 +72,20 @@ Dialog { } } } + + Keys.onEscapePressed: { + enabled = false; + } + + function toggleOrGo() { + if (addressLine.text == "") { + enabled = false + } else { + addressBarDialog.loadAddress(addressLine.text) + } + } + + Keys.onReturnPressed: toggleOrGo() + Keys.onEnterPressed: toggleOrGo() } diff --git a/interface/resources/qml/HifiMenu.qml b/interface/resources/qml/HifiMenu.qml index d86821601a..1afa39c5d1 100644 --- a/interface/resources/qml/HifiMenu.qml +++ b/interface/resources/qml/HifiMenu.qml @@ -111,8 +111,8 @@ Hifi.HifiMenu { Border { SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } x: root.models.length == 1 ? - (root.width / 2 - width / 2) : - root.columns[root.models.length - 2].x + 60; + (root.width / 2 - width / 2) : + root.columns[root.models.length - 2].x + 60; anchors.verticalCenter: parent.verticalCenter border.color: hifiPalette.hifiBlue color: sysPalette.window diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml index 26fd30db27..315af8c6c9 100644 --- a/interface/resources/qml/MessageDialog.qml +++ b/interface/resources/qml/MessageDialog.qml @@ -1,43 +1,3 @@ -/***************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtQuick.Dialogs module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -*****************************************************************************/ - import Hifi 1.0 as Hifi import QtQuick 2.2 import QtQuick.Controls 1.2 @@ -49,6 +9,7 @@ Dialog { property real spacing: 8 property real outerSpacing: 16 + destroyOnCloseButton: true destroyOnInvisible: true implicitHeight: content.implicitHeight + outerSpacing * 2 + 48 @@ -69,9 +30,13 @@ Dialog { content.buttonsRowImplicitWidth = outerSpacing + calcWidth + 48 } + Component.onCompleted: { + enabled = true + } + onEnabledChanged: { if (enabled) { - content.forceActiveFocus(); + root.forceActiveFocus(); } } @@ -87,37 +52,6 @@ Dialog { implicitWidth: Math.max(mainText.implicitWidth, buttonsRowImplicitWidth); property real buttonsRowImplicitWidth: Screen.pixelDensity * 50 - Keys.onPressed: { - console.log("Key press at content") - event.accepted = true - if (event.modifiers === Qt.ControlModifier) - switch (event.key) { - case Qt.Key_A: - console.log("Select All") - detailedText.selectAll() - break - case Qt.Key_C: - console.log("Copy") - detailedText.copy() - break - case Qt.Key_Period: - if (Qt.platform.os === "osx") - reject() - break - } else switch (event.key) { - case Qt.Key_Escape: - case Qt.Key_Back: - console.log("Rejecting") - reject() - break - case Qt.Key_Enter: - case Qt.Key_Return: - console.log("Accepting") - accept() - break - } - } - onImplicitWidthChanged: root.width = implicitWidth Component.onCompleted: { @@ -140,9 +74,46 @@ Dialog { Item { width: parent.width height: Math.max(icon.height, mainText.height + informativeText.height + root.spacing) - Image { + + FontAwesome { id: icon - source: content.standardIconSource + width: content.icon ? 48 : 0 + height: content.icon ? 48 : 0 + visible: content.icon ? true : false + font.pixelSize: 48 + verticalAlignment: Text.AlignTop + horizontalAlignment: Text.AlignLeft + color: iconColor() + text: iconSymbol() + + function iconSymbol() { + switch (content.icon) { + case Hifi.MessageDialog.Information: + return "\uF05A" + case Hifi.MessageDialog.Question: + return "\uF059" + case Hifi.MessageDialog.Warning: + return "\uF071" + case Hifi.MessageDialog.Critical: + return "\uF057" + default: + break; + } + return content.icon; + } + function iconColor() { + switch (content.icon) { + case Hifi.MessageDialog.Information: + case Hifi.MessageDialog.Question: + return "blue" + case Hifi.MessageDialog.Warning: + case Hifi.MessageDialog.Critical: + return "red" + default: + break + } + return "black" + } } Text { @@ -348,12 +319,38 @@ Dialog { } } ] - -/* - Rectangle { + } + Keys.onPressed: { + if (event.modifiers === Qt.ControlModifier) + switch (event.key) { + case Qt.Key_A: + event.accepted = true + detailedText.selectAll() + break + case Qt.Key_C: + event.accepted = true + detailedText.copy() + break + case Qt.Key_Period: + if (Qt.platform.os === "osx") { + event.accepted = true + content.reject() + } + break + } else switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + event.accepted = true + content.reject() + break + + case Qt.Key_Enter: + case Qt.Key_Return: + console.log("Accepting"); + event.accepted = true + content.accept() + break } - Component.onCompleted: calculateImplicitWidth() - */ } } diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index b2db7d18bf..9b2e5af6b5 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -6,5 +6,9 @@ import QtQuick 2.3 Root { id: root anchors.fill: parent + + onParentChanged: { + forceActiveFocus(); + } } diff --git a/interface/resources/qml/TestRoot.qml b/interface/resources/qml/TestRoot.qml index 80f8c900e3..cb53d34ce2 100644 --- a/interface/resources/qml/TestRoot.qml +++ b/interface/resources/qml/TestRoot.qml @@ -6,21 +6,11 @@ import QtQuick.Controls 1.3 import "controls" Root { - id: root + id: root anchors.fill: parent - - onWidthChanged: { - console.log("Root width: " + width) + onParentChanged: { + forceActiveFocus(); } - onHeightChanged: { - console.log("Root height: " + height) - } - - Component.onCompleted: { - console.log("Completed root") - root.forceActiveFocus() - } - Button { id: messageBox anchors.right: createDialog.left @@ -34,7 +24,6 @@ Root { console.log("Bar") } } - Button { id: createDialog anchors.right: parent.right @@ -48,7 +37,7 @@ Root { } Keys.onPressed: { - console.log(event.key); - } + console.log("Key press root") + } } diff --git a/interface/resources/qml/controls/Dialog.qml b/interface/resources/qml/controls/Dialog.qml index 07162ad1d8..d722d5264a 100644 --- a/interface/resources/qml/controls/Dialog.qml +++ b/interface/resources/qml/controls/Dialog.qml @@ -17,7 +17,7 @@ Item { HifiPalette { id: hifiPalette } SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } x: parent ? parent.width / 2 - width / 2 : 0 - y: parent ? parent.height / 2 - height / 2 : 0 + y: parent ? parent.height / 2 - height / 2 : 0 property int animationDuration: 400 property bool destroyOnInvisible: false diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5a8b3ecee9..4217bb75b8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -82,6 +82,7 @@ #include #include #include +#include #include @@ -1086,6 +1087,11 @@ void Application::keyPressEvent(QKeyEvent* event) { bool isKeypad = event->modifiers().testFlag(Qt::KeypadModifier); switch (event->key()) { break; + case Qt::Key_Enter: + case Qt::Key_Return: + Menu::getInstance()->triggerOption(MenuOption::AddressBar); + break; + case Qt::Key_L: if (isShifted && isMeta) { Menu::getInstance()->triggerOption(MenuOption::Log); diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 4df42c0f15..5726818b2d 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -37,7 +37,9 @@ void LoginDialog::toggleAction() { } else { // change the menu item to login loginAction->setText("Login"); - connect(loginAction, &QAction::triggered, &LoginDialog::show); + connect(loginAction, &QAction::triggered, [] { + LoginDialog::show(); + }); } } diff --git a/libraries/ui/src/MessageDialog.cpp b/libraries/ui/src/MessageDialog.cpp index c16f5653e5..89d6b69384 100644 --- a/libraries/ui/src/MessageDialog.cpp +++ b/libraries/ui/src/MessageDialog.cpp @@ -10,8 +10,7 @@ // #include "MessageDialog.h" -QML_DIALOG_DEF(MessageDialog) - +HIFI_QML_DEF(MessageDialog) MessageDialog::MessageDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { _buttons = StandardButtons(Ok | Cancel); @@ -76,23 +75,23 @@ void MessageDialog::setStandardButtons(StandardButtons buttons) { } void MessageDialog::click(StandardButton button) { - click(static_cast(button), - static_cast( - QPlatformDialogHelper::buttonRole(static_cast(button)))); + // FIXME try to do it more like the standard dialog + click(StandardButton(button), ButtonRole::NoRole); } +QMessageBox::ButtonRole br; QUrl MessageDialog::standardIconSource() { switch (icon()) { - case QMessageDialogOptions::Information: + case Information: return QUrl("images/information.png"); break; - case QMessageDialogOptions::Warning: + case Warning: return QUrl("images/warning.png"); break; - case QMessageDialogOptions::Critical: + case Critical: return QUrl("images/critical.png"); break; - case QMessageDialogOptions::Question: + case Question: return QUrl("images/question.png"); break; default: @@ -109,7 +108,7 @@ MessageDialog::StandardButton MessageDialog::clickedButton() const { return _clickedButton; } -void MessageDialog::click(StandardButton button, QPlatformDialogHelper::ButtonRole) { +void MessageDialog::click(StandardButton button, ButtonRole) { _clickedButton = button; if (_resultCallback) { _resultCallback(QMessageBox::StandardButton(_clickedButton)); diff --git a/libraries/ui/src/MessageDialog.h b/libraries/ui/src/MessageDialog.h index 8b5a895068..d700754513 100644 --- a/libraries/ui/src/MessageDialog.h +++ b/libraries/ui/src/MessageDialog.h @@ -13,12 +13,11 @@ #define hifi_MessageDialog_h #include "OffscreenQmlDialog.h" -#include <5.4.1/QtGui/qpa/qplatformdialoghelper.h> class MessageDialog : public OffscreenQmlDialog { Q_OBJECT - QML_DIALOG_DECL + HIFI_QML_DECL private: Q_ENUMS(Icon) @@ -31,14 +30,23 @@ private: Q_PROPERTY(StandardButton clickedButton READ clickedButton NOTIFY buttonClicked) public: - enum Icon { - NoIcon = QMessageDialogOptions::NoIcon, - Information = QMessageDialogOptions::Information, - Warning = QMessageDialogOptions::Warning, - Critical = QMessageDialogOptions::Critical, - Question = QMessageDialogOptions::Question - }; + enum Icon { NoIcon, Information, Warning, Critical, Question }; + enum ButtonRole { + // keep this in sync with QDialogButtonBox::ButtonRole and QPlatformDialogHelper::ButtonRole + InvalidRole = -1, + AcceptRole, + RejectRole, + DestructiveRole, + ActionRole, + HelpRole, + YesRole, + NoRole, + ResetRole, + ApplyRole, + + NRoles + }; MessageDialog(QQuickItem *parent = 0); virtual ~MessageDialog(); @@ -76,7 +84,7 @@ signals: void reset(); protected slots: - virtual void click(StandardButton button, QPlatformDialogHelper::ButtonRole); + virtual void click(StandardButton button, ButtonRole); virtual void accept(); virtual void reject(); diff --git a/libraries/ui/src/OffscreenQmlDialog.h b/libraries/ui/src/OffscreenQmlDialog.h index 7b7c83ad65..b97bc1914f 100644 --- a/libraries/ui/src/OffscreenQmlDialog.h +++ b/libraries/ui/src/OffscreenQmlDialog.h @@ -13,7 +13,6 @@ #define hifi_OffscreenQmlDialog_h #include -#include <5.4.1/QtGui/qpa/qplatformdialoghelper.h> #include "OffscreenUi.h" @@ -57,25 +56,26 @@ public: virtual ~OffscreenQmlDialog(); enum StandardButton { - NoButton = QPlatformDialogHelper::NoButton, - Ok = QPlatformDialogHelper::Ok, - Save = QPlatformDialogHelper::Save, - SaveAll = QPlatformDialogHelper::SaveAll, - Open = QPlatformDialogHelper::Open, - Yes = QPlatformDialogHelper::Yes, - YesToAll = QPlatformDialogHelper::YesToAll, - No = QPlatformDialogHelper::No, - NoToAll = QPlatformDialogHelper::NoToAll, - Abort = QPlatformDialogHelper::Abort, - Retry = QPlatformDialogHelper::Retry, - Ignore = QPlatformDialogHelper::Ignore, - Close = QPlatformDialogHelper::Close, - Cancel = QPlatformDialogHelper::Cancel, - Discard = QPlatformDialogHelper::Discard, - Help = QPlatformDialogHelper::Help, - Apply = QPlatformDialogHelper::Apply, - Reset = QPlatformDialogHelper::Reset, - RestoreDefaults = QPlatformDialogHelper::RestoreDefaults, + // keep this in sync with QDialogButtonBox::StandardButton and QMessageBox::StandardButton + NoButton = 0x00000000, + Ok = 0x00000400, + Save = 0x00000800, + SaveAll = 0x00001000, + Open = 0x00002000, + Yes = 0x00004000, + YesToAll = 0x00008000, + No = 0x00010000, + NoToAll = 0x00020000, + Abort = 0x00040000, + Retry = 0x00080000, + Ignore = 0x00100000, + Close = 0x00200000, + Cancel = 0x00400000, + Discard = 0x00800000, + Help = 0x01000000, + Apply = 0x02000000, + Reset = 0x04000000, + RestoreDefaults = 0x08000000, NButtons }; Q_DECLARE_FLAGS(StandardButtons, StandardButton) diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 7b84bb763f..27c33cbae9 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -151,17 +151,18 @@ void OffscreenUi::setBaseUrl(const QUrl& baseUrl) { _qmlEngine->setBaseUrl(baseUrl); } -void OffscreenUi::load(const QUrl& qmlSource, std::function f) { +QObject* OffscreenUi::load(const QUrl& qmlSource, std::function f) { qDebug() << "Loading QML from URL " << qmlSource; _qmlComponent->loadUrl(qmlSource); - if (_qmlComponent->isLoading()) + if (_qmlComponent->isLoading()) { connect(_qmlComponent, &QQmlComponent::statusChanged, this, [this, f](QQmlComponent::Status){ finishQmlLoad(f); }); - else { - finishQmlLoad(f); + return nullptr; } + + return finishQmlLoad(f); } void OffscreenUi::requestUpdate() { @@ -177,14 +178,14 @@ void OffscreenUi::requestRender() { } } -void OffscreenUi::finishQmlLoad(std::function f) { +QObject* OffscreenUi::finishQmlLoad(std::function f) { disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, 0); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); foreach(const QQmlError &error, errorList) { qWarning() << error.url() << error.line() << error; } - return; + return nullptr; } QQmlContext * newContext = new QQmlContext(_qmlEngine, qApp); @@ -196,38 +197,41 @@ void OffscreenUi::finishQmlLoad(std::function f) { if (!_rootItem) { qFatal("Unable to finish loading QML root"); } - return; + return nullptr; } f(newContext, newObject); _qmlComponent->completeCreate(); + + // All quick items should be focusable QQuickItem* newItem = qobject_cast(newObject); - if (!newItem) { - qWarning("run: Not a QQuickItem"); - return; - delete newObject; - if (!_rootItem) { - qFatal("Unable to find root QQuickItem"); - } - return; + if (newItem) { + // Make sure we make items focusable (critical for + // supporting keyboard shortcuts) + newItem->setFlag(QQuickItem::ItemIsFocusScope, true); } - // Make sure we make items focusable (critical for - // supporting keyboard shortcuts) - newItem->setFlag(QQuickItem::ItemIsFocusScope, true); - if (!_rootItem) { - // The root item is ready. Associate it with the window. - _rootItem = newItem; - _rootItem->setParentItem(_quickWindow->contentItem()); - _rootItem->setSize(_quickWindow->renderTargetSize()); - _rootItem->forceActiveFocus(); - } else { + // If we already have a root, just set a couple of flags and the ancestry + if (_rootItem) { // Allow child windows to be destroyed from JS - QQmlEngine::setObjectOwnership(newItem, QQmlEngine::JavaScriptOwnership); - newItem->setParent(_rootItem); - newItem->setParentItem(_rootItem); + QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership); + newObject->setParent(_rootItem); + if (newItem) { + newItem->setParentItem(_rootItem); + } + return newObject; } + + if (!newItem) { + qFatal("Could not load object as root item"); + return nullptr; + } + // The root item is ready. Associate it with the window. + _rootItem = newItem; + _rootItem->setParentItem(_quickWindow->contentItem()); + _rootItem->setSize(_quickWindow->renderTargetSize()); + return _rootItem; } @@ -415,7 +419,9 @@ void OffscreenUi::show(const QUrl& url, const QString& name, std::functionfindChild(name); } - item->setEnabled(true); + if (item) { + item->setEnabled(true); + } } void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function f) { @@ -425,21 +431,25 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::functionfindChild(name); } - item->setEnabled(!item->isEnabled()); + if (item) { + item->setEnabled(!item->isEnabled()); + } } void OffscreenUi::messageBox(const QString& title, const QString& text, ButtonCallback callback, QMessageBox::Icon icon, QMessageBox::StandardButtons buttons) { - MessageDialog::show([=](QQmlContext*ctx, QObject*item) { - MessageDialog * pDialog = item->findChild(); + MessageDialog * pDialog{ nullptr }; + MessageDialog::show([&](QQmlContext*ctx, QObject*item) { + pDialog = item->findChild(); pDialog->setIcon((MessageDialog::Icon)icon); pDialog->setTitle(title); pDialog->setText(text); pDialog->setStandardButtons(MessageDialog::StandardButtons((int)buttons)); pDialog->setResultCallback(callback); }); + pDialog->setEnabled(true); } void OffscreenUi::information(const QString& title, const QString& text, diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index b58b4e59cb..bc27fc2195 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -38,9 +38,9 @@ private: \ static const QUrl QML; \ public: \ static void registerType(); \ - static void show(std::function f = [](QQmlContext*, QQuickItem*) {}); \ - static void toggle(std::function f = [](QQmlContext*, QQuickItem*) {}); \ - static void load(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void show(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void toggle(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void load(std::function f = [](QQmlContext*, QQuickItem*) {}); \ private: #define HIFI_QML_DECL_LAMBDA \ @@ -62,16 +62,16 @@ private: qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ } \ \ - void x::show(std::function f) { \ + void x::show(std::function f) { \ auto offscreenUi = DependencyManager::get(); \ offscreenUi->show(QML, NAME, f); \ } \ \ - void x::toggle(std::function f) { \ + void x::toggle(std::function f) { \ auto offscreenUi = DependencyManager::get(); \ offscreenUi->toggle(QML, NAME, f); \ } \ - void x::load(std::function f) { \ + void x::load(std::function f) { \ auto offscreenUi = DependencyManager::get(); \ offscreenUi->load(QML, f); \ } @@ -122,9 +122,9 @@ public: virtual ~OffscreenUi(); void create(QOpenGLContext* context); void resize(const QSize& size); - void load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); - void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { - load(QUrl(qmlSourceFile), f); + QObject* load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); + QObject* load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { + return load(QUrl(qmlSourceFile), f); } void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); @@ -173,7 +173,7 @@ protected: private slots: void updateQuick(); - void finishQmlLoad(std::function f); + QObject* finishQmlLoad(std::function f); public slots: void requestUpdate(); diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 4189282de1..0f7a66c0cd 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -185,18 +185,18 @@ public: QObject* menuObject = offscreenUi->getRootItem()->findChild("HifiMenu"); HifiMenu* menu = offscreenUi->getRootItem()->findChild(); menu->addMenu("", "File"); - menu->addMenuItem("File", "Quit", []{ + menu->addItem("File", "Quit", []{ QApplication::quit(); }); - menu->addCheckableMenuItem("File", "Toggle", false, [](bool toggled) { + menu->addCheckableItem("File", "Toggle", false, [](bool toggled) { qDebug() << "Toggle is " << toggled; }); menu->addMenu("", "Edit"); - menu->addMenuItem("Edit", "Undo"); - menu->addMenuItem("Edit", "Redo"); - menu->addMenuItem("Edit", "Copy"); - menu->addMenuItem("Edit", "Cut"); - menu->addMenuItem("Edit", "Paste"); + menu->addItem("Edit", "Undo"); + menu->addItem("Edit", "Redo"); + menu->addItem("Edit", "Copy"); + menu->addItem("Edit", "Cut"); + menu->addItem("Edit", "Paste"); menu->addMenu("", "Long Menu Name..."); #endif installEventFilter(offscreenUi.data()); @@ -255,8 +255,8 @@ protected: if (event->modifiers() & Qt::CTRL) { auto offscreenUi = DependencyManager::get(); HifiMenu * menu = offscreenUi->findChild(); - menu->addMenuItem("", "Test 3"); - menu->addMenuItem("File", "Test 3"); + menu->addItem("", "Test 3"); + menu->addItem("File", "Test 3"); } break; case Qt::Key_K: From e7b8efc2d9d3fa2c526d81f8f989aa90c8b62b02 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 24 Apr 2015 16:44:48 -0700 Subject: [PATCH 319/401] Cleaning up unused stuff --- interface/resources/qml/images/critical.png | Bin 253 -> 0 bytes .../resources/qml/images/information.png | Bin 254 -> 0 bytes interface/resources/qml/images/question.png | Bin 257 -> 0 bytes interface/resources/qml/images/warning.png | Bin 224 -> 0 bytes libraries/ui/src/MessageDialog.cpp | 21 ------------------ libraries/ui/src/MessageDialog.h | 1 - tests/ui/src/main.cpp | 11 +++++++++ 7 files changed, 11 insertions(+), 22 deletions(-) delete mode 100644 interface/resources/qml/images/critical.png delete mode 100644 interface/resources/qml/images/information.png delete mode 100644 interface/resources/qml/images/question.png delete mode 100644 interface/resources/qml/images/warning.png diff --git a/interface/resources/qml/images/critical.png b/interface/resources/qml/images/critical.png deleted file mode 100644 index dc9c5aebf453dd92dba60c48f060b34f0087e02c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 253 zcmVkNDWE^AyB8@ZEC00000NkvXXu0mjf DKfYr$ diff --git a/interface/resources/qml/images/information.png b/interface/resources/qml/images/information.png deleted file mode 100644 index 0a2eb87d108d2a24b71559998627570a252ebe69..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8`~f~8uBj!u3?T4-=FFM@ z|NrludHNay0|R48kY6x^!?PP{3=9l&JzX3_G|sP`c#-$80*{Mh+yV`sgwlqP>#QC( z>X#+u7`Xm@Q`=BsWqr<)MUc^=nfrazYu@_ss|q3QYrOu5+ux47bKp#oZChf4k#&aW z_6qNdiK4+zLkc4MIa@Ri#52@3K4zcMoZ;%Na4X>suaM`rgBP8<|7A}r*;L-N)XQ^~ z*Qd}2Q;+ng3Z7t^78=O>`qh(QX^u+vLUu-L1y=d3FMU5VRZj!?kipZ{&t;ucLK6Te CT3=!S diff --git a/interface/resources/qml/images/question.png b/interface/resources/qml/images/question.png deleted file mode 100644 index 2dd92fd7915a09de670b8b6022ddcf02d4cc90e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 257 zcmV+c0sj7pP)NklQ}7)nBez2^$+jK{Nw%L3xK4m{g6jm}2|@>7z7zk+b}w*O&>f9X*ioevByCmJtfv0xgg* zX&;ac>>nrw_75mp9NLlK=){M}g!K&|3b4W-F*J23VSVK);JN=%IJYXN$un1x$~;9b a#PS7=(1SoC6O>K>0000a diff --git a/libraries/ui/src/MessageDialog.cpp b/libraries/ui/src/MessageDialog.cpp index 89d6b69384..7d226fb774 100644 --- a/libraries/ui/src/MessageDialog.cpp +++ b/libraries/ui/src/MessageDialog.cpp @@ -78,27 +78,6 @@ void MessageDialog::click(StandardButton button) { // FIXME try to do it more like the standard dialog click(StandardButton(button), ButtonRole::NoRole); } -QMessageBox::ButtonRole br; - -QUrl MessageDialog::standardIconSource() { - switch (icon()) { - case Information: - return QUrl("images/information.png"); - break; - case Warning: - return QUrl("images/warning.png"); - break; - case Critical: - return QUrl("images/critical.png"); - break; - case Question: - return QUrl("images/question.png"); - break; - default: - return QUrl(); - break; - } -} MessageDialog::StandardButtons MessageDialog::standardButtons() const { return _buttons; diff --git a/libraries/ui/src/MessageDialog.h b/libraries/ui/src/MessageDialog.h index d700754513..fdae6e6c8d 100644 --- a/libraries/ui/src/MessageDialog.h +++ b/libraries/ui/src/MessageDialog.h @@ -25,7 +25,6 @@ private: Q_PROPERTY(QString informativeText READ informativeText WRITE setInformativeText NOTIFY informativeTextChanged) Q_PROPERTY(QString detailedText READ detailedText WRITE setDetailedText NOTIFY detailedTextChanged) Q_PROPERTY(Icon icon READ icon WRITE setIcon NOTIFY iconChanged) - Q_PROPERTY(QUrl standardIconSource READ standardIconSource NOTIFY iconChanged) Q_PROPERTY(StandardButtons standardButtons READ standardButtons WRITE setStandardButtons NOTIFY standardButtonsChanged) Q_PROPERTY(StandardButton clickedButton READ clickedButton NOTIFY buttonClicked) diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 0f7a66c0cd..2ad2fa639c 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -325,6 +326,16 @@ const char * LOG_FILTER_RULES = R"V0G0N( qt.quick.mouse.debug=false )V0G0N"; +//int main(int argc, char *argv[]) { +// QGuiApplication app(argc, argv); +// QQmlApplicationEngine engine; +// engine.setBaseUrl(QUrl::fromLocalFile(getQmlDir())); +// engine.load(QUrl("Main.qml")); +// return app.exec(); +//} + + + int main(int argc, char** argv) { QGuiApplication app(argc, argv); // QLoggingCategory::setFilterRules(LOG_FILTER_RULES); From eb02bdc67f7071519cae94dbaf8c52c12dc995cc Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 24 Apr 2015 16:57:39 -0700 Subject: [PATCH 320/401] Dangling function --- libraries/ui/src/MessageDialog.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/ui/src/MessageDialog.h b/libraries/ui/src/MessageDialog.h index fdae6e6c8d..a4b04eb2d9 100644 --- a/libraries/ui/src/MessageDialog.h +++ b/libraries/ui/src/MessageDialog.h @@ -64,7 +64,6 @@ public slots: void setStandardButtons(StandardButtons buttons); void setResultCallback(OffscreenUi::ButtonCallback callback); void click(StandardButton button); - QUrl standardIconSource(); StandardButtons standardButtons() const; StandardButton clickedButton() const; From fdf2f8395d0949b5cfaf4f55eb21287f91a281c8 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 24 Apr 2015 17:28:43 -0700 Subject: [PATCH 321/401] Bad lambda type --- libraries/ui/src/OffscreenUi.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index bc27fc2195..84626cab52 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -38,9 +38,9 @@ private: \ static const QUrl QML; \ public: \ static void registerType(); \ - static void show(std::function f = [](QQmlContext*, QQuickItem*) {}); \ - static void toggle(std::function f = [](QQmlContext*, QQuickItem*) {}); \ - static void load(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void show(std::function f = [](QQmlContext*, QObject*) {}); \ + static void toggle(std::function f = [](QQmlContext*, QObject*) {}); \ + static void load(std::function f = [](QQmlContext*, QObject*) {}); \ private: #define HIFI_QML_DECL_LAMBDA \ From 218393a2b3c5f26c9fe9ed289702118c917513f4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 17:37:19 -0700 Subject: [PATCH 322/401] rather than keeping track of previous pos/rot sent by server, use a new flag that indicates that the values should be updated in the physics engine, but that the object should not be woken --- libraries/entities/src/EntityItem.cpp | 86 ++++++++------------- libraries/entities/src/EntityItem.h | 9 +-- libraries/physics/src/EntityMotionState.cpp | 7 +- 3 files changed, 40 insertions(+), 62 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 8db68785d0..243958b4a8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -65,13 +65,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), _physicsInfo(NULL), _dirtyFlags(0), - _element(NULL), - _previousPositionFromServer(ENTITY_ITEM_ZERO_VEC3), - _previousRotationFromServer(ENTITY_ITEM_DEFAULT_ROTATION), - _previousVelocityFromServer(ENTITY_ITEM_ZERO_VEC3), - _previousAngularVelocityFromServer(ENTITY_ITEM_ZERO_VEC3), - _previousGravityFromServer(ENTITY_ITEM_ZERO_VEC3), - _previousAccelerationFromServer(ENTITY_ITEM_ZERO_VEC3) + _element(NULL) { quint64 now = usecTimestampNow(); _lastSimulated = now; @@ -1100,12 +1094,10 @@ void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { } void EntityItem::updatePosition(const glm::vec3& value) { - if (/* false && */ value == _previousPositionFromServer) { + if (value != _position) { + auto distance = glm::distance(_position, value); + _dirtyFlags |= (distance > MIN_POSITION_DELTA) ? EntityItem::DIRTY_POSITION : EntityItem::DIRTY_PHYSICS_NO_WAKE; _position = value; - } else if (glm::distance(_position, value) > MIN_POSITION_DELTA) { - _position = value; - _previousPositionFromServer = value; - _dirtyFlags |= EntityItem::DIRTY_POSITION; } } @@ -1122,12 +1114,10 @@ void EntityItem::updateDimensions(const glm::vec3& value) { } void EntityItem::updateRotation(const glm::quat& rotation) { - if (/* false && */ rotation == _previousRotationFromServer) { + if (rotation != _rotation) { + auto alignmentDot = glm::abs(glm::dot(_rotation, rotation)); + _dirtyFlags |= (alignmentDot < MIN_ALIGNMENT_DOT) ? EntityItem::DIRTY_POSITION : EntityItem::DIRTY_PHYSICS_NO_WAKE; _rotation = rotation; - } else if (glm::abs(glm::dot(_rotation, rotation)) < MIN_ALIGNMENT_DOT) { - _rotation = rotation; - _previousRotationFromServer = rotation; - _dirtyFlags |= EntityItem::DIRTY_POSITION; } } @@ -1161,20 +1151,15 @@ void EntityItem::updateVelocityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateVelocity(const glm::vec3& value) { - if (/* false && */ value == _previousVelocityFromServer) { - if (glm::length(value) < MIN_VELOCITY_DELTA) { - _velocity = ENTITY_ITEM_ZERO_VEC3; - } else { - _velocity = value; - } - } else if (glm::distance(_velocity, value) > MIN_VELOCITY_DELTA) { - if (glm::length(value) < MIN_VELOCITY_DELTA) { - _velocity = ENTITY_ITEM_ZERO_VEC3; - } else { - _velocity = value; - } - _previousVelocityFromServer = value; + if (value != _velocity) { + auto distance = glm::distance(_velocity, value); + // _dirtyFlags |= (distance > MIN_VELOCITY_DELTA) ? EntityItem::DIRTY_VELOCITY : EntityItem::DIRTY_PHYSICS_NO_WAKE; _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + if (distance < MIN_VELOCITY_DELTA) { + _velocity = ENTITY_ITEM_ZERO_VEC3; + } else { + _velocity = value; + } } } @@ -1191,39 +1176,36 @@ void EntityItem::updateGravityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateGravity(const glm::vec3& value) { - if (/* false && */ value == _previousGravityFromServer) { - _gravity = value; - } else if (glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) { - _gravity = value; - _previousGravityFromServer = value; + auto distance = glm::distance(_gravity, value); + // if (value != _gravity) { + if (distance > MIN_GRAVITY_DELTA) { + // _dirtyFlags |= (distance > MIN_GRAVITY_DELTA) ? EntityItem::DIRTY_VELOCITY : EntityItem::DIRTY_PHYSICS_NO_WAKE; _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + _gravity = value; } } void EntityItem::updateAcceleration(const glm::vec3& value) { - if (/* false && */ value == _previousAccelerationFromServer) { - _acceleration = value; - } else if (glm::distance(_acceleration, value) > MIN_ACCELERATION_DELTA) { - _acceleration = value; - _previousAccelerationFromServer = value; + auto distance = glm::distance(_acceleration, value); + // if (value != _acceleration) { + if (distance > MIN_ACCELERATION_DELTA) { + // _dirtyFlags |= (distance > MIN_ACCELERATION_DELTA) ? EntityItem::DIRTY_VELOCITY : EntityItem::DIRTY_PHYSICS_NO_WAKE; _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + _acceleration = value; } } void EntityItem::updateAngularVelocity(const glm::vec3& value) { - if (/* false && */ value == _previousAngularVelocityFromServer) { - if (glm::length(value) < MIN_SPIN_DELTA) { - _angularVelocity = ENTITY_ITEM_ZERO_VEC3; - } else { - _angularVelocity = value; - } - } else if (glm::distance(_angularVelocity, value) > MIN_SPIN_DELTA) { - if (glm::length(value) < MIN_SPIN_DELTA) { - _angularVelocity = ENTITY_ITEM_ZERO_VEC3; - } else { - _angularVelocity = value; - } + auto distance = glm::distance(_angularVelocity, value); + // if (value != _angularVelocity) { + if (distance > MIN_SPIN_DELTA) { + // _dirtyFlags |= (distance > MIN_SPIN_DELTA) ? EntityItem::DIRTY_VELOCITY : EntityItem::DIRTY_PHYSICS_NO_WAKE; _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + if (glm::length(value) < MIN_SPIN_DELTA) { + _angularVelocity = ENTITY_ITEM_ZERO_VEC3; + } else { + _angularVelocity = value; + } } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e726e5b11b..890134828a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -55,7 +55,7 @@ public: DIRTY_SHAPE = 0x0020, DIRTY_LIFETIME = 0x0040, DIRTY_UPDATEABLE = 0x0080, - DIRTY_TWEAK = 0x0100 + DIRTY_PHYSICS_NO_WAKE = 0x0100 // we want to update values in physics engine without "waking" the object up }; DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly @@ -369,13 +369,6 @@ protected: uint32_t _dirtyFlags; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation EntityTreeElement* _element; // back pointer to containing Element - - glm::vec3 _previousPositionFromServer; - glm::quat _previousRotationFromServer; - glm::vec3 _previousVelocityFromServer; - glm::vec3 _previousAngularVelocityFromServer; - glm::vec3 _previousGravityFromServer; - glm::vec3 _previousAccelerationFromServer; }; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d0c362b852..5e863030c5 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -132,7 +132,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { } void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { - if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { + if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY | EntityItem::DIRTY_PHYSICS_NO_WAKE)) { if (flags & EntityItem::DIRTY_POSITION) { _sentPosition = _entity->getPosition() - ObjectMotionState::getWorldOffset(); btTransform worldTrans; @@ -147,6 +147,10 @@ void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { updateObjectVelocities(); } _sentStep = step; + + if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { + _body->activate(); + } } // TODO: entity support for friction and restitution @@ -166,7 +170,6 @@ void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { _body->setMassProps(mass, inertia); _body->updateInertiaTensor(); } - _body->activate(); }; void EntityMotionState::updateObjectVelocities() { From 03706359f5898b4c81797f104e36a5fb0e974b9f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 17:44:52 -0700 Subject: [PATCH 323/401] cleanups --- libraries/entities/src/EntityItem.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 243958b4a8..06a0cc52c2 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1151,9 +1151,8 @@ void EntityItem::updateVelocityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateVelocity(const glm::vec3& value) { - if (value != _velocity) { - auto distance = glm::distance(_velocity, value); - // _dirtyFlags |= (distance > MIN_VELOCITY_DELTA) ? EntityItem::DIRTY_VELOCITY : EntityItem::DIRTY_PHYSICS_NO_WAKE; + auto distance = glm::distance(_velocity, value); + if (distance > MIN_VELOCITY_DELTA) { _dirtyFlags |= EntityItem::DIRTY_VELOCITY; if (distance < MIN_VELOCITY_DELTA) { _velocity = ENTITY_ITEM_ZERO_VEC3; @@ -1176,20 +1175,14 @@ void EntityItem::updateGravityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateGravity(const glm::vec3& value) { - auto distance = glm::distance(_gravity, value); - // if (value != _gravity) { - if (distance > MIN_GRAVITY_DELTA) { - // _dirtyFlags |= (distance > MIN_GRAVITY_DELTA) ? EntityItem::DIRTY_VELOCITY : EntityItem::DIRTY_PHYSICS_NO_WAKE; + if (glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) { _dirtyFlags |= EntityItem::DIRTY_VELOCITY; _gravity = value; } } void EntityItem::updateAcceleration(const glm::vec3& value) { - auto distance = glm::distance(_acceleration, value); - // if (value != _acceleration) { - if (distance > MIN_ACCELERATION_DELTA) { - // _dirtyFlags |= (distance > MIN_ACCELERATION_DELTA) ? EntityItem::DIRTY_VELOCITY : EntityItem::DIRTY_PHYSICS_NO_WAKE; + if (glm::distance(_acceleration, value) > MIN_ACCELERATION_DELTA) { _dirtyFlags |= EntityItem::DIRTY_VELOCITY; _acceleration = value; } @@ -1197,9 +1190,7 @@ void EntityItem::updateAcceleration(const glm::vec3& value) { void EntityItem::updateAngularVelocity(const glm::vec3& value) { auto distance = glm::distance(_angularVelocity, value); - // if (value != _angularVelocity) { if (distance > MIN_SPIN_DELTA) { - // _dirtyFlags |= (distance > MIN_SPIN_DELTA) ? EntityItem::DIRTY_VELOCITY : EntityItem::DIRTY_PHYSICS_NO_WAKE; _dirtyFlags |= EntityItem::DIRTY_VELOCITY; if (glm::length(value) < MIN_SPIN_DELTA) { _angularVelocity = ENTITY_ITEM_ZERO_VEC3; From 9fbd5d79e4e2bf34c6f7fbb5a665d318322c6bae Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 24 Apr 2015 17:46:56 -0700 Subject: [PATCH 324/401] Removing duplicate declaration --- interface/src/ui/AddressBarDialog.cpp | 2 +- interface/src/ui/AddressBarDialog.h | 2 +- interface/src/ui/LoginDialog.cpp | 2 +- interface/src/ui/LoginDialog.h | 2 +- libraries/ui/src/OffscreenQmlDialog.h | 28 --------------------------- 5 files changed, 4 insertions(+), 32 deletions(-) diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 6b5c92c194..837702d253 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -15,7 +15,7 @@ #include "DependencyManager.h" #include "AddressManager.h" -QML_DIALOG_DEF(AddressBarDialog) +HIFI_QML_DEF(AddressBarDialog) AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) { auto addressManager = DependencyManager::get(); diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index 28056edd30..395cf3c725 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -17,7 +17,7 @@ class AddressBarDialog : public OffscreenQmlDialog { Q_OBJECT - QML_DIALOG_DECL + HIFI_QML_DECL public: AddressBarDialog(QQuickItem* parent = nullptr); diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 5726818b2d..b452f153f0 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -15,7 +15,7 @@ #include "Menu.h" #include -QML_DIALOG_DEF(LoginDialog) +HIFI_QML_DEF(LoginDialog) LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) { connect(&AccountManager::getInstance(), &AccountManager::loginComplete, diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index b6d505943e..e9ae0a1c16 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -17,7 +17,7 @@ class LoginDialog : public OffscreenQmlDialog { Q_OBJECT - QML_DIALOG_DECL + HIFI_QML_DECL Q_PROPERTY(QString statusText READ statusText WRITE setStatusText NOTIFY statusTextChanged) Q_PROPERTY(QString rootUrl READ rootUrl) diff --git a/libraries/ui/src/OffscreenQmlDialog.h b/libraries/ui/src/OffscreenQmlDialog.h index b97bc1914f..0ff9156f8f 100644 --- a/libraries/ui/src/OffscreenQmlDialog.h +++ b/libraries/ui/src/OffscreenQmlDialog.h @@ -16,34 +16,6 @@ #include "OffscreenUi.h" -#define QML_DIALOG_DECL \ -private: \ - static const QString NAME; \ - static const QUrl QML; \ -public: \ - static void registerType(); \ - static void show(std::function f = [](QQmlContext*, QObject*) {}); \ - static void toggle(std::function f = [](QQmlContext*, QObject*) {}); \ -private: - -#define QML_DIALOG_DEF(x) \ - const QUrl x::QML = QUrl(#x ".qml"); \ - const QString x::NAME = #x; \ - \ - void x::registerType() { \ - qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ - } \ - \ - void x::show(std::function f) { \ - auto offscreenUi = DependencyManager::get(); \ - offscreenUi->show(QML, NAME, f); \ - } \ - \ - void x::toggle(std::function f) { \ - auto offscreenUi = DependencyManager::get(); \ - offscreenUi->toggle(QML, NAME, f); \ - } - class OffscreenQmlDialog : public QQuickItem { Q_OBJECT From ac46f84291d9325b0b41124eae6159ed6cfff76e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Apr 2015 18:36:41 -0700 Subject: [PATCH 325/401] cleanups --- .../entities-renderer/src/EntityTreeRenderer.cpp | 15 --------------- .../src/RenderableModelEntityItem.cpp | 16 ++++------------ libraries/entities/src/EntityItem.cpp | 11 +++++------ 3 files changed, 9 insertions(+), 33 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index fbfa882494..586e9a50ad 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -677,26 +677,11 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) if (bigEnoughToRender) { renderProxies(entityItem, args); - - // XXX - // auto nodeList = DependencyManager::get(); - // const QUuid& myNodeID = nodeList->getSessionUUID(); - // XXX - - Glower* glower = NULL; if (entityItem->getGlowLevel() > 0.0f) { glower = new Glower(entityItem->getGlowLevel()); } - // XXX glow things we are simulating - // if (entityItem->getSimulatorID() == myNodeID) { - // if (glower) delete glower; - // glower = new Glower(); - // } - // XXX glow things we are simulating - - entityItem->render(args); args->_itemsRendered++; if (glower) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c4e12eb957..25922bed10 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -119,25 +119,17 @@ void RenderableModelEntityItem::render(RenderArgs* args) { glm::vec3 dimensions = getDimensions(); float size = glm::length(dimensions); - // XXX - auto nodeList = DependencyManager::get(); - const QUuid& myNodeID = nodeList->getSessionUUID(); - // XXX - + auto nodeList = DependencyManager::get(); // XXX for debugging + const QUuid& myNodeID = nodeList->getSessionUUID(); // XXX for debugging + if (drawAsModel - && getSimulatorID() != myNodeID // XXX + && getSimulatorID() != myNodeID // XXX for debugging ) { remapTextures(); glPushMatrix(); { float alpha = getLocalRenderAlpha(); - // XXX - // if (getSimulatorID() == myNodeID) { - // alpha = 1.0; - // } - // XXX - if (!_model || _needsModelReload) { // TODO: this getModel() appears to be about 3% of model render time. We should optimize PerformanceTimer perfTimer("getModel"); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 06a0cc52c2..5552013ca2 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1151,14 +1151,13 @@ void EntityItem::updateVelocityInDomainUnits(const glm::vec3& value) { } void EntityItem::updateVelocity(const glm::vec3& value) { - auto distance = glm::distance(_velocity, value); - if (distance > MIN_VELOCITY_DELTA) { - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; - if (distance < MIN_VELOCITY_DELTA) { + if (glm::distance(_velocity, value) > MIN_VELOCITY_DELTA) { + if (glm::length(value) < MIN_VELOCITY_DELTA) { _velocity = ENTITY_ITEM_ZERO_VEC3; } else { _velocity = value; } + _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } @@ -1176,15 +1175,15 @@ void EntityItem::updateGravityInDomainUnits(const glm::vec3& value) { void EntityItem::updateGravity(const glm::vec3& value) { if (glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) { - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; _gravity = value; + _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } void EntityItem::updateAcceleration(const glm::vec3& value) { if (glm::distance(_acceleration, value) > MIN_ACCELERATION_DELTA) { - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; _acceleration = value; + _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } From ba507cef98aa1a34a0d47235906d6967ee8e3c08 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Sat, 25 Apr 2015 11:01:02 +0200 Subject: [PATCH 326/401] Fix a few warnings --- interface/src/Application.cpp | 1 - interface/src/ui/ApplicationOverlay.cpp | 1 - libraries/entities/src/EntityItem.cpp | 1 - libraries/gpu/src/gpu/GLBackendTexture.cpp | 6 ++++-- libraries/physics/src/DynamicCharacterController.cpp | 2 -- libraries/render-utils/src/Model.cpp | 4 ++-- 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b4d155319d..95700f3257 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1058,7 +1058,6 @@ void Application::keyPressEvent(QKeyEvent* event) { bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); bool isOption = event->modifiers().testFlag(Qt::AltModifier); - bool isKeypad = event->modifiers().testFlag(Qt::KeypadModifier); switch (event->key()) { break; case Qt::Key_L: diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 2a8f01aafc..bf93a3e7d2 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -257,7 +257,6 @@ void ApplicationOverlay::displayOverlayTexture() { if (_alpha == 0.0f) { return; } - auto glCanvas = Application::getInstance()->getGLWidget(); glMatrixMode(GL_PROJECTION); glPushMatrix(); { glLoadIdentity(); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f968244ab3..65d4849b0e 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1080,7 +1080,6 @@ const float MIN_ALIGNMENT_DOT = 0.999999f; const float MIN_VELOCITY_DELTA = 0.01f; const float MIN_DAMPING_DELTA = 0.001f; const float MIN_GRAVITY_DELTA = 0.001f; -const float MIN_ACCELERATION_DELTA = 0.001f; const float MIN_SPIN_DELTA = 0.0003f; void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index b8f9ab0bf1..1c41860f49 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -16,8 +16,8 @@ GLBackend::GLTexture::GLTexture() : _storageStamp(0), _contentStamp(0), _texture(0), - _size(0), - _target(GL_TEXTURE_2D) + _target(GL_TEXTURE_2D), + _size(0) {} GLBackend::GLTexture::~GLTexture() { @@ -176,6 +176,8 @@ public: texel.internalFormat = GL_DEPTH_COMPONENT24; break; } + case gpu::NUM_TYPES: + Q_UNREACHABLE(); } break; default: diff --git a/libraries/physics/src/DynamicCharacterController.cpp b/libraries/physics/src/DynamicCharacterController.cpp index 46ff2e524e..3557511fab 100644 --- a/libraries/physics/src/DynamicCharacterController.cpp +++ b/libraries/physics/src/DynamicCharacterController.cpp @@ -8,11 +8,9 @@ const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f); const float DEFAULT_GRAVITY = -5.0f; -const float TERMINAL_VELOCITY = 55.0f; const float JUMP_SPEED = 3.5f; const float MAX_FALL_HEIGHT = 20.0f; -const float MIN_HOVER_HEIGHT = 3.0f; const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0; const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 4bc69f1bea..fe82af6b3c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -111,7 +111,7 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3)); gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); - bool makeResult = gpu::Shader::makeProgram(*program, slotBindings); + gpu::Shader::makeProgram(*program, slotBindings); auto locations = std::shared_ptr(new Locations()); @@ -139,7 +139,7 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, // Good to go add the brand new pipeline auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); - auto it = insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); + insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); // If not a shadow pass, create the mirror version from the same state, just change the FrontFace if (!key.isShadow()) { From 48ec0c833908ba73fc41f6ea9bec6ad81a0583d7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Apr 2015 06:56:19 -0700 Subject: [PATCH 327/401] formatting, re-enable code that causes an interface to attempt to claim a moving object with no current simulation-owner --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 1 - libraries/physics/src/EntityMotionState.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 586e9a50ad..dde13552f3 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -681,7 +681,6 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) if (entityItem->getGlowLevel() > 0.0f) { glower = new Glower(entityItem->getGlowLevel()); } - entityItem->render(args); args->_itemsRendered++; if (glower) { diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 5e863030c5..31e615249c 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -116,7 +116,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (_entity->getSimulatorID().isNull() && isMoving()) { // object is moving and has no owner. attempt to claim simulation ownership. - // setShouldClaimSimulationOwnership(true); + setShouldClaimSimulationOwnership(true); } _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; From 81ff8a4448e85e1cabefb5a8e12b3a0ecaaa7a9a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Apr 2015 07:17:21 -0700 Subject: [PATCH 328/401] count steps during which an EntityItem is moving but has no simulation owner. Once the count is high enough (how high is TBD), attempt to claim ownership --- libraries/physics/src/EntityMotionState.cpp | 9 ++++++++- libraries/physics/src/EntityMotionState.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 31e615249c..c722336ca2 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -38,7 +38,8 @@ void EntityMotionState::enqueueOutgoingEntity(EntityItem* entity) { EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity), _accelerationNearlyGravityCount(0), - _shouldClaimSimulationOwnership(false) + _shouldClaimSimulationOwnership(false), + _movingStepsWithoutSimulationOwner(0) { _type = MOTION_STATE_TYPE_ENTITY; assert(entity != NULL); @@ -116,6 +117,12 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (_entity->getSimulatorID().isNull() && isMoving()) { // object is moving and has no owner. attempt to claim simulation ownership. + _movingStepsWithoutSimulationOwner++; + } else { + _movingStepsWithoutSimulationOwner = 0; + } + + if (_movingStepsWithoutSimulationOwner > 4) { // XXX maybe meters from our characterController ? setShouldClaimSimulationOwnership(true); } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 07f82aaa42..087d5b49b9 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -74,6 +74,7 @@ protected: EntityItem* _entity; quint8 _accelerationNearlyGravityCount; bool _shouldClaimSimulationOwnership; + quint32 _movingStepsWithoutSimulationOwner; }; #endif // hifi_EntityMotionState_h From 0fb1a83e3bc4956d12e09c48994430c9b4ee864f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Apr 2015 09:20:00 -0700 Subject: [PATCH 329/401] quiet compiler, remove some trailing control-Ms --- CMakeLists.txt | 2 +- .../src/DomainServerWebSessionData.cpp | 2 +- interface/src/Application.cpp | 2 +- interface/src/ScriptsModel.h | 2 +- interface/src/avatar/Head.h | 2 +- interface/src/ui/ApplicationOverlay.cpp | 2 +- interface/src/ui/overlays/Overlays.cpp | 4 +- libraries/audio/src/AudioEffectOptions.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 2 +- libraries/fbx/src/FBXReader.cpp | 8 +- libraries/gpu/src/gpu/GLBackend.cpp | 50 +- libraries/gpu/src/gpu/GLBackendBuffer.cpp | 4 +- libraries/gpu/src/gpu/GLBackendInput.cpp | 8 +- libraries/gpu/src/gpu/GLBackendOutput.cpp | 172 ++--- libraries/gpu/src/gpu/GLBackendPipeline.cpp | 8 +- libraries/gpu/src/gpu/GLBackendState.cpp | 26 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 112 +-- libraries/gpu/src/gpu/GLBackendTransform.cpp | 4 +- libraries/gpu/src/gpu/State.h | 2 +- libraries/gpu/src/gpu/Stream.h | 4 +- libraries/gpu/src/gpu/Texture.cpp | 702 +++++++++--------- libraries/gpu/src/gpu/Texture.h | 6 +- libraries/model/src/model/Geometry.cpp | 2 +- .../networking/src/DataServerAccountInfo.cpp | 3 + libraries/networking/src/HifiSockAddr.cpp | 1 + libraries/networking/src/NetworkPeer.cpp | 3 +- libraries/networking/src/OAuthAccessToken.cpp | 2 +- .../networking/src/RSAKeypairGenerator.cpp | 2 + libraries/octree/src/OctreeRenderer.cpp | 2 +- libraries/render-utils/src/GeometryCache.cpp | 4 +- libraries/render-utils/src/JointState.cpp | 2 +- libraries/render-utils/src/JointState.h | 2 +- libraries/render-utils/src/MatrixStack.h | 2 +- libraries/render-utils/src/Model.cpp | 6 +- libraries/shared/src/ShapeInfo.h | 2 +- 36 files changed, 588 insertions(+), 573 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 32e79c8443..b271664c35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,7 @@ if (WIN32) elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic") #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-strict-aliasing -ggdb") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter -ggdb") endif(WIN32) if (NOT MSVC12) diff --git a/domain-server/src/DomainServerWebSessionData.cpp b/domain-server/src/DomainServerWebSessionData.cpp index ee32a17570..0a921d65c3 100644 --- a/domain-server/src/DomainServerWebSessionData.cpp +++ b/domain-server/src/DomainServerWebSessionData.cpp @@ -33,7 +33,7 @@ DomainServerWebSessionData::DomainServerWebSessionData(const QJsonObject& userOb } } -DomainServerWebSessionData::DomainServerWebSessionData(const DomainServerWebSessionData& otherSessionData) { +DomainServerWebSessionData::DomainServerWebSessionData(const DomainServerWebSessionData& otherSessionData) : QObject() { _username = otherSessionData._username; _roles = otherSessionData._roles; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b4d155319d..565aa07332 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1058,7 +1058,7 @@ void Application::keyPressEvent(QKeyEvent* event) { bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); bool isOption = event->modifiers().testFlag(Qt::AltModifier); - bool isKeypad = event->modifiers().testFlag(Qt::KeypadModifier); + // bool isKeypad = event->modifiers().testFlag(Qt::KeypadModifier); switch (event->key()) { break; case Qt::Key_L: diff --git a/interface/src/ScriptsModel.h b/interface/src/ScriptsModel.h index 914a197201..ae75acfa3b 100644 --- a/interface/src/ScriptsModel.h +++ b/interface/src/ScriptsModel.h @@ -50,7 +50,7 @@ public: TreeNodeScript(const QString& localPath, const QString& fullPath, ScriptOrigin origin); const QString& getLocalPath() { return _localPath; } const QString& getFullPath() { return _fullPath; }; - const ScriptOrigin getOrigin() { return _origin; }; + ScriptOrigin getOrigin() { return _origin; }; private: QString _localPath; diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index d6d4cc1352..7ae36675be 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -81,7 +81,7 @@ public: FaceModel& getFaceModel() { return _faceModel; } const FaceModel& getFaceModel() const { return _faceModel; } - const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) + bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) float getAverageLoudness() const { return _averageLoudness; } /// \return the point about which scaling occurs. glm::vec3 getScalePivot() const; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 2a8f01aafc..9978a05dac 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -257,7 +257,7 @@ void ApplicationOverlay::displayOverlayTexture() { if (_alpha == 0.0f) { return; } - auto glCanvas = Application::getInstance()->getGLWidget(); + // auto glCanvas = Application::getInstance()->getGLWidget(); glMatrixMode(GL_PROJECTION); glPushMatrix(); { glLoadIdentity(); diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 158deb00ff..191f3f4a99 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -91,7 +91,7 @@ void Overlays::renderHUD() { lodManager->getOctreeSizeScale(), lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; foreach(Overlay* thisOverlay, _overlaysHUD) { if (thisOverlay->is3D()) { @@ -126,7 +126,7 @@ void Overlays::renderWorld(bool drawFront, RenderArgs::RenderMode renderMode, Re lodManager->getOctreeSizeScale(), lodManager->getBoundaryLevelAdjust(), renderMode, renderSide, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; foreach(Overlay* thisOverlay, _overlaysWorld) { diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 480779afd2..221d70aa75 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -64,7 +64,7 @@ AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) : } } -AudioEffectOptions::AudioEffectOptions(const AudioEffectOptions &other) { +AudioEffectOptions::AudioEffectOptions(const AudioEffectOptions &other) : QObject() { *this = other; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c744ec0165..029161dec4 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -391,7 +391,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R _viewState->getShadowViewFrustum() : _viewState->getCurrentViewFrustum(); RenderArgs args = { this, frustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; _tree->lockForRead(); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 5b15aa26b4..a63a7ef7c3 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -521,7 +521,7 @@ bool EntityTree::findInSphereOperation(OctreeElement* element, void* extraData) // NOTE: assumes caller has handled locking void EntityTree::findEntities(const glm::vec3& center, float radius, QVector& foundEntities) { - FindAllNearPointArgs args = { center, radius }; + FindAllNearPointArgs args = { center, radius, QVector() }; // NOTE: This should use recursion, since this is a spatial operation recurseTreeWithOperation(findInSphereOperation, &args); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 1c89ee4067..ca4ccc294f 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -133,7 +133,7 @@ bool FBXGeometry::convexHullContains(const glm::vec3& point) const { auto checkEachPrimitive = [=](FBXMesh& mesh, QVector indices, int primitiveSize) -> bool { // Check whether the point is "behind" all the primitives. - for (unsigned int j = 0; j < indices.size(); j += primitiveSize) { + for (int j = 0; j < indices.size(); j += primitiveSize) { if (!isPointBehindTrianglesPlane(point, mesh.vertices[indices[j]], mesh.vertices[indices[j + 1]], @@ -1469,7 +1469,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, bool rotationMinX = false, rotationMinY = false, rotationMinZ = false; bool rotationMaxX = false, rotationMaxY = false, rotationMaxZ = false; glm::vec3 rotationMin, rotationMax; - FBXModel model = { name, -1 }; + FBXModel model = { name, -1, glm::vec3(), glm::mat4(), glm::quat(), glm::quat(), glm::quat(), + glm::mat4(), glm::vec3(), glm::vec3()}; ExtractedMesh* mesh = NULL; QVector blendshapes; foreach (const FBXNode& subobject, object.children) { @@ -1685,7 +1686,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, textureContent.insert(filename, content); } } else if (object.name == "Material") { - Material material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(), 96.0f, 1.0f }; + Material material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(), 96.0f, 1.0f, + QString(""), QSharedPointer(NULL)}; foreach (const FBXNode& subobject, object.children) { bool properties = false; QByteArray propertyName; diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index c9de132b73..a898c9042b 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -143,7 +143,7 @@ void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { uint32 startVertex = batch._params[paramOffset + 0]._uint; glDrawArrays(mode, startVertex, numVertices); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { @@ -159,15 +159,15 @@ void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { GLenum glType = _elementTypeToGLType[_input._indexBufferType]; glDrawElements(mode, numIndices, glType, reinterpret_cast(startIndex + _input._indexBufferOffset)); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) { - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } // TODO: As long as we have gl calls explicitely issued from interface @@ -189,7 +189,7 @@ void Batch::_glEnable(GLenum cap) { } void GLBackend::do_glEnable(Batch& batch, uint32 paramOffset) { glEnable(batch._params[paramOffset]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glDisable(GLenum cap) { @@ -201,7 +201,7 @@ void Batch::_glDisable(GLenum cap) { } void GLBackend::do_glDisable(Batch& batch, uint32 paramOffset) { glDisable(batch._params[paramOffset]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glEnableClientState(GLenum array) { @@ -213,7 +213,7 @@ void Batch::_glEnableClientState(GLenum array) { } void GLBackend::do_glEnableClientState(Batch& batch, uint32 paramOffset) { glEnableClientState(batch._params[paramOffset]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glDisableClientState(GLenum array) { @@ -225,7 +225,7 @@ void Batch::_glDisableClientState(GLenum array) { } void GLBackend::do_glDisableClientState(Batch& batch, uint32 paramOffset) { glDisableClientState(batch._params[paramOffset]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glCullFace(GLenum mode) { @@ -237,7 +237,7 @@ void Batch::_glCullFace(GLenum mode) { } void GLBackend::do_glCullFace(Batch& batch, uint32 paramOffset) { glCullFace(batch._params[paramOffset]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glAlphaFunc(GLenum func, GLclampf ref) { @@ -252,7 +252,7 @@ void GLBackend::do_glAlphaFunc(Batch& batch, uint32 paramOffset) { glAlphaFunc( batch._params[paramOffset + 1]._uint, batch._params[paramOffset + 0]._float); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glDepthFunc(GLenum func) { @@ -264,7 +264,7 @@ void Batch::_glDepthFunc(GLenum func) { } void GLBackend::do_glDepthFunc(Batch& batch, uint32 paramOffset) { glDepthFunc(batch._params[paramOffset]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glDepthMask(GLboolean flag) { @@ -276,7 +276,7 @@ void Batch::_glDepthMask(GLboolean flag) { } void GLBackend::do_glDepthMask(Batch& batch, uint32 paramOffset) { glDepthMask(batch._params[paramOffset]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glDepthRange(GLfloat zNear, GLfloat zFar) { @@ -291,7 +291,7 @@ void GLBackend::do_glDepthRange(Batch& batch, uint32 paramOffset) { glDepthRange( batch._params[paramOffset + 1]._float, batch._params[paramOffset + 0]._float); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glBindBuffer(GLenum target, GLuint buffer) { @@ -306,7 +306,7 @@ void GLBackend::do_glBindBuffer(Batch& batch, uint32 paramOffset) { glBindBuffer( batch._params[paramOffset + 1]._uint, batch._params[paramOffset + 0]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glBindTexture(GLenum target, GLuint texture) { @@ -321,7 +321,7 @@ void GLBackend::do_glBindTexture(Batch& batch, uint32 paramOffset) { glBindTexture( batch._params[paramOffset + 1]._uint, batch._params[paramOffset + 0]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glActiveTexture(GLenum texture) { @@ -333,7 +333,7 @@ void Batch::_glActiveTexture(GLenum texture) { } void GLBackend::do_glActiveTexture(Batch& batch, uint32 paramOffset) { glActiveTexture(batch._params[paramOffset]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glDrawBuffers(GLsizei n, const GLenum* bufs) { @@ -348,7 +348,7 @@ void GLBackend::do_glDrawBuffers(Batch& batch, uint32 paramOffset) { glDrawBuffers( batch._params[paramOffset + 1]._uint, (const GLenum*)batch.editData(batch._params[paramOffset + 0]._uint)); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glUseProgram(GLuint program) { @@ -365,7 +365,7 @@ void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) { _pipeline._invalidProgram = false; glUseProgram(_pipeline._program); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glUniform1f(GLint location, GLfloat v0) { @@ -385,7 +385,7 @@ void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) { glUniform1f( batch._params[paramOffset + 1]._int, batch._params[paramOffset + 0]._float); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glUniform2f(GLint location, GLfloat v0, GLfloat v1) { @@ -402,7 +402,7 @@ void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) { batch._params[paramOffset + 2]._int, batch._params[paramOffset + 1]._float, batch._params[paramOffset + 0]._float); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glUniform4fv(GLint location, GLsizei count, const GLfloat* value) { @@ -421,7 +421,7 @@ void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) { batch._params[paramOffset + 1]._uint, (const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint)); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { @@ -441,7 +441,7 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) { batch._params[paramOffset + 2]._uint, batch._params[paramOffset + 1]._uint, (const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint)); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glEnableVertexAttribArray(GLint location) { @@ -453,7 +453,7 @@ void Batch::_glEnableVertexAttribArray(GLint location) { } void GLBackend::do_glEnableVertexAttribArray(Batch& batch, uint32 paramOffset) { glEnableVertexAttribArray(batch._params[paramOffset]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glDisableVertexAttribArray(GLint location) { @@ -465,7 +465,7 @@ void Batch::_glDisableVertexAttribArray(GLint location) { } void GLBackend::do_glDisableVertexAttribArray(Batch& batch, uint32 paramOffset) { glDisableVertexAttribArray(batch._params[paramOffset]._uint); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void Batch::_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { @@ -484,6 +484,6 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) { batch._params[paramOffset + 2]._float, batch._params[paramOffset + 1]._float, batch._params[paramOffset + 0]._float); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } diff --git a/libraries/gpu/src/gpu/GLBackendBuffer.cpp b/libraries/gpu/src/gpu/GLBackendBuffer.cpp index 12eab21686..3eeedc5dc3 100755 --- a/libraries/gpu/src/gpu/GLBackendBuffer.cpp +++ b/libraries/gpu/src/gpu/GLBackendBuffer.cpp @@ -35,7 +35,7 @@ GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { if (!object) { object = new GLBuffer(); glGenBuffers(1, &object->_buffer); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); Backend::setGPUObject(buffer, object); } @@ -48,7 +48,7 @@ GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { object->_stamp = buffer.getSysmem().getStamp(); object->_size = buffer.getSysmem().getSize(); //} - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); return object; } diff --git a/libraries/gpu/src/gpu/GLBackendInput.cpp b/libraries/gpu/src/gpu/GLBackendInput.cpp index 982d2656a0..fcaa28aaaa 100755 --- a/libraries/gpu/src/gpu/GLBackendInput.cpp +++ b/libraries/gpu/src/gpu/GLBackendInput.cpp @@ -83,7 +83,7 @@ void GLBackend::updateInput() { glDisableVertexAttribArray(i); } } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _input._attributeActivation.flip(i); } @@ -108,7 +108,7 @@ void GLBackend::updateInput() { if (_input._buffersState.test(bufferNum) || _input._invalidFormat) { GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum])); glBindBuffer(GL_ARRAY_BUFFER, vbo); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _input._buffersState[bufferNum] = false; for (unsigned int i = 0; i < channel._slots.size(); i++) { @@ -142,7 +142,7 @@ void GLBackend::updateInput() { glVertexAttribPointer(slot, count, type, isNormalized, stride, reinterpret_cast(pointer)); } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } } } @@ -219,5 +219,5 @@ void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { } else { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index bd8a2ab457..e03ab43962 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -24,7 +24,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe GLFramebuffer* object = Backend::getGPUObject(framebuffer); // If GPU object already created and in sync - bool needUpdate = false; + // bool needUpdate = false; if (object) { return object; } else if (framebuffer.isEmpty()) { @@ -36,90 +36,90 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe if (!object) { GLuint fbo; glGenFramebuffers(1, &fbo); - CHECK_GL_ERROR(); - - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - unsigned int nbColorBuffers = 0; - GLenum colorBuffers[16]; - if (framebuffer.hasColor()) { - static const GLenum colorAttachments[] = { - GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1, - GL_COLOR_ATTACHMENT2, - GL_COLOR_ATTACHMENT3, - GL_COLOR_ATTACHMENT4, - GL_COLOR_ATTACHMENT5, - GL_COLOR_ATTACHMENT6, - GL_COLOR_ATTACHMENT7, - GL_COLOR_ATTACHMENT8, - GL_COLOR_ATTACHMENT9, - GL_COLOR_ATTACHMENT10, - GL_COLOR_ATTACHMENT11, - GL_COLOR_ATTACHMENT12, - GL_COLOR_ATTACHMENT13, - GL_COLOR_ATTACHMENT14, - GL_COLOR_ATTACHMENT15 }; - - int unit = 0; - for (auto& b : framebuffer.getRenderBuffers()) { - auto surface = b._texture; - if (surface) { - auto gltexture = GLBackend::syncGPUObject(*surface); - if (gltexture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); - } - colorBuffers[nbColorBuffers] = colorAttachments[unit]; - nbColorBuffers++; - unit++; - } - } - } - - if (framebuffer.hasDepthStencil()) { - auto surface = framebuffer.getDepthStencilBuffer(); - if (surface) { - auto gltexture = GLBackend::syncGPUObject(*surface); - if (gltexture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, gltexture->_texture, 0); - } - } - } - - // Last but not least, define where we draw - if (nbColorBuffers > 0) { - glDrawBuffers(nbColorBuffers, colorBuffers); - } else { - glDrawBuffer( GL_NONE ); - } - - // Now check for completness - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - bool result = false; - switch (status) { - case GL_FRAMEBUFFER_COMPLETE : - // Success ! - result = true; - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT : - qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT."; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : - qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT."; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER : - qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER."; - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER : - qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER."; - break; - case GL_FRAMEBUFFER_UNSUPPORTED : - qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED."; - break; - } - if (!result && fbo) { - glDeleteFramebuffers( 1, &fbo ); - return nullptr; + (void) CHECK_GL_ERROR(); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + unsigned int nbColorBuffers = 0; + GLenum colorBuffers[16]; + if (framebuffer.hasColor()) { + static const GLenum colorAttachments[] = { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7, + GL_COLOR_ATTACHMENT8, + GL_COLOR_ATTACHMENT9, + GL_COLOR_ATTACHMENT10, + GL_COLOR_ATTACHMENT11, + GL_COLOR_ATTACHMENT12, + GL_COLOR_ATTACHMENT13, + GL_COLOR_ATTACHMENT14, + GL_COLOR_ATTACHMENT15 }; + + int unit = 0; + for (auto& b : framebuffer.getRenderBuffers()) { + auto surface = b._texture; + if (surface) { + auto gltexture = GLBackend::syncGPUObject(*surface); + if (gltexture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); + } + colorBuffers[nbColorBuffers] = colorAttachments[unit]; + nbColorBuffers++; + unit++; + } + } + } + + if (framebuffer.hasDepthStencil()) { + auto surface = framebuffer.getDepthStencilBuffer(); + if (surface) { + auto gltexture = GLBackend::syncGPUObject(*surface); + if (gltexture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, gltexture->_texture, 0); + } + } + } + + // Last but not least, define where we draw + if (nbColorBuffers > 0) { + glDrawBuffers(nbColorBuffers, colorBuffers); + } else { + glDrawBuffer( GL_NONE ); + } + + // Now check for completness + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + bool result = false; + switch (status) { + case GL_FRAMEBUFFER_COMPLETE : + // Success ! + result = true; + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT : + qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT."; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : + qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT."; + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER : + qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER."; + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER : + qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER."; + break; + case GL_FRAMEBUFFER_UNSUPPORTED : + qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED."; + break; + } + if (!result && fbo) { + glDeleteFramebuffers( 1, &fbo ); + return nullptr; } @@ -154,4 +154,4 @@ void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) { _output._framebuffer = framebuffer; } } - + diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index d285cdd8d8..48a45ce93f 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -103,7 +103,7 @@ void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) { // THis should be done on Pipeline::update... if (_pipeline._invalidProgram) { glUseProgram(_pipeline._program); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._invalidProgram = false; } } @@ -122,7 +122,7 @@ void GLBackend::updatePipeline() { if (_pipeline._invalidProgram) { // doing it here is aproblem for calls to glUniform.... so will do it on assing... glUseProgram(_pipeline._program); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._invalidProgram = false; } @@ -164,7 +164,7 @@ void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { // GLuint bo = getBufferID(*uniformBuffer); //glUniformBufferEXT(_shader._program, slot, bo); #endif - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void GLBackend::do_setUniformTexture(Batch& batch, uint32 paramOffset) { @@ -175,6 +175,6 @@ void GLBackend::do_setUniformTexture(Batch& batch, uint32 paramOffset) { glActiveTexture(GL_TEXTURE0 + slot); glBindTexture(GL_TEXTURE_2D, to); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index fb85d30fe2..2d3eacd37f 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -458,7 +458,7 @@ void GLBackend::getCurrentGLState(State::Data& state) { | (mask[3] ? State::WRITE_ALPHA : 0); } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } void GLBackend::syncPipelineStateCache() { @@ -485,7 +485,7 @@ void GLBackend::do_setStateFillMode(int32 mode) { if (_pipeline._stateCache.fillMode != mode) { static GLenum GL_FILL_MODES[] = { GL_POINT, GL_LINE, GL_FILL }; glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_MODES[mode]); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._stateCache.fillMode = State::FillMode(mode); } @@ -501,7 +501,7 @@ void GLBackend::do_setStateCullMode(int32 mode) { glEnable(GL_CULL_FACE); glCullFace(GL_CULL_MODES[mode]); } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._stateCache.cullMode = State::CullMode(mode); } @@ -511,7 +511,7 @@ void GLBackend::do_setStateFrontFaceClockwise(bool isClockwise) { if (_pipeline._stateCache.frontFaceClockwise != isClockwise) { static GLenum GL_FRONT_FACES[] = { GL_CCW, GL_CW }; glFrontFace(GL_FRONT_FACES[isClockwise]); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._stateCache.frontFaceClockwise = isClockwise; } @@ -524,7 +524,7 @@ void GLBackend::do_setStateDepthClipEnable(bool enable) { } else { glDisable(GL_DEPTH_CLAMP); } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._stateCache.depthClipEnable = enable; } @@ -537,7 +537,7 @@ void GLBackend::do_setStateScissorEnable(bool enable) { } else { glDisable(GL_SCISSOR_TEST); } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._stateCache.scissorEnable = enable; } @@ -550,7 +550,7 @@ void GLBackend::do_setStateMultisampleEnable(bool enable) { } else { glDisable(GL_MULTISAMPLE); } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._stateCache.multisampleEnable = enable; } @@ -565,7 +565,7 @@ void GLBackend::do_setStateAntialiasedLineEnable(bool enable) { glDisable(GL_POINT_SMOOTH); glDisable(GL_LINE_SMOOTH); } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._stateCache.antialisedLineEnable = enable; } @@ -637,7 +637,7 @@ void GLBackend::do_setStateStencil(State::StencilActivation activation, State::S } else { glDisable(GL_STENCIL_TEST); } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._stateCache.stencilActivation = activation; _pipeline._stateCache.stencilTestFront = frontTest; @@ -652,7 +652,7 @@ void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) { } else { glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); _pipeline._stateCache.alphaToCoverageEnable = enable; } } @@ -684,7 +684,7 @@ void GLBackend::do_setStateBlend(State::BlendFunction function) { GL_MAX }; glBlendEquationSeparate(GL_BLEND_OPS[function.getOperationColor()], GL_BLEND_OPS[function.getOperationAlpha()]); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); static GLenum BLEND_ARGS[] = { GL_ZERO, @@ -706,7 +706,7 @@ void GLBackend::do_setStateBlend(State::BlendFunction function) { glBlendFuncSeparate(BLEND_ARGS[function.getSourceColor()], BLEND_ARGS[function.getDestinationColor()], BLEND_ARGS[function.getSourceAlpha()], BLEND_ARGS[function.getDestinationAlpha()]); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } else { glDisable(GL_BLEND); } @@ -735,5 +735,5 @@ void GLBackend::do_setStateBlendFactor(Batch& batch, uint32 paramOffset) { batch._params[paramOffset + 3]._float); glBlendColor(factor.x, factor.y, factor.z, factor.w); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index b8f9ab0bf1..4bb16ba0b8 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -16,8 +16,8 @@ GLBackend::GLTexture::GLTexture() : _storageStamp(0), _contentStamp(0), _texture(0), - _size(0), - _target(GL_TEXTURE_2D) + _target(GL_TEXTURE_2D), + _size(0) {} GLBackend::GLTexture::~GLTexture() { @@ -176,6 +176,10 @@ public: texel.internalFormat = GL_DEPTH_COMPONENT24; break; } + case gpu::NUM_TYPES: { // quiet compiler + assert(false); + break; + } } break; default: @@ -279,7 +283,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { if (!object) { object = new GLTexture(); glGenTextures(1, &object->_texture); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); Backend::setGPUObject(texture, object); } @@ -363,7 +367,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { default: qCDebug(gpulogging) << "GLBackend::syncGPUObject(const Texture&) case for Texture Type " << texture.getType() << " not supported"; } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); return object; } @@ -386,42 +390,42 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur if (!object) return; if (!object->_texture) return; - class GLFilterMode { - public: - GLint minFilter; - GLint magFilter; - }; - static const GLFilterMode filterModes[] = { - {GL_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_POINT, - {GL_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR, - {GL_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT, - {GL_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR, - - {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, - {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, - {GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_MAG_POINT_MIP_LINEAR, - {GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, - {GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_POINT_MAG_MIP_LINEAR, - {GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_MIP_POINT, - {GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, - {GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR_MIP_POINT, - {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_MIP_LINEAR, - {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} //FILTER_ANISOTROPIC, - }; + class GLFilterMode { + public: + GLint minFilter; + GLint magFilter; + }; + static const GLFilterMode filterModes[] = { + {GL_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_POINT, + {GL_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR, + {GL_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT, + {GL_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR, + + {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, + {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, + {GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_MAG_POINT_MIP_LINEAR, + {GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, + {GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_POINT_MAG_MIP_LINEAR, + {GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_MIP_POINT, + {GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, + {GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR_MIP_POINT, + {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_MIP_LINEAR, + {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} //FILTER_ANISOTROPIC, + }; auto fm = filterModes[sampler.getFilter()]; - glTexParameteri(object->_target, GL_TEXTURE_MIN_FILTER, fm.minFilter); - glTexParameteri(object->_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); + glTexParameteri(object->_target, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glTexParameteri(object->_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); - static const GLenum comparisonFuncs[] = { - GL_NEVER, - GL_LESS, - GL_EQUAL, - GL_LEQUAL, - GL_GREATER, - GL_NOTEQUAL, - GL_GEQUAL, - GL_ALWAYS }; + static const GLenum comparisonFuncs[] = { + GL_NEVER, + GL_LESS, + GL_EQUAL, + GL_LEQUAL, + GL_GREATER, + GL_NOTEQUAL, + GL_GEQUAL, + GL_ALWAYS }; if (sampler.doComparison()) { glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); @@ -430,22 +434,22 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_NONE); } - static const GLenum wrapModes[] = { - GL_REPEAT, // WRAP_REPEAT, - GL_MIRRORED_REPEAT, // WRAP_MIRROR, - GL_CLAMP_TO_EDGE, // WRAP_CLAMP, - GL_CLAMP_TO_BORDER, // WRAP_BORDER, - GL_MIRROR_CLAMP_TO_EDGE_EXT }; // WRAP_MIRROR_ONCE, - - glTexParameteri(object->_target, GL_TEXTURE_WRAP_S, wrapModes[sampler.getWrapModeU()]); - glTexParameteri(object->_target, GL_TEXTURE_WRAP_T, wrapModes[sampler.getWrapModeV()]); - glTexParameteri(object->_target, GL_TEXTURE_WRAP_R, wrapModes[sampler.getWrapModeW()]); + static const GLenum wrapModes[] = { + GL_REPEAT, // WRAP_REPEAT, + GL_MIRRORED_REPEAT, // WRAP_MIRROR, + GL_CLAMP_TO_EDGE, // WRAP_CLAMP, + GL_CLAMP_TO_BORDER, // WRAP_BORDER, + GL_MIRROR_CLAMP_TO_EDGE_EXT }; // WRAP_MIRROR_ONCE, + + glTexParameteri(object->_target, GL_TEXTURE_WRAP_S, wrapModes[sampler.getWrapModeU()]); + glTexParameteri(object->_target, GL_TEXTURE_WRAP_T, wrapModes[sampler.getWrapModeV()]); + glTexParameteri(object->_target, GL_TEXTURE_WRAP_R, wrapModes[sampler.getWrapModeW()]); + + glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*) &sampler.getBorderColor()); + glTexParameteri(object->_target, GL_TEXTURE_BASE_LEVEL, sampler.getMipOffset()); + glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float) sampler.getMinMip()); + glTexParameterf(object->_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); + (void) CHECK_GL_ERROR(); - glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*) &sampler.getBorderColor()); - glTexParameteri(object->_target, GL_TEXTURE_BASE_LEVEL, sampler.getMipOffset()); - glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float) sampler.getMinMip()); - glTexParameterf(object->_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); - glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); - CHECK_GL_ERROR(); - } diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index f0318a66aa..88c993985f 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -109,7 +109,7 @@ void GLBackend::updateTransform() { } glLoadMatrixf(reinterpret_cast< const GLfloat* >(&_transform._projection)); - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } if (_transform._invalidModel || _transform._invalidView) { @@ -141,7 +141,7 @@ void GLBackend::updateTransform() { // glLoadIdentity(); } } - CHECK_GL_ERROR(); + (void) CHECK_GL_ERROR(); } #endif diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 9307882bab..c9bd38efeb 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -41,7 +41,7 @@ public: State(); virtual ~State(); - const Stamp getStamp() const { return _stamp; } + Stamp getStamp() const { return _stamp; } typedef ::gpu::ComparisonFunction ComparisonFunction; diff --git a/libraries/gpu/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h index b1aaec665f..7cd859cbf5 100644 --- a/libraries/gpu/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -101,9 +101,9 @@ public: uint32 getNumAttributes() const { return _attributes.size(); } const AttributeMap& getAttributes() const { return _attributes; } - uint8 getNumChannels() const { return _channels.size(); } + uint8 getNumChannels() const { return _channels.size(); } const ChannelMap& getChannels() const { return _channels; } - const Offset getChannelStride(Slot channel) const { return _channels.at(channel)._stride; } + Offset getChannelStride(Slot channel) const { return _channels.at(channel)._stride; } uint32 getElementTotalSize() const { return _elementTotalSize; } diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 76cac74a59..f73b24411b 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -1,354 +1,354 @@ -// -// Texture.cpp -// libraries/gpu/src/gpu -// -// Created by Sam Gateau on 1/17/2015. -// 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 "Texture.h" -#include -#include - -using namespace gpu; - -Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) : - _sysmem(size, bytes), - _format(format), - _isGPULoaded(false) { -} - -Texture::Pixels::~Pixels() { -} - -void Texture::Storage::assignTexture(Texture* texture) { - _texture = texture; -} - -Stamp Texture::Storage::getStamp(uint16 level) const { - PixelsPointer mip = getMip(level); - if (mip) { - return mip->_sysmem.getStamp(); - } - return 0; -} - -void Texture::Storage::reset() { - _mips.clear(); -} - -Texture::PixelsPointer Texture::Storage::editMip(uint16 level) { - if (level < _mips.size()) { - return _mips[level]; - } - return PixelsPointer(); -} - -const Texture::PixelsPointer Texture::Storage::getMip(uint16 level) const { - if (level < _mips.size()) { - return _mips[level]; - } - return PixelsPointer(); -} - -void Texture::Storage::notifyGPULoaded(uint16 level) const { - PixelsPointer mip = getMip(level); - if (mip) { - mip->_isGPULoaded = true; - mip->_sysmem.resize(0); - } -} - -bool Texture::Storage::isMipAvailable(uint16 level) const { - PixelsPointer mip = getMip(level); - return (mip && mip->_sysmem.getSize()); -} - -bool Texture::Storage::allocateMip(uint16 level) { - bool changed = false; - if (level >= _mips.size()) { - _mips.resize(level+1, PixelsPointer()); - changed = true; - } - - if (!_mips[level]) { - _mips[level] = PixelsPointer(new Pixels()); - changed = true; - } - - return changed; -} - -bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes) { - // Ok we should be able to do that... - allocateMip(level); - auto mip = _mips[level]; - mip->_format = format; - Size allocated = mip->_sysmem.setData(size, bytes); - mip->_isGPULoaded = false; - - return allocated == size; -} - -Texture* Texture::create1D(const Element& texelFormat, uint16 width, const Sampler& sampler) { - return create(TEX_1D, texelFormat, width, 1, 1, 1, 1, sampler); -} - -Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) { - return create(TEX_2D, texelFormat, width, height, 1, 1, 1, sampler); -} - -Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler) { - return create(TEX_3D, texelFormat, width, height, depth, 1, 1, sampler); -} - -Texture* Texture::createCube(const Element& texelFormat, uint16 width, const Sampler& sampler) { - return create(TEX_CUBE, texelFormat, width, width, 1, 1, 1, sampler); -} - -Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler) -{ - Texture* tex = new Texture(); - tex->_storage.reset(new Storage()); - tex->_storage->_texture = tex; - tex->_type = type; - tex->_maxMip = 0; - tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices); - - tex->_sampler = sampler; - - return tex; -} - -Texture* Texture::createFromStorage(Storage* storage) { - Texture* tex = new Texture(); - tex->_storage.reset(storage); - storage->assignTexture(tex); - return tex; -} - -Texture::Texture(): - Resource(), - _storage(), - _stamp(0), - _size(0), - _width(1), - _height(1), - _depth(1), - _numSamples(1), - _numSlices(1), - _maxMip(0), - _type(TEX_1D), - _autoGenerateMips(false), - _defined(false) -{ -} - -Texture::~Texture() -{ -} - -Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) { - if (width && height && depth && numSamples && numSlices) { - bool changed = false; - - if ( _type != type) { - _type = type; - changed = true; - } - - if (_numSlices != numSlices) { - _numSlices = numSlices; - changed = true; - } - - numSamples = evalNumSamplesUsed(numSamples); - if ((_type >= TEX_2D) && (_numSamples != numSamples)) { - _numSamples = numSamples; - changed = true; - } - - if (_width != width) { - _width = width; - changed = true; - } - - if ((_type >= TEX_2D) && (_height != height)) { - _height = height; - changed = true; - } - - - if ((_type >= TEX_3D) && (_depth != depth)) { - _depth = depth; - changed = true; - } - - // Evaluate the new size with the new format - const int DIM_SIZE[] = {1, 1, 1, 6}; - uint32_t size = DIM_SIZE[_type] *_width * _height * _depth * _numSamples * texelFormat.getSize(); - - // If size change then we need to reset - if (changed || (size != getSize())) { - _size = size; - _storage->reset(); - _stamp++; - } - - // TexelFormat might have change, but it's mostly interpretation - if (texelFormat != _texelFormat) { - _texelFormat = texelFormat; - _stamp++; - } - - // Here the Texture has been fully defined from the gpu point of view (size and format) - _defined = true; - } else { - _stamp++; - } - - return _size; -} - -Texture::Size Texture::resize1D(uint16 width, uint16 numSamples) { - return resize(TEX_1D, getTexelFormat(), width, 1, 1, numSamples, 1); -} -Texture::Size Texture::resize2D(uint16 width, uint16 height, uint16 numSamples) { - return resize(TEX_2D, getTexelFormat(), width, height, 1, numSamples, 1); -} -Texture::Size Texture::resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples) { - return resize(TEX_3D, getTexelFormat(), width, height, depth, numSamples, 1); -} -Texture::Size Texture::resizeCube(uint16 width, uint16 numSamples) { - return resize(TEX_CUBE, getTexelFormat(), width, 1, 1, numSamples, 1); -} - -Texture::Size Texture::reformat(const Element& texelFormat) { - return resize(_type, texelFormat, getWidth(), getHeight(), getDepth(), getNumSamples(), getNumSlices()); -} - -bool Texture::isColorRenderTarget() const { - return (_texelFormat.getSemantic() == gpu::RGBA); -} - -bool Texture::isDepthStencilRenderTarget() const { - return (_texelFormat.getSemantic() == gpu::DEPTH) || (_texelFormat.getSemantic() == gpu::DEPTH_STENCIL); -} - -uint16 Texture::evalDimNumMips(uint16 size) { - double largerDim = size; - double val = log(largerDim)/log(2.0); - return 1 + (uint16) val; -} - -// The number mips that the texture could have if all existed -// = log2(max(width, height, depth)) -uint16 Texture::evalNumMips() const { - double largerDim = std::max(std::max(_width, _height), _depth); - double val = log(largerDim)/log(2.0); - return 1 + (uint16) val; -} - -uint16 Texture::maxMip() const { - return _maxMip; -} - -bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes) { - // Check that level accessed make sense - if (level != 0) { - if (_autoGenerateMips) { - return false; - } - if (level >= evalNumMips()) { - return false; - } - } - - // THen check that the mem buffer passed make sense with its format - Size expectedSize = evalStoredMipSize(level, format); - if (size == expectedSize) { - _storage->assignMipData(level, format, size, bytes); - _stamp++; - return true; - } else if (size > expectedSize) { - // NOTE: We are facing this case sometime because apparently QImage (from where we get the bits) is generating images - // and alligning the line of pixels to 32 bits. - // We should probably consider something a bit more smart to get the correct result but for now (UI elements) - // it seems to work... - _storage->assignMipData(level, format, size, bytes); - _stamp++; - return true; - } - - return false; -} - -uint16 Texture::autoGenerateMips(uint16 maxMip) { - _autoGenerateMips = true; - _maxMip = std::min((uint16) (evalNumMips() - 1), maxMip); - _stamp++; - return _maxMip; -} - -uint16 Texture::getStoredMipWidth(uint16 level) const { - PixelsPointer mip = accessStoredMip(level); - if (mip && mip->_sysmem.getSize()) { - return evalMipWidth(level); - } - return 0; -} - -uint16 Texture::getStoredMipHeight(uint16 level) const { - PixelsPointer mip = accessStoredMip(level); - if (mip && mip->_sysmem.getSize()) { - return evalMipHeight(level); - } - return 0; -} - -uint16 Texture::getStoredMipDepth(uint16 level) const { - PixelsPointer mip = accessStoredMip(level); - if (mip && mip->_sysmem.getSize()) { - return evalMipDepth(level); - } - return 0; -} - -uint32 Texture::getStoredMipNumTexels(uint16 level) const { - PixelsPointer mip = accessStoredMip(level); - if (mip && mip->_sysmem.getSize()) { - return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); - } - return 0; -} - -uint32 Texture::getStoredMipSize(uint16 level) const { - PixelsPointer mip = accessStoredMip(level); - if (mip && mip->_sysmem.getSize()) { - return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize(); - } - return 0; -} - -uint16 Texture::evalNumSamplesUsed(uint16 numSamplesTried) { - uint16 sample = numSamplesTried; - if (numSamplesTried <= 1) - sample = 1; - else if (numSamplesTried < 4) - sample = 2; - else if (numSamplesTried < 8) - sample = 4; - else if (numSamplesTried < 16) - sample = 8; - else - sample = 8; - - return sample; -} - +// +// Texture.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 1/17/2015. +// 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 "Texture.h" +#include +#include + +using namespace gpu; + +Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) : + _sysmem(size, bytes), + _format(format), + _isGPULoaded(false) { +} + +Texture::Pixels::~Pixels() { +} + +void Texture::Storage::assignTexture(Texture* texture) { + _texture = texture; +} + +Stamp Texture::Storage::getStamp(uint16 level) const { + PixelsPointer mip = getMip(level); + if (mip) { + return mip->_sysmem.getStamp(); + } + return 0; +} + +void Texture::Storage::reset() { + _mips.clear(); +} + +Texture::PixelsPointer Texture::Storage::editMip(uint16 level) { + if (level < _mips.size()) { + return _mips[level]; + } + return PixelsPointer(); +} + +const Texture::PixelsPointer Texture::Storage::getMip(uint16 level) const { + if (level < _mips.size()) { + return _mips[level]; + } + return PixelsPointer(); +} + +void Texture::Storage::notifyGPULoaded(uint16 level) const { + PixelsPointer mip = getMip(level); + if (mip) { + mip->_isGPULoaded = true; + mip->_sysmem.resize(0); + } +} + +bool Texture::Storage::isMipAvailable(uint16 level) const { + PixelsPointer mip = getMip(level); + return (mip && mip->_sysmem.getSize()); +} + +bool Texture::Storage::allocateMip(uint16 level) { + bool changed = false; + if (level >= _mips.size()) { + _mips.resize(level+1, PixelsPointer()); + changed = true; + } + + if (!_mips[level]) { + _mips[level] = PixelsPointer(new Pixels()); + changed = true; + } + + return changed; +} + +bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes) { + // Ok we should be able to do that... + allocateMip(level); + auto mip = _mips[level]; + mip->_format = format; + Size allocated = mip->_sysmem.setData(size, bytes); + mip->_isGPULoaded = false; + + return allocated == size; +} + +Texture* Texture::create1D(const Element& texelFormat, uint16 width, const Sampler& sampler) { + return create(TEX_1D, texelFormat, width, 1, 1, 1, 1, sampler); +} + +Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) { + return create(TEX_2D, texelFormat, width, height, 1, 1, 1, sampler); +} + +Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler) { + return create(TEX_3D, texelFormat, width, height, depth, 1, 1, sampler); +} + +Texture* Texture::createCube(const Element& texelFormat, uint16 width, const Sampler& sampler) { + return create(TEX_CUBE, texelFormat, width, width, 1, 1, 1, sampler); +} + +Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler) +{ + Texture* tex = new Texture(); + tex->_storage.reset(new Storage()); + tex->_storage->_texture = tex; + tex->_type = type; + tex->_maxMip = 0; + tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices); + + tex->_sampler = sampler; + + return tex; +} + +Texture* Texture::createFromStorage(Storage* storage) { + Texture* tex = new Texture(); + tex->_storage.reset(storage); + storage->assignTexture(tex); + return tex; +} + +Texture::Texture(): + Resource(), + _storage(), + _stamp(0), + _size(0), + _width(1), + _height(1), + _depth(1), + _numSamples(1), + _numSlices(1), + _maxMip(0), + _type(TEX_1D), + _autoGenerateMips(false), + _defined(false) +{ +} + +Texture::~Texture() +{ +} + +Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) { + if (width && height && depth && numSamples && numSlices) { + bool changed = false; + + if ( _type != type) { + _type = type; + changed = true; + } + + if (_numSlices != numSlices) { + _numSlices = numSlices; + changed = true; + } + + numSamples = evalNumSamplesUsed(numSamples); + if ((_type >= TEX_2D) && (_numSamples != numSamples)) { + _numSamples = numSamples; + changed = true; + } + + if (_width != width) { + _width = width; + changed = true; + } + + if ((_type >= TEX_2D) && (_height != height)) { + _height = height; + changed = true; + } + + + if ((_type >= TEX_3D) && (_depth != depth)) { + _depth = depth; + changed = true; + } + + // Evaluate the new size with the new format + const int DIM_SIZE[] = {1, 1, 1, 6}; + uint32_t size = DIM_SIZE[_type] *_width * _height * _depth * _numSamples * texelFormat.getSize(); + + // If size change then we need to reset + if (changed || (size != getSize())) { + _size = size; + _storage->reset(); + _stamp++; + } + + // TexelFormat might have change, but it's mostly interpretation + if (texelFormat != _texelFormat) { + _texelFormat = texelFormat; + _stamp++; + } + + // Here the Texture has been fully defined from the gpu point of view (size and format) + _defined = true; + } else { + _stamp++; + } + + return _size; +} + +Texture::Size Texture::resize1D(uint16 width, uint16 numSamples) { + return resize(TEX_1D, getTexelFormat(), width, 1, 1, numSamples, 1); +} +Texture::Size Texture::resize2D(uint16 width, uint16 height, uint16 numSamples) { + return resize(TEX_2D, getTexelFormat(), width, height, 1, numSamples, 1); +} +Texture::Size Texture::resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples) { + return resize(TEX_3D, getTexelFormat(), width, height, depth, numSamples, 1); +} +Texture::Size Texture::resizeCube(uint16 width, uint16 numSamples) { + return resize(TEX_CUBE, getTexelFormat(), width, 1, 1, numSamples, 1); +} + +Texture::Size Texture::reformat(const Element& texelFormat) { + return resize(_type, texelFormat, getWidth(), getHeight(), getDepth(), getNumSamples(), getNumSlices()); +} + +bool Texture::isColorRenderTarget() const { + return (_texelFormat.getSemantic() == gpu::RGBA); +} + +bool Texture::isDepthStencilRenderTarget() const { + return (_texelFormat.getSemantic() == gpu::DEPTH) || (_texelFormat.getSemantic() == gpu::DEPTH_STENCIL); +} + +uint16 Texture::evalDimNumMips(uint16 size) { + double largerDim = size; + double val = log(largerDim)/log(2.0); + return 1 + (uint16) val; +} + +// The number mips that the texture could have if all existed +// = log2(max(width, height, depth)) +uint16 Texture::evalNumMips() const { + double largerDim = std::max(std::max(_width, _height), _depth); + double val = log(largerDim)/log(2.0); + return 1 + (uint16) val; +} + +uint16 Texture::maxMip() const { + return _maxMip; +} + +bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes) { + // Check that level accessed make sense + if (level != 0) { + if (_autoGenerateMips) { + return false; + } + if (level >= evalNumMips()) { + return false; + } + } + + // THen check that the mem buffer passed make sense with its format + Size expectedSize = evalStoredMipSize(level, format); + if (size == expectedSize) { + _storage->assignMipData(level, format, size, bytes); + _stamp++; + return true; + } else if (size > expectedSize) { + // NOTE: We are facing this case sometime because apparently QImage (from where we get the bits) is generating images + // and alligning the line of pixels to 32 bits. + // We should probably consider something a bit more smart to get the correct result but for now (UI elements) + // it seems to work... + _storage->assignMipData(level, format, size, bytes); + _stamp++; + return true; + } + + return false; +} + +uint16 Texture::autoGenerateMips(uint16 maxMip) { + _autoGenerateMips = true; + _maxMip = std::min((uint16) (evalNumMips() - 1), maxMip); + _stamp++; + return _maxMip; +} + +uint16 Texture::getStoredMipWidth(uint16 level) const { + PixelsPointer mip = accessStoredMip(level); + if (mip && mip->_sysmem.getSize()) { + return evalMipWidth(level); + } + return 0; +} + +uint16 Texture::getStoredMipHeight(uint16 level) const { + PixelsPointer mip = accessStoredMip(level); + if (mip && mip->_sysmem.getSize()) { + return evalMipHeight(level); + } + return 0; +} + +uint16 Texture::getStoredMipDepth(uint16 level) const { + PixelsPointer mip = accessStoredMip(level); + if (mip && mip->_sysmem.getSize()) { + return evalMipDepth(level); + } + return 0; +} + +uint32 Texture::getStoredMipNumTexels(uint16 level) const { + PixelsPointer mip = accessStoredMip(level); + if (mip && mip->_sysmem.getSize()) { + return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); + } + return 0; +} + +uint32 Texture::getStoredMipSize(uint16 level) const { + PixelsPointer mip = accessStoredMip(level); + if (mip && mip->_sysmem.getSize()) { + return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize(); + } + return 0; +} + +uint16 Texture::evalNumSamplesUsed(uint16 numSamplesTried) { + uint16 sample = numSamplesTried; + if (numSamplesTried <= 1) + sample = 1; + else if (numSamplesTried < 4) + sample = 2; + else if (numSamplesTried < 8) + sample = 4; + else if (numSamplesTried < 16) + sample = 8; + else + sample = 8; + + return sample; +} + void Texture::setSampler(const Sampler& sampler) { _sampler = sampler; _samplerStamp++; diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 1d1e82123a..7bf936958b 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -151,8 +151,8 @@ public: Texture& operator=(const Texture& buf); // deep copy of the sysmem texture ~Texture(); - const Stamp getStamp() const { return _stamp; } - const Stamp getDataStamp(uint16 level = 0) const { return _storage->getStamp(level); } + Stamp getStamp() const { return _stamp; } + Stamp getDataStamp(uint16 level = 0) const { return _storage->getStamp(level); } // The size in bytes of data stored in the texture Size getSize() const { return _size; } @@ -264,7 +264,7 @@ public: // Own sampler void setSampler(const Sampler& sampler); const Sampler& getSampler() const { return _sampler; } - const Stamp getSamplerStamp() const { return _samplerStamp; } + Stamp getSamplerStamp() const { return _samplerStamp; } protected: std::unique_ptr< Storage > _storage; diff --git a/libraries/model/src/model/Geometry.cpp b/libraries/model/src/model/Geometry.cpp index d5d3ba6c07..156f593421 100755 --- a/libraries/model/src/model/Geometry.cpp +++ b/libraries/model/src/model/Geometry.cpp @@ -97,7 +97,7 @@ const Box Mesh::evalPartBounds(int partStart, int partEnd, Boxes& bounds) const auto vertices = &_vertexBuffer.get((*part)._baseVertex); for (;index != endIndex; index++) { // skip primitive restart indices - if ((*index) != PRIMITIVE_RESTART_INDEX) { + if ((*index) != (uint) PRIMITIVE_RESTART_INDEX) { partBound += vertices[(*index)]; } } diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index 0df4887b74..b58af5e4e7 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -17,7 +17,9 @@ #include "NetworkLogging.h" #include "DataServerAccountInfo.h" +#ifndef __GNUC__ #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif DataServerAccountInfo::DataServerAccountInfo() : _accessToken(), @@ -34,6 +36,7 @@ DataServerAccountInfo::DataServerAccountInfo() : } DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) { + QObject(), _accessToken = otherInfo._accessToken; _username = otherInfo._username; _xmppPassword = otherInfo._xmppPassword; diff --git a/libraries/networking/src/HifiSockAddr.cpp b/libraries/networking/src/HifiSockAddr.cpp index c0fb0ecb69..8a967d7818 100644 --- a/libraries/networking/src/HifiSockAddr.cpp +++ b/libraries/networking/src/HifiSockAddr.cpp @@ -33,6 +33,7 @@ HifiSockAddr::HifiSockAddr(const QHostAddress& address, quint16 port) : } HifiSockAddr::HifiSockAddr(const HifiSockAddr& otherSockAddr) : + QObject(), _address(otherSockAddr._address), _port(otherSockAddr._port) { diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index c6026b3a23..de1b8f66ba 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -39,8 +39,7 @@ NetworkPeer::NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, co } -NetworkPeer::NetworkPeer(const NetworkPeer& otherPeer) { - +NetworkPeer::NetworkPeer(const NetworkPeer& otherPeer) : QObject() { _uuid = otherPeer._uuid; _publicSocket = otherPeer._publicSocket; _localSocket = otherPeer._localSocket; diff --git a/libraries/networking/src/OAuthAccessToken.cpp b/libraries/networking/src/OAuthAccessToken.cpp index b8ec58099f..0c14e5e074 100644 --- a/libraries/networking/src/OAuthAccessToken.cpp +++ b/libraries/networking/src/OAuthAccessToken.cpp @@ -31,7 +31,7 @@ OAuthAccessToken::OAuthAccessToken(const QJsonObject& jsonObject) : } -OAuthAccessToken::OAuthAccessToken(const OAuthAccessToken& otherToken) { +OAuthAccessToken::OAuthAccessToken(const OAuthAccessToken& otherToken) : QObject() { token = otherToken.token; refreshToken = otherToken.refreshToken; expiryTimestamp = otherToken.expiryTimestamp; diff --git a/libraries/networking/src/RSAKeypairGenerator.cpp b/libraries/networking/src/RSAKeypairGenerator.cpp index f142ce1831..2368b5e6d2 100644 --- a/libraries/networking/src/RSAKeypairGenerator.cpp +++ b/libraries/networking/src/RSAKeypairGenerator.cpp @@ -18,7 +18,9 @@ #include "NetworkLogging.h" #include "RSAKeypairGenerator.h" +#ifndef __GNUC__ #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif RSAKeypairGenerator::RSAKeypairGenerator(QObject* parent) : QObject(parent) diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index ae40cbfa15..6629d9ceb7 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -166,7 +166,7 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) { void OctreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) { RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (_tree) { _tree->lockForRead(); _tree->recurseTreeWithOperation(renderOperation, &args); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 051cbb0e17..9d71ec5cc2 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1796,7 +1796,9 @@ NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer(), -1 }; + FBXJoint joint = { false, QVector(), -1, 0.0f, 0.0f, glm::vec3(), glm::mat4(), glm::quat(), glm::quat(), + glm::quat(), glm::mat4(), glm::mat4(), glm::vec3(), glm::vec3(), glm::quat(), glm::quat(), + glm::mat4(), QString(""), glm::vec3(), glm::quat(), SHAPE_TYPE_NONE, false}; _geometry.joints.append(joint); _geometry.leftEyeJointIndex = -1; _geometry.rightEyeJointIndex = -1; diff --git a/libraries/render-utils/src/JointState.cpp b/libraries/render-utils/src/JointState.cpp index cf98d69baa..a82a57f0ed 100644 --- a/libraries/render-utils/src/JointState.cpp +++ b/libraries/render-utils/src/JointState.cpp @@ -256,7 +256,7 @@ void JointState::setVisibleRotationInConstrainedFrame(const glm::quat& targetRot _visibleRotation = parentRotation * _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation; } -const bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) const { +bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) const { glm::quat defaultRotation = _fbxJoint->rotation; return glm::abs(rotation.x - defaultRotation.x) < tolerance && glm::abs(rotation.y - defaultRotation.y) < tolerance && diff --git a/libraries/render-utils/src/JointState.h b/libraries/render-utils/src/JointState.h index b502083463..363aeecd01 100644 --- a/libraries/render-utils/src/JointState.h +++ b/libraries/render-utils/src/JointState.h @@ -88,7 +88,7 @@ public: const glm::quat& getRotationInConstrainedFrame() const { return _rotationInConstrainedFrame; } const glm::quat& getVisibleRotationInConstrainedFrame() const { return _visibleRotationInConstrainedFrame; } - const bool rotationIsDefault(const glm::quat& rotation, float tolerance = EPSILON) const; + bool rotationIsDefault(const glm::quat& rotation, float tolerance = EPSILON) const; glm::quat getDefaultRotationInParentFrame() const; const glm::vec3& getDefaultTranslationInConstrainedFrame() const; diff --git a/libraries/render-utils/src/MatrixStack.h b/libraries/render-utils/src/MatrixStack.h index 505818fc4a..a71bfcbc4a 100644 --- a/libraries/render-utils/src/MatrixStack.h +++ b/libraries/render-utils/src/MatrixStack.h @@ -38,7 +38,7 @@ public: push(glm::mat4()); } - explicit MatrixStack(const MatrixStack & other) { + explicit MatrixStack(const MatrixStack & other) : std::stack() { *((std::stack*)this) = *((std::stack*)&other); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 4bc69f1bea..bcdba0dd42 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -111,7 +111,8 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3)); gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); - bool makeResult = gpu::Shader::makeProgram(*program, slotBindings); + // bool makeResult = + gpu::Shader::makeProgram(*program, slotBindings); auto locations = std::shared_ptr(new Locations()); @@ -139,7 +140,8 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, // Good to go add the brand new pipeline auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); - auto it = insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); + // auto it = + insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); // If not a shadow pass, create the mirror version from the same state, just change the FrontFace if (!key.isShadow()) { diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index 114d209788..0bfc91c9c5 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -46,7 +46,7 @@ public: void setConvexHulls(const QVector>& points); void setCapsuleY(float radius, float halfHeight); - const int getType() const { return _type; } + int getType() const { return _type; } const glm::vec3& getHalfExtents() const { return _halfExtents; } From ee30588fd47c498bb598a0c64ee5ffb2f12eb653 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 25 Apr 2015 10:41:06 -0700 Subject: [PATCH 330/401] More menu work --- interface/resources/qml/HifiAction.qml | 20 - interface/resources/qml/HifiMenu.qml | 177 ++-- interface/resources/qml/Menu.qml | 1072 ++++++++++++++++++++++++ interface/src/Application.cpp | 11 - interface/src/ui/LoginDialog.cpp | 4 +- interface/src/ui/MarketplaceDialog.cpp | 2 +- interface/src/ui/MarketplaceDialog.h | 2 +- interface/src/ui/MenuQml.cpp | 19 - interface/src/ui/MenuQml.h | 26 - libraries/ui/src/HifiMenu.cpp | 23 + libraries/ui/src/HifiMenu.h | 3 + libraries/ui/src/OffscreenUi.cpp | 7 +- libraries/ui/src/OffscreenUi.h | 22 +- tests/ui/src/main.cpp | 187 ++++- 14 files changed, 1376 insertions(+), 199 deletions(-) delete mode 100644 interface/resources/qml/HifiAction.qml create mode 100644 interface/resources/qml/Menu.qml delete mode 100644 interface/src/ui/MenuQml.cpp delete mode 100644 interface/src/ui/MenuQml.h diff --git a/interface/resources/qml/HifiAction.qml b/interface/resources/qml/HifiAction.qml deleted file mode 100644 index 0cecff91d7..0000000000 --- a/interface/resources/qml/HifiAction.qml +++ /dev/null @@ -1,20 +0,0 @@ -import QtQuick 2.4 -import QtQuick.Controls 1.3 - -Action { - property string name - objectName: name + "HifiAction" - text: qsTr(name) - - signal triggeredByName(string name); - signal toggledByName(string name); - - onTriggered: { - triggeredByName(name); - } - - onToggled: { - toggledByName(name, checked); - } -} - diff --git a/interface/resources/qml/HifiMenu.qml b/interface/resources/qml/HifiMenu.qml index 1afa39c5d1..2c6963a349 100644 --- a/interface/resources/qml/HifiMenu.qml +++ b/interface/resources/qml/HifiMenu.qml @@ -17,7 +17,7 @@ Hifi.HifiMenu { onEnabledChanged: { if (enabled && columns.length == 0) { - pushColumn(rootMenu.items); + pushColumn(rootMenu.menus); } opacity = enabled ? 1.0 : 0.0 if (enabled) { @@ -42,9 +42,95 @@ Hifi.HifiMenu { } - property var menu: Menu {} property var models: [] property var columns: [] + + property var menuBuilder: Component { + Border { + SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } + x: root.models.length == 1 ? + (root.width / 2 - width / 2) : + root.columns[root.models.length - 2].x + 60; + anchors.verticalCenter: parent.verticalCenter + border.color: hifiPalette.hifiBlue + color: sysPalette.window + + ListView { + spacing: 6 + property int outerMargin: 8 + property real minWidth: 0 + anchors.fill: parent + anchors.margins: outerMargin + id: listView + height: root.height + currentIndex: -1 + + onCountChanged: { + recalculateSize() + } + + function recalculateSize() { + var newHeight = 0 + var newWidth = minWidth; + for (var i = 0; i < children.length; ++i) { + var item = children[i]; + newHeight += item.height + } + parent.height = newHeight + outerMargin * 2; + parent.width = newWidth + outerMargin * 2 + } + + highlight: Rectangle { + width: listView.minWidth - 32; + height: 32 + color: sysPalette.highlight + y: (listView.currentItem) ? listView.currentItem.y : 0; + x: 32 + Behavior on y { + NumberAnimation { + duration: 100 + easing.type: Easing.InOutQuint + } + } + } + + + property int columnIndex: root.models.length - 1 + model: root.models[columnIndex] + delegate: Loader { + id: loader + sourceComponent: root.itemBuilder + Binding { + target: loader.item + property: "root" + value: root + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "source" + value: modelData + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "listViewIndex" + value: index + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "listView" + value: listView + when: loader.status == Loader.Ready + } + } + + } + + } + } + property var itemBuilder: Component { Text { SystemPalette { id: sp; colorGroup: SystemPalette.Active } @@ -93,6 +179,8 @@ Hifi.HifiMenu { MouseArea { id: mouseArea acceptedButtons: Qt.LeftButton + anchors.left: parent.left + anchors.leftMargin: -32 anchors.bottom: parent.bottom anchors.bottomMargin: 0 anchors.top: parent.top @@ -106,91 +194,6 @@ Hifi.HifiMenu { } } - - property var menuBuilder: Component { - Border { - SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } - x: root.models.length == 1 ? - (root.width / 2 - width / 2) : - root.columns[root.models.length - 2].x + 60; - anchors.verticalCenter: parent.verticalCenter - border.color: hifiPalette.hifiBlue - color: sysPalette.window - - ListView { - spacing: 6 - property int outerMargin: 8 - property real minWidth: 0 - anchors.fill: parent - anchors.margins: outerMargin - id: listView - height: root.height - currentIndex: -1 - - onCountChanged: { - recalculateSize() - } - - function recalculateSize() { - var newHeight = 0 - var newWidth = minWidth; - for (var i = 0; i < children.length; ++i) { - var item = children[i]; - newHeight += item.height - } - parent.height = newHeight + outerMargin * 2; - parent.width = newWidth + outerMargin * 2 - } - - highlight: Rectangle { - width: listView.minWidth; height: 32 - color: sysPalette.highlight - y: (listView.currentItem) ? listView.currentItem.y : 0; - x: 32 - Behavior on y { - NumberAnimation { - duration: 100 - easing.type: Easing.InOutQuint - } - } - } - - - property int columnIndex: root.models.length - 1 - model: root.models[columnIndex] - delegate: Loader { - id: loader - sourceComponent: root.itemBuilder - Binding { - target: loader.item - property: "root" - value: root - when: loader.status == Loader.Ready - } - Binding { - target: loader.item - property: "source" - value: modelData - when: loader.status == Loader.Ready - } - Binding { - target: loader.item - property: "listViewIndex" - value: index - when: loader.status == Loader.Ready - } - Binding { - target: loader.item - property: "listView" - value: listView - when: loader.status == Loader.Ready - } - } - - } - - } - } function lastColumn() { diff --git a/interface/resources/qml/Menu.qml b/interface/resources/qml/Menu.qml new file mode 100644 index 0000000000..3939794fb2 --- /dev/null +++ b/interface/resources/qml/Menu.qml @@ -0,0 +1,1072 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.3 +import Hifi 1.0 + +Item { + Item { + objectName: "AllActions" + Action { + id: aboutApp + objectName: "HifiAction_" + MenuConstants.AboutApp + text: qsTr("About Interface") + } + + // + // File Menu + // + Action { + id: login + objectName: "HifiAction_" + MenuConstants.Login + text: qsTr("Login") + } + Action { + id: quit + objectName: "HifiAction_" + MenuConstants.Quit + text: qsTr("Quit") + //shortcut: StandardKey.Quit + shortcut: "Ctrl+Q" + } + + // Scripts + Action { + id: loadScript + objectName: "HifiAction_" + MenuConstants.LoadScript + text: qsTr("Open and Run Script File...") + shortcut: "Ctrl+O" + onTriggered: { + console.log("Shortcut ctrl+o hit"); + } + } + Action { + id: loadScriptURL + objectName: "HifiAction_" + MenuConstants.LoadScriptURL + text: qsTr("Open and Run Script from URL...") + shortcut: "Ctrl+Shift+O" + } + Action { + id: reloadAllScripts + objectName: "HifiAction_" + MenuConstants.ReloadAllScripts + text: qsTr("Reload All Scripts") + } + Action { + id: runningScripts + objectName: "HifiAction_" + MenuConstants.RunningScripts + text: qsTr("Running Scripts") + } + Action { + id: stopAllScripts + objectName: "HifiAction_" + MenuConstants.StopAllScripts + text: qsTr("Stop All Scripts") + } + + // Locations + Action { + id: bookmarkLocation + objectName: "HifiAction_" + MenuConstants.BookmarkLocation + text: qsTr("Bookmark Location") + } + Action { + id: bookmarks + objectName: "HifiAction_" + MenuConstants.Bookmarks + text: qsTr("Bookmarks") + } + Action { + id: addressBar + objectName: "HifiAction_" + MenuConstants.AddressBar + text: qsTr("Show Address Bar") + } + + // + // Edit menu + // + Action { + id: undo + text: "Undo" + shortcut: StandardKey.Undo + } + + Action { + id: redo + text: "Redo" + shortcut: StandardKey.Redo + } + + Action { + id: animations + objectName: "HifiAction_" + MenuConstants.Animations + text: qsTr("Animations...") + } + Action { + id: attachments + objectName: "HifiAction_" + MenuConstants.Attachments + text: qsTr("Attachments...") + } + + // + // Tools menu + // + Action { + id: scriptEditor + objectName: "HifiAction_" + MenuConstants.ScriptEditor + text: qsTr("Script Editor...") + } + Action { + id: controlWithSpeech + objectName: "HifiAction_" + MenuConstants.ControlWithSpeech + text: qsTr("Control With Speech") + } + Action { + id: chat + objectName: "HifiAction_" + MenuConstants.Chat + text: qsTr("Chat...") + } + Action { + id: addRemoveFriends + objectName: "HifiAction_" + MenuConstants.AddRemoveFriends + text: qsTr("Add/Remove Friends...") + } + ExclusiveGroup { + Action { + id: visibleToEveryone + objectName: "HifiAction_" + MenuConstants.VisibleToEveryone + text: qsTr("Everyone") + } + Action { + id: visibleToFriends + objectName: "HifiAction_" + MenuConstants.VisibleToFriends + text: qsTr("Friends") + } + Action { + id: visibleToNoOne + objectName: "HifiAction_" + MenuConstants.VisibleToNoOne + text: qsTr("No one") + } + } + Action { + id: toolWindow + objectName: "HifiAction_" + MenuConstants.ToolWindow + text: qsTr("Tool Window") + } + Action { + id: javascriptConsole + objectName: "HifiAction_" + MenuConstants.JavascriptConsole + text: qsTr("Console...") + } + Action { + id: resetSensors + objectName: "HifiAction_" + MenuConstants.ResetSensors + text: qsTr("Reset Sensors") + } + + + + + + + + + + + + + Action { + id: alignForearmsWithWrists + objectName: "HifiAction_" + MenuConstants.AlignForearmsWithWrists + text: qsTr("Align Forearms with Wrists") + checkable: true + } + Action { + id: alternateIK + objectName: "HifiAction_" + MenuConstants.AlternateIK + text: qsTr("Alternate IK") + checkable: true + } + Action { + id: ambientOcclusion + objectName: "HifiAction_" + MenuConstants.AmbientOcclusion + text: qsTr("Ambient Occlusion") + checkable: true + } + Action { + id: atmosphere + objectName: "HifiAction_" + MenuConstants.Atmosphere + text: qsTr("Atmosphere") + } + Action { + id: audioNoiseReduction + objectName: "HifiAction_" + MenuConstants.AudioNoiseReduction + text: qsTr("Audio Noise Reduction") + checkable: true + } + Action { + id: audioScope + objectName: "HifiAction_" + MenuConstants.AudioScope + text: qsTr("Show Scope") + checkable: true + } + ExclusiveGroup { + Action { + id: audioScopeFiveFrames + objectName: "HifiAction_" + MenuConstants.AudioScopeFiveFrames + text: qsTr("Five") + checkable: true + checked: true + } + Action { + id: audioScopeFiftyFrames + objectName: "HifiAction_" + MenuConstants.AudioScopeFiftyFrames + text: qsTr("Fifty") + checkable: true + } + Action { + id: audioScopeTwentyFrames + objectName: "HifiAction_" + MenuConstants.AudioScopeTwentyFrames + text: qsTr("Twenty") + checkable: true + } + } + Action { + id: audioScopePause + objectName: "HifiAction_" + MenuConstants.AudioScopePause + text: qsTr("Pause Scope") + checkable: true + } + Action { + id: audioStats + objectName: "HifiAction_" + MenuConstants.AudioStats + text: qsTr("Audio Stats") + checkable: true + } + Action { + id: audioStatsShowInjectedStreams + objectName: "HifiAction_" + MenuConstants.AudioStatsShowInjectedStreams + text: qsTr("Audio Stats Show Injected Streams") + checkable: true + } + Action { + id: bandwidthDetails + objectName: "HifiAction_" + MenuConstants.BandwidthDetails + text: qsTr("Bandwidth Details") + checkable: true + } + Action { + id: blueSpeechSphere + objectName: "HifiAction_" + MenuConstants.BlueSpeechSphere + text: qsTr("Blue Sphere While Speaking") + checkable: true + } + Action { + id: cascadedShadows + objectName: "HifiAction_" + MenuConstants.CascadedShadows + text: qsTr("Cascaded") + } + Action { + id: cachesSize + objectName: "HifiAction_" + MenuConstants.CachesSize + text: qsTr("RAM Caches Size") + } + Action { + id: collisions + objectName: "HifiAction_" + MenuConstants.Collisions + text: qsTr("Collisions") + } + Action { + id: copyAddress + objectName: "HifiAction_" + MenuConstants.CopyAddress + text: qsTr("Copy Address to Clipboard") + } + Action { + id: copyPath + objectName: "HifiAction_" + MenuConstants.CopyPath + text: qsTr("Copy Path to Clipboard") + } + Action { + id: decreaseAvatarSize + objectName: "HifiAction_" + MenuConstants.DecreaseAvatarSize + text: qsTr("Decrease Avatar Size") + } + Action { + id: deleteBookmark + objectName: "HifiAction_" + MenuConstants.DeleteBookmark + text: qsTr("Delete Bookmark...") + } + Action { + id: disableActivityLogger + objectName: "HifiAction_" + MenuConstants.DisableActivityLogger + text: qsTr("Disable Activity Logger") + } + Action { + id: disableLightEntities + objectName: "HifiAction_" + MenuConstants.DisableLightEntities + text: qsTr("Disable Light Entities") + } + Action { + id: disableNackPackets + objectName: "HifiAction_" + MenuConstants.DisableNackPackets + text: qsTr("Disable NACK Packets") + } + Action { + id: diskCacheEditor + objectName: "HifiAction_" + MenuConstants.DiskCacheEditor + text: qsTr("Disk Cache Editor") + } + Action { + id: displayHands + objectName: "HifiAction_" + MenuConstants.DisplayHands + text: qsTr("Show Hand Info") + } + Action { + id: displayHandTargets + objectName: "HifiAction_" + MenuConstants.DisplayHandTargets + text: qsTr("Show Hand Targets") + } + Action { + id: displayModelBounds + objectName: "HifiAction_" + MenuConstants.DisplayModelBounds + text: qsTr("Display Model Bounds") + } + Action { + id: displayModelTriangles + objectName: "HifiAction_" + MenuConstants.DisplayModelTriangles + text: qsTr("Display Model Triangles") + } + Action { + id: displayModelElementChildProxies + objectName: "HifiAction_" + MenuConstants.DisplayModelElementChildProxies + text: qsTr("Display Model Element Children") + } + Action { + id: displayModelElementProxy + objectName: "HifiAction_" + MenuConstants.DisplayModelElementProxy + text: qsTr("Display Model Element Bounds") + } + Action { + id: displayDebugTimingDetails + objectName: "HifiAction_" + MenuConstants.DisplayDebugTimingDetails + text: qsTr("Display Timing Details") + } + Action { + id: dontDoPrecisionPicking + objectName: "HifiAction_" + MenuConstants.DontDoPrecisionPicking + text: qsTr("Don't Do Precision Picking") + } + Action { + id: dontFadeOnOctreeServerChanges + objectName: "HifiAction_" + MenuConstants.DontFadeOnOctreeServerChanges + text: qsTr("Don't Fade In/Out on Octree Server Changes") + } + Action { + id: dontRenderEntitiesAsScene + objectName: "HifiAction_" + MenuConstants.DontRenderEntitiesAsScene + text: qsTr("Don't Render Entities as Scene") + } + Action { + id: echoLocalAudio + objectName: "HifiAction_" + MenuConstants.EchoLocalAudio + text: qsTr("Echo Local Audio") + } + Action { + id: echoServerAudio + objectName: "HifiAction_" + MenuConstants.EchoServerAudio + text: qsTr("Echo Server Audio") + } + Action { + id: editEntitiesHelp + objectName: "HifiAction_" + MenuConstants.EditEntitiesHelp + text: qsTr("Edit Entities Help...") + } + Action { + id: enable3DTVMode + objectName: "HifiAction_" + MenuConstants.Enable3DTVMode + text: qsTr("Enable 3DTV Mode") + } + Action { + id: enableCharacterController + objectName: "HifiAction_" + MenuConstants.EnableCharacterController + text: qsTr("Enable avatar collisions") + } + Action { + id: enableGlowEffect + objectName: "HifiAction_" + MenuConstants.EnableGlowEffect + text: qsTr("Enable Glow Effect (Warning: Poor Oculus Performance)") + } + Action { + id: enableVRMode + objectName: "HifiAction_" + MenuConstants.EnableVRMode + text: qsTr("Enable VR Mode") + } + Action { + id: expandMyAvatarSimulateTiming + objectName: "HifiAction_" + MenuConstants.ExpandMyAvatarSimulateTiming + text: qsTr("Expand /myAvatar/simulation") + } + Action { + id: expandMyAvatarTiming + objectName: "HifiAction_" + MenuConstants.ExpandMyAvatarTiming + text: qsTr("Expand /myAvatar") + } + Action { + id: expandOtherAvatarTiming + objectName: "HifiAction_" + MenuConstants.ExpandOtherAvatarTiming + text: qsTr("Expand /otherAvatar") + } + Action { + id: expandPaintGLTiming + objectName: "HifiAction_" + MenuConstants.ExpandPaintGLTiming + text: qsTr("Expand /paintGL") + } + Action { + id: expandUpdateTiming + objectName: "HifiAction_" + MenuConstants.ExpandUpdateTiming + text: qsTr("Expand /update") + } + Action { + id: faceshift + objectName: "HifiAction_" + MenuConstants.Faceshift + text: qsTr("Faceshift") + } + Action { + id: filterSixense + objectName: "HifiAction_" + MenuConstants.FilterSixense + text: qsTr("Smooth Sixense Movement") + } + Action { + id: firstPerson + objectName: "HifiAction_" + MenuConstants.FirstPerson + text: qsTr("First Person") + } + Action { + id: frameTimer + objectName: "HifiAction_" + MenuConstants.FrameTimer + text: qsTr("Show Timer") + } + Action { + id: fullscreen + objectName: "HifiAction_" + MenuConstants.Fullscreen + text: qsTr("Fullscreen") + } + Action { + id: fullscreenMirror + objectName: "HifiAction_" + MenuConstants.FullscreenMirror + text: qsTr("Fullscreen Mirror") + } + Action { + id: glowWhenSpeaking + objectName: "HifiAction_" + MenuConstants.GlowWhenSpeaking + text: qsTr("Glow When Speaking") + } + Action { + id: namesAboveHeads + objectName: "HifiAction_" + MenuConstants.NamesAboveHeads + text: qsTr("Names Above Heads") + } + Action { + id: goToUser + objectName: "HifiAction_" + MenuConstants.GoToUser + text: qsTr("Go To User") + } + Action { + id: hMDTools + objectName: "HifiAction_" + MenuConstants.HMDTools + text: qsTr("HMD Tools") + } + Action { + id: increaseAvatarSize + objectName: "HifiAction_" + MenuConstants.IncreaseAvatarSize + text: qsTr("Increase Avatar Size") + } + Action { + id: keyboardMotorControl + objectName: "HifiAction_" + MenuConstants.KeyboardMotorControl + text: qsTr("Enable Keyboard Motor Control") + } + Action { + id: leapMotionOnHMD + objectName: "HifiAction_" + MenuConstants.LeapMotionOnHMD + text: qsTr("Leap Motion on HMD") + } + Action { + id: loadRSSDKFile + objectName: "HifiAction_" + MenuConstants.LoadRSSDKFile + text: qsTr("Load .rssdk file") + } + Action { + id: lodTools + objectName: "HifiAction_" + MenuConstants.LodTools + text: qsTr("LOD Tools") + } + Action { + id: log + objectName: "HifiAction_" + MenuConstants.Log + text: qsTr("Log") + } + Action { + id: lowVelocityFilter + objectName: "HifiAction_" + MenuConstants.LowVelocityFilter + text: qsTr("Low Velocity Filter") + } + Action { + id: mirror + objectName: "HifiAction_" + MenuConstants.Mirror + text: qsTr("Mirror") + } + Action { + id: muteAudio + objectName: "HifiAction_" + MenuConstants.MuteAudio + text: qsTr("Mute Microphone") + } + Action { + id: muteEnvironment + objectName: "HifiAction_" + MenuConstants.MuteEnvironment + text: qsTr("Mute Environment") + } + Action { + id: noFaceTracking + objectName: "HifiAction_" + MenuConstants.NoFaceTracking + text: qsTr("None") + } + Action { + id: noShadows + objectName: "HifiAction_" + MenuConstants.NoShadows + text: qsTr("None") + } + Action { + id: octreeStats + objectName: "HifiAction_" + MenuConstants.OctreeStats + text: qsTr("Entity Statistics") + } + Action { + id: offAxisProjection + objectName: "HifiAction_" + MenuConstants.OffAxisProjection + text: qsTr("Off-Axis Projection") + } + Action { + id: onlyDisplayTopTen + objectName: "HifiAction_" + MenuConstants.OnlyDisplayTopTen + text: qsTr("Only Display Top Ten") + } + Action { + id: packageModel + objectName: "HifiAction_" + MenuConstants.PackageModel + text: qsTr("Package Model...") + } + Action { + id: pair + objectName: "HifiAction_" + MenuConstants.Pair + text: qsTr("Pair") + } + Action { + id: pipelineWarnings + objectName: "HifiAction_" + MenuConstants.PipelineWarnings + text: qsTr("Log Render Pipeline Warnings") + } + Action { + id: preferences + objectName: "HifiAction_" + MenuConstants.Preferences + text: qsTr("Preferences...") + } + Action { + id: renderBoundingCollisionShapes + objectName: "HifiAction_" + MenuConstants.RenderBoundingCollisionShapes + text: qsTr("Show Bounding Collision Shapes") + checkable: true + } + Action { + id: renderFocusIndicator + objectName: "HifiAction_" + MenuConstants.RenderFocusIndicator + text: qsTr("Show Eye Focus") + checkable: true + } + Action { + id: renderHeadCollisionShapes + objectName: "HifiAction_" + MenuConstants.RenderHeadCollisionShapes + text: qsTr("Show Head Collision Shapes") + checkable: true + } + Action { + id: renderLookAtVectors + objectName: "HifiAction_" + MenuConstants.RenderLookAtVectors + text: qsTr("Show Look-at Vectors") + checkable: true + } + Action { + id: renderSkeletonCollisionShapes + objectName: "HifiAction_" + MenuConstants.RenderSkeletonCollisionShapes + text: qsTr("Show Skeleton Collision Shapes") + checkable: true + } + ExclusiveGroup { + Action { + id: renderTargetFramerateUnlimited + objectName: "HifiAction_" + MenuConstants.RenderTargetFramerateUnlimited + text: qsTr("Unlimited") + checked: true + checkable: true + } + Action { + id: renderTargetFramerate60 + objectName: "HifiAction_" + MenuConstants.RenderTargetFramerate60 + text: qsTr("60") + checkable: true + } + Action { + id: renderTargetFramerate50 + objectName: "HifiAction_" + MenuConstants.RenderTargetFramerate50 + text: qsTr("50") + checkable: true + } + Action { + id: renderTargetFramerate40 + objectName: "HifiAction_" + MenuConstants.RenderTargetFramerate40 + text: qsTr("40") + checkable: true + } + Action { + id: renderTargetFramerate30 + objectName: "HifiAction_" + MenuConstants.RenderTargetFramerate30 + text: qsTr("30") + checkable: true + } + } + Action { + id: renderTargetFramerateVSyncOn + objectName: "HifiAction_" + MenuConstants.RenderTargetFramerateVSyncOn + text: qsTr("V-Sync On") + checkable: true + } + Action { + id: renderResolution + objectName: "HifiAction_" + MenuConstants.RenderResolution + text: qsTr("Scale Resolution") + } + ExclusiveGroup { + Action { + id: renderResolutionOne + objectName: "HifiAction_" + MenuConstants.RenderResolutionOne + text: qsTr("1") + checkable: true + checked: true + } + Action { + id: renderResolutionTwoThird + objectName: "HifiAction_" + MenuConstants.RenderResolutionTwoThird + text: qsTr("2/3") + checkable: true + } + Action { + id: renderResolutionHalf + objectName: "HifiAction_" + MenuConstants.RenderResolutionHalf + text: qsTr("1/2") + checkable: true + } + Action { + id: renderResolutionThird + objectName: "HifiAction_" + MenuConstants.RenderResolutionThird + text: qsTr("1/3") + checkable: true + } + Action { + id: renderResolutionQuarter + objectName: "HifiAction_" + MenuConstants.RenderResolutionQuarter + text: qsTr("1/4") + checkable: true + } + } + Action { + id: renderAmbientLight + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight + text: qsTr("Ambient Light") + } + ExclusiveGroup { + Action { + id: renderAmbientLightGlobal + objectName: "HifiAction_" + MenuConstants.RenderAmbientLightGlobal + text: qsTr("Global") + checked: true + checkable: true + } + Action { + id: renderAmbientLight0 + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight0 + text: qsTr("OLD_TOWN_SQUARE") + checkable: true + } + Action { + id: renderAmbientLight1 + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight1 + text: qsTr("GRACE_CATHEDRAL") + checkable: true + } + Action { + id: renderAmbientLight2 + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight2 + text: qsTr("EUCALYPTUS_GROVE") + checkable: true + } + Action { + id: renderAmbientLight3 + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight3 + text: qsTr("ST_PETERS_BASILICA") + checkable: true + } + Action { + id: renderAmbientLight4 + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight4 + text: qsTr("UFFIZI_GALLERY") + checkable: true + } + Action { + id: renderAmbientLight5 + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight5 + text: qsTr("GALILEOS_TOMB") + checkable: true + } + Action { + id: renderAmbientLight6 + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight6 + text: qsTr("VINE_STREET_KITCHEN") + checkable: true + } + Action { + id: renderAmbientLight7 + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight7 + text: qsTr("BREEZEWAY") + checkable: true + } + Action { + id: renderAmbientLight8 + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight8 + text: qsTr("CAMPUS_SUNSET") + checkable: true + } + Action { + id: renderAmbientLight9 + objectName: "HifiAction_" + MenuConstants.RenderAmbientLight9 + text: qsTr("FUNSTON_BEACH_SUNSET") + checkable: true + } + } + Action { + id: resetAvatarSize + objectName: "HifiAction_" + MenuConstants.ResetAvatarSize + text: qsTr("Reset Avatar Size") + } + Action { + id: runTimingTests + objectName: "HifiAction_" + MenuConstants.RunTimingTests + text: qsTr("Run Timing Tests") + } + Action { + id: scriptedMotorControl + objectName: "HifiAction_" + MenuConstants.ScriptedMotorControl + text: qsTr("Enable Scripted Motor Control") + } + Action { + id: showBordersEntityNodes + objectName: "HifiAction_" + MenuConstants.ShowBordersEntityNodes + text: qsTr("Show Entity Nodes") + } + Action { + id: showIKConstraints + objectName: "HifiAction_" + MenuConstants.ShowIKConstraints + text: qsTr("Show IK Constraints") + } + Action { + id: simpleShadows + objectName: "HifiAction_" + MenuConstants.SimpleShadows + text: qsTr("Simple") + } + Action { + id: sixenseEnabled + objectName: "HifiAction_" + MenuConstants.SixenseEnabled + text: qsTr("Enable Hydra Support") + } + Action { + id: sixenseMouseInput + objectName: "HifiAction_" + MenuConstants.SixenseMouseInput + text: qsTr("Enable Sixense Mouse Input") + } + Action { + id: sixenseLasers + objectName: "HifiAction_" + MenuConstants.SixenseLasers + text: qsTr("Enable Sixense UI Lasers") + } + Action { + id: shiftHipsForIdleAnimations + objectName: "HifiAction_" + MenuConstants.ShiftHipsForIdleAnimations + text: qsTr("Shift hips for idle animations") + } + Action { + id: stars + objectName: "HifiAction_" + MenuConstants.Stars + text: qsTr("Stars") + } + Action { + id: stats + objectName: "HifiAction_" + MenuConstants.Stats + text: qsTr("Stats") + } + Action { + id: stereoAudio + objectName: "HifiAction_" + MenuConstants.StereoAudio + text: qsTr("Stereo Audio (disables spatial sound)") + } + Action { + id: suppressShortTimings + objectName: "HifiAction_" + MenuConstants.SuppressShortTimings + text: qsTr("Suppress Timings Less than 10ms") + } + Action { + id: testPing + objectName: "HifiAction_" + MenuConstants.TestPing + text: qsTr("Test Ping") + } + Action { + id: transmitterDrive + objectName: "HifiAction_" + MenuConstants.TransmitterDrive + text: qsTr("Transmitter Drive") + } + Action { + id: turnWithHead + objectName: "HifiAction_" + MenuConstants.TurnWithHead + text: qsTr("Turn using Head") + } + Action { + id: useAudioForMouth + objectName: "HifiAction_" + MenuConstants.UseAudioForMouth + text: qsTr("Use Audio for Mouth") + } + Action { + id: useCamera + objectName: "HifiAction_" + MenuConstants.UseCamera + text: qsTr("Use Camera") + } + Action { + id: velocityFilter + objectName: "HifiAction_" + MenuConstants.VelocityFilter + text: qsTr("Velocity Filter") + } + Action { + id: wireframe + objectName: "HifiAction_" + MenuConstants.Wireframe + text: qsTr("Wireframe") + } + } + + MenuBar { + objectName: "rootMenu"; + Menu { + title: "File" + MenuItem { + action: login + } + MenuItem { + action: aboutApp + } + MenuSeparator {} MenuItem { text: "Scripts"; enabled: false } + MenuItem { action: loadScript; } + MenuItem { action: loadScriptURL; } + MenuItem { action: stopAllScripts; } + MenuItem { action: reloadAllScripts; } + MenuItem { action: runningScripts; } + MenuSeparator {} MenuItem { text: "Locations"; enabled: false } + MenuItem { action: addressBar; } + MenuItem { action: copyAddress; } + MenuItem { action: copyPath; } + MenuSeparator {} + MenuItem { action: quit; } + } + Menu { + title: "Edit" + MenuItem { action: preferences; } + MenuItem { action: animations; } + } + Menu { + title: "Tools" + MenuItem { action: scriptEditor; } + MenuItem { action: controlWithSpeech; } + MenuItem { action: chat; } + MenuItem { action: addRemoveFriends; } + Menu { + title: "I Am Visible To" + MenuItem { action: visibleToEveryone; } + MenuItem { action: visibleToFriends; } + MenuItem { action: visibleToNoOne; } + } + MenuItem { action: toolWindow; } + MenuItem { action: javascriptConsole; } + MenuItem { action: resetSensors; } + MenuItem { action: packageModel; } + } + Menu { + title: "Avatar" + Menu { + title: "Size" + MenuItem { action: increaseAvatarSize; } + MenuItem { action: decreaseAvatarSize; } + MenuItem { action: resetAvatarSize; } + } + MenuItem { action: keyboardMotorControl; } + MenuItem { action: scriptedMotorControl; } + MenuItem { action: namesAboveHeads; } + MenuItem { action: glowWhenSpeaking; } + MenuItem { action: blueSpeechSphere; } + MenuItem { action: enableCharacterController; } + MenuItem { action: shiftHipsForIdleAnimations; } + } + Menu { + title: "View" + MenuItem { action: fullscreen; } + MenuItem { action: firstPerson; } + MenuItem { action: mirror; } + MenuItem { action: fullscreenMirror; } + MenuItem { action: hMDTools; } + MenuItem { action: enableVRMode; } + MenuItem { action: enable3DTVMode; } + MenuItem { action: showBordersEntityNodes; } + MenuItem { action: offAxisProjection; } + MenuItem { action: turnWithHead; } + MenuItem { action: stats; } + MenuItem { action: log; } + MenuItem { action: bandwidthDetails; } + MenuItem { action: octreeStats; } + } + Menu { + title: "Developer" + Menu { + title: "Render" + MenuItem { action: atmosphere; } + MenuItem { action: ambientOcclusion; } + MenuItem { action: dontFadeOnOctreeServerChanges; } + Menu { + title: "Ambient Light" + MenuItem { action: renderAmbientLightGlobal; } + MenuItem { action: renderAmbientLight0; } + MenuItem { action: renderAmbientLight1; } + MenuItem { action: renderAmbientLight2; } + MenuItem { action: renderAmbientLight3; } + MenuItem { action: renderAmbientLight4; } + MenuItem { action: renderAmbientLight5; } + MenuItem { action: renderAmbientLight6; } + MenuItem { action: renderAmbientLight7; } + MenuItem { action: renderAmbientLight8; } + MenuItem { action: renderAmbientLight9; } + } + Menu { + title: "Shadows" + MenuItem { action: noShadows; } + MenuItem { action: simpleShadows; } + MenuItem { action: cascadedShadows; } + } + Menu { + title: "Framerate" + MenuItem { action: renderTargetFramerateUnlimited; } + MenuItem { action: renderTargetFramerate60; } + MenuItem { action: renderTargetFramerate50; } + MenuItem { action: renderTargetFramerate40; } + MenuItem { action: renderTargetFramerate30; } + } + MenuItem { action: renderTargetFramerateVSyncOn; } + Menu { + title: "Scale Resolution" + MenuItem { action: renderResolutionOne; } + MenuItem { action: renderResolutionTwoThird; } + MenuItem { action: renderResolutionHalf; } + MenuItem { action: renderResolutionThird; } + MenuItem { action: renderResolutionQuarter; } + } + MenuItem { action: stars; } + MenuItem { action: enableGlowEffect; } + MenuItem { action: wireframe; } + MenuItem { action: lodTools; } + } + Menu { + title: "Avatar" + Menu { + title: "Face Tracking" + MenuItem { action: noFaceTracking; } + MenuItem { action: faceshift; } + MenuItem { action: useCamera; } + MenuItem { action: useAudioForMouth; } + MenuItem { action: velocityFilter; } + } + MenuItem { action: renderSkeletonCollisionShapes; } + MenuItem { action: renderHeadCollisionShapes; } + MenuItem { action: renderBoundingCollisionShapes; } + MenuItem { action: renderLookAtVectors; } + MenuItem { action: renderFocusIndicator; } + } + Menu { + title: "Hands" + MenuItem { action: alignForearmsWithWrists; } + MenuItem { action: alternateIK; } + MenuItem { action: displayHands; } + MenuItem { action: displayHandTargets; } + MenuItem { action: showIKConstraints; } + Menu { + title: "Sixense" + MenuItem { action: sixenseEnabled; } + MenuItem { action: filterSixense; } + MenuItem { action: lowVelocityFilter; } + MenuItem { action: sixenseMouseInput; } + MenuItem { action: sixenseLasers; } + } + Menu { + title: "Leap Motion" + MenuItem { action: leapMotionOnHMD; } + } + MenuItem { action: loadRSSDKFile; } + } + Menu { + title: "Network" + MenuItem { action: disableNackPackets; } + MenuItem { action: disableActivityLogger; } + MenuItem { action: cachesSize; } + MenuItem { action: diskCacheEditor; } + } + Menu { + title: "Timing and Stats" + Menu { + title: "Performance Timer" + MenuItem { action: displayDebugTimingDetails; } + MenuItem { action: onlyDisplayTopTen; } + MenuItem { action: expandUpdateTiming; } + MenuItem { action: expandMyAvatarTiming; } + MenuItem { action: expandMyAvatarSimulateTiming; } + MenuItem { action: expandOtherAvatarTiming; } + MenuItem { action: expandPaintGLTiming; } + } + MenuItem { action: testPing; } + MenuItem { action: frameTimer; } + MenuItem { action: runTimingTests; } + MenuItem { action: pipelineWarnings; } + MenuItem { action: suppressShortTimings; } + } + Menu { + title: "Audio" + MenuItem { action: audioNoiseReduction; } + MenuItem { action: echoServerAudio; } + MenuItem { action: echoLocalAudio; } + MenuItem { action: stereoAudio; } + MenuItem { action: muteAudio; } + MenuItem { action: muteEnvironment; } + Menu { + title: "Audio Scope" + MenuItem { action: audioScope; } + MenuItem { action: audioScopePause; } + MenuSeparator {} MenuItem { text: "Audio Scope"; enabled: false; } + MenuItem { action: audioScopeFiveFrames; } + MenuItem { action: audioScopeTwentyFrames; } + MenuItem { action: audioScopeFiftyFrames; } + } + MenuItem { action: audioStats; } + MenuItem { action: audioStatsShowInjectedStreams; } + } + } + Menu { + title: "Help" + MenuItem { action: editEntitiesHelp; } + MenuItem { action: aboutApp; } + } + } +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1f22cf3550..b22bacef33 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -761,17 +761,6 @@ void Application::initializeGL() { InfoView::showFirstTime(INFO_HELP_PATH); } -class OAuthFactory : public QQmlNetworkAccessManagerFactory { - QThreadStorage oauthNetworkAccessManagers; -public: - virtual QNetworkAccessManager * create(QObject * parent) { - if (!oauthNetworkAccessManagers.hasLocalData()) { - oauthNetworkAccessManagers.setLocalData(OAuthNetworkAccessManager::getInstance()); - } - return oauthNetworkAccessManagers.localData(); - } -}; - void Application::initializeUi() { AddressBarDialog::registerType(); LoginDialog::registerType(); diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 56fa7a0aef..5922d9f3bb 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -35,8 +35,8 @@ void LoginDialog::toggleAction() { }); } else { // change the menu item to login - loginAction->setText("Login"); - connect(loginAction, &QAction::triggered, [] { + menu->setOptionText(MenuOption::Login, "Login"); + menu->setOptionTriggerAction(MenuOption::Login, [] { LoginDialog::show(); }); } diff --git a/interface/src/ui/MarketplaceDialog.cpp b/interface/src/ui/MarketplaceDialog.cpp index 4893d47103..f37f71ef54 100644 --- a/interface/src/ui/MarketplaceDialog.cpp +++ b/interface/src/ui/MarketplaceDialog.cpp @@ -12,7 +12,7 @@ #include "MarketplaceDialog.h" #include "DependencyManager.h" -QML_DIALOG_DEF(MarketplaceDialog) +HIFI_QML_DEF(MarketplaceDialog) MarketplaceDialog::MarketplaceDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { diff --git a/interface/src/ui/MarketplaceDialog.h b/interface/src/ui/MarketplaceDialog.h index f5fa355201..241d4a7131 100644 --- a/interface/src/ui/MarketplaceDialog.h +++ b/interface/src/ui/MarketplaceDialog.h @@ -17,7 +17,7 @@ class MarketplaceDialog : public OffscreenQmlDialog { Q_OBJECT - QML_DIALOG_DECL + HIFI_QML_DECL public: MarketplaceDialog(QQuickItem *parent = 0); diff --git a/interface/src/ui/MenuQml.cpp b/interface/src/ui/MenuQml.cpp deleted file mode 100644 index 991b7e4574..0000000000 --- a/interface/src/ui/MenuQml.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// -// MenuQml.cpp -// -// Created by Bradley Austin Davis on 2015/04/14 -// Copyright 2015 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 "Application.h" -#include "MenuQml.h" - -QML_DIALOG_DEF(MenuQml) - -MenuQml::MenuQml(QQuickItem *parent) : QQuickItem(parent) { - auto menu = Menu::getInstance(); - -} diff --git a/interface/src/ui/MenuQml.h b/interface/src/ui/MenuQml.h deleted file mode 100644 index a007ec8735..0000000000 --- a/interface/src/ui/MenuQml.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// MenuQml.h -// -// Created by Bradley Austin Davis on 2015/04/14 -// Copyright 2015 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 -// - -#pragma once -#ifndef hifi_MenuQml_h -#define hifi_MenuQml_h - -#include - -class MenuQml : public QQuickItem -{ - Q_OBJECT - QML_DIALOG_DECL - -public: - MenuQml(QQuickItem *parent = 0); -}; - -#endif diff --git a/libraries/ui/src/HifiMenu.cpp b/libraries/ui/src/HifiMenu.cpp index 27517f99d7..88c9b48f43 100644 --- a/libraries/ui/src/HifiMenu.cpp +++ b/libraries/ui/src/HifiMenu.cpp @@ -277,3 +277,26 @@ void HifiMenu::connectItem(const QString& menuOption, QObject* receiver, const c QObject* result = findMenuObject(menuOption); connect(result, SIGNAL(triggered()), receiver, slot); } + +void HifiMenu::setExclusiveGroup(const QString& menuOption, const QString& groupName) { + static const QString GROUP_SUFFIX{ "__Group" }; + auto offscreenUi = DependencyManager::get(); + QObject* group = offscreenUi->getRootItem()->findChild(groupName + GROUP_SUFFIX); + if (!group) { + group = offscreenUi->load("ExclusiveGroup.qml"); + Q_ASSERT(group); + } + QObject* menuItem = findMenuObject(menuOption); + bool result = menuItem->setProperty("text", QVariant::fromValue(group)); + Q_ASSERT(result); +} + +bool HifiMenu::connectAction(int action, QObject * receiver, const char * slot) { + auto offscreenUi = DependencyManager::get(); + QObject* rootMenu = offscreenUi->getRootItem()->findChild("AllActions"); + QString name = "HifiAction_" + QVariant(action).toString(); + QObject* quitAction = rootMenu->findChild(name); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + return true; +} + diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/HifiMenu.h index c89c91b028..501baa3cc0 100644 --- a/libraries/ui/src/HifiMenu.h +++ b/libraries/ui/src/HifiMenu.h @@ -23,6 +23,9 @@ class HifiMenu : public QQuickItem { HIFI_QML_DECL_LAMBDA public: + + static bool connectAction(int action, QObject * receiver, const char * slot); + HifiMenu(QQuickItem* parent = nullptr); void setToggleAction(const QString& name, std::function f); diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 76a5e71b25..052a6aac4e 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -152,13 +152,12 @@ void OffscreenUi::setBaseUrl(const QUrl& baseUrl) { } QObject* OffscreenUi::load(const QUrl& qmlSource, std::function f) { - qDebug() << "Loading QML from URL " << qmlSource; _qmlComponent->loadUrl(qmlSource); if (_qmlComponent->isLoading()) { connect(_qmlComponent, &QQmlComponent::statusChanged, this, - [this, f](QQmlComponent::Status){ - finishQmlLoad(f); - }); + [this, f](QQmlComponent::Status){ + finishQmlLoad(f); + }); return nullptr; } diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index b58b4e59cb..ce40bec943 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -38,9 +38,9 @@ private: \ static const QUrl QML; \ public: \ static void registerType(); \ - static void show(std::function f = [](QQmlContext*, QQuickItem*) {}); \ - static void toggle(std::function f = [](QQmlContext*, QQuickItem*) {}); \ - static void load(std::function f = [](QQmlContext*, QQuickItem*) {}); \ + static void show(std::function f = [](QQmlContext*, QObject*) {}); \ + static void toggle(std::function f = [](QQmlContext*, QObject*) {}); \ + static void load(std::function f = [](QQmlContext*, QObject*) {}); \ private: #define HIFI_QML_DECL_LAMBDA \ @@ -62,16 +62,16 @@ private: qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ } \ \ - void x::show(std::function f) { \ + void x::show(std::function f) { \ auto offscreenUi = DependencyManager::get(); \ offscreenUi->show(QML, NAME, f); \ } \ \ - void x::toggle(std::function f) { \ + void x::toggle(std::function f) { \ auto offscreenUi = DependencyManager::get(); \ offscreenUi->toggle(QML, NAME, f); \ } \ - void x::load(std::function f) { \ + void x::load(std::function f) { \ auto offscreenUi = DependencyManager::get(); \ offscreenUi->load(QML, f); \ } @@ -122,9 +122,9 @@ public: virtual ~OffscreenUi(); void create(QOpenGLContext* context); void resize(const QSize& size); - void load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); - void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { - load(QUrl(qmlSourceFile), f); + QObject* load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); + QObject* load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { + return load(QUrl(qmlSourceFile), f); } void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); @@ -169,11 +169,11 @@ public: ButtonCallback callback = NO_OP_CALLBACK, QMessageBox::StandardButtons buttons = QMessageBox::Ok); -protected: +private: + QObject* finishQmlLoad(std::function f); private slots: void updateQuick(); - void finishQmlLoad(std::function f); public slots: void requestUpdate(); diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 6af87fec2e..37e229d571 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -74,6 +74,171 @@ public: }; +class MenuConstants : public QObject{ + Q_OBJECT + Q_ENUMS(Item) + +public: + enum Item { + AboutApp, + AddRemoveFriends, + AddressBar, + AlignForearmsWithWrists, + AlternateIK, + AmbientOcclusion, + Animations, + Atmosphere, + Attachments, + AudioNoiseReduction, + AudioScope, + AudioScopeFiftyFrames, + AudioScopeFiveFrames, + AudioScopeFrames, + AudioScopePause, + AudioScopeTwentyFrames, + AudioStats, + AudioStatsShowInjectedStreams, + BandwidthDetails, + BlueSpeechSphere, + BookmarkLocation, + Bookmarks, + CascadedShadows, + CachesSize, + Chat, + Collisions, + Console, + ControlWithSpeech, + CopyAddress, + CopyPath, + DecreaseAvatarSize, + DeleteBookmark, + DisableActivityLogger, + DisableLightEntities, + DisableNackPackets, + DiskCacheEditor, + DisplayHands, + DisplayHandTargets, + DisplayModelBounds, + DisplayModelTriangles, + DisplayModelElementChildProxies, + DisplayModelElementProxy, + DisplayDebugTimingDetails, + DontDoPrecisionPicking, + DontFadeOnOctreeServerChanges, + DontRenderEntitiesAsScene, + EchoLocalAudio, + EchoServerAudio, + EditEntitiesHelp, + Enable3DTVMode, + EnableCharacterController, + EnableGlowEffect, + EnableVRMode, + ExpandMyAvatarSimulateTiming, + ExpandMyAvatarTiming, + ExpandOtherAvatarTiming, + ExpandPaintGLTiming, + ExpandUpdateTiming, + Faceshift, + FilterSixense, + FirstPerson, + FrameTimer, + Fullscreen, + FullscreenMirror, + GlowWhenSpeaking, + NamesAboveHeads, + GoToUser, + HMDTools, + IncreaseAvatarSize, + KeyboardMotorControl, + LeapMotionOnHMD, + LoadScript, + LoadScriptURL, + LoadRSSDKFile, + LodTools, + Login, + Log, + LowVelocityFilter, + Mirror, + MuteAudio, + MuteEnvironment, + NoFaceTracking, + NoShadows, + OctreeStats, + OffAxisProjection, + OnlyDisplayTopTen, + PackageModel, + Pair, + PipelineWarnings, + Preferences, + Quit, + ReloadAllScripts, + RenderBoundingCollisionShapes, + RenderFocusIndicator, + RenderHeadCollisionShapes, + RenderLookAtVectors, + RenderSkeletonCollisionShapes, + RenderTargetFramerate, + RenderTargetFramerateUnlimited, + RenderTargetFramerate60, + RenderTargetFramerate50, + RenderTargetFramerate40, + RenderTargetFramerate30, + RenderTargetFramerateVSyncOn, + RenderResolution, + RenderResolutionOne, + RenderResolutionTwoThird, + RenderResolutionHalf, + RenderResolutionThird, + RenderResolutionQuarter, + RenderAmbientLight, + RenderAmbientLightGlobal, + RenderAmbientLight0, + RenderAmbientLight1, + RenderAmbientLight2, + RenderAmbientLight3, + RenderAmbientLight4, + RenderAmbientLight5, + RenderAmbientLight6, + RenderAmbientLight7, + RenderAmbientLight8, + RenderAmbientLight9, + ResetAvatarSize, + ResetSensors, + RunningScripts, + RunTimingTests, + ScriptEditor, + ScriptedMotorControl, + ShowBordersEntityNodes, + ShowIKConstraints, + SimpleShadows, + SixenseEnabled, + SixenseMouseInput, + SixenseLasers, + ShiftHipsForIdleAnimations, + Stars, + Stats, + StereoAudio, + StopAllScripts, + SuppressShortTimings, + TestPing, + ToolWindow, + TransmitterDrive, + TurnWithHead, + UseAudioForMouth, + UseCamera, + VelocityFilter, + VisibleToEveryone, + VisibleToFriends, + VisibleToNoOne, + Wireframe, + }; + +public: + MenuConstants(QObject * parent = nullptr) : QObject(parent) { + + } +}; + const QString & getQmlDir() { static QString dir; if (dir.isEmpty()) { @@ -156,6 +321,8 @@ public: MessageDialog::registerType(); HifiMenu::registerType(); + qmlRegisterType("Hifi", 1, 0, "MenuConstants"); + auto offscreenUi = DependencyManager::get(); offscreenUi->create(_context); @@ -181,24 +348,10 @@ public: #else offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); offscreenUi->load(QUrl("TestRoot.qml")); - offscreenUi->load(QUrl("RootMenu.qml")); + offscreenUi->load(QUrl("Menu.qml")); + // Requires a root menu to have been loaded before it can load HifiMenu::load(); - QObject* menuObject = offscreenUi->getRootItem()->findChild("HifiMenu"); - HifiMenu* menu = offscreenUi->getRootItem()->findChild(); - menu->addMenu("", "File"); - menu->addItem("File", "Quit", []{ - QApplication::quit(); - }); - menu->addCheckableItem("File", "Toggle", false, [](bool toggled) { - qDebug() << "Toggle is " << toggled; - }); - menu->addMenu("", "Edit"); - menu->addItem("Edit", "Undo"); - menu->addItem("Edit", "Redo"); - menu->addItem("Edit", "Copy"); - menu->addItem("Edit", "Cut"); - menu->addItem("Edit", "Paste"); - menu->addMenu("", "Long Menu Name..."); + HifiMenu::connectAction(MenuConstants::Quit, qApp, SLOT(quit())); #endif installEventFilter(offscreenUi.data()); offscreenUi->resume(); From b69cba1aba174da4b1f368db54cf632e685cb80b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Apr 2015 10:50:18 -0700 Subject: [PATCH 331/401] respond to code-review --- interface/src/Application.cpp | 1 - interface/src/ui/ApplicationOverlay.cpp | 1 - libraries/gpu/src/gpu/GLBackendOutput.cpp | 1 - libraries/gpu/src/gpu/GLBackendTexture.cpp | 3 +-- libraries/networking/src/DataServerAccountInfo.cpp | 3 +-- libraries/render-utils/src/Model.cpp | 1 - 6 files changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 565aa07332..95700f3257 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1058,7 +1058,6 @@ void Application::keyPressEvent(QKeyEvent* event) { bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); bool isOption = event->modifiers().testFlag(Qt::AltModifier); - // bool isKeypad = event->modifiers().testFlag(Qt::KeypadModifier); switch (event->key()) { break; case Qt::Key_L: diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 9978a05dac..bf93a3e7d2 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -257,7 +257,6 @@ void ApplicationOverlay::displayOverlayTexture() { if (_alpha == 0.0f) { return; } - // auto glCanvas = Application::getInstance()->getGLWidget(); glMatrixMode(GL_PROJECTION); glPushMatrix(); { glLoadIdentity(); diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index e03ab43962..2529070b18 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -24,7 +24,6 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe GLFramebuffer* object = Backend::getGPUObject(framebuffer); // If GPU object already created and in sync - // bool needUpdate = false; if (object) { return object; } else if (framebuffer.isEmpty()) { diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 4bb16ba0b8..da39ab16fa 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -177,8 +177,7 @@ public: break; } case gpu::NUM_TYPES: { // quiet compiler - assert(false); - break; + Q_UNREACHABLE(); } } break; diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index b58af5e4e7..44e8dbef90 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -35,8 +35,7 @@ DataServerAccountInfo::DataServerAccountInfo() : } -DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) { - QObject(), +DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) : QObject() { _accessToken = otherInfo._accessToken; _username = otherInfo._username; _xmppPassword = otherInfo._xmppPassword; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index bcdba0dd42..be2ccdb60e 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -111,7 +111,6 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3)); gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); - // bool makeResult = gpu::Shader::makeProgram(*program, slotBindings); From 736691e3ec2e3c4715782fc5067bd3ca1ae342cc Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 25 Apr 2015 11:33:32 -0700 Subject: [PATCH 332/401] Refactor face tracking FPS calculation --- interface/src/devices/DdeFaceTracker.cpp | 43 +++++++----------------- interface/src/devices/DdeFaceTracker.h | 6 ---- interface/src/devices/FaceTracker.cpp | 37 +++++++++++++++++++- interface/src/devices/FaceTracker.h | 15 ++++++++- interface/src/devices/Faceshift.cpp | 32 ++++-------------- interface/src/devices/Faceshift.h | 5 --- 6 files changed, 69 insertions(+), 69 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 8f1b070c02..ef9ab6fdc6 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -136,9 +136,6 @@ struct Packet { const float STARTING_DDE_MESSAGE_TIME = 0.033f; -const int FPS_TIMER_DELAY = 2000; // ms -const int FPS_TIMER_DURATION = 2000; // ms - DdeFaceTracker::DdeFaceTracker() : DdeFaceTracker(QHostAddress::Any, DDE_SERVER_PORT, DDE_CONTROL_PORT) { @@ -171,9 +168,7 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui _lastLeftEyeBlink(0.0f), _filteredLeftEyeBlink(0.0f), _lastRightEyeBlink(0.0f), - _filteredRightEyeBlink(0.0f), - _isCalculatingFPS(false), - _frameCount(0) + _filteredRightEyeBlink(0.0f) { _coefficients.resize(NUM_FACESHIFT_BLENDSHAPES); @@ -228,19 +223,18 @@ void DdeFaceTracker::processFinished(int exitCode, QProcess::ExitStatus exitStat } void DdeFaceTracker::reset() { - _reset = true; + if (_udpSocket.state() == QAbstractSocket::BoundState) { + _reset = true; - qDebug() << "[Info] Reset DDE Tracking"; - const char* DDE_RESET_COMMAND = "reset"; - _udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort); + qCDebug(interfaceapp) << "DDE Face Tracker: Reset"; - // Log camera FPS after a reset - if (!_isCalculatingFPS) { - QTimer::singleShot(FPS_TIMER_DELAY, this, SLOT(startFPSTimer())); - _isCalculatingFPS = true; + const char* DDE_RESET_COMMAND = "reset"; + _udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort); + + FaceTracker::reset(); + + _reset = true; } - - _reset = true; } bool DdeFaceTracker::isActive() const { @@ -419,23 +413,10 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { } _lastMessageReceived = usecsNow; - // Count frames if timing - if (_isCalculatingFPS) { - _frameCount++; - } - + FaceTracker::countFrame(); + } else { qCDebug(interfaceapp) << "[Error] DDE Face Tracker Decode Error"; } _lastReceiveTimestamp = usecTimestampNow(); } - -void DdeFaceTracker::startFPSTimer() { - _frameCount = 0; - QTimer::singleShot(FPS_TIMER_DURATION, this, SLOT(finishFPSTimer())); -} - -void DdeFaceTracker::finishFPSTimer() { - qDebug() << "[Info] DDE FPS =" << (float)_frameCount / ((float)FPS_TIMER_DURATION / 1000.0f); - _isCalculatingFPS = false; -} diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 7cca1e31be..302150773e 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -59,9 +59,6 @@ private slots: void readPendingDatagrams(); void socketStateChanged(QAbstractSocket::SocketState socketState); - void startFPSTimer(); - void finishFPSTimer(); - private: DdeFaceTracker(); DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort); @@ -111,9 +108,6 @@ private: float _filteredLeftEyeBlink; float _lastRightEyeBlink; float _filteredRightEyeBlink; - - bool _isCalculatingFPS; - int _frameCount; }; #endif // hifi_DdeFaceTracker_h \ No newline at end of file diff --git a/interface/src/devices/FaceTracker.cpp b/interface/src/devices/FaceTracker.cpp index 7c1c757ec1..0d40249c26 100644 --- a/interface/src/devices/FaceTracker.cpp +++ b/interface/src/devices/FaceTracker.cpp @@ -9,9 +9,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include #include "FaceTracker.h" +#include "InterfaceLogging.h" + +const int FPS_TIMER_DELAY = 2000; // ms +const int FPS_TIMER_DURATION = 2000; // ms + +FaceTracker::FaceTracker() : + _isCalculatingFPS(false), + _frameCount(0) +{ +} inline float FaceTracker::getBlendshapeCoefficient(int index) const { return isValidBlendshapeIndex(index) ? glm::mix(0.0f, _blendshapeCoefficients[index], getFadeCoefficient()) @@ -65,4 +77,27 @@ void FaceTracker::update(float deltaTime) { _relaxationStatus = glm::clamp(_relaxationStatus - deltaTime / RELAXATION_TIME, 0.0f, 1.0f); _fadeCoefficient = std::exp(-(1.0f - _relaxationStatus) * INVERSE_AT_EPSILON); } -} \ No newline at end of file +} + +void FaceTracker::reset() { + if (isActive() && !_isCalculatingFPS) { + QTimer::singleShot(FPS_TIMER_DELAY, this, SLOT(startFPSTimer())); + _isCalculatingFPS = true; + } +} + +void FaceTracker::startFPSTimer() { + _frameCount = 0; + QTimer::singleShot(FPS_TIMER_DURATION, this, SLOT(finishFPSTimer())); +} + +void FaceTracker::countFrame() { + if (_isCalculatingFPS) { + _frameCount++; + } +} + +void FaceTracker::finishFPSTimer() { + qCDebug(interfaceapp) << "Face tracker FPS =" << (float)_frameCount / ((float)FPS_TIMER_DURATION / 1000.0f); + _isCalculatingFPS = false; +} diff --git a/interface/src/devices/FaceTracker.h b/interface/src/devices/FaceTracker.h index db6fdd74b9..a0a434ee9e 100644 --- a/interface/src/devices/FaceTracker.h +++ b/interface/src/devices/FaceTracker.h @@ -28,7 +28,7 @@ public: virtual void init() {} virtual void update(float deltaTime); - virtual void reset() {} + virtual void reset(); float getFadeCoefficient() const; @@ -44,6 +44,9 @@ public: float getBlendshapeCoefficient(int index) const; protected: + FaceTracker(); + virtual ~FaceTracker() {}; + glm::vec3 _headTranslation = glm::vec3(0.0f); glm::quat _headRotation = glm::quat(); float _estimatedEyePitch = 0.0f; @@ -52,6 +55,16 @@ protected: float _relaxationStatus = 0.0f; // Between 0.0f and 1.0f float _fadeCoefficient = 0.0f; // Between 0.0f and 1.0f + + void countFrame(); + +private slots: + void startFPSTimer(); + void finishFPSTimer(); + +private: + bool _isCalculatingFPS; + int _frameCount; }; #endif // hifi_FaceTracker_h diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index a2c1cd693a..a0af6c7e2f 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -30,14 +30,9 @@ const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost"; const quint16 FACESHIFT_PORT = 33433; const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; -const int FPS_TIMER_DELAY = 2000; // ms -const int FPS_TIMER_DURATION = 2000; // ms - Faceshift::Faceshift() : _eyeDeflection("faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION), - _hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME), - _isCalculatingFPS(false), - _frameCount(0) + _hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME) { #ifdef HAVE_FACESHIFT connect(&_tcpSocket, SIGNAL(connected()), SLOT(noteConnected())); @@ -83,15 +78,13 @@ void Faceshift::update(float deltaTime) { void Faceshift::reset() { if (_tcpSocket.state() == QAbstractSocket::ConnectedState) { + qCDebug(interfaceapp, "Faceshift: Reset"); + + FaceTracker::reset(); + string message; fsBinaryStream::encode_message(message, fsMsgCalibrateNeutral()); send(message); - - // Log camera FPS after a reset - if (!_isCalculatingFPS) { - QTimer::singleShot(FPS_TIMER_DELAY, this, SLOT(startFPSTimer())); - _isCalculatingFPS = true; - } } _longTermAverageInitialized = false; } @@ -294,10 +287,8 @@ void Faceshift::receive(const QByteArray& buffer) { } } #endif - // Count frames if timing - if (_isCalculatingFPS) { - _frameCount++; - } + + FaceTracker::countFrame(); } void Faceshift::setEyeDeflection(float faceshiftEyeDeflection) { @@ -308,12 +299,3 @@ void Faceshift::setHostname(const QString& hostname) { _hostname.set(hostname); } -void Faceshift::startFPSTimer() { - _frameCount = 0; - QTimer::singleShot(FPS_TIMER_DURATION, this, SLOT(finishFPSTimer())); -} - -void Faceshift::finishFPSTimer() { - qCDebug(interfaceapp) << "Faceshift: FPS =" << (float)_frameCount / ((float)FPS_TIMER_DURATION / 1000.0f); - _isCalculatingFPS = false; -} diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index 18d88e6fe9..994a7586ae 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -95,8 +95,6 @@ private slots: void noteError(QAbstractSocket::SocketError error); void readPendingDatagrams(); void readFromSocket(); - void startFPSTimer(); - void finishFPSTimer(); private: Faceshift(); @@ -154,9 +152,6 @@ private: int _mouthSmileRightIndex = 29; int _jawOpenIndex = 21; - - bool _isCalculatingFPS; - int _frameCount; }; #endif // hifi_Faceshift_h From c37eb3de8a35259aebe9207761bf1e263a52476f Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 25 Apr 2015 11:34:50 -0700 Subject: [PATCH 333/401] Fix DDE shutdown --- interface/src/devices/DdeFaceTracker.cpp | 16 +++++++++++----- interface/src/devices/DdeFaceTracker.h | 3 ++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index ef9ab6fdc6..741863abf4 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -144,6 +144,7 @@ DdeFaceTracker::DdeFaceTracker() : DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort) : _ddeProcess(NULL), + _ddeStopping(false), _host(host), _serverPort(serverPort), _controlPort(controlPort), @@ -196,6 +197,7 @@ void DdeFaceTracker::setEnabled(bool enabled) { if (enabled && !_ddeProcess) { // Terminate any existing DDE process, perhaps left running after an Interface crash _udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort); + _ddeStopping = false; qDebug() << "[Info] DDE Face Tracker Starting"; _ddeProcess = new QProcess(qApp); @@ -204,9 +206,8 @@ void DdeFaceTracker::setEnabled(bool enabled) { } if (!enabled && _ddeProcess) { + _ddeStopping = true; _udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort); - delete _ddeProcess; - _ddeProcess = NULL; qDebug() << "[Info] DDE Face Tracker Stopped"; } #endif @@ -214,11 +215,16 @@ void DdeFaceTracker::setEnabled(bool enabled) { void DdeFaceTracker::processFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (_ddeProcess) { - // DDE crashed or was manually terminated - qDebug() << "[Info] DDE Face Tracker Stopped Unexpectedly"; + if (_ddeStopping) { + qCDebug(interfaceapp) << "DDE Face Tracker: Stopped"; + + } else { + qCWarning(interfaceapp) << "DDE Face Tracker: Stopped unexpectedly"; + Menu::getInstance()->setIsOptionChecked(MenuOption::NoFaceTracking, true); + } _udpSocket.close(); + delete _ddeProcess; _ddeProcess = NULL; - Menu::getInstance()->setIsOptionChecked(MenuOption::NoFaceTracking, true); } } diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 302150773e..d9df5723cf 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -62,9 +62,10 @@ private slots: private: DdeFaceTracker(); DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort); - ~DdeFaceTracker(); + virtual ~DdeFaceTracker(); QProcess* _ddeProcess; + bool _ddeStopping; QHostAddress _host; quint16 _serverPort; From 6071e44ba4b2efa7bd678f34c5a9c2d29a303507 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 25 Apr 2015 11:35:14 -0700 Subject: [PATCH 334/401] Regularize debug messages for Faceshift and DDE --- interface/src/devices/DdeFaceTracker.cpp | 10 +++++----- interface/src/devices/Faceshift.cpp | 12 ++++++++++-- interface/src/devices/Faceshift.h | 1 + 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 741863abf4..be25c0794d 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -199,7 +199,7 @@ void DdeFaceTracker::setEnabled(bool enabled) { _udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort); _ddeStopping = false; - qDebug() << "[Info] DDE Face Tracker Starting"; + qCDebug(interfaceapp) << "DDE Face Tracker: Starting"; _ddeProcess = new QProcess(qApp); connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus))); _ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS); @@ -208,7 +208,7 @@ void DdeFaceTracker::setEnabled(bool enabled) { if (!enabled && _ddeProcess) { _ddeStopping = true; _udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort); - qDebug() << "[Info] DDE Face Tracker Stopped"; + qCDebug(interfaceapp) << "DDE Face Tracker: Stopping"; } #endif } @@ -250,7 +250,7 @@ bool DdeFaceTracker::isActive() const { //private slots and methods void DdeFaceTracker::socketErrorOccurred(QAbstractSocket::SocketError socketError) { - qCDebug(interfaceapp) << "[Error] DDE Face Tracker Socket Error: " << _udpSocket.errorString(); + qCWarning(interfaceapp) << "DDE Face Tracker: Socket error: " << _udpSocket.errorString(); } void DdeFaceTracker::socketStateChanged(QAbstractSocket::SocketState socketState) { @@ -278,7 +278,7 @@ void DdeFaceTracker::socketStateChanged(QAbstractSocket::SocketState socketState state = "Unconnected"; break; } - qCDebug(interfaceapp) << "[Info] DDE Face Tracker Socket: " << state; + qCDebug(interfaceapp) << "DDE Face Tracker: Socket: " << state; } void DdeFaceTracker::readPendingDatagrams() { @@ -422,7 +422,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { FaceTracker::countFrame(); } else { - qCDebug(interfaceapp) << "[Error] DDE Face Tracker Decode Error"; + qCWarning(interfaceapp) << "DDE Face Tracker: Decode error"; } _lastReceiveTimestamp = usecTimestampNow(); } diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index a0af6c7e2f..8a0e5a324c 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -39,6 +39,7 @@ Faceshift::Faceshift() : connect(&_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(noteError(QAbstractSocket::SocketError))); connect(&_tcpSocket, SIGNAL(readyRead()), SLOT(readFromSocket())); connect(&_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SIGNAL(connectionStateChanged())); + connect(&_tcpSocket, SIGNAL(disconnected()), SLOT(noteDisconnected())); connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams())); @@ -131,6 +132,7 @@ void Faceshift::setTCPEnabled(bool enabled) { if ((_tcpEnabled = enabled)) { connectSocket(); } else { + qCDebug(interfaceapp, "Faceshift: Disconnecting..."); _tcpSocket.disconnectFromHost(); } #endif @@ -149,7 +151,7 @@ void Faceshift::connectSocket() { void Faceshift::noteConnected() { #ifdef HAVE_FACESHIFT - qCDebug(interfaceapp, "Faceshift: Connected."); + qCDebug(interfaceapp, "Faceshift: Connected"); // request the list of blendshape names string message; fsBinaryStream::encode_message(message, fsMsgSendBlendshapeNames()); @@ -157,10 +159,16 @@ void Faceshift::noteConnected() { #endif } +void Faceshift::noteDisconnected() { +#ifdef HAVE_FACESHIFT + qCDebug(interfaceapp, "Faceshift: Disconnected"); +#endif +} + void Faceshift::noteError(QAbstractSocket::SocketError error) { if (!_tcpRetryCount) { // Only spam log with fail to connect the first time, so that we can keep waiting for server - qCDebug(interfaceapp) << "Faceshift: " << _tcpSocket.errorString(); + qCWarning(interfaceapp) << "Faceshift: " << _tcpSocket.errorString(); } // retry connection after a 2 second delay if (_tcpEnabled) { diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index 994a7586ae..3d38af5654 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -95,6 +95,7 @@ private slots: void noteError(QAbstractSocket::SocketError error); void readPendingDatagrams(); void readFromSocket(); + void noteDisconnected(); private: Faceshift(); From 2eebfb9cf1983ed9be99c01869ae2a11f3062e38 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Apr 2015 12:50:16 -0700 Subject: [PATCH 335/401] merge from upstream --- libraries/render-utils/src/Model.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index fdb448ea14..fe82af6b3c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -139,10 +139,6 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, // Good to go add the brand new pipeline auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); -<<<<<<< HEAD - // auto it = -======= ->>>>>>> 3ce65d297a31c83c06f8838dd21ca128b59cef59 insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); // If not a shadow pass, create the mirror version from the same state, just change the FrontFace From a96f69a67316bf245b49cec5dc7b5b54fc973f1a Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 25 Apr 2015 16:20:15 -0700 Subject: [PATCH 336/401] Switching to a wrapper mechanism for VR menus --- interface/resources/qml/AddressBarDialog.qml | 2 +- .../qml/{Menu.qml => InterfaceMenu.qml} | 17 +- interface/resources/qml/Main.qml | 20 - interface/resources/qml/MessageDialog.qml | 7 +- interface/resources/qml/Root.qml | 2 +- interface/resources/qml/TestRoot.qml | 7 +- .../qml/{HifiMenu.qml => VrMenu.qml} | 40 +- interface/resources/qml/controls/Dialog.qml | 2 +- interface/resources/qml/images/critical.png | Bin 253 -> 0 bytes .../resources/qml/images/information.png | Bin 254 -> 0 bytes interface/resources/qml/images/question.png | Bin 257 -> 0 bytes interface/resources/qml/images/warning.png | Bin 224 -> 0 bytes interface/src/Application.cpp | 96 +- interface/src/Application.h | 3 + interface/src/Bookmarks.cpp | 67 +- interface/src/Bookmarks.h | 14 +- interface/src/MainWindow.cpp | 6 +- interface/src/Menu.cpp | 1423 ++++++++++------- interface/src/Menu.h | 144 +- interface/src/devices/OculusManager.cpp | 2 +- .../src/scripting/MenuScriptingInterface.cpp | 48 +- .../scripting/WindowScriptingInterface.cpp | 1 + interface/src/ui/HMDToolsDialog.cpp | 1 - interface/src/ui/LoginDialog.cpp | 17 +- interface/src/ui/RunningScriptsWidget.cpp | 9 +- interface/src/ui/ToolWindow.cpp | 3 +- libraries/ui/src/HifiMenu.cpp | 366 ++--- libraries/ui/src/HifiMenu.h | 63 +- libraries/ui/src/OffscreenUi.cpp | 7 +- tests/ui/src/main.cpp | 13 +- 30 files changed, 1335 insertions(+), 1045 deletions(-) rename interface/resources/qml/{Menu.qml => InterfaceMenu.qml} (99%) delete mode 100644 interface/resources/qml/Main.qml rename interface/resources/qml/{HifiMenu.qml => VrMenu.qml} (87%) delete mode 100644 interface/resources/qml/images/critical.png delete mode 100644 interface/resources/qml/images/information.png delete mode 100644 interface/resources/qml/images/question.png delete mode 100644 interface/resources/qml/images/warning.png diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 8a2bc3e2b4..8d2439e5b8 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -48,7 +48,7 @@ Dialog { helperText: "domain, location, @user, /x,y,z" anchors.margins: 8 onAccepted: { - event.accepted + event.accepted addressBarDialog.loadAddress(addressLine.text) } } diff --git a/interface/resources/qml/Menu.qml b/interface/resources/qml/InterfaceMenu.qml similarity index 99% rename from interface/resources/qml/Menu.qml rename to interface/resources/qml/InterfaceMenu.qml index 3939794fb2..2a5ed8d212 100644 --- a/interface/resources/qml/Menu.qml +++ b/interface/resources/qml/InterfaceMenu.qml @@ -2,6 +2,7 @@ import QtQuick 2.4 import QtQuick.Controls 1.3 import Hifi 1.0 +// Currently for testing a pure QML replacement menu Item { Item { objectName: "AllActions" @@ -10,7 +11,7 @@ Item { objectName: "HifiAction_" + MenuConstants.AboutApp text: qsTr("About Interface") } - + // // File Menu // @@ -26,7 +27,7 @@ Item { //shortcut: StandardKey.Quit shortcut: "Ctrl+Q" } - + // Scripts Action { id: loadScript @@ -58,7 +59,7 @@ Item { objectName: "HifiAction_" + MenuConstants.StopAllScripts text: qsTr("Stop All Scripts") } - + // Locations Action { id: bookmarkLocation @@ -75,7 +76,7 @@ Item { objectName: "HifiAction_" + MenuConstants.AddressBar text: qsTr("Show Address Bar") } - + // // Edit menu // @@ -84,13 +85,13 @@ Item { text: "Undo" shortcut: StandardKey.Undo } - + Action { id: redo text: "Redo" shortcut: StandardKey.Redo } - + Action { id: animations objectName: "HifiAction_" + MenuConstants.Animations @@ -157,7 +158,7 @@ Item { objectName: "HifiAction_" + MenuConstants.ResetSensors text: qsTr("Reset Sensors") } - + @@ -853,7 +854,7 @@ Item { } } - MenuBar { + Menu { objectName: "rootMenu"; Menu { title: "File" diff --git a/interface/resources/qml/Main.qml b/interface/resources/qml/Main.qml deleted file mode 100644 index 8911a4c9f4..0000000000 --- a/interface/resources/qml/Main.qml +++ /dev/null @@ -1,20 +0,0 @@ -import QtQuick 2.4 -import QtQuick.Controls 1.3 - -ApplicationWindow { - id: root - width: 800 - height: 600 - visible: true - - menuBar: MenuBar { - Menu { - title: "File" - MenuItem { - text: "Quit" - } - } - } - -} - diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml index 3a1c92cdf3..f469e33c30 100644 --- a/interface/resources/qml/MessageDialog.qml +++ b/interface/resources/qml/MessageDialog.qml @@ -9,6 +9,7 @@ Dialog { property real spacing: 8 property real outerSpacing: 16 + destroyOnCloseButton: true destroyOnInvisible: true implicitHeight: content.implicitHeight + outerSpacing * 2 + 48 @@ -35,7 +36,7 @@ Dialog { onEnabledChanged: { if (enabled) { - root.forceActiveFocus(); + root.forceActiveFocus(); } } @@ -334,7 +335,7 @@ Dialog { case Qt.Key_Period: if (Qt.platform.os === "osx") { event.accepted = true - content.reject() + content.reject() } break } else switch (event.key) { @@ -346,7 +347,7 @@ Dialog { case Qt.Key_Enter: case Qt.Key_Return: - console.log("Accepting"); + console.log("Accepting"); event.accepted = true content.accept() break diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index 9b2e5af6b5..1b0f09558f 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -8,7 +8,7 @@ Root { anchors.fill: parent onParentChanged: { - forceActiveFocus(); + forceActiveFocus(); } } diff --git a/interface/resources/qml/TestRoot.qml b/interface/resources/qml/TestRoot.qml index 0b9209aa76..bd38c696bf 100644 --- a/interface/resources/qml/TestRoot.qml +++ b/interface/resources/qml/TestRoot.qml @@ -6,12 +6,11 @@ import QtQuick.Controls 1.3 import "controls" Root { - id: root + id: root anchors.fill: parent onParentChanged: { - forceActiveFocus(); + forceActiveFocus(); } - Button { id: messageBox anchors.right: createDialog.left @@ -38,7 +37,7 @@ Root { } Keys.onPressed: { - console.log(event.key); + console.log("Key press root") } } diff --git a/interface/resources/qml/HifiMenu.qml b/interface/resources/qml/VrMenu.qml similarity index 87% rename from interface/resources/qml/HifiMenu.qml rename to interface/resources/qml/VrMenu.qml index 2c6963a349..8c4aaafb3b 100644 --- a/interface/resources/qml/HifiMenu.qml +++ b/interface/resources/qml/VrMenu.qml @@ -5,10 +5,10 @@ import QtQuick.Controls.Styles 1.3 import "controls" import "styles" -Hifi.HifiMenu { +Hifi.VrMenu { id: root anchors.fill: parent - objectName: "HifiMenu" + objectName: "VrMenu" enabled: false opacity: 0.0 property int animationDuration: 200 @@ -17,7 +17,7 @@ Hifi.HifiMenu { onEnabledChanged: { if (enabled && columns.length == 0) { - pushColumn(rootMenu.menus); + pushColumn(rootMenu.items); } opacity = enabled ? 1.0 : 0.0 if (enabled) { @@ -47,13 +47,21 @@ Hifi.HifiMenu { property var menuBuilder: Component { Border { + Component.onCompleted: { + menuDepth = root.models.length - 1 + if (menuDepth == 0) { + x = lastMousePosition.x - 20 + y = lastMousePosition.y - 20 + } else { + var lastColumn = root.columns[menuDepth - 1] + x = lastColumn.x + 64; + y = lastMousePosition.y - height / 2; + } + } SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } - x: root.models.length == 1 ? - (root.width / 2 - width / 2) : - root.columns[root.models.length - 2].x + 60; - anchors.verticalCenter: parent.verticalCenter border.color: hifiPalette.hifiBlue color: sysPalette.window + property int menuDepth ListView { spacing: 6 @@ -186,7 +194,25 @@ Hifi.HifiMenu { anchors.top: parent.top anchors.topMargin: 0 width: listView.width + hoverEnabled: true + Timer { + id: timer + interval: 1000 + onTriggered: parent.select(); + } + onEntered: { + if (source.type == 2 && enabled) { + timer.start() + } + } + onExited: { + timer.stop() + } onClicked: { + select(); + } + function select() { + timer.stop(); listView.currentIndex = listViewIndex parent.root.selectItem(parent.source); } diff --git a/interface/resources/qml/controls/Dialog.qml b/interface/resources/qml/controls/Dialog.qml index 07162ad1d8..d722d5264a 100644 --- a/interface/resources/qml/controls/Dialog.qml +++ b/interface/resources/qml/controls/Dialog.qml @@ -17,7 +17,7 @@ Item { HifiPalette { id: hifiPalette } SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } x: parent ? parent.width / 2 - width / 2 : 0 - y: parent ? parent.height / 2 - height / 2 : 0 + y: parent ? parent.height / 2 - height / 2 : 0 property int animationDuration: 400 property bool destroyOnInvisible: false diff --git a/interface/resources/qml/images/critical.png b/interface/resources/qml/images/critical.png deleted file mode 100644 index dc9c5aebf453dd92dba60c48f060b34f0087e02c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 253 zcmVkNDWE^AyB8@ZEC00000NkvXXu0mjf DKfYr$ diff --git a/interface/resources/qml/images/information.png b/interface/resources/qml/images/information.png deleted file mode 100644 index 0a2eb87d108d2a24b71559998627570a252ebe69..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8`~f~8uBj!u3?T4-=FFM@ z|NrludHNay0|R48kY6x^!?PP{3=9l&JzX3_G|sP`c#-$80*{Mh+yV`sgwlqP>#QC( z>X#+u7`Xm@Q`=BsWqr<)MUc^=nfrazYu@_ss|q3QYrOu5+ux47bKp#oZChf4k#&aW z_6qNdiK4+zLkc4MIa@Ri#52@3K4zcMoZ;%Na4X>suaM`rgBP8<|7A}r*;L-N)XQ^~ z*Qd}2Q;+ng3Z7t^78=O>`qh(QX^u+vLUu-L1y=d3FMU5VRZj!?kipZ{&t;ucLK6Te CT3=!S diff --git a/interface/resources/qml/images/question.png b/interface/resources/qml/images/question.png deleted file mode 100644 index 2dd92fd7915a09de670b8b6022ddcf02d4cc90e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 257 zcmV+c0sj7pP)NklQ}7)nBez2^$+jK{Nw%L3xK4m{g6jm}2|@>7z7zk+b}w*O&>f9X*ioevByCmJtfv0xgg* zX&;ac>>nrw_75mp9NLlK=){M}g!K&|3b4W-F*J23VSVK);JN=%IJYXN$un1x$~;9b a#PS7=(1SoC6O>K>0000a diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b22bacef33..a9bbaf7de0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -52,8 +52,6 @@ #include #include #include -#include -#include #include #include @@ -65,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -135,7 +134,6 @@ #include "ui/DialogsManager.h" #include "ui/InfoView.h" #include "ui/LoginDialog.h" -#include "ui/MarketplaceDialog.h" #include "ui/Snapshot.h" #include "ui/StandAloneJSConsole.h" #include "ui/Stats.h" @@ -510,6 +508,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); + _fullscreenMenuWidget->setParent(_glWidget); + _menuBarHeight = Menu::getInstance()->height(); if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) { setFullscreen(true); // Initialize menu bar show/hide } @@ -730,6 +730,10 @@ void Application::initializeGL() { qCDebug(interfaceapp, "Initialized Offscreen UI."); _glWidget->makeCurrent(); + // call Menu getInstance static method to set up the menu + // Needs to happen AFTER the QML UI initialization + _window->setMenuBar(Menu::getInstance()); + init(); qCDebug(interfaceapp, "init() complete."); @@ -764,9 +768,7 @@ void Application::initializeGL() { void Application::initializeUi() { AddressBarDialog::registerType(); LoginDialog::registerType(); - MarketplaceDialog::registerType(); MessageDialog::registerType(); - Menu::registerType(); auto offscreenUi = DependencyManager::get(); offscreenUi->create(_glWidget->context()->contextHandle()); @@ -902,7 +904,9 @@ void Application::runTests() { } void Application::audioMuteToggled() { - Menu::getInstance()->setIsOptionChecked(MenuOption::MuteAudio, DependencyManager::get()->isMuted()); + QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteAudio); + Q_CHECK_PTR(muteAction); + muteAction->setChecked(DependencyManager::get()->isMuted()); } void Application::aboutApp() { @@ -1067,12 +1071,10 @@ bool Application::eventFilter(QObject* object, QEvent* event) { return false; } -static bool altPressed; -static bool ctrlPressed; +static bool _altPressed{ false }; void Application::keyPressEvent(QKeyEvent* event) { - altPressed = event->key() == Qt::Key_Alt; - ctrlPressed = event->key() == Qt::Key_Control; + _altPressed = event->key() == Qt::Key_Alt; _keysPressed.insert(event->key()); _controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts @@ -1162,9 +1164,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_Backslash: - MarketplaceDialog::show(); - - //Menu::getInstance()->triggerOption(MenuOption::Chat); + Menu::getInstance()->triggerOption(MenuOption::Chat); break; case Qt::Key_Up: @@ -1329,13 +1329,15 @@ void Application::keyPressEvent(QKeyEvent* event) { } void Application::keyReleaseEvent(QKeyEvent* event) { - if (event->key() == Qt::Key_Alt && altPressed && _window->isActiveWindow()) { - Menu::toggle(); + if (event->key() == Qt::Key_Alt && _altPressed && _window->isActiveWindow()) { +#ifndef DEBUG + if (OculusManager::isConnected()) { +#endif + VrMenu::toggle(); +#ifndef DEBUG + } +#endif } - if (event->key() == Qt::Key_Control && ctrlPressed && _window->isActiveWindow()) { - Menu::toggle(); - } - ctrlPressed = altPressed = false; _keysPressed.remove(event->key()); @@ -1346,6 +1348,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { return; } + switch (event->key()) { case Qt::Key_E: case Qt::Key_PageUp: @@ -1442,6 +1445,18 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { return; } + if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen) + && !Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { + // Show/hide menu bar in fullscreen + if (event->globalY() > _menuBarHeight) { + _fullscreenMenuWidget->setFixedHeight(0); + Menu::getInstance()->setFixedHeight(0); + } else { + _fullscreenMenuWidget->setFixedHeight(_menuBarHeight); + Menu::getInstance()->setFixedHeight(_menuBarHeight); + } + } + _entities.mouseMoveEvent(event, deviceID); _controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts @@ -1449,6 +1464,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { if (_controllerScriptingInterface.isMouseCaptured()) { return; } + } void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { @@ -1735,6 +1751,34 @@ void Application::setFullscreen(bool fullscreen) { Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen); } +// The following code block is useful on platforms that can have a visible +// app menu in a fullscreen window. However the OSX mechanism hides the +// application menu for fullscreen apps, so the check is not required. +#ifndef Q_OS_MAC + if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { + if (fullscreen) { + // Menu hide() disables menu commands, and show() after hide() doesn't work with Rift VR display. + // So set height instead. + _window->menuBar()->setMaximumHeight(0); + } else { + _window->menuBar()->setMaximumHeight(QWIDGETSIZE_MAX); + } + } else { + if (fullscreen) { + // Move menu to a QWidget floating above _glWidget so that show/hide doesn't adjust viewport. + _menuBarHeight = Menu::getInstance()->height(); + Menu::getInstance()->setParent(_fullscreenMenuWidget); + Menu::getInstance()->setFixedWidth(_window->windowHandle()->screen()->size().width()); + _fullscreenMenuWidget->show(); + } else { + // Restore menu to being part of MainWindow. + _fullscreenMenuWidget->hide(); + _window->setMenuBar(Menu::getInstance()); + _window->menuBar()->setMaximumHeight(QWIDGETSIZE_MAX); + } + } +#endif + // Work around Qt bug that prevents floating menus being shown when in fullscreen mode. // https://bugreports.qt.io/browse/QTBUG-41883 // Known issue: Top-level menu items don't highlight when cursor hovers. This is probably a side-effect of the work-around. @@ -1987,18 +2031,16 @@ void Application::init() { OculusManager::connect(); if (OculusManager::isConnected()) { - // perform as a post-event so that the code is run after init is complete - qApp->postLambdaEvent([] { - Menu::getInstance()->triggerOption(MenuOption::Fullscreen); - }); + QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), + "trigger", + Qt::QueuedConnection); } TV3DManager::connect(); if (TV3DManager::isConnected()) { - // perform as a post-event so that the code is run after init is complete - qApp->postLambdaEvent([] { - Menu::getInstance()->triggerOption(MenuOption::Fullscreen); - }); + QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), + "trigger", + Qt::QueuedConnection); } _timerStart.start(); diff --git a/interface/src/Application.h b/interface/src/Application.h index f63f548c47..688cf23876 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -623,6 +623,9 @@ private: void checkSkeleton(); + QWidget* _fullscreenMenuWidget = new QWidget(); + int _menuBarHeight; + QHash _acceptedExtensions; QList _domainConnectionRefusals; diff --git a/interface/src/Bookmarks.cpp b/interface/src/Bookmarks.cpp index 76ab607ff5..896a50acca 100644 --- a/interface/src/Bookmarks.cpp +++ b/interface/src/Bookmarks.cpp @@ -84,16 +84,13 @@ void Bookmarks::persistToFile() { saveFile.write(data); } -void Bookmarks::setupMenus(const QString & parentMenu) { +void Bookmarks::setupMenus(Menu* menubar, MenuWrapper* menu) { // Add menus/actions - Menu * menu = Menu::getInstance(); - menu->addItem(parentMenu, MenuOption::BookmarkLocation, [this] { - bookmarkLocation(); - }); - menu->addMenu(parentMenu, MenuOption::Bookmarks); - menu->addItem(parentMenu, MenuOption::DeleteBookmark, [this] { - deleteBookmark(); - }); + menubar->addActionToQMenuAndActionHash(menu, MenuOption::BookmarkLocation, 0, + this, SLOT(bookmarkLocation())); + _bookmarksMenu = menu->addMenu(MenuOption::Bookmarks); + _deleteBookmarksAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::DeleteBookmark, 0, + this, SLOT(deleteBookmark())); // Enable/Disable menus as needed enableMenuItems(_bookmarks.count() > 0); @@ -102,7 +99,7 @@ void Bookmarks::setupMenus(const QString & parentMenu) { for (auto it = _bookmarks.begin(); it != _bookmarks.end(); ++it ) { QString bookmarkName = it.key(); QString bookmarkAddress = it.value().toString(); - addLocationToMenu(bookmarkName, bookmarkAddress); + addLocationToMenu(menubar, bookmarkName, bookmarkAddress); } } @@ -137,20 +134,29 @@ void Bookmarks::bookmarkLocation() { if (duplicateBookmarkMessage.exec() == QMessageBox::No) { return; } - removeLocationFromMenu(bookmarkName); + removeLocationFromMenu(menubar, bookmarkName); } - addLocationToMenu(bookmarkName, bookmarkAddress); + addLocationToMenu(menubar, bookmarkName, bookmarkAddress); insert(bookmarkName, bookmarkAddress); // Overwrites any item with the same bookmarkName. enableMenuItems(true); } +void Bookmarks::teleportToBookmark() { + QAction* action = qobject_cast(sender()); + QString address = action->data().toString(); + DependencyManager::get()->handleLookupString(address); +} + void Bookmarks::deleteBookmark() { + QStringList bookmarkList; - bookmarkList.append(_bookmarks.keys()); - - + QList menuItems = _bookmarksMenu->actions(); + for (int i = 0; i < menuItems.count(); i += 1) { + bookmarkList.append(menuItems[i]->text()); + } + QInputDialog deleteBookmarkDialog(qApp->getWindow()); deleteBookmarkDialog.setWindowTitle("Delete Bookmark"); deleteBookmarkDialog.setLabelText("Select the bookmark to delete"); @@ -168,29 +174,34 @@ void Bookmarks::deleteBookmark() { return; } - removeLocationFromMenu(bookmarkName); + removeLocationFromMenu(Menu::getInstance(), bookmarkName); remove(bookmarkName); - - if (_bookmarks.keys().isEmpty()) { + + if (_bookmarksMenu->actions().count() == 0) { enableMenuItems(false); } } void Bookmarks::enableMenuItems(bool enabled) { - Menu* menu = Menu::getInstance(); - menu->enableItem(MenuOption::Bookmarks, enabled); - menu->enableItem(MenuOption::DeleteBookmark, enabled); + if (_bookmarksMenu) { + _bookmarksMenu->setEnabled(enabled); + } + if (_deleteBookmarksAction) { + _deleteBookmarksAction->setEnabled(enabled); + } } -void Bookmarks::addLocationToMenu(QString& name, QString& address) { - - Menu::getInstance()->addItem(MenuOption::Bookmarks, name, [=] { - DependencyManager::get()->handleLookupString(address); - }); +void Bookmarks::addLocationToMenu(Menu* menubar, QString& name, QString& address) { + QAction* teleportAction = _bookmarksMenu->newAction(); + teleportAction->setData(address); + connect(teleportAction, SIGNAL(triggered()), this, SLOT(teleportToBookmark())); + + menubar->addActionToQMenuAndActionHash(_bookmarksMenu, teleportAction, + name, 0, QAction::NoRole); } -void Bookmarks::removeLocationFromMenu(QString& name) { - Menu::getInstance()->removeItem(name); +void Bookmarks::removeLocationFromMenu(Menu* menubar, QString& name) { + menubar->removeAction(_bookmarksMenu, name); } diff --git a/interface/src/Bookmarks.h b/interface/src/Bookmarks.h index d996d7c0f0..7ff9d48e8a 100644 --- a/interface/src/Bookmarks.h +++ b/interface/src/Bookmarks.h @@ -19,6 +19,7 @@ class QAction; class QMenu; class Menu; +class MenuWrapper; class Bookmarks: public QObject { Q_OBJECT @@ -26,16 +27,19 @@ class Bookmarks: public QObject { public: Bookmarks(); - void setupMenus(const QString & menu); + void setupMenus(Menu* menubar, MenuWrapper* menu); private slots: void bookmarkLocation(); + void teleportToBookmark(); void deleteBookmark(); private: - // FIXME bookmarks should be more categorizable - // Can we leverage a system browser favorites API? QVariantMap _bookmarks; // { name: address, ... } + + QPointer _bookmarksMenu; + QPointer _deleteBookmarksAction; + const QString BOOKMARKS_FILENAME = "bookmarks.json"; QString _bookmarksFilename; @@ -47,8 +51,8 @@ private: void persistToFile(); void enableMenuItems(bool enabled); - void addLocationToMenu(QString& name, QString& address); - void removeLocationFromMenu(QString& name); + void addLocationToMenu(Menu* menubar, QString& name, QString& address); + void removeLocationFromMenu(Menu* menubar, QString& name); }; #endif // hifi_Bookmarks_h \ No newline at end of file diff --git a/interface/src/MainWindow.cpp b/interface/src/MainWindow.cpp index 7e8d46f5ee..f60716dc48 100644 --- a/interface/src/MainWindow.cpp +++ b/interface/src/MainWindow.cpp @@ -94,9 +94,9 @@ void MainWindow::changeEvent(QEvent* event) { emit windowShown(true); } - //if (isFullScreen() != Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) { - // Menu::getInstance()->setIsOptionChecked(MenuOption::Fullscreen, isFullScreen()); - //} + if (isFullScreen() != Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) { + Menu::getInstance()->setIsOptionChecked(MenuOption::Fullscreen, isFullScreen()); + } } else if (event->type() == QEvent::ActivationChange) { if (isActiveWindow()) { emit windowShown(true); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8c45f583f1..67fae46b33 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -21,7 +20,8 @@ #include #include #include -#include +#include + #include "Application.h" #include "AccountManager.h" #include "audio/AudioIOStatsRenderer.h" @@ -42,625 +42,529 @@ #include "InterfaceLogging.h" #include "Menu.h" -#include "Util.h" -// Proxy object to simplify porting over -HifiAction::HifiAction(const QString& menuOption) : _menuOption(menuOption) { -} - -void HifiAction::setCheckable(bool checkable) { - Menu::getInstance()->setCheckable(_menuOption, checkable); -} - -void HifiAction::setChecked(bool checked) { - Menu::getInstance()->setChecked(_menuOption, checked); -} - -void HifiAction::setVisible(bool visible) { - return Menu::getInstance()->setItemVisible(_menuOption); -} - -QString HifiAction::shortcut() const { - return Menu::getInstance()->getItemShortcut(_menuOption); -} - -void HifiAction::setText(const QString& text) { - Menu::getInstance()->setItemText(_menuOption, text); -} - -void HifiAction::setTriggerAction(std::function f) { - Menu::getInstance()->setTriggerAction(_menuOption, f); -} - -void HifiAction::setToggleAction(std::function f) { - Menu::getInstance()->setToggleAction(_menuOption, f); -} - -Menu* Menu::_instance = nullptr; +Menu* Menu::_instance = NULL; Menu* Menu::getInstance() { - // Optimistic check for menu existence + static QMutex menuInstanceMutex; + + // lock the menu instance mutex to make sure we don't race and create two menus and crash + menuInstanceMutex.lock(); + if (!_instance) { - static QMutex menuInstanceMutex; - withLock(menuInstanceMutex, [] { - if (!_instance) { - qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); - qCDebug(interfaceapp, "First call to Menu::getInstance() - initing menu."); - Menu::load(); - auto uiRoot = DependencyManager::get()->getRootItem(); - _instance = uiRoot->findChild(NAME); - if (!_instance) { - qFatal("Could not load menu QML"); - } else { - _instance->init(); - } - } - }); + qCDebug(interfaceapp, "First call to Menu::getInstance() - initing menu."); + _instance = new Menu(); } + + menuInstanceMutex.unlock(); + return _instance; } -Menu::Menu(QQuickItem* parent) : HifiMenu(parent) { -} - -void Menu::init() { +Menu::Menu() { + MenuWrapper * fileMenu = addMenu("File"); +#ifdef Q_OS_MAC + addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); +#endif auto dialogsManager = DependencyManager::get(); AccountManager& accountManager = AccountManager::getInstance(); - static const QString ROOT_MENU; + { - static const QString FILE_MENU{ "File" }; - addMenu(ROOT_MENU, FILE_MENU); - { - addItem(FILE_MENU, MenuOption::Login); - // connect to the appropriate signal of the AccountManager so that we can change the Login/Logout menu item - connect(&accountManager, &AccountManager::profileChanged, + addActionToQMenuAndActionHash(fileMenu, MenuOption::Login); + + // connect to the appropriate signal of the AccountManager so that we can change the Login/Logout menu item + connect(&accountManager, &AccountManager::profileChanged, dialogsManager.data(), &DialogsManager::toggleLoginDialog); - connect(&accountManager, &AccountManager::logoutComplete, + connect(&accountManager, &AccountManager::logoutComplete, dialogsManager.data(), &DialogsManager::toggleLoginDialog); - } - -#ifdef Q_OS_MAC - addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); -#endif - - { -#if 0 - static const QString SCRIPTS_MENU{ "Scripts" }; - addMenu(FILE_MENU, LOCATION_MENU); -#else - static const QString SCRIPTS_MENU{ FILE_MENU }; - addSeparator(FILE_MENU, "Scripts"); -#endif - //Qt::CTRL | Qt::Key_O - addItem(SCRIPTS_MENU, MenuOption::LoadScript, qApp, SLOT(loadDialog())); - //Qt::CTRL | Qt::SHIFT | Qt::Key_O - addItem(SCRIPTS_MENU, MenuOption::LoadScriptURL, [=] { - qApp->loadScriptURLDialog(); - }); - addItem(SCRIPTS_MENU, MenuOption::StopAllScripts, [=] { - qApp->stopAllScripts(); - }); - //Qt::CTRL | Qt::Key_R, - addItem(SCRIPTS_MENU, MenuOption::ReloadAllScripts, [=] { - qApp->reloadAllScripts(); - }); - // Qt::CTRL | Qt::Key_J, - addItem(SCRIPTS_MENU, MenuOption::RunningScripts, [=] { - qApp->toggleRunningScriptsWidget(); - }); - } - - { -#if 0 - static const QString LOCATION_MENU{ "Location" }; - addMenu(FILE_MENU, LOCATION_MENU); -#else - addSeparator(FILE_MENU, "Location"); - static const QString LOCATION_MENU{ FILE_MENU }; -#endif - qApp->getBookmarks()->setupMenus(LOCATION_MENU); - - //Qt::CTRL | Qt::Key_L - addItem(LOCATION_MENU, MenuOption::AddressBar, [=] { - auto dialogsManager = DependencyManager::get(); - dialogsManager->toggleAddressBar(); - }); - addItem(LOCATION_MENU, MenuOption::CopyAddress, [=] { - auto addressManager = DependencyManager::get(); - addressManager->copyAddress(); - }); - addItem(LOCATION_MENU, MenuOption::CopyPath, [=] { - auto addressManager = DependencyManager::get(); - addressManager->copyPath(); - }); - } - - // Qt::CTRL | Qt::Key_Q - // QAction::QuitRole - addItem(FILE_MENU, MenuOption::Quit, [=] { - qApp->quit(); - }); } + + addDisabledActionAndSeparator(fileMenu, "Scripts"); + addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, + qApp, SLOT(loadDialog())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL, + Qt::CTRL | Qt::SHIFT | Qt::Key_O, qApp, SLOT(loadScriptURLDialog())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, qApp, SLOT(stopAllScripts())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::Key_R, + qApp, SLOT(reloadAllScripts())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, + qApp, SLOT(toggleRunningScriptsWidget())); + + addDisabledActionAndSeparator(fileMenu, "Location"); + qApp->getBookmarks()->setupMenus(this, fileMenu); + + addActionToQMenuAndActionHash(fileMenu, + MenuOption::AddressBar, + Qt::CTRL | Qt::Key_L, + dialogsManager.data(), + SLOT(toggleAddressBar())); + auto addressManager = DependencyManager::get(); + addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyAddress, 0, + addressManager.data(), SLOT(copyAddress())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyPath, 0, + addressManager.data(), SLOT(copyPath())); + + addActionToQMenuAndActionHash(fileMenu, + MenuOption::Quit, + Qt::CTRL | Qt::Key_Q, + qApp, + SLOT(quit()), + QAction::QuitRole); - { - static const QString EDIT_MENU{ "Edit" }; - addMenu(ROOT_MENU, EDIT_MENU); + MenuWrapper* editMenu = addMenu("Edit"); - QUndoStack* undoStack = qApp->getUndoStack(); - QAction* undoAction = undoStack->createUndoAction(this); - //undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); - addItem(EDIT_MENU, undoAction->text(), undoAction, SLOT(trigger())); + QUndoStack* undoStack = qApp->getUndoStack(); + QAction* undoAction = undoStack->createUndoAction(editMenu); + undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); + addActionToQMenuAndActionHash(editMenu, undoAction); - QAction* redoAction = undoStack->createRedoAction(this); - //redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); - addItem(EDIT_MENU, redoAction->text(), redoAction, SLOT(trigger())); + QAction* redoAction = undoStack->createRedoAction(editMenu); + redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); + addActionToQMenuAndActionHash(editMenu, redoAction); - // Qt::CTRL | Qt::Key_Comma - // QAction::PreferencesRole - addItem(EDIT_MENU, MenuOption::Preferences, [=] { - dialogsManager->editPreferences(); - }); - addItem(EDIT_MENU, MenuOption::Animations, [=] { - dialogsManager->editAnimations(); - }); - } + addActionToQMenuAndActionHash(editMenu, + MenuOption::Preferences, + Qt::CTRL | Qt::Key_Comma, + dialogsManager.data(), + SLOT(editPreferences()), + QAction::PreferencesRole); - { - static const QString TOOLS_MENU{ "Tools" }; - addMenu(ROOT_MENU, TOOLS_MENU); + addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0, + dialogsManager.data(), SLOT(editAttachments())); + addActionToQMenuAndActionHash(editMenu, MenuOption::Animations, 0, + dialogsManager.data(), SLOT(editAnimations())); + + MenuWrapper* toolsMenu = addMenu("Tools"); + addActionToQMenuAndActionHash(toolsMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S, + dialogsManager.data(), SLOT(showScriptEditor())); #if defined(Q_OS_MAC) || defined(Q_OS_WIN) - auto speechRecognizer = DependencyManager::get(); - //Qt::CTRL | Qt::SHIFT | Qt::Key_C - addItem(TOOLS_MENU, MenuOption::ControlWithSpeech); - setChecked(MenuOption::ControlWithSpeech, speechRecognizer->getEnabled()); - connect(speechRecognizer.data(), &SpeechRecognizer::enabledUpdated, [=] { - setChecked(MenuOption::ControlWithSpeech, speechRecognizer->getEnabled()); - }); + auto speechRecognizer = DependencyManager::get(); + QAction* speechRecognizerAction = addCheckableActionToQMenuAndActionHash(toolsMenu, MenuOption::ControlWithSpeech, + Qt::CTRL | Qt::SHIFT | Qt::Key_C, + speechRecognizer->getEnabled(), + speechRecognizer.data(), + SLOT(setEnabled(bool))); + connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool))); #endif - // Qt::ALT | Qt::Key_S, - addItem(TOOLS_MENU, MenuOption::ScriptEditor, [=] { - dialogsManager->showScriptEditor(); - }); - // QML Qt::Key_Backslash, - addItem(TOOLS_MENU, MenuOption::Chat, [=] { - dialogsManager->showIRCLink(); - }); - addItem(TOOLS_MENU, MenuOption::AddRemoveFriends, [=] { - qApp->showFriendsWindow(); - }); + + addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, + 0, // QML Qt::Key_Backslash, + dialogsManager.data(), SLOT(showIRCLink())); + addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0, + qApp, SLOT(showFriendsWindow())); - { - static const QString VIZ_MENU{ "I Am Visible To" }; - addMenu(TOOLS_MENU, VIZ_MENU); - auto discoverabilityManager = DependencyManager::get(); - // FIXME group - addCheckableItem(VIZ_MENU, MenuOption::VisibleToEveryone, - discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, - discoverabilityManager.data(), SLOT(setVisibility())); - addCheckableItem(VIZ_MENU, MenuOption::VisibleToFriends, - discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, - discoverabilityManager.data(), SLOT(setVisibility())); - addCheckableItem(VIZ_MENU, MenuOption::VisibleToNoOne, - discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, - discoverabilityManager.data(), SLOT(setVisibility())); - connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, - discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged); - } + MenuWrapper* visibilityMenu = toolsMenu->addMenu("I Am Visible To"); + { + QActionGroup* visibilityGroup = new QActionGroup(toolsMenu); + auto discoverabilityManager = DependencyManager::get(); - //Qt::CTRL | Qt::ALT | Qt::Key_T, - addItem(TOOLS_MENU, MenuOption::ToolWindow, - dialogsManager.data(), SLOT(toggleToolWindow())); + QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, + discoverabilityManager.data(), SLOT(setVisibility())); + visibilityGroup->addAction(visibleToEveryone); - //Qt::CTRL | Qt::ALT | Qt::Key_J, - addItem(TOOLS_MENU, MenuOption::Console, [=] { - DependencyManager::get()->toggleConsole(); - }); + QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, + discoverabilityManager.data(), SLOT(setVisibility())); + visibilityGroup->addAction(visibleToFriends); - // QML Qt::Key_Apostrophe, - addItem(TOOLS_MENU, MenuOption::ResetSensors, [=] { - qApp->resetSensors(); - }); + QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, + discoverabilityManager.data(), SLOT(setVisibility())); + visibilityGroup->addAction(visibleToNoOne); - addItem(TOOLS_MENU, MenuOption::PackageModel, [=] { - qApp->packageModel(); - }); + connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, + discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged); } - { - static const QString AVATAR_MENU{ "Avatar" }; - addMenu(ROOT_MENU, AVATAR_MENU); - auto avatar = DependencyManager::get()->getMyAvatar(); - { - static const QString SIZE_MENU{ "Size" }; - addMenu(AVATAR_MENU, SIZE_MENU); - // QML Qt::Key_Plus, - addItem(SIZE_MENU, MenuOption::IncreaseAvatarSize, [=] { - avatar->increaseSize(); - }); - // QML Qt::Key_Minus, - addItem(SIZE_MENU, MenuOption::DecreaseAvatarSize, [=] { - avatar->decreaseSize(); - }); - // QML Qt::Key_Equal, - addItem(SIZE_MENU, MenuOption::ResetAvatarSize, [=] { - avatar->resetSize(); - }); + addActionToQMenuAndActionHash(toolsMenu, + MenuOption::ToolWindow, + Qt::CTRL | Qt::ALT | Qt::Key_T, + dialogsManager.data(), + SLOT(toggleToolWindow())); - addItem(SIZE_MENU, MenuOption::ResetAvatarSize, [=] { - avatar->resetSize(); - }); - } + addActionToQMenuAndActionHash(toolsMenu, + MenuOption::Console, + Qt::CTRL | Qt::ALT | Qt::Key_J, + DependencyManager::get().data(), + SLOT(toggleConsole())); - //Qt::CTRL | Qt::SHIFT | Qt::Key_K - addCheckableItem(AVATAR_MENU, MenuOption::KeyboardMotorControl, true, [=](bool) { - avatar->updateMotionBehavior(); - }); - addCheckableItem(AVATAR_MENU, MenuOption::ScriptedMotorControl, true); - addCheckableItem(AVATAR_MENU, MenuOption::NamesAboveHeads, true); - addCheckableItem(AVATAR_MENU, MenuOption::GlowWhenSpeaking, true); - addCheckableItem(AVATAR_MENU, MenuOption::BlueSpeechSphere, true); - addCheckableItem(AVATAR_MENU, MenuOption::EnableCharacterController, true, + addActionToQMenuAndActionHash(toolsMenu, + MenuOption::ResetSensors, + 0, // QML Qt::Key_Apostrophe, + qApp, + SLOT(resetSensors())); + + addActionToQMenuAndActionHash(toolsMenu, MenuOption::PackageModel, 0, + qApp, SLOT(packageModel())); + + MenuWrapper* avatarMenu = addMenu("Avatar"); + QObject* avatar = DependencyManager::get()->getMyAvatar(); + + MenuWrapper* avatarSizeMenu = avatarMenu->addMenu("Size"); + addActionToQMenuAndActionHash(avatarSizeMenu, + MenuOption::IncreaseAvatarSize, + 0, // QML Qt::Key_Plus, + avatar, + SLOT(increaseSize())); + addActionToQMenuAndActionHash(avatarSizeMenu, + MenuOption::DecreaseAvatarSize, + 0, // QML Qt::Key_Minus, + avatar, + SLOT(decreaseSize())); + addActionToQMenuAndActionHash(avatarSizeMenu, + MenuOption::ResetAvatarSize, + 0, // QML Qt::Key_Equal, + avatar, + SLOT(resetSize())); + + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::KeyboardMotorControl, + Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehavior())); + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ScriptedMotorControl, 0, true, avatar, SLOT(updateMotionBehavior())); - addCheckableItem(AVATAR_MENU, MenuOption::ShiftHipsForIdleAnimations, false, + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true); + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true); + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true, + avatar, SLOT(updateMotionBehavior())); + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false, avatar, SLOT(updateMotionBehavior())); - } - { - static const QString VIEW_MENU{ "View" }; - addMenu(ROOT_MENU, VIEW_MENU); + MenuWrapper* viewMenu = addMenu("View"); - // Mac Qt::CTRL | Qt::META | Qt::Key_F, - // Win32/Linux Qt::CTRL | Qt::Key_F, - addCheckableItem(VIEW_MENU, MenuOption::Fullscreen, false); - connectCheckable(MenuOption::Fullscreen, qApp, SLOT(setFullscreen(bool))); - // QML Qt::Key_P, - addCheckableItem(VIEW_MENU, MenuOption::FirstPerson, true, - qApp, SLOT(cameraMenuChanged())); - //QML Qt::SHIFT | Qt::Key_H, - addCheckableItem(VIEW_MENU, MenuOption::Mirror, true, - qApp, SLOT(cameraMenuChanged())); - // QML Qt::Key_H, - addCheckableItem(VIEW_MENU, MenuOption::FullscreenMirror, false, - qApp, SLOT(cameraMenuChanged())); - - - // Mac Qt::META | Qt::Key_H, - // Win32/Linux Qt::CTRL | Qt::Key_H, - addCheckableItem(VIEW_MENU, MenuOption::HMDTools, false, [=](bool checked) { - dialogsManager->hmdTools(checked); - }); - addCheckableItem(VIEW_MENU, MenuOption::EnableVRMode, false); - connectCheckable(MenuOption::EnableVRMode, qApp, SLOT(setEnableVRMode(bool))); - addCheckableItem(VIEW_MENU, MenuOption::Enable3DTVMode, false); - connectCheckable(MenuOption::Enable3DTVMode, qApp, SLOT(setEnable3DTVMode(bool))); - - { - static const QString BORDER_MENU{ "Server Borders" }; - addMenu(VIEW_MENU, BORDER_MENU); - // Qt::CTRL | Qt::SHIFT | Qt::Key_1 - addCheckableItem(BORDER_MENU, MenuOption::ShowBordersEntityNodes, false, [=](bool checked) { - qApp->getNodeBoundsDisplay().setShowEntityNodes(checked); - }); - } - addCheckableItem(VIEW_MENU, MenuOption::OffAxisProjection, false); - addCheckableItem(VIEW_MENU, MenuOption::TurnWithHead, false); - // QML Qt::Key_Slash - addCheckableItem(VIEW_MENU, MenuOption::Stats, false); - - // Qt::CTRL | Qt::SHIFT | Qt::Key_L - addItem(VIEW_MENU, MenuOption::Log, [=] { - qApp->toggleLogDialog(); - }); - addItem(VIEW_MENU, MenuOption::BandwidthDetails, [=] { - dialogsManager->bandwidthDetails(); - }); - addItem(VIEW_MENU, MenuOption::OctreeStats, [=] { - dialogsManager->octreeStatsDetails(); - }); - } - - { - static const QString DEV_MENU{ "Developer" }; - addMenu(ROOT_MENU, DEV_MENU); - { - static const QString RENDER_MENU{ "Render" }; - addMenu(DEV_MENU, RENDER_MENU); - // QML Qt::SHIFT | Qt::Key_A, - addCheckableItem(RENDER_MENU, MenuOption::Atmosphere, true); - addCheckableItem(RENDER_MENU, MenuOption::AmbientOcclusion); - addCheckableItem(RENDER_MENU, MenuOption::DontFadeOnOctreeServerChanges); - { - static const QString LIGHT_MENU{ MenuOption::RenderAmbientLight }; - addMenu(RENDER_MENU, LIGHT_MENU); - static QStringList LIGHTS{ - MenuOption::RenderAmbientLightGlobal, - MenuOption::RenderAmbientLight0, - MenuOption::RenderAmbientLight1, - MenuOption::RenderAmbientLight2, - MenuOption::RenderAmbientLight3, - MenuOption::RenderAmbientLight4, - MenuOption::RenderAmbientLight5, - MenuOption::RenderAmbientLight6, - MenuOption::RenderAmbientLight7, - MenuOption::RenderAmbientLight8, - MenuOption::RenderAmbientLight9, - }; - foreach(QString option, LIGHTS) { - addCheckableItem(LIGHT_MENU, option); - // FIXME - // setExclusiveGroup() - } - setChecked(MenuOption::RenderAmbientLightGlobal, true); - } - { - static const QString SHADOWS_MENU{ "Shadows" }; - addMenu(RENDER_MENU, SHADOWS_MENU); - addCheckableItem(SHADOWS_MENU, "No Shadows", true); - addCheckableItem(SHADOWS_MENU, MenuOption::SimpleShadows); - addCheckableItem(SHADOWS_MENU, MenuOption::CascadedShadows); - } - { - static const QString FRAMERATE_MENU{ MenuOption::RenderTargetFramerate }; - addMenu(RENDER_MENU, FRAMERATE_MENU); - //framerateGroup->setExclusive(true); - addCheckableItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerateUnlimited, true); - addCheckableItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate60); - addCheckableItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate50); - addCheckableItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate40); - addCheckableItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate30); - } -#if !defined(Q_OS_MAC) - addCheckableItem(RENDER_MENU, MenuOption::RenderTargetFramerateVSyncOn, true, [](bool checked) { - qApp->setVSyncEnabled(); - }); + addCheckableActionToQMenuAndActionHash(viewMenu, + MenuOption::Fullscreen, +#ifdef Q_OS_MAC + Qt::CTRL | Qt::META | Qt::Key_F, +#else + Qt::CTRL | Qt::Key_F, #endif - { - static const QString RES_MENU{ MenuOption::RenderResolution }; - addMenu(RENDER_MENU, RES_MENU); - // resolutionGroup->setExclusive(true); - addCheckableItem(RES_MENU, MenuOption::RenderResolutionOne, true); - addCheckableItem(RES_MENU, MenuOption::RenderResolutionTwoThird); - addCheckableItem(RES_MENU, MenuOption::RenderResolutionHalf); - addCheckableItem(RES_MENU, MenuOption::RenderResolutionThird); - addCheckableItem(RES_MENU, MenuOption::RenderResolutionQuarter); - } - // QML Qt::Key_Asterisk, - addCheckableItem(RENDER_MENU, MenuOption::Stars, true); - addCheckableItem(RENDER_MENU, MenuOption::EnableGlowEffect, true, [](bool checked){ - DependencyManager::get()->toggleGlowEffect(checked); - }); - //Qt::ALT | Qt::Key_W - addCheckableItem(RENDER_MENU, MenuOption::Wireframe); - // QML Qt::SHIFT | Qt::Key_L, - addItem(RENDER_MENU, MenuOption::LodTools, [=] { - dialogsManager->lodTools(); - }); - } // Developer -> Render + false, + qApp, + SLOT(setFullscreen(bool))); + + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, + 0, // QML Qt::Key_P, + true, qApp, SLOT(cameraMenuChanged())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, + 0, //QML Qt::SHIFT | Qt::Key_H, + true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, + 0, // QML Qt::Key_H, + false, qApp, SLOT(cameraMenuChanged())); + + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, +#ifdef Q_OS_MAC + Qt::META | Qt::Key_H, +#else + Qt::CTRL | Qt::Key_H, +#endif + false, + dialogsManager.data(), + SLOT(hmdTools(bool))); + + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0, + false, + qApp, + SLOT(setEnableVRMode(bool))); + + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0, + false, + qApp, + SLOT(setEnable3DTVMode(bool))); + + + MenuWrapper* nodeBordersMenu = viewMenu->addMenu("Server Borders"); + NodeBounds& nodeBounds = qApp->getNodeBoundsDisplay(); + addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersEntityNodes, + Qt::CTRL | Qt::SHIFT | Qt::Key_1, false, + &nodeBounds, SLOT(setShowEntityNodes(bool))); + + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); + + + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, + 0); // QML Qt::Key_Slash); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats); + addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, + Qt::CTRL | Qt::SHIFT | Qt::Key_L, + qApp, SLOT(toggleLogDialog())); + addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, + dialogsManager.data(), SLOT(bandwidthDetails())); + addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, + dialogsManager.data(), SLOT(octreeStatsDetails())); + + + MenuWrapper* developerMenu = addMenu("Developer"); + + MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render"); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, + 0, // QML Qt::SHIFT | Qt::Key_A, + true); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges); + + MenuWrapper* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight); + QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu); + ambientLightGroup->setExclusive(true); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLightGlobal, 0, true)); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight0, 0, false)); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight1, 0, false)); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight2, 0, false)); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight3, 0, false)); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight4, 0, false)); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight5, 0, false)); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight6, 0, false)); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight7, 0, false)); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false)); + ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false)); + + MenuWrapper* shadowMenu = renderOptionsMenu->addMenu("Shadows"); + QActionGroup* shadowGroup = new QActionGroup(shadowMenu); + shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true)); + shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); + shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); + + { + MenuWrapper* framerateMenu = renderOptionsMenu->addMenu(MenuOption::RenderTargetFramerate); + QActionGroup* framerateGroup = new QActionGroup(framerateMenu); + framerateGroup->setExclusive(true); + framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerateUnlimited, 0, true)); + framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate60, 0, false)); + framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate50, 0, false)); + framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate40, 0, false)); + framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate30, 0, false)); + +#if defined(Q_OS_MAC) +#else + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderTargetFramerateVSyncOn, 0, true, + qApp, SLOT(setVSyncEnabled())); +#endif + } + + + MenuWrapper* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution); + QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu); + resolutionGroup->setExclusive(true); + resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionOne, 0, true)); + resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionTwoThird, 0, false)); + resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionHalf, 0, false)); + resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false)); + resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false)); + + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, + 0, // QML Qt::Key_Asterisk, + true); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true, + DependencyManager::get().data(), SLOT(toggleGlowEffect(bool))); + + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Wireframe, Qt::ALT | Qt::Key_W, false); + addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, + 0, // QML Qt::SHIFT | Qt::Key_L, + dialogsManager.data(), SLOT(lodTools())); + + MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar"); + + MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking"); + { + QActionGroup* faceTrackerGroup = new QActionGroup(avatarDebugMenu); + + QAction* noFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::NoFaceTracking, + 0, true, + qApp, SLOT(setActiveFaceTracker())); + faceTrackerGroup->addAction(noFaceTracker); - { - static const QString AVATAR_MENU{ "Avatar Dev" }; - addMenu(DEV_MENU, AVATAR_MENU); - setItemText(AVATAR_MENU, "Avatar"); - { - static const QString FACE_MENU{ "Face Tracking" }; - addMenu(AVATAR_MENU, FACE_MENU); - // FIXME GROUP - addCheckableItem(FACE_MENU, MenuOption::NoFaceTracking, true, [](bool checked) { - qApp->setActiveFaceTracker(); - }); #ifdef HAVE_FACESHIFT - addCheckableItem(FACE_MENU, MenuOption::Faceshift, true, [](bool checked) { - qApp->setActiveFaceTracker(); - }); + QAction* faceshiftFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Faceshift, + 0, false, + qApp, SLOT(setActiveFaceTracker())); + faceTrackerGroup->addAction(faceshiftFaceTracker); #endif #ifdef HAVE_DDE - addCheckableItem(FACE_MENU, MenuOption::UseCamera, true, [](bool checked) { - qApp->setActiveFaceTracker(); - }); + QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseCamera, + 0, false, + qApp, SLOT(setActiveFaceTracker())); + faceTrackerGroup->addAction(ddeFaceTracker); +#endif + } +#ifdef HAVE_DDE + faceTrackingMenu->addSeparator(); + QAction* useAudioForMouth = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseAudioForMouth, 0, true); + useAudioForMouth->setVisible(false); + QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true); + ddeFiltering->setVisible(false); #endif - addCheckableItem(FACE_MENU, MenuOption::UseAudioForMouth, true); - // FIXME integrate the visibility into the main API - getActionForOption(MenuOption::UseAudioForMouth)->setVisible(false); - addCheckableItem(FACE_MENU, MenuOption::VelocityFilter, true); - // FIXME integrate the visibility into the main API - getActionForOption(MenuOption::VelocityFilter)->setVisible(false); - } - addCheckableItem(AVATAR_MENU, MenuOption::RenderSkeletonCollisionShapes); - addCheckableItem(AVATAR_MENU, MenuOption::RenderHeadCollisionShapes); - addCheckableItem(AVATAR_MENU, MenuOption::RenderBoundingCollisionShapes); - addCheckableItem(AVATAR_MENU, MenuOption::RenderLookAtVectors); - addCheckableItem(AVATAR_MENU, MenuOption::RenderFocusIndicator); - { - static const QString HANDS_MENU{ "Hands" }; - addMenu(AVATAR_MENU, HANDS_MENU); - addCheckableItem(HANDS_MENU, MenuOption::AlignForearmsWithWrists); - addCheckableItem(HANDS_MENU, MenuOption::AlternateIK); - addCheckableItem(HANDS_MENU, MenuOption::DisplayHands, true); - addCheckableItem(HANDS_MENU, MenuOption::DisplayHandTargets); - addCheckableItem(HANDS_MENU, MenuOption::ShowIKConstraints); - { - static const QString SIXENSE_MENU{ "Sixense" }; - addMenu(HANDS_MENU, SIXENSE_MENU); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderHeadCollisionShapes); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false); + + MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands"); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, false); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false); + + MenuWrapper* sixenseOptionsMenu = handOptionsMenu->addMenu("Sixense"); #ifdef __APPLE__ - addCheckableItem(SIXENSE_MENU, MenuOption::SixenseEnabled, false, [](bool checked) { - SixenseManager::getInstance().toggleSixense(checked); - }); + addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, + MenuOption::SixenseEnabled, + 0, false, + &SixenseManager::getInstance(), + SLOT(toggleSixense(bool))); #endif - addCheckableItem(SIXENSE_MENU, MenuOption::FilterSixense, true, [](bool checked) { - SixenseManager::getInstance().setFilter(checked); - }); - addCheckableItem(SIXENSE_MENU, MenuOption::LowVelocityFilter, true, [](bool checked) { - qApp->setLowVelocityFilter(checked); - }); - addCheckableItem(SIXENSE_MENU, MenuOption::SixenseMouseInput, true); - addCheckableItem(SIXENSE_MENU, MenuOption::SixenseLasers); - } + addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, + MenuOption::FilterSixense, + 0, + true, + &SixenseManager::getInstance(), + SLOT(setFilter(bool))); + addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, + MenuOption::LowVelocityFilter, + 0, + true, + qApp, + SLOT(setLowVelocityFilter(bool))); + addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true); + addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseLasers, 0, false); - { - static const QString LEAP_MENU{ "Leap Motion" }; - addMenu(HANDS_MENU, LEAP_MENU); - addCheckableItem(LEAP_MENU, MenuOption::LeapMotionOnHMD); - addCheckableItem(LEAP_MENU, MenuOption::LeapMotionOnHMD); - } + MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion"); + addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false); #ifdef HAVE_RSSDK - { - static const QString RSS_MENU{ "RealSense" }; - addMenu(HANDS_MENU, RSS_MENU); - addItem(RSS_MENU, MenuOption::LoadRSSDKFile, [] { - RealSense::getInstance()->loadRSSDKFile(); - }); - addCheckableItem(RSS_MENU, MenuOption::LeapMotionOnHMD); - } + QMenu* realSenseOptionsMenu = handOptionsMenu->addMenu("RealSense"); + addActionToQMenuAndActionHash(realSenseOptionsMenu, MenuOption::LoadRSSDKFile, 0, + RealSense::getInstance(), SLOT(loadRSSDKFile())); #endif - } // Developer -> Hands - { - static const QString NETWORK_MENU{ "Network" }; - addMenu(DEV_MENU, NETWORK_MENU); - addCheckableItem(NETWORK_MENU, MenuOption::DisableNackPackets); - addCheckableItem(NETWORK_MENU, MenuOption::DisableActivityLogger, false, [](bool checked) { - UserActivityLogger::getInstance().disable(checked); - }); - addItem(NETWORK_MENU, MenuOption::CachesSize, [=] { - dialogsManager->cachesSizeDialog(); - }); - addItem(NETWORK_MENU, MenuOption::DiskCacheEditor, [=] { - dialogsManager->toggleDiskCacheEditor(); - }); - } // Developer -> Network + MenuWrapper* networkMenu = developerMenu->addMenu("Network"); + addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false); + addCheckableActionToQMenuAndActionHash(networkMenu, + MenuOption::DisableActivityLogger, + 0, + false, + &UserActivityLogger::getInstance(), + SLOT(disable(bool))); + addActionToQMenuAndActionHash(networkMenu, MenuOption::CachesSize, 0, + dialogsManager.data(), SLOT(cachesSizeDialog())); + addActionToQMenuAndActionHash(networkMenu, MenuOption::DiskCacheEditor, 0, + dialogsManager.data(), SLOT(toggleDiskCacheEditor())); - { - static const QString TIMING_MENU{ "Timing and Stats" }; - addMenu(DEV_MENU, TIMING_MENU); - { - static const QString PERF_MENU{ "Performance Timer" }; - addMenu(TIMING_MENU, PERF_MENU); - addCheckableItem(PERF_MENU, MenuOption::DisplayDebugTimingDetails); - addCheckableItem(PERF_MENU, MenuOption::OnlyDisplayTopTen, true); - addCheckableItem(PERF_MENU, MenuOption::ExpandUpdateTiming); - addCheckableItem(PERF_MENU, MenuOption::ExpandMyAvatarTiming); - addCheckableItem(PERF_MENU, MenuOption::ExpandMyAvatarSimulateTiming); - addCheckableItem(PERF_MENU, MenuOption::ExpandOtherAvatarTiming); - addCheckableItem(PERF_MENU, MenuOption::ExpandPaintGLTiming); - } - addCheckableItem(TIMING_MENU, MenuOption::TestPing, true); - addCheckableItem(TIMING_MENU, MenuOption::FrameTimer); - addItem(TIMING_MENU, MenuOption::RunTimingTests, [] { runTimingTests(); }); - addCheckableItem(TIMING_MENU, MenuOption::PipelineWarnings); - addCheckableItem(TIMING_MENU, MenuOption::SuppressShortTimings); - } // Developer -> Timing and Stats + MenuWrapper* timingMenu = developerMenu->addMenu("Timing and Stats"); + MenuWrapper* perfTimerMenu = timingMenu->addMenu("Performance Timer"); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarSimulateTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandOtherAvatarTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false); - { - static const QString AUDIO_MENU{ "Audio" }; - addMenu(DEV_MENU, AUDIO_MENU); - auto audioIO = DependencyManager::get(); - addCheckableItem(AUDIO_MENU, MenuOption::AudioNoiseReduction, true, - audioIO.data(), SLOT(toggleAudioNoiseReduction())); - addCheckableItem(AUDIO_MENU, MenuOption::EchoServerAudio, false, - audioIO.data(), SLOT(toggleServerEcho())); - addCheckableItem(AUDIO_MENU, MenuOption::EchoLocalAudio, false, - audioIO.data(), SLOT(toggleLocalEcho())); - addCheckableItem(AUDIO_MENU, MenuOption::StereoAudio, false, - audioIO.data(), SLOT(toggleStereoInput())); - // Qt::CTRL | Qt::Key_M, - addCheckableItem(AUDIO_MENU, MenuOption::MuteAudio, false, - audioIO.data(), SLOT(toggleMute())); - addCheckableItem(AUDIO_MENU, MenuOption::MuteEnvironment, false, - audioIO.data(), SLOT(sendMuteEnvironmentPacket())); - { - static const QString SCOPE_MENU{ "Audio Scope" }; - addMenu(AUDIO_MENU, SCOPE_MENU); - auto scope = DependencyManager::get(); - // Qt::CTRL | Qt::Key_P - addCheckableItem(SCOPE_MENU, MenuOption::AudioScope, false, [=](bool checked) { - scope->toggle(); - }); - // Qt::CTRL | Qt::SHIFT | Qt::Key_P - addCheckableItem(SCOPE_MENU, MenuOption::AudioScopePause, false, [=](bool checked) { - scope->togglePause(); - }); - addSeparator(SCOPE_MENU, "Display Frames"); + addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::TestPing, 0, true); + addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer); + addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, qApp, SLOT(runTests())); + addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::PipelineWarnings); + addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SuppressShortTimings); - // FIXME GROUP - addCheckableItem(SCOPE_MENU, MenuOption::AudioScopeFiveFrames, true, [=](bool checked) { - scope->selectAudioScopeFiveFrames(); - }); - addCheckableItem(SCOPE_MENU, MenuOption::AudioScopeTwentyFrames, false, [=](bool checked) { - scope->selectAudioScopeTwentyFrames(); - }); - addCheckableItem(SCOPE_MENU, MenuOption::AudioScopeFiftyFrames, false, [=](bool checked) { - scope->selectAudioScopeFiftyFrames(); - }); - } - auto statsRenderer = DependencyManager::get(); + auto audioIO = DependencyManager::get(); + MenuWrapper* audioDebugMenu = developerMenu->addMenu("Audio"); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, + 0, + true, + audioIO.data(), + SLOT(toggleAudioNoiseReduction())); - // Qt::CTRL | Qt::SHIFT | Qt::Key_A, - addCheckableItem(AUDIO_MENU, MenuOption::AudioStats, false, [=](bool checked) { - statsRenderer->toggle(); - }); - addCheckableItem(AUDIO_MENU, MenuOption::AudioStatsShowInjectedStreams, false, [=](bool checked) { - statsRenderer->toggleShowInjectedStreams(); - }); - } // Developer -> Audio - } // Developer + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio, 0, false, + audioIO.data(), SLOT(toggleServerEcho())); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio, 0, false, + audioIO.data(), SLOT(toggleLocalEcho())); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false, + audioIO.data(), SLOT(toggleStereoInput())); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteAudio, + Qt::CTRL | Qt::Key_M, + false, + audioIO.data(), + SLOT(toggleMute())); + addActionToQMenuAndActionHash(audioDebugMenu, + MenuOption::MuteEnvironment, + 0, + audioIO.data(), + SLOT(sendMuteEnvironmentPacket())); + + auto scope = DependencyManager::get(); - { - static const QString HELP_MENU{ "Help" }; - addMenu(ROOT_MENU, HELP_MENU); - addItem(HELP_MENU, MenuOption::EditEntitiesHelp, [] { - qApp->showEditEntitiesHelp(); - }); - addItem(HELP_MENU, MenuOption::AboutApp, [] { - qApp->aboutApp(); - }); - } // Help + MenuWrapper* audioScopeMenu = audioDebugMenu->addMenu("Audio Scope"); + addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScope, + Qt::CTRL | Qt::Key_P, false, + scope.data(), + SLOT(toggle())); + addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopePause, + Qt::CTRL | Qt::SHIFT | Qt::Key_P , + false, + scope.data(), + SLOT(togglePause())); + addDisabledActionAndSeparator(audioScopeMenu, "Display Frames"); + { + QAction *fiveFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeFiveFrames, + 0, + true, + scope.data(), + SLOT(selectAudioScopeFiveFrames())); + + QAction *twentyFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeTwentyFrames, + 0, + false, + scope.data(), + SLOT(selectAudioScopeTwentyFrames())); + + QAction *fiftyFrames = addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScopeFiftyFrames, + 0, + false, + scope.data(), + SLOT(selectAudioScopeFiftyFrames())); + + QActionGroup* audioScopeFramesGroup = new QActionGroup(audioScopeMenu); + audioScopeFramesGroup->addAction(fiveFrames); + audioScopeFramesGroup->addAction(twentyFrames); + audioScopeFramesGroup->addAction(fiftyFrames); } + + auto statsRenderer = DependencyManager::get(); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioStats, + Qt::CTRL | Qt::SHIFT | Qt::Key_A, + false, + statsRenderer.data(), + SLOT(toggle())); + + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioStatsShowInjectedStreams, + 0, + false, + statsRenderer.data(), + SLOT(toggleShowInjectedStreams())); + + MenuWrapper* helpMenu = addMenu("Help"); + addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp())); + +#ifndef Q_OS_MAC + QAction* aboutAction = helpMenu->addAction(MenuOption::AboutApp); + connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutApp())); +#endif } void Menu::loadSettings() { -// scanMenuBar(&Menu::loadAction); + scanMenuBar(&Menu::loadAction); } void Menu::saveSettings() { -// scanMenuBar(&Menu::saveAction); + scanMenuBar(&Menu::saveAction); } -void Menu::addMenuItem(const MenuItemProperties& properties) { - if (QThread::currentThread() != Application::getInstance()->getMainThread()) { - Application::getInstance()->postLambdaEvent([=]{ - addMenuItem(properties); - }); - return; - } - // Shortcut key items: in order of priority - //QString shortcutKey; - //KeyEvent shortcutKeyEvent; - //QKeySequence shortcutKeySequence; // this is what we actually use, it's set from one of the above - - //// location related items: in order of priority - //int position; - //QString beforeItem; - //QString afterItem; - - if (properties.isSeparator) { - addSeparator(properties.menuName, properties.menuItemName); - return; - } - addItem(properties.menuName, properties.menuItemName); - if (properties.isCheckable) { - setCheckable(properties.menuItemName); - if (properties.isChecked) { - setChecked(properties.menuItemName); - } - } - } - -#if 0 - void Menu::loadAction(Settings& settings, QAction& action) { if (action.isChecked() != settings.value(action.text(), action.isChecked()).toBool()) { action.trigger(); @@ -690,7 +594,7 @@ void Menu::scanMenu(QMenu& menu, settingsAction modifySetting, Settings& setting settings.endGroup(); } -void Menu::addDisabledActionAndSeparator(QMenu* destinationMenu, const QString& actionName, int menuItemLocation) { +void Menu::addDisabledActionAndSeparator(MenuWrapper* destinationMenu, const QString& actionName, int menuItemLocation) { QAction* actionBefore = NULL; if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) { actionBefore = destinationMenu->actions()[menuItemLocation]; @@ -710,5 +614,406 @@ void Menu::addDisabledActionAndSeparator(QMenu* destinationMenu, const QString& } } +QAction* Menu::addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, + const QString& actionName, + const QKeySequence& shortcut, + const QObject* receiver, + const char* member, + QAction::MenuRole role, + int menuItemLocation) { + QAction* action = NULL; + QAction* actionBefore = NULL; -#endif + if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) { + actionBefore = destinationMenu->actions()[menuItemLocation]; + } + + if (!actionBefore) { + if (receiver && member) { + action = destinationMenu->addAction(actionName, receiver, member, shortcut); + } else { + action = destinationMenu->addAction(actionName); + action->setShortcut(shortcut); + } + } else { + action = new QAction(actionName, destinationMenu); + action->setShortcut(shortcut); + destinationMenu->insertAction(actionBefore, action); + + if (receiver && member) { + connect(action, SIGNAL(triggered()), receiver, member); + } + } + action->setMenuRole(role); + + _actionHash.insert(actionName, action); + + return action; +} + +QAction* Menu::addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, + QAction* action, + const QString& actionName, + const QKeySequence& shortcut, + QAction::MenuRole role, + int menuItemLocation) { + QAction* actionBefore = NULL; + + if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) { + actionBefore = destinationMenu->actions()[menuItemLocation]; + } + + if (!actionName.isEmpty()) { + action->setText(actionName); + } + + if (shortcut != 0) { + action->setShortcut(shortcut); + } + + if (role != QAction::NoRole) { + action->setMenuRole(role); + } + + if (!actionBefore) { + destinationMenu->addAction(action); + } else { + destinationMenu->insertAction(actionBefore, action); + } + + _actionHash.insert(action->text(), action); + + return action; +} + +QAction* Menu::addCheckableActionToQMenuAndActionHash(MenuWrapper* destinationMenu, + const QString& actionName, + const QKeySequence& shortcut, + const bool checked, + const QObject* receiver, + const char* member, + int menuItemLocation) { + + QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member, + QAction::NoRole, menuItemLocation); + action->setCheckable(true); + action->setChecked(checked); + + return action; +} + +void Menu::removeAction(MenuWrapper* menu, const QString& actionName) { + menu->removeAction(_actionHash.value(actionName)); + _actionHash.remove(actionName); +} + +void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(Menu::getInstance(), "setIsOptionChecked", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, menuOption), + Q_ARG(bool, isChecked)); + return; + } + QAction* menu = _actionHash.value(menuOption); + if (menu) { + menu->setChecked(isChecked); + } +} + +bool Menu::isOptionChecked(const QString& menuOption) const { + const QAction* menu = _actionHash.value(menuOption); + if (menu) { + return menu->isChecked(); + } + return false; +} + +void Menu::triggerOption(const QString& menuOption) { + QAction* action = _actionHash.value(menuOption); + if (action) { + action->trigger(); + } else { + qCDebug(interfaceapp) << "NULL Action for menuOption '" << menuOption << "'"; + } +} + +QAction* Menu::getActionForOption(const QString& menuOption) { + return _actionHash.value(menuOption); +} + +QAction* Menu::getActionFromName(const QString& menuName, MenuWrapper* menu) { + QList menuActions; + if (menu) { + menuActions = menu->actions(); + } else { + menuActions = actions(); + } + + foreach (QAction* menuAction, menuActions) { + QString actionText = menuAction->text(); + if (menuName == menuAction->text()) { + return menuAction; + } + } + return NULL; +} + +MenuWrapper* Menu::getSubMenuFromName(const QString& menuName, MenuWrapper* menu) { + QAction* action = getActionFromName(menuName, menu); + if (action) { + return MenuWrapper::fromMenu(action->menu()); + } + return NULL; +} + +MenuWrapper* Menu::getMenuParent(const QString& menuName, QString& finalMenuPart) { + QStringList menuTree = menuName.split(">"); + MenuWrapper* parent = NULL; + MenuWrapper* menu = NULL; + foreach (QString menuTreePart, menuTree) { + parent = menu; + finalMenuPart = menuTreePart.trimmed(); + menu = getSubMenuFromName(finalMenuPart, parent); + if (!menu) { + break; + } + } + return parent; +} + +MenuWrapper* Menu::getMenu(const QString& menuName) { + QStringList menuTree = menuName.split(">"); + MenuWrapper* parent = NULL; + MenuWrapper* menu = NULL; + int item = 0; + foreach (QString menuTreePart, menuTree) { + menu = getSubMenuFromName(menuTreePart.trimmed(), parent); + if (!menu) { + break; + } + parent = menu; + item++; + } + return menu; +} + +QAction* Menu::getMenuAction(const QString& menuName) { + QStringList menuTree = menuName.split(">"); + MenuWrapper* parent = NULL; + QAction* action = NULL; + foreach (QString menuTreePart, menuTree) { + action = getActionFromName(menuTreePart.trimmed(), parent); + if (!action) { + break; + } + parent = MenuWrapper::fromMenu(action->menu()); + } + return action; +} + +int Menu::findPositionOfMenuItem(MenuWrapper* menu, const QString& searchMenuItem) { + int position = 0; + foreach(QAction* action, menu->actions()) { + if (action->text() == searchMenuItem) { + return position; + } + position++; + } + return UNSPECIFIED_POSITION; // not found +} + +int Menu::positionBeforeSeparatorIfNeeded(MenuWrapper* menu, int requestedPosition) { + QList menuActions = menu->actions(); + if (requestedPosition > 1 && requestedPosition < menuActions.size()) { + QAction* beforeRequested = menuActions[requestedPosition - 1]; + if (beforeRequested->isSeparator()) { + requestedPosition--; + } + } + return requestedPosition; +} + + +MenuWrapper* Menu::addMenu(const QString& menuName) { + QStringList menuTree = menuName.split(">"); + MenuWrapper* addTo = NULL; + MenuWrapper* menu = NULL; + foreach (QString menuTreePart, menuTree) { + menu = getSubMenuFromName(menuTreePart.trimmed(), addTo); + if (!menu) { + if (!addTo) { + menu = new MenuWrapper(QMenuBar::addMenu(menuTreePart.trimmed())); + } else { + menu = addTo->addMenu(menuTreePart.trimmed()); + } + } + addTo = menu; + } + + QMenuBar::repaint(); + return menu; +} + +void Menu::removeMenu(const QString& menuName) { + QAction* action = getMenuAction(menuName); + + // only proceed if the menu actually exists + if (action) { + QString finalMenuPart; + MenuWrapper* parent = getMenuParent(menuName, finalMenuPart); + if (parent) { + parent->removeAction(action); + } else { + QMenuBar::removeAction(action); + } + + QMenuBar::repaint(); + } +} + +bool Menu::menuExists(const QString& menuName) { + QAction* action = getMenuAction(menuName); + + // only proceed if the menu actually exists + if (action) { + return true; + } + return false; +} + +void Menu::addSeparator(const QString& menuName, const QString& separatorName) { + MenuWrapper* menuObj = getMenu(menuName); + if (menuObj) { + addDisabledActionAndSeparator(menuObj, separatorName); + } +} + +void Menu::removeSeparator(const QString& menuName, const QString& separatorName) { + MenuWrapper* menu = getMenu(menuName); + bool separatorRemoved = false; + if (menu) { + int textAt = findPositionOfMenuItem(menu, separatorName); + QList menuActions = menu->actions(); + QAction* separatorText = menuActions[textAt]; + if (textAt > 0 && textAt < menuActions.size()) { + QAction* separatorLine = menuActions[textAt - 1]; + if (separatorLine) { + if (separatorLine->isSeparator()) { + menu->removeAction(separatorText); + menu->removeAction(separatorLine); + separatorRemoved = true; + } + } + } + } + if (separatorRemoved) { + QMenuBar::repaint(); + } +} + +void Menu::addMenuItem(const MenuItemProperties& properties) { + MenuWrapper* menuObj = getMenu(properties.menuName); + if (menuObj) { + QShortcut* shortcut = NULL; + if (!properties.shortcutKeySequence.isEmpty()) { + shortcut = new QShortcut(properties.shortcutKeySequence, this); + } + + // check for positioning requests + int requestedPosition = properties.position; + if (requestedPosition == UNSPECIFIED_POSITION && !properties.beforeItem.isEmpty()) { + requestedPosition = findPositionOfMenuItem(menuObj, properties.beforeItem); + // double check that the requested location wasn't a separator label + requestedPosition = positionBeforeSeparatorIfNeeded(menuObj, requestedPosition); + } + if (requestedPosition == UNSPECIFIED_POSITION && !properties.afterItem.isEmpty()) { + int afterPosition = findPositionOfMenuItem(menuObj, properties.afterItem); + if (afterPosition != UNSPECIFIED_POSITION) { + requestedPosition = afterPosition + 1; + } + } + + QAction* menuItemAction = NULL; + if (properties.isSeparator) { + addDisabledActionAndSeparator(menuObj, properties.menuItemName, requestedPosition); + } else if (properties.isCheckable) { + menuItemAction = addCheckableActionToQMenuAndActionHash(menuObj, properties.menuItemName, + properties.shortcutKeySequence, properties.isChecked, + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), requestedPosition); + } else { + menuItemAction = addActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence, + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), + QAction::NoRole, requestedPosition); + } + if (shortcut && menuItemAction) { + connect(shortcut, SIGNAL(activated()), menuItemAction, SLOT(trigger())); + } + QMenuBar::repaint(); + } +} + +void Menu::removeMenuItem(const QString& menu, const QString& menuitem) { + MenuWrapper* menuObj = getMenu(menu); + if (menuObj) { + removeAction(menuObj, menuitem); + QMenuBar::repaint(); + } +}; + +bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { + QAction* menuItemAction = _actionHash.value(menuitem); + if (menuItemAction) { + return (getMenu(menu) != NULL); + } + return false; +}; + + +MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) { + VrMenu::instance()->addMenu(menu); + _backMap[menu] = this; +} + +QList MenuWrapper::actions() { + return _realMenu->actions(); +} + +MenuWrapper* MenuWrapper::addMenu(const QString& menuName) { + return new MenuWrapper(_realMenu->addMenu(menuName)); +} + +void MenuWrapper::setEnabled(bool enabled) { + _realMenu->setEnabled(enabled); +} + +void MenuWrapper::addSeparator() { + _realMenu->addSeparator(); +} + +void MenuWrapper::addAction(QAction* action) { + _realMenu->addAction(action); + VrMenu::instance()->addAction(_realMenu, action); +} + +QAction* MenuWrapper::addAction(const QString& menuName) { + QAction* action = _realMenu->addAction(menuName); + VrMenu::instance()->addAction(_realMenu, action); + return action; +} + +QAction* MenuWrapper::addAction(const QString& menuName, const QObject* receiver, const char* member, const QKeySequence& shortcut) { + QAction* action = _realMenu->addAction(menuName, receiver, member, shortcut); + VrMenu::instance()->addAction(_realMenu, action); + return action; +} + +void MenuWrapper::removeAction(QAction* action) { + _realMenu->removeAction(action); +} + +void MenuWrapper::insertAction(QAction* before, QAction* action) { + _realMenu->insertAction(before, action); + VrMenu::instance()->insertAction(before, action); +} + +QHash MenuWrapper::_backMap; diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d23d7658d0..194f64ddc7 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -18,77 +18,114 @@ #include #include #include -#include + #include -#include - #include "DiscoverabilityManager.h" -#include class Settings; -// Proxy object to simplify porting over -class HifiAction { - const QString _menuOption; +class MenuWrapper : public QObject { public: - HifiAction(const QString & menuOption); - void setCheckable(bool); - void setChecked(bool); - void setVisible(bool); - QString shortcut() const; - void setText(const QString &); - void setTriggerAction(std::function); - void setToggleAction(std::function); + QList actions(); + MenuWrapper* addMenu(const QString& menuName); + void setEnabled(bool enabled = true); + void addSeparator(); + void addAction(QAction* action); + + QAction* addAction(const QString& menuName); + void insertAction(QAction* before, QAction* menuName); + + QAction* addAction(const QString& menuName, const QObject* receiver, const char* member, const QKeySequence& shortcut = 0); + void removeAction(QAction* action); + + QAction* newAction() { + return new QAction(_realMenu); + } +private: + MenuWrapper(QMenu* menu); + + static MenuWrapper* fromMenu(QMenu* menu) { + return _backMap[menu]; + } + + QMenu* const _realMenu; + static QHash _backMap; + friend class Menu; }; -class Menu : public HifiMenu { +class Menu : public QMenuBar { Q_OBJECT - public: - Menu(QQuickItem * parent = 0); static Menu* getInstance(); - - // Override the base type HifiMenu with this class instead - static void registerType() { - qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); - } - + void loadSettings(); void saveSettings(); + + MenuWrapper* getMenu(const QString& menuName); - HifiAction * getActionForOption(const QString& menuOption) { - return new HifiAction(menuOption); - } - + void triggerOption(const QString& menuOption); + QAction* getActionForOption(const QString& menuOption); + + QAction* addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, + const QString& actionName, + const QKeySequence& shortcut = 0, + const QObject* receiver = NULL, + const char* member = NULL, + QAction::MenuRole role = QAction::NoRole, + int menuItemLocation = UNSPECIFIED_POSITION); + QAction* addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, + QAction* action, + const QString& actionName = QString(), + const QKeySequence& shortcut = 0, + QAction::MenuRole role = QAction::NoRole, + int menuItemLocation = UNSPECIFIED_POSITION); + + void removeAction(MenuWrapper* menu, const QString& actionName); + +public slots: + MenuWrapper* addMenu(const QString& menuName); + void removeMenu(const QString& menuName); + bool menuExists(const QString& menuName); + void addSeparator(const QString& menuName, const QString& separatorName); + void removeSeparator(const QString& menuName, const QString& separatorName); void addMenuItem(const MenuItemProperties& properties); - - bool isOptionChecked(const QString& menuOption) const { - return HifiMenu::isChecked(menuOption); - } - - void setIsOptionChecked(const QString& menuOption, bool isChecked) { - HifiMenu::setChecked(menuOption, isChecked); - } - - void triggerOption(const QString& menuOption) { - HifiMenu::triggerItem(menuOption); - } - - void setOptionText(const QString& menuOption, const QString & text) { - HifiMenu::setItemText(menuOption, text); - } - - void setOptionTriggerAction(const QString& menuOption, std::function f) { - HifiMenu::setTriggerAction(menuOption, f); - } - -private: - void init(); - + void removeMenuItem(const QString& menuName, const QString& menuitem); + bool menuItemExists(const QString& menuName, const QString& menuitem); + bool isOptionChecked(const QString& menuOption) const; + void setIsOptionChecked(const QString& menuOption, bool isChecked); + private: static Menu* _instance; - friend class HifiAction; + Menu(); + + typedef void(*settingsAction)(Settings&, QAction&); + static void loadAction(Settings& settings, QAction& action); + static void saveAction(Settings& settings, QAction& action); + void scanMenuBar(settingsAction modifySetting); + void scanMenu(QMenu& menu, settingsAction modifySetting, Settings& settings); + + /// helper method to have separators with labels that are also compatible with OS X + void addDisabledActionAndSeparator(MenuWrapper* destinationMenu, const QString& actionName, + int menuItemLocation = UNSPECIFIED_POSITION); + + QAction* addCheckableActionToQMenuAndActionHash(MenuWrapper* destinationMenu, + const QString& actionName, + const QKeySequence& shortcut = 0, + const bool checked = false, + const QObject* receiver = NULL, + const char* member = NULL, + int menuItemLocation = UNSPECIFIED_POSITION); + + QAction* getActionFromName(const QString& menuName, MenuWrapper* menu); + MenuWrapper* getSubMenuFromName(const QString& menuName, MenuWrapper* menu); + MenuWrapper* getMenuParent(const QString& menuName, QString& finalMenuPart); + + QAction* getMenuAction(const QString& menuName); + int findPositionOfMenuItem(MenuWrapper* menu, const QString& searchMenuItem); + int positionBeforeSeparatorIfNeeded(MenuWrapper* menu, int requestedPosition); + + QHash _actionHash; }; namespace MenuOption { @@ -243,4 +280,5 @@ namespace MenuOption { const QString VisibleToNoOne = "No one"; const QString Wireframe = "Wireframe"; } + #endif // hifi_Menu_h diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 043d5bf40d..7d719873f4 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -216,7 +216,7 @@ void OculusManager::connect() { _isConnected = false; // we're definitely not in "VR mode" so tell the menu that - Menu::getInstance()->setIsOptionChecked(MenuOption::EnableVRMode, false); + Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); } } diff --git a/interface/src/scripting/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index 823bb9f8d0..277c611f04 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -28,50 +28,72 @@ void MenuScriptingInterface::menuItemTriggered() { } void MenuScriptingInterface::addMenu(const QString& menu) { - Menu::getInstance()->addMenu("", menu); + QMetaObject::invokeMethod(Menu::getInstance(), "addMenu", Q_ARG(const QString&, menu)); } void MenuScriptingInterface::removeMenu(const QString& menu) { - Menu::getInstance()->removeMenu(menu); + QMetaObject::invokeMethod(Menu::getInstance(), "removeMenu", Q_ARG(const QString&, menu)); } bool MenuScriptingInterface::menuExists(const QString& menu) { - return Menu::getInstance()->menuExists(menu); + bool result; + QMetaObject::invokeMethod(Menu::getInstance(), "menuExists", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, result), + Q_ARG(const QString&, menu)); + return result; } void MenuScriptingInterface::addSeparator(const QString& menuName, const QString& separatorName) { - Menu::getInstance()->addSeparator(menuName, separatorName); + QMetaObject::invokeMethod(Menu::getInstance(), "addSeparator", + Q_ARG(const QString&, menuName), + Q_ARG(const QString&, separatorName)); } void MenuScriptingInterface::removeSeparator(const QString& menuName, const QString& separatorName) { - Menu::getInstance()->removeSeparator(menuName, separatorName); + QMetaObject::invokeMethod(Menu::getInstance(), "removeSeparator", + Q_ARG(const QString&, menuName), + Q_ARG(const QString&, separatorName)); } void MenuScriptingInterface::addMenuItem(const MenuItemProperties& properties) { - Menu::getInstance()->addMenuItem(properties); + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); } void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey) { - Menu::getInstance()->addItem(menu, menuitem); - Menu::getInstance()->setItemShortcut(menuitem, shortcutKey); + MenuItemProperties properties(menu, menuitem, shortcutKey); + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); } void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem) { - Menu::getInstance()->addItem(menu, menuitem); + MenuItemProperties properties(menu, menuitem); + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); } void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& menuitem) { - Menu::getInstance()->removeItem(menuitem); + QMetaObject::invokeMethod(Menu::getInstance(), "removeMenuItem", + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem)); }; bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString& menuitem) { - return Menu::getInstance()->itemExists(menu, menuitem); + bool result; + QMetaObject::invokeMethod(Menu::getInstance(), "menuItemExists", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, result), + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem)); + return result; } bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { - return Menu::getInstance()->isChecked(menuOption); + bool result; + QMetaObject::invokeMethod(Menu::getInstance(), "isOptionChecked", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, result), + Q_ARG(const QString&, menuOption)); + return result; } void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool isChecked) { - Menu::getInstance()->setChecked(menuOption, isChecked); + QMetaObject::invokeMethod(Menu::getInstance(), "setIsOptionChecked", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, menuOption), + Q_ARG(bool, isChecked)); } diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 5e747f216d..bd2903863d 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -45,6 +45,7 @@ QScriptValue WindowScriptingInterface::hasFocus() { } void WindowScriptingInterface::setFocus() { + // It's forbidden to call focus() from another thread. Application::getInstance()->postLambdaEvent([] { auto window = Application::getInstance()->getWindow(); window->activateWindow(); diff --git a/interface/src/ui/HMDToolsDialog.cpp b/interface/src/ui/HMDToolsDialog.cpp index cedb26fd9b..4a899a641e 100644 --- a/interface/src/ui/HMDToolsDialog.cpp +++ b/interface/src/ui/HMDToolsDialog.cpp @@ -8,7 +8,6 @@ // 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 diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 5922d9f3bb..b452f153f0 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -25,18 +25,19 @@ LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent), _root } void LoginDialog::toggleAction() { - AccountManager & accountManager = AccountManager::getInstance(); - Menu* menu = Menu::getInstance(); + AccountManager& accountManager = AccountManager::getInstance(); + QAction* loginAction = Menu::getInstance()->getActionForOption(MenuOption::Login); + Q_CHECK_PTR(loginAction); + disconnect(loginAction, 0, 0, 0); + if (accountManager.isLoggedIn()) { // change the menu item to logout - menu->setOptionText(MenuOption::Login, "Logout " + accountManager.getAccountInfo().getUsername()); - menu->setOptionTriggerAction(MenuOption::Login, [] { - AccountManager::getInstance().logout(); - }); + loginAction->setText("Logout " + accountManager.getAccountInfo().getUsername()); + connect(loginAction, &QAction::triggered, &accountManager, &AccountManager::logout); } else { // change the menu item to login - menu->setOptionText(MenuOption::Login, "Login"); - menu->setOptionTriggerAction(MenuOption::Login, [] { + loginAction->setText("Login"); + connect(loginAction, &QAction::triggered, [] { LoginDialog::show(); }); } diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 4c8d29d84c..e1fb0ce481 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -44,9 +44,9 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : connect(&_scriptsModelFilter, &QSortFilterProxyModel::modelReset, this, &RunningScriptsWidget::selectFirstInList); - // FIXME - // QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText); - // ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts."); + // FIXME: menu isn't prepared at this point. + //QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText); + //ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts."); _scriptsModelFilter.setSourceModel(&_scriptsModel); _scriptsModelFilter.sort(0, Qt::AscendingOrder); @@ -162,7 +162,8 @@ void RunningScriptsWidget::showEvent(QShowEvent* event) { QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry(); int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); - int topMargin = titleBarHeight; + int menuBarHeight = Menu::getInstance()->geometry().height(); + int topMargin = titleBarHeight + menuBarHeight; setGeometry(parentGeometry.topLeft().x(), parentGeometry.topLeft().y() + topMargin, size().width(), parentWidget()->height() - topMargin); diff --git a/interface/src/ui/ToolWindow.cpp b/interface/src/ui/ToolWindow.cpp index 4edae4f2a4..5888b83f4a 100644 --- a/interface/src/ui/ToolWindow.cpp +++ b/interface/src/ui/ToolWindow.cpp @@ -38,7 +38,8 @@ bool ToolWindow::event(QEvent* event) { QRect mainGeometry = mainWindow->geometry(); int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); - int topMargin = titleBarHeight; + int menuBarHeight = Menu::getInstance()->geometry().height(); + int topMargin = titleBarHeight + menuBarHeight; _lastGeometry = QRect(mainGeometry.topLeft().x(), mainGeometry.topLeft().y() + topMargin, DEFAULT_WIDTH, mainGeometry.height() - topMargin); diff --git a/libraries/ui/src/HifiMenu.cpp b/libraries/ui/src/HifiMenu.cpp index 88c9b48f43..f677fe0aef 100644 --- a/libraries/ui/src/HifiMenu.cpp +++ b/libraries/ui/src/HifiMenu.cpp @@ -1,47 +1,64 @@ #include "HifiMenu.h" #include +#include -// FIXME can this be made a class member? -static const QString MENU_SUFFIX{ "__Menu" }; +// Binds together a Qt Action or Menu with the QML Menu or MenuItem +class MenuUserData : public QObjectUserData { + static const int USER_DATA_ID; -HIFI_QML_DEF_LAMBDA(HifiMenu, [=](QQmlContext* context, QObject* newItem) { +public: + MenuUserData(QAction* action, QObject* qmlObject) { + init(action, qmlObject); + } + MenuUserData(QMenu* menu, QObject* qmlObject) { + init(menu, qmlObject); + } + + const QUuid uuid{ QUuid::createUuid() }; + + static MenuUserData* forObject(QObject* object) { + return static_cast(object->userData(USER_DATA_ID)); + } + +private: + MenuUserData(const MenuUserData&); + + void init(QObject* widgetObject, QObject* qmlObject) { + widgetObject->setUserData(USER_DATA_ID, this); + qmlObject->setUserData(USER_DATA_ID, this); + qmlObject->setObjectName(uuid.toString()); + // Make sure we can find it again in the future + Q_ASSERT(VrMenu::instance()->findMenuObject(uuid.toString())); + } +}; + +const int MenuUserData::USER_DATA_ID = QObject::registerUserData(); + +HIFI_QML_DEF_LAMBDA(VrMenu, [&](QQmlContext* context, QObject* newItem) { auto offscreenUi = DependencyManager::get(); QObject * rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); Q_ASSERT(rootMenu); - static_cast(newItem)->setRootMenu(rootMenu); + static_cast(newItem)->setRootMenu(rootMenu); context->setContextProperty("rootMenu", rootMenu); }); -HifiMenu::HifiMenu(QQuickItem* parent) : QQuickItem(parent), _triggerMapper(this), _toggleMapper(this) { +VrMenu* VrMenu::_instance{ nullptr }; + +VrMenu* VrMenu::instance() { + if (!_instance) { + VrMenu::registerType(); + VrMenu::load(); + Q_ASSERT(_instance); + } + return _instance; +} + +VrMenu::VrMenu(QQuickItem* parent) : QQuickItem(parent) { + _instance = this; this->setEnabled(false); - connect(&_triggerMapper, SIGNAL(mapped(QString)), this, SLOT(onTriggeredByName(const QString &))); - connect(&_toggleMapper, SIGNAL(mapped(QString)), this, SLOT(onToggledByName(const QString &))); -} - -void HifiMenu::onTriggeredByName(const QString & name) { - qDebug() << name << " triggered"; - if (_triggerActions.count(name)) { - _triggerActions[name](); - } -} - -void HifiMenu::onToggledByName(const QString & name) { - qDebug() << name << " toggled"; - if (_toggleActions.count(name)) { - QObject* menu = findMenuObject(name); - bool checked = menu->property("checked").toBool(); - _toggleActions[name](checked); - } -} - -void HifiMenu::setToggleAction(const QString & name, std::function f) { - _toggleActions[name] = f; -} - -void HifiMenu::setTriggerAction(const QString & name, std::function f) { - _triggerActions[name] = f; } +// QML helper functions QObject* addMenu(QObject* parent, const QString & text) { // FIXME add more checking here to ensure no name conflicts QVariant returnedValue; @@ -50,7 +67,7 @@ QObject* addMenu(QObject* parent, const QString & text) { Q_ARG(QVariant, text)); QObject* result = returnedValue.value(); if (result) { - result->setObjectName(text + MENU_SUFFIX); + result->setObjectName(text); } return result; } @@ -67,236 +84,109 @@ QObject* addItem(QObject* parent, const QString& text) { return result; } -const QObject* HifiMenu::findMenuObject(const QString & menuOption) const { +const QObject* VrMenu::findMenuObject(const QString & menuOption) const { if (menuOption.isEmpty()) { return _rootMenu; } - const QObject* result = _rootMenu->findChild(menuOption + MENU_SUFFIX); + const QObject* result = _rootMenu->findChild(menuOption); return result; } -QObject* HifiMenu::findMenuObject(const QString & menuOption) { +QObject* VrMenu::findMenuObject(const QString & menuOption) { if (menuOption.isEmpty()) { return _rootMenu; } - QObject* result = _rootMenu->findChild(menuOption + MENU_SUFFIX); + QObject* result = _rootMenu->findChild(menuOption); return result; } -void HifiMenu::addMenu(const QString & parentMenu, const QString & menuOption) { - QObject* parent = findMenuObject(parentMenu); - QObject* result = ::addMenu(parent, menuOption); - Q_ASSERT(result); - result->setObjectName(menuOption + MENU_SUFFIX); - Q_ASSERT(findMenuObject(menuOption)); -} - -void HifiMenu::removeMenu(const QString& menuName) { - QObject* menu = findMenuObject(menuName); - Q_ASSERT(menu); - Q_ASSERT(menu != _rootMenu); - QMetaObject::invokeMethod(menu->parent(), "removeItem", - Q_ARG(QVariant, QVariant::fromValue(menu))); -} - -bool HifiMenu::menuExists(const QString& menuName) const { - return findMenuObject(menuName); -} - -void HifiMenu::addSeparator(const QString& parentMenu, const QString& separatorName) { - QObject * parent = findMenuObject(parentMenu); - bool invokeResult = QMetaObject::invokeMethod(parent, "addSeparator", Qt::DirectConnection); - Q_ASSERT(invokeResult); - addItem(parentMenu, separatorName); - enableItem(separatorName, false); -} - -void HifiMenu::removeSeparator(const QString& parentMenu, const QString& separatorName) { -} - -void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption) { - QObject* parent = findMenuObject(parentMenu); - Q_ASSERT(parent); - QObject* result = ::addItem(parent, menuOption); - Q_ASSERT(result); - result->setObjectName(menuOption + MENU_SUFFIX); - Q_ASSERT(findMenuObject(menuOption)); - - _triggerMapper.setMapping(result, menuOption); - connect(result, SIGNAL(triggered()), &_triggerMapper, SLOT(map())); - - _toggleMapper.setMapping(result, menuOption); - connect(result, SIGNAL(toggled(bool)), &_toggleMapper, SLOT(map())); -} - -void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption, std::function f) { - setTriggerAction(menuOption, f); - addItem(parentMenu, menuOption); -} - -void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption, QObject* receiver, const char* slot) { - addItem(parentMenu, menuOption); - connectItem(menuOption, receiver, slot); -} - -void HifiMenu::removeItem(const QString& menuOption) { - removeMenu(menuOption); -} - -bool HifiMenu::itemExists(const QString& menuName, const QString& menuitem) const { - return findMenuObject(menuName); -} - -void HifiMenu::triggerItem(const QString& menuOption) { - QObject* menuItem = findMenuObject(menuOption); - Q_ASSERT(menuItem); - Q_ASSERT(menuItem != _rootMenu); - QMetaObject::invokeMethod(menuItem, "trigger"); -} - -QHash warned; -void warn(const QString & menuOption) { - if (!warned.contains(menuOption)) { - warned[menuOption] = menuOption; - qWarning() << "No menu item: " << menuOption; - } -} - -bool HifiMenu::isChecked(const QString& menuOption) const { - const QObject* menuItem = findMenuObject(menuOption); - if (!menuItem) { - warn(menuOption); - return false; - } - return menuItem->property("checked").toBool(); -} - -void HifiMenu::setChecked(const QString& menuOption, bool isChecked) { - QObject* menuItem = findMenuObject(menuOption); - if (!menuItem) { - warn(menuOption); - return; - } - if (menuItem->property("checked").toBool() != isChecked) { - menuItem->setProperty("checked", QVariant::fromValue(isChecked)); - Q_ASSERT(menuItem->property("checked").toBool() == isChecked); - } -} - -void HifiMenu::setCheckable(const QString& menuOption, bool checkable) { - QObject* menuItem = findMenuObject(menuOption); - if (!menuItem) { - warn(menuOption); - return; - } - - menuItem->setProperty("checkable", QVariant::fromValue(checkable)); - Q_ASSERT(menuItem->property("checkable").toBool() == checkable); -} - -void HifiMenu::setItemText(const QString& menuOption, const QString& text) { - QObject* menuItem = findMenuObject(menuOption); - if (!menuItem) { - warn(menuOption); - return; - } - if (menuItem->property("type").toInt() == 2) { - menuItem->setProperty("title", QVariant::fromValue(text)); - } else { - menuItem->setProperty("text", QVariant::fromValue(text)); - } -} - -void HifiMenu::setRootMenu(QObject* rootMenu) { +void VrMenu::setRootMenu(QObject* rootMenu) { _rootMenu = rootMenu; } -void HifiMenu::enableItem(const QString & menuOption, bool enabled) { - QObject* menuItem = findMenuObject(menuOption); - if (!menuItem) { - warn(menuOption); - return; +void VrMenu::addMenu(QMenu* menu) { + Q_ASSERT(!MenuUserData::forObject(menu)); + QObject * parent = menu->parent(); + QObject * qmlParent; + if (dynamic_cast(parent)) { + MenuUserData* userData = MenuUserData::forObject(parent); + qmlParent = findMenuObject(userData->uuid.toString()); + } else if (dynamic_cast(parent)) { + qmlParent = _rootMenu; + } else { + Q_ASSERT(false); } - menuItem->setProperty("enabled", QVariant::fromValue(enabled)); + QObject* result = ::addMenu(qmlParent, menu->title()); + new MenuUserData(menu, result); } -void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked) { - addItem(parentMenu, menuOption); - setCheckable(menuOption); - if (checked) { - setChecked(menuOption, checked); - } +void updateQmlItemFromAction(QObject* target, QAction* source) { + target->setProperty("checkable", source->isCheckable()); + target->setProperty("enabled", source->isEnabled()); + target->setProperty("visible", source->isVisible()); + target->setProperty("text", source->text()); + target->setProperty("checked", source->isChecked()); } -void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f) { - setToggleAction(menuOption, f); - addCheckableItem(parentMenu, menuOption, checked); +void bindActionToQmlAction(QObject* qmlAction, QAction* action) { + new MenuUserData(action, qmlAction); + updateQmlItemFromAction(qmlAction, action); + QObject::connect(action, &QAction::changed, [=] { + updateQmlItemFromAction(qmlAction, action); + }); + QObject::connect(action, &QAction::toggled, [=](bool checked) { + qmlAction->setProperty("checked", checked); + }); + QObject::connect(qmlAction, SIGNAL(triggered()), action, SLOT(trigger())); } -void HifiMenu::setItemVisible(const QString& menuOption, bool visible) { - QObject* result = findMenuObject(menuOption); - if (result) { - result->setProperty("visible", visible); - } -} - -bool HifiMenu::isItemVisible(const QString& menuOption) { - QObject* result = findMenuObject(menuOption); - if (result) { - return result->property("visible").toBool(); - } - return false; -} - -void HifiMenu::setItemShortcut(const QString& menuOption, const QString& shortcut) { - QObject* result = findMenuObject(menuOption); - if (result) { - result->setProperty("shortcut", shortcut); - } -} - -QString HifiMenu::getItemShortcut(const QString& menuOption) { - QObject* result = findMenuObject(menuOption); - if (result) { - return result->property("shortcut").toString(); - } - return QString(); -} - -void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, QObject* receiver, const char* slot) { - addCheckableItem(parentMenu, menuOption, checked); - connectItem(menuOption, receiver, slot); -} - -void HifiMenu::connectCheckable(const QString& menuOption, QObject* receiver, const char* slot) { - QObject* result = findMenuObject(menuOption); - connect(result, SIGNAL(toggled(bool)), receiver, slot); -} - -void HifiMenu::connectItem(const QString& menuOption, QObject* receiver, const char* slot) { - QObject* result = findMenuObject(menuOption); - connect(result, SIGNAL(triggered()), receiver, slot); -} - -void HifiMenu::setExclusiveGroup(const QString& menuOption, const QString& groupName) { - static const QString GROUP_SUFFIX{ "__Group" }; - auto offscreenUi = DependencyManager::get(); - QObject* group = offscreenUi->getRootItem()->findChild(groupName + GROUP_SUFFIX); - if (!group) { - group = offscreenUi->load("ExclusiveGroup.qml"); - Q_ASSERT(group); - } - QObject* menuItem = findMenuObject(menuOption); - bool result = menuItem->setProperty("text", QVariant::fromValue(group)); +void VrMenu::addAction(QMenu* menu, QAction* action) { + Q_ASSERT(!MenuUserData::forObject(action)); + Q_ASSERT(MenuUserData::forObject(menu)); + MenuUserData* userData = MenuUserData::forObject(menu); + QObject* parent = findMenuObject(userData->uuid.toString()); + Q_ASSERT(parent); + QObject* result = ::addItem(parent, action->text()); Q_ASSERT(result); + // Bind the QML and Widget together + bindActionToQmlAction(result, action); } -bool HifiMenu::connectAction(int action, QObject * receiver, const char * slot) { - auto offscreenUi = DependencyManager::get(); - QObject* rootMenu = offscreenUi->getRootItem()->findChild("AllActions"); - QString name = "HifiAction_" + QVariant(action).toString(); - QObject* quitAction = rootMenu->findChild(name); - connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); - return true; +void VrMenu::insertAction(QAction* before, QAction* action) { + QObject* beforeQml{ nullptr }; + { + MenuUserData* beforeUserData = MenuUserData::forObject(before); + Q_ASSERT(beforeUserData); + beforeQml = findMenuObject(beforeUserData->uuid.toString()); + } + + QObject* menu = beforeQml->parent(); + int index{ -1 }; + QVariant itemsVar = menu->property("items"); + QList items = itemsVar.toList(); + // FIXME add more checking here to ensure no name conflicts + for (index = 0; index < items.length(); ++index) { + QObject* currentQmlItem = items.at(index).value(); + if (currentQmlItem == beforeQml) { + break; + } + } + + QObject* result{ nullptr }; + if (index < 0 || index >= items.length()) { + result = ::addItem(menu, action->text()); + } else { + QQuickMenuItem* returnedValue{ nullptr }; + bool invokeResult = QMetaObject::invokeMethod(menu, "insertItem", Qt::DirectConnection, + Q_RETURN_ARG(QQuickMenuItem*, returnedValue), + Q_ARG(int, index), Q_ARG(QString, action->text())); + Q_ASSERT(invokeResult); + result = reinterpret_cast(returnedValue); + } + Q_ASSERT(result); + bindActionToQmlAction(result, action); } +void VrMenu::removeAction(QAction* action) { + // FIXME implement +} diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/HifiMenu.h index 501baa3cc0..c8e555d464 100644 --- a/libraries/ui/src/HifiMenu.h +++ b/libraries/ui/src/HifiMenu.h @@ -16,67 +16,32 @@ #include #include #include +#include +#include #include "OffscreenUi.h" -class HifiMenu : public QQuickItem { +class VrMenu : public QQuickItem { Q_OBJECT HIFI_QML_DECL_LAMBDA public: - - static bool connectAction(int action, QObject * receiver, const char * slot); - - HifiMenu(QQuickItem* parent = nullptr); - - void setToggleAction(const QString& name, std::function f); - void setTriggerAction(const QString& name, std::function f); - - void addMenu(const QString& parentMenu, const QString& menuOption); - void removeMenu(const QString& menuName); - bool menuExists(const QString& menuName) const; - - void addSeparator(const QString& menuName, const QString& separatorName); - void removeSeparator(const QString& menuName, const QString& separatorName); - - void addItem(const QString& parentMenu, const QString& menuOption); - void addItem(const QString& parentMenu, const QString& menuOption, std::function f); - void addItem(const QString& parentMenu, const QString& menuOption, QObject* receiver, const char* slot); - - void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked = false); - void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function f); - void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, QObject* receiver, const char* slot); - void connectCheckable(const QString& menuOption, QObject* receiver, const char* slot); - void connectItem(const QString& menuOption, QObject* receiver, const char* slot); - - void removeItem(const QString& menuitem); - bool itemExists(const QString& menuName, const QString& menuitem) const; - void triggerItem(const QString& menuOption); - void enableItem(const QString& menuOption, bool enabled = true); - bool isChecked(const QString& menuOption) const; - void setChecked(const QString& menuOption, bool checked = true); - void setCheckable(const QString& menuOption, bool checkable = true); - void setExclusiveGroup(const QString& menuOption, const QString& groupName); - void setItemText(const QString& menuOption, const QString& text); - void setItemVisible(const QString& menuOption, bool visible = true); - bool isItemVisible(const QString& menuOption); - - void setItemShortcut(const QString& menuOption, const QString& shortcut); - QString getItemShortcut(const QString& menuOption); + static VrMenu* instance(); + VrMenu(QQuickItem* parent = nullptr); + void addMenu(QMenu* menu); + void addAction(QMenu* parent, QAction* action); + void insertAction(QAction* before, QAction* action); + void removeAction(QAction* action); void setRootMenu(QObject* rootMenu); -private slots: - void onTriggeredByName(const QString& name); - void onToggledByName(const QString& name); - protected: - QHash> _triggerActions; - QHash> _toggleActions; + QObject* _rootMenu{ nullptr }; + QObject* findMenuObject(const QString& name); const QObject* findMenuObject(const QString& name) const; - QObject* _rootMenu{ nullptr }; - QSignalMapper _triggerMapper; - QSignalMapper _toggleMapper; + + static VrMenu* _instance; + friend class MenuUserData; }; #endif // hifi_MenuConstants_h diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 052a6aac4e..563beb0cc8 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -366,10 +366,14 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { QMouseEvent* mouseEvent = static_cast(event); QPointF originalPos = mouseEvent->localPos(); QPointF transformedPos = _mouseTranslator(originalPos); + transformedPos = mapWindowToUi(transformedPos, originalDestination); QMouseEvent mappedEvent(mouseEvent->type(), - mapWindowToUi(transformedPos, originalDestination), + transformedPos, mouseEvent->screenPos(), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); + if (event->type() == QEvent::MouseMove) { + _qmlEngine->rootContext()->setContextProperty("lastMousePosition", transformedPos); + } mappedEvent.ignore(); if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) { return mappedEvent.isAccepted(); @@ -429,6 +433,7 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::functionfindChild(name); } if (item) { + qDebug() << "Turning item " << !item->isEnabled(); item->setEnabled(!item->isEnabled()); } } diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 37e229d571..192bfd928b 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -320,7 +320,7 @@ public: glDisable(GL_DEPTH_TEST); MessageDialog::registerType(); - HifiMenu::registerType(); + VrMenu::registerType(); qmlRegisterType("Hifi", 1, 0, "MenuConstants"); @@ -348,10 +348,9 @@ public: #else offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); offscreenUi->load(QUrl("TestRoot.qml")); - offscreenUi->load(QUrl("Menu.qml")); + offscreenUi->load(QUrl("InterfaceMenu.qml")); // Requires a root menu to have been loaded before it can load - HifiMenu::load(); - HifiMenu::connectAction(MenuConstants::Quit, qApp, SLOT(quit())); + VrMenu::load(); #endif installEventFilter(offscreenUi.data()); offscreenUi->resume(); @@ -407,10 +406,6 @@ protected: switch (event->key()) { case Qt::Key_L: if (event->modifiers() & Qt::CTRL) { - auto offscreenUi = DependencyManager::get(); - HifiMenu * menu = offscreenUi->findChild(); - menu->addItem("", "Test 3"); - menu->addItem("File", "Test 3"); } break; case Qt::Key_K: @@ -433,7 +428,7 @@ protected: QQmlContext* menuContext{ nullptr }; void keyReleaseEvent(QKeyEvent *event) { if (_altPressed && Qt::Key_Alt == event->key()) { - HifiMenu::toggle(); + VrMenu::toggle(); } } From 82e3c4c5879e3be0555d9c43667b5074cb7f03aa Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 25 Apr 2015 16:26:15 -0700 Subject: [PATCH 337/401] Updating the build notes to refelect the new Qt version requirement --- BUILD.md | 10 +++++----- BUILD_OSX.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/BUILD.md b/BUILD.md index ed3fea5c5f..0de8d32b82 100644 --- a/BUILD.md +++ b/BUILD.md @@ -1,7 +1,7 @@ ###Dependencies * [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.12.2 -* [Qt](http://qt-project.org/downloads) ~> 5.3.2 +* [Qt](http://www.qt.io/download-open-source) ~> 5.4.1 * [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g * IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability. * [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional) @@ -37,12 +37,12 @@ Hifi uses CMake to generate build files and project files for your platform. ####Qt In order for CMake to find the Qt5 find modules, you will need to set an ENV variable pointing to your Qt installation. -For example, a Qt5 5.3.2 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment). +For example, a Qt5 5.4.1 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment). The path it needs to be set to will depend on where and how Qt5 was installed. e.g. - export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.3.2/clang_64/lib/cmake/ - export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.3.2/lib/cmake + export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.4.1/clang_64/lib/cmake/ + export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.4.1/lib/cmake export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake ####Generating build files @@ -57,7 +57,7 @@ Any variables that need to be set for CMake to find dependencies can be set as E For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation: - cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.3.2/lib/cmake + cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.4.1/lib/cmake ####Finding Dependencies diff --git a/BUILD_OSX.md b/BUILD_OSX.md index c199fe4c73..2598507c90 100644 --- a/BUILD_OSX.md +++ b/BUILD_OSX.md @@ -10,7 +10,7 @@ Please read the [general build guide](BUILD.md) for information on dependencies We have a [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) that you can use/tap to install some of the dependencies. In the code block above qt5 is installed from a formula in this repository. -*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.3.x stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.* +*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.4.x stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.* ###Xcode If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles. From 0afe8c0e3268b0a92f09ebe382d635c7a08b05b2 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 25 Apr 2015 16:46:05 -0700 Subject: [PATCH 338/401] Coding standards --- libraries/ui/src/HifiMenu.cpp | 10 ++++++++ libraries/ui/src/HifiMenu.h | 8 +++--- libraries/ui/src/MessageDialog.cpp | 9 +++---- libraries/ui/src/MessageDialog.h | 12 +++------ libraries/ui/src/OffscreenQmlDialog.cpp | 6 ++--- libraries/ui/src/OffscreenQmlDialog.h | 2 +- libraries/ui/src/OffscreenUi.cpp | 33 +++++++++++-------------- 7 files changed, 41 insertions(+), 39 deletions(-) diff --git a/libraries/ui/src/HifiMenu.cpp b/libraries/ui/src/HifiMenu.cpp index 27517f99d7..3edcaebead 100644 --- a/libraries/ui/src/HifiMenu.cpp +++ b/libraries/ui/src/HifiMenu.cpp @@ -1,3 +1,13 @@ +// +// HifiMenu.cpp +// +// Created by Bradley Austin Davis on 2015/04/21 +// Copyright 2015 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 "HifiMenu.h" #include diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/HifiMenu.h index c89c91b028..03b3ed9de2 100644 --- a/libraries/ui/src/HifiMenu.h +++ b/libraries/ui/src/HifiMenu.h @@ -1,5 +1,5 @@ // -// MenuConstants.h +// HifiMenu.h // // Created by Bradley Austin Davis on 2015/04/21 // Copyright 2015 High Fidelity, Inc. @@ -9,8 +9,8 @@ // #pragma once -#ifndef hifi_MenuContants_h -#define hifi_MenuConstants_h +#ifndef hifi_HifiMenu_h +#define hifi_HifiMenu_h #include #include @@ -76,7 +76,7 @@ protected: QSignalMapper _toggleMapper; }; -#endif // hifi_MenuConstants_h +#endif // hifi_HifiMenu_h diff --git a/libraries/ui/src/MessageDialog.cpp b/libraries/ui/src/MessageDialog.cpp index 7d226fb774..695f87552a 100644 --- a/libraries/ui/src/MessageDialog.cpp +++ b/libraries/ui/src/MessageDialog.cpp @@ -1,5 +1,4 @@ // -// // MessageDialog.cpp // // Created by Bradley Austin Davis on 2015/04/14 @@ -12,7 +11,7 @@ HIFI_QML_DEF(MessageDialog) -MessageDialog::MessageDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { +MessageDialog::MessageDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) { _buttons = StandardButtons(Ok | Cancel); } @@ -39,21 +38,21 @@ void MessageDialog::setVisible(bool v) { OffscreenQmlDialog::setVisible(v); } -void MessageDialog::setText(const QString &arg) { +void MessageDialog::setText(const QString& arg) { if (arg != _text) { _text = arg; emit textChanged(); } } -void MessageDialog::setInformativeText(const QString &arg) { +void MessageDialog::setInformativeText(const QString& arg) { if (arg != _informativeText) { _informativeText = arg; emit informativeTextChanged(); } } -void MessageDialog::setDetailedText(const QString &arg) { +void MessageDialog::setDetailedText(const QString& arg) { if (arg != _detailedText) { _detailedText = arg; emit detailedTextChanged(); diff --git a/libraries/ui/src/MessageDialog.h b/libraries/ui/src/MessageDialog.h index a4b04eb2d9..461bca8251 100644 --- a/libraries/ui/src/MessageDialog.h +++ b/libraries/ui/src/MessageDialog.h @@ -47,7 +47,7 @@ public: NRoles }; - MessageDialog(QQuickItem *parent = 0); + MessageDialog(QQuickItem* parent = 0); virtual ~MessageDialog(); QString text() const; @@ -57,9 +57,9 @@ public: public slots: virtual void setVisible(bool v); - void setText(const QString &arg); - void setInformativeText(const QString &arg); - void setDetailedText(const QString &arg); + void setText(const QString& arg); + void setInformativeText(const QString& arg); + void setDetailedText(const QString& arg); void setIcon(Icon icon); void setStandardButtons(StandardButtons buttons); void setResultCallback(OffscreenUi::ButtonCallback callback); @@ -98,7 +98,3 @@ private: }; #endif // hifi_MessageDialog_h - - - - diff --git a/libraries/ui/src/OffscreenQmlDialog.cpp b/libraries/ui/src/OffscreenQmlDialog.cpp index dbd621ad85..eba81f708b 100644 --- a/libraries/ui/src/OffscreenQmlDialog.cpp +++ b/libraries/ui/src/OffscreenQmlDialog.cpp @@ -24,9 +24,9 @@ QString OffscreenQmlDialog::title() const { return _title; } -void OffscreenQmlDialog::setTitle(const QString &arg) { - if (arg != _title) { - _title = arg; +void OffscreenQmlDialog::setTitle(const QString& title) { + if (title != _title) { + _title = title; emit titleChanged(); } } diff --git a/libraries/ui/src/OffscreenQmlDialog.h b/libraries/ui/src/OffscreenQmlDialog.h index 0ff9156f8f..33201c385d 100644 --- a/libraries/ui/src/OffscreenQmlDialog.h +++ b/libraries/ui/src/OffscreenQmlDialog.h @@ -59,7 +59,7 @@ protected: public: QString title() const; - void setTitle(const QString &arg); + void setTitle(const QString& title); signals: void accepted(); diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 76a5e71b25..105e81404b 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -140,13 +140,6 @@ QQuickItem* OffscreenUi::getRootItem() { return _rootItem; } -//QQmlContext* OffscreenUi::qmlContext() { -// if (nullptr == _rootItem) { -// return _qmlComponent->creationContext(); -// } -// return QQmlEngine::contextForObject(_rootItem); -//} - void OffscreenUi::setBaseUrl(const QUrl& baseUrl) { _qmlEngine->setBaseUrl(baseUrl); } @@ -188,7 +181,7 @@ QObject* OffscreenUi::finishQmlLoad(std::function return nullptr; } - QQmlContext * newContext = new QQmlContext(_qmlEngine, qApp); + QQmlContext* newContext = new QQmlContext(_qmlEngine, qApp); QObject* newObject = _qmlComponent->beginCreate(newContext); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); @@ -294,9 +287,9 @@ QPointF OffscreenUi::mapWindowToUi(const QPointF& sourcePosition, QObject* sourc // // However, the problem may go away once we switch to the new menu system, // so I think it's OK for the time being. -bool OffscreenUi::shouldSwallowShortcut(QEvent * event) { +bool OffscreenUi::shouldSwallowShortcut(QEvent* event) { Q_ASSERT(event->type() == QEvent::ShortcutOverride); - QObject * focusObject = _quickWindow->focusObject(); + QObject* focusObject = _quickWindow->focusObject(); if (focusObject != _quickWindow && focusObject != _rootItem) { //qDebug() << "Swallowed shortcut " << static_cast(event)->key(); event->accept(); @@ -319,7 +312,7 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { #ifdef DEBUG // Don't intercept our own events, or we enter an infinite recursion - QObject * recurseTest = originalDestination; + QObject* recurseTest = originalDestination; while (recurseTest) { Q_ASSERT(recurseTest != _rootItem && recurseTest != _quickWindow); recurseTest = recurseTest->parent(); @@ -438,13 +431,13 @@ void OffscreenUi::messageBox(const QString& title, const QString& text, ButtonCallback callback, QMessageBox::Icon icon, QMessageBox::StandardButtons buttons) { - MessageDialog * pDialog{ nullptr }; - MessageDialog::show([&](QQmlContext*ctx, QObject*item) { + MessageDialog* pDialog{ nullptr }; + MessageDialog::show([&](QQmlContext* ctx, QObject* item) { pDialog = item->findChild(); pDialog->setIcon((MessageDialog::Icon)icon); pDialog->setTitle(title); pDialog->setText(text); - pDialog->setStandardButtons(MessageDialog::StandardButtons((int)buttons)); + pDialog->setStandardButtons(MessageDialog::StandardButtons(static_cast(buttons))); pDialog->setResultCallback(callback); }); pDialog->setEnabled(true); @@ -453,25 +446,29 @@ void OffscreenUi::messageBox(const QString& title, const QString& text, void OffscreenUi::information(const QString& title, const QString& text, ButtonCallback callback, QMessageBox::StandardButtons buttons) { - messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Information, buttons); + messageBox(title, text, callback, + static_cast(MessageDialog::Information), buttons); } void OffscreenUi::question(const QString& title, const QString& text, ButtonCallback callback, QMessageBox::StandardButtons buttons) { - messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Question, buttons); + messageBox(title, text, callback, + static_cast(MessageDialog::Question), buttons); } void OffscreenUi::warning(const QString& title, const QString& text, ButtonCallback callback, QMessageBox::StandardButtons buttons) { - messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Warning, buttons); + messageBox(title, text, callback, + static_cast(MessageDialog::Warning), buttons); } void OffscreenUi::critical(const QString& title, const QString& text, ButtonCallback callback, QMessageBox::StandardButtons buttons) { - messageBox(title, text, callback, (QMessageBox::Icon)MessageDialog::Critical, buttons); + messageBox(title, text, callback, + static_cast(MessageDialog::Critical), buttons); } From 2e61b5a933a502c8f32edddfc1f9710ee40b0194 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 25 Apr 2015 16:59:33 -0700 Subject: [PATCH 339/401] Coding standards --- libraries/ui/src/HifiMenu.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/HifiMenu.h index 03b3ed9de2..0adc485211 100644 --- a/libraries/ui/src/HifiMenu.h +++ b/libraries/ui/src/HifiMenu.h @@ -77,7 +77,3 @@ protected: }; #endif // hifi_HifiMenu_h - - - - From d4d469b88114ea5dd922db27e8a7dbbedc8f098d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 25 Apr 2015 20:13:59 -0700 Subject: [PATCH 340/401] Adding note to change filename --- libraries/ui/src/HifiMenu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/HifiMenu.h index 6e133bd54c..43af05a426 100644 --- a/libraries/ui/src/HifiMenu.h +++ b/libraries/ui/src/HifiMenu.h @@ -20,6 +20,7 @@ #include #include "OffscreenUi.h" +// FIXME rename the compilation files to VrMenu.h and VrMenu.cpp after upstream pull requests are merged. class VrMenu : public QQuickItem { Q_OBJECT HIFI_QML_DECL_LAMBDA From b760a033603fecff2d83288e2209cccd325a352d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 26 Apr 2015 15:24:00 -0700 Subject: [PATCH 341/401] pass arguments by const reference --- libraries/entities/src/EntityItem.cpp | 4 ++-- libraries/entities/src/EntityItem.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 54a00cdcb0..1f4ef5d454 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -846,11 +846,11 @@ glm::mat4 EntityItem::getWorldToEntityMatrix() const { return glm::inverse(getEntityToWorldMatrix()); } -glm::vec3 EntityItem::entityToWorld(const glm::vec3 point) const { +glm::vec3 EntityItem::entityToWorld(const glm::vec3& point) const { return glm::vec3(getEntityToWorldMatrix() * glm::vec4(point, 1.0f)); } -glm::vec3 EntityItem::worldToEntity(const glm::vec3 point) const { +glm::vec3 EntityItem::worldToEntity(const glm::vec3& point) const { return glm::vec3(getWorldToEntityMatrix() * glm::vec4(point, 1.0f)); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d6f9a9506f..f666151e0d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -174,7 +174,7 @@ public: float getDensity() const { return _density; } - const glm::vec3 getVelocity() const { return _velocity; } /// get velocity in meters + const glm::vec3& getVelocity() const { return _velocity; } /// get velocity in meters void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in meters bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; } @@ -182,7 +182,7 @@ public: void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; } - const glm::vec3 getAcceleration() const { return _acceleration; } /// get acceleration in meters/second/second + const glm::vec3& getAcceleration() const { return _acceleration; } /// get acceleration in meters/second/second void setAcceleration(const glm::vec3& value) { _acceleration = value; } /// acceleration in meters/second/second bool hasAcceleration() const { return _acceleration != ENTITY_ITEM_ZERO_VEC3; } @@ -301,8 +301,8 @@ public: glm::mat4 getEntityToWorldMatrix() const; glm::mat4 getWorldToEntityMatrix() const; - glm::vec3 worldToEntity(const glm::vec3 point) const; - glm::vec3 entityToWorld(const glm::vec3 point) const; + glm::vec3 worldToEntity(const glm::vec3& point) const; + glm::vec3 entityToWorld(const glm::vec3& point) const; protected: From e3d29d74aff2d87335e36f0be8e44c5293d7eb08 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 26 Apr 2015 15:24:30 -0700 Subject: [PATCH 342/401] name changes and preparation for more cleanup --- libraries/physics/src/EntityMotionState.cpp | 46 +++++++++++---------- libraries/physics/src/EntityMotionState.h | 22 +++++++--- libraries/physics/src/ObjectMotionState.cpp | 24 +++++------ libraries/physics/src/ObjectMotionState.h | 37 ++++++++++++----- libraries/physics/src/PhysicsEngine.cpp | 26 ++++++------ 5 files changed, 91 insertions(+), 64 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f905b00ffa..1015693213 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -50,7 +50,7 @@ EntityMotionState::~EntityMotionState() { _entity = NULL; } -MotionType EntityMotionState::computeMotionType() const { +MotionType EntityMotionState::computeObjectMotionType() const { if (_entity->getCollisionsWillMove()) { return MOTION_TYPE_DYNAMIC; } @@ -67,7 +67,7 @@ void EntityMotionState::stepKinematicSimulation(quint64 now) { // which is different from physical kinematic motion (inside getWorldTransform()) // which steps in physics simulation time. _entity->simulate(now); - // TODO: we can't use ObjectMotionState::measureAcceleration() here because the entity + // TODO: we can't use measureBodyAcceleration() here because the entity // has no RigidBody and the timestep is a little bit out of sync with the physics simulation anyway. // Hence we must manually measure kinematic velocity and acceleration. } @@ -100,7 +100,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { // This callback is invoked by the physics simulation at the end of each simulation step... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { - measureAcceleration(); + measureBodyAcceleration(); _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset()); _entity->setRotation(bulletToGLM(worldTrans.getRotation())); @@ -128,63 +128,65 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { if (flags & EntityItem::DIRTY_POSITION) { - _sentPosition = _entity->getPosition() - ObjectMotionState::getWorldOffset(); + _sentPosition = getObjectPosition() - ObjectMotionState::getWorldOffset(); btTransform worldTrans; worldTrans.setOrigin(glmToBullet(_sentPosition)); - _sentRotation = _entity->getRotation(); + _sentRotation = getObjectRotation(); worldTrans.setRotation(glmToBullet(_sentRotation)); _body->setWorldTransform(worldTrans); } if (flags & EntityItem::DIRTY_VELOCITY) { - updateObjectVelocities(); + updateBodyVelocities(); } _sentStep = step; + _body->activate(); } if (flags & EntityItem::DIRTY_MATERIAL) { - updateMaterialProperties(); + updateBodyMaterialProperties(); } if (flags & EntityItem::DIRTY_MASS) { - float mass = _entity->computeMass(); + ShapeInfo shapeInfo; + _entity->computeShapeInfo(shapeInfo); + float mass = computeObjectMass(shapeInfo); btVector3 inertia(0.0f, 0.0f, 0.0f); _body->getCollisionShape()->calculateLocalInertia(mass, inertia); _body->setMassProps(mass, inertia); _body->updateInertiaTensor(); } - _body->activate(); } -void EntityMotionState::updateMaterialProperties() { - _body->setRestitution(_entity->getRestitution()); - _body->setFriction(_entity->getFriction()); - _body->setDamping(fabsf(btMin(_entity->getDamping(), 1.0f)), fabsf(btMin(_entity->getAngularDamping(), 1.0f))); +void EntityMotionState::updateBodyMaterialProperties() { + _body->setRestitution(getObjectRestitution()); + _body->setFriction(getObjectFriction()); + _body->setDamping(fabsf(btMin(getObjectLinearDamping(), 1.0f)), fabsf(btMin(getObjectAngularDamping(), 1.0f))); } -void EntityMotionState::updateObjectVelocities() { +void EntityMotionState::updateBodyVelocities() { if (_body) { - _sentVelocity = _entity->getVelocity(); - setVelocity(_sentVelocity); + _sentVelocity = getObjectLinearVelocity(); + setBodyVelocity(_sentVelocity); - _sentAngularVelocity = _entity->getAngularVelocity(); - setAngularVelocity(_sentAngularVelocity); + _sentAngularVelocity = getObjectAngularVelocity(); + setBodyAngularVelocity(_sentAngularVelocity); - _sentGravity = _entity->getGravity(); - setGravity(_sentGravity); + _sentGravity = getObjectGravity(); + setBodyGravity(_sentGravity); _body->setActivationState(ACTIVE_TAG); } } -void EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) { +void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) { if (_entity->isReadyToComputeShape()) { _entity->computeShapeInfo(shapeInfo); } } -float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const { +float EntityMotionState::computeObjectMass(const ShapeInfo& shapeInfo) const { return _entity->computeMass(); } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index e8a96428a0..7cdc3acbf7 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -31,12 +31,11 @@ public: static void setOutgoingEntityList(QSet* list); static void enqueueOutgoingEntity(EntityItem* entity); - EntityMotionState() = delete; // prevent compiler from making default ctor EntityMotionState(EntityItem* item); virtual ~EntityMotionState(); /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem - virtual MotionType computeMotionType() const; + virtual MotionType computeObjectMotionType() const; virtual void updateKinematicState(uint32_t substep); virtual void stepKinematicSimulation(quint64 now); @@ -51,11 +50,11 @@ public: // these relay incoming values to the RigidBody virtual void updateObjectEasy(uint32_t flags, uint32_t step); - virtual void updateMaterialProperties(); - virtual void updateObjectVelocities(); + virtual void updateBodyMaterialProperties(); + virtual void updateBodyVelocities(); - virtual void computeShapeInfo(ShapeInfo& shapeInfo); - virtual float computeMass(const ShapeInfo& shapeInfo) const; + virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo); + virtual float computeObjectMass(const ShapeInfo& shapeInfo) const; virtual bool shouldSendUpdate(uint32_t simulationFrame); virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step); @@ -71,6 +70,17 @@ public: virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } virtual bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } + virtual float getObjectRestitution() const { return _entity->getRestitution(); } + virtual float getObjectFriction() const { return _entity->getFriction(); } + virtual float getObjectLinearDamping() const { return _entity->getDamping(); } + virtual float getObjectAngularDamping() const { return _entity->getAngularDamping(); } + + virtual const glm::vec3& getObjectPosition() const { return _entity->getPosition(); } + virtual const glm::quat& getObjectRotation() const { return _entity->getRotation(); } + virtual const glm::vec3& getObjectLinearVelocity() const { return _entity->getVelocity(); } + virtual const glm::vec3& getObjectAngularVelocity() const { return _entity->getAngularVelocity(); } + virtual const glm::vec3& getObjectGravity() const { return _entity->getGravity(); } + protected: EntityItem* _entity; quint8 _accelerationNearlyGravityCount; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 96257950ff..d8eb86f0b4 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -36,10 +36,10 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { } // static -uint32_t _simulationStep = 0; -void ObjectMotionState::setSimulationStep(uint32_t step) { - assert(step > _simulationStep); - _simulationStep = step; +uint32_t _worldSimulationStep = 0; +void ObjectMotionState::setWorldSimulationStep(uint32_t step) { + assert(step > _worldSimulationStep); + _worldSimulationStep = step; } ObjectMotionState::ObjectMotionState() : @@ -65,13 +65,13 @@ ObjectMotionState::~ObjectMotionState() { assert(_body == NULL); } -void ObjectMotionState::measureAcceleration() { +void ObjectMotionState::measureBodyAcceleration() { // try to manually measure the true acceleration of the object - uint32_t numSubsteps = _simulationStep - _lastSimulationStep; + uint32_t numSubsteps = _worldSimulationStep - _lastSimulationStep; if (numSubsteps > 0) { float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP); float invDt = 1.0f / dt; - _lastSimulationStep = _simulationStep; + _lastSimulationStep = _worldSimulationStep; // Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt // hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt @@ -81,20 +81,20 @@ void ObjectMotionState::measureAcceleration() { } } -void ObjectMotionState::resetMeasuredAcceleration() { - _lastSimulationStep = _simulationStep; +void ObjectMotionState::resetMeasuredBodyAcceleration() { + _lastSimulationStep = _worldSimulationStep; _lastVelocity = bulletToGLM(_body->getLinearVelocity()); } -void ObjectMotionState::setVelocity(const glm::vec3& velocity) const { +void ObjectMotionState::setBodyVelocity(const glm::vec3& velocity) const { _body->setLinearVelocity(glmToBullet(velocity)); } -void ObjectMotionState::setAngularVelocity(const glm::vec3& velocity) const { +void ObjectMotionState::setBodyAngularVelocity(const glm::vec3& velocity) const { _body->setAngularVelocity(glmToBullet(velocity)); } -void ObjectMotionState::setGravity(const glm::vec3& gravity) const { +void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const { _body->setGravity(glmToBullet(gravity)); } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 0f1d04d0bd..049e3c6a37 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -59,28 +59,29 @@ public: static void setWorldOffset(const glm::vec3& offset); static const glm::vec3& getWorldOffset(); - static void setSimulationStep(uint32_t step); + // The WorldSimulationStep is a cached copy of number of SubSteps of the simulation, used for local time measurements. + static void setWorldSimulationStep(uint32_t step); ObjectMotionState(); ~ObjectMotionState(); - void measureAcceleration(); - void resetMeasuredAcceleration(); + void measureBodyAcceleration(); + void resetMeasuredBodyAcceleration(); // An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0; - virtual void updateMaterialProperties() = 0; - virtual void updateObjectVelocities() = 0; + virtual void updateBodyMaterialProperties() = 0; + virtual void updateBodyVelocities() = 0; MotionStateType getType() const { return _type; } virtual MotionType getMotionType() const { return _motionType; } - virtual void computeShapeInfo(ShapeInfo& info) = 0; - virtual float computeMass(const ShapeInfo& shapeInfo) const = 0; + virtual void computeObjectShapeInfo(ShapeInfo& info) = 0; + virtual float computeObjectMass(const ShapeInfo& shapeInfo) const = 0; - void setVelocity(const glm::vec3& velocity) const; - void setAngularVelocity(const glm::vec3& velocity) const; - void setGravity(const glm::vec3& gravity) const; + void setBodyVelocity(const glm::vec3& velocity) const; + void setBodyAngularVelocity(const glm::vec3& velocity) const; + void setBodyGravity(const glm::vec3& gravity) const; void getVelocity(glm::vec3& velocityOut) const; void getAngularVelocity(glm::vec3& angularVelocityOut) const; @@ -93,7 +94,7 @@ public: virtual bool shouldSendUpdate(uint32_t simulationStep); virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0; - virtual MotionType computeMotionType() const = 0; + virtual MotionType computeObjectMotionType() const = 0; virtual void updateKinematicState(uint32_t substep) = 0; @@ -113,6 +114,20 @@ public: virtual void setShouldClaimSimulationOwnership(bool value) { } virtual bool getShouldClaimSimulationOwnership() { return false; } + // These pure virtual methods must be implemented for each MotionState type + // and make it possible to implement more complicated methods in this base class. + + virtual float getObjectRestitution() const = 0; + virtual float getObjectFriction() const = 0; + virtual float getObjectLinearDamping() const = 0; + virtual float getObjectAngularDamping() const = 0; + + virtual const glm::vec3& getObjectPosition() const = 0; + virtual const glm::quat& getObjectRotation() const = 0; + virtual const glm::vec3& getObjectLinearVelocity() const = 0; + virtual const glm::vec3& getObjectAngularVelocity() const = 0; + virtual const glm::vec3& getObjectGravity() const = 0; + protected: void setRigidBody(btRigidBody* body); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 00ac807808..5422917aa7 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -196,7 +196,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { motionState->updateObjectEasy(flags, _numSubsteps); } if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { - motionState->resetMeasuredAcceleration(); + motionState->resetMeasuredBodyAcceleration(); } } else { // the only way we should ever get here (motionState exists but no body) is when the object @@ -206,7 +206,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { // it is possible that the changes are such that the object can now be added to the physical simulation if (flags & EntityItem::DIRTY_SHAPE) { ShapeInfo shapeInfo; - motionState->computeShapeInfo(shapeInfo); + motionState->computeObjectShapeInfo(shapeInfo); btCollisionShape* shape = _shapeManager.getShape(shapeInfo); if (shape) { addObject(shapeInfo, shape, motionState); @@ -340,7 +340,7 @@ void PhysicsEngine::stepSimulation() { // lock on the tree before we re-lock ourselves. // // TODO: untangle these lock sequences. - ObjectMotionState::setSimulationStep(_numSubsteps); + ObjectMotionState::setWorldSimulationStep(_numSubsteps); _entityTree->lockForWrite(); lock(); _dynamicsWorld->synchronizeMotionStates(); @@ -485,7 +485,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = 0.0f; btRigidBody* body = NULL; - switch(motionState->computeMotionType()) { + switch(motionState->computeObjectMotionType()) { case MOTION_TYPE_KINEMATIC: { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); @@ -498,13 +498,13 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap break; } case MOTION_TYPE_DYNAMIC: { - mass = motionState->computeMass(shapeInfo); + mass = motionState->computeObjectMass(shapeInfo); shape->calculateLocalInertia(mass, inertia); body = new btRigidBody(mass, motionState, shape, inertia); body->updateInertiaTensor(); motionState->setRigidBody(body); motionState->setKinematic(false, _numSubsteps); - motionState->updateObjectVelocities(); + motionState->updateBodyVelocities(); // NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds. // (the 2 seconds is determined by: static btRigidBody::gDeactivationTime const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec @@ -527,10 +527,10 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap } } body->setFlags(BT_DISABLE_WORLD_GRAVITY); - motionState->updateMaterialProperties(); + motionState->updateBodyMaterialProperties(); _dynamicsWorld->addRigidBody(body); - motionState->resetMeasuredAcceleration(); + motionState->resetMeasuredBodyAcceleration(); } void PhysicsEngine::bump(EntityItem* bumpEntity) { @@ -597,7 +597,7 @@ void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { // private bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { - MotionType newType = motionState->computeMotionType(); + MotionType newType = motionState->computeObjectMotionType(); // pull body out of physics engine _dynamicsWorld->removeRigidBody(body); @@ -609,7 +609,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio // get new shape btCollisionShape* oldShape = body->getCollisionShape(); ShapeInfo shapeInfo; - motionState->computeShapeInfo(shapeInfo); + motionState->computeObjectShapeInfo(shapeInfo); btCollisionShape* newShape = _shapeManager.getShape(shapeInfo); if (!newShape) { // FAIL! we are unable to support these changes! @@ -628,7 +628,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio _shapeManager.releaseShape(oldShape); // compute mass properties - float mass = motionState->computeMass(shapeInfo); + float mass = motionState->computeObjectMass(shapeInfo); btVector3 inertia(0.0f, 0.0f, 0.0f); body->getCollisionShape()->calculateLocalInertia(mass, inertia); body->setMassProps(mass, inertia); @@ -663,8 +663,8 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio if (! (flags & EntityItem::DIRTY_MASS)) { // always update mass properties when going dynamic (unless it's already been done above) ShapeInfo shapeInfo; - motionState->computeShapeInfo(shapeInfo); - float mass = motionState->computeMass(shapeInfo); + motionState->computeObjectShapeInfo(shapeInfo); + float mass = motionState->computeObjectMass(shapeInfo); btVector3 inertia(0.0f, 0.0f, 0.0f); body->getCollisionShape()->calculateLocalInertia(mass, inertia); body->setMassProps(mass, inertia); From 3071be162ad935a82ec72a7212539866a4042c07 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 26 Apr 2015 20:11:27 -0700 Subject: [PATCH 343/401] Coding standards --- libraries/render-utils/src/MatrixStack.h | 6 +++--- libraries/ui/src/OffscreenUi.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/MatrixStack.h b/libraries/render-utils/src/MatrixStack.h index 505818fc4a..afbd732b5d 100644 --- a/libraries/render-utils/src/MatrixStack.h +++ b/libraries/render-utils/src/MatrixStack.h @@ -38,7 +38,7 @@ public: push(glm::mat4()); } - explicit MatrixStack(const MatrixStack & other) { + explicit MatrixStack(const MatrixStack& other) { *((std::stack*)this) = *((std::stack*)&other); } @@ -173,12 +173,12 @@ public: } template - static void withPush(MatrixStack & stack, Function f) { + static void withPush(MatrixStack& stack, Function f) { stack.withPush(f); } template - static void withPush(MatrixStack & stack1, MatrixStack & stack2, Function f) { + static void withPush(MatrixStack& stack1, MatrixStack& stack2, Function f) { stack1.withPush([&]{ stack2.withPush(f); }); diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 105e81404b..95e847d24b 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -175,7 +175,7 @@ QObject* OffscreenUi::finishQmlLoad(std::function disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, 0); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); - foreach(const QQmlError &error, errorList) { + foreach(const QQmlError& error, errorList) { qWarning() << error.url() << error.line() << error; } return nullptr; @@ -185,7 +185,7 @@ QObject* OffscreenUi::finishQmlLoad(std::function QObject* newObject = _qmlComponent->beginCreate(newContext); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); - foreach(const QQmlError &error, errorList) + foreach(const QQmlError& error, errorList) qWarning() << error.url() << error.line() << error; if (!_rootItem) { qFatal("Unable to finish loading QML root"); From 7a222dff1d7fc92f58768e9da574b761316b994b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 27 Apr 2015 09:54:58 -0700 Subject: [PATCH 344/401] move one-liner isEnabled() to header --- libraries/physics/src/DynamicCharacterController.cpp | 4 ---- libraries/physics/src/DynamicCharacterController.h | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/libraries/physics/src/DynamicCharacterController.cpp b/libraries/physics/src/DynamicCharacterController.cpp index fa1a2d42d1..0bd363dd1f 100644 --- a/libraries/physics/src/DynamicCharacterController.cpp +++ b/libraries/physics/src/DynamicCharacterController.cpp @@ -257,10 +257,6 @@ void DynamicCharacterController::setEnabled(bool enabled) { } } -bool DynamicCharacterController::isEnabled() const { - return _enabled && _dynamicsWorld; -} - void DynamicCharacterController::setDynamicsWorld(btDynamicsWorld* world) { if (_dynamicsWorld != world) { if (_dynamicsWorld) { diff --git a/libraries/physics/src/DynamicCharacterController.h b/libraries/physics/src/DynamicCharacterController.h index bd71a8bcdc..06ff555f66 100644 --- a/libraries/physics/src/DynamicCharacterController.h +++ b/libraries/physics/src/DynamicCharacterController.h @@ -78,7 +78,8 @@ public: bool needsRemoval() const; bool needsAddition() const; void setEnabled(bool enabled); - bool isEnabled() const; + bool isEnabled() const { return _enabled && _dynamicsWorld; } + void setDynamicsWorld(btDynamicsWorld* world); void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); From e00761711206213e4e2cf4ce8dd16ea497a396b8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Apr 2015 09:56:24 -0700 Subject: [PATCH 345/401] hook up menu-items to control debug rendering of collision hulls and owned simulations --- interface/src/Application.cpp | 26 +++++++++---------- interface/src/Menu.cpp | 5 ++++ interface/src/Menu.h | 2 ++ .../src/EntityTreeRenderer.cpp | 7 ++--- .../src/EntityTreeRenderer.h | 3 ++- .../src/RenderableModelEntityItem.cpp | 12 +++++---- libraries/entities/src/EntityItem.cpp | 1 + libraries/octree/src/OctreeRenderer.cpp | 6 +++-- libraries/octree/src/OctreeRenderer.h | 3 ++- libraries/render-utils/src/Model.cpp | 4 +-- libraries/shared/src/RenderArgs.h | 9 ++++++- 11 files changed, 50 insertions(+), 28 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 95700f3257..c6c9514cc2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -164,8 +164,6 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js"; -bool renderCollisionHulls = false; - #ifdef Q_OS_WIN class MyNativeEventFilter : public QAbstractNativeEventFilter { public: @@ -1280,11 +1278,6 @@ void Application::keyPressEvent(QKeyEvent* event) { break; } - case Qt::Key_Comma: { - renderCollisionHulls = !renderCollisionHulls; - break; - } - default: event->ignore(); break; @@ -3110,13 +3103,20 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs PerformanceTimer perfTimer("entities"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... entities..."); - if (renderCollisionHulls) { - _entities.render(RenderArgs::DEBUG_RENDER_MODE, renderSide); - } else if (theCamera.getMode() == CAMERA_MODE_MIRROR) { - _entities.render(RenderArgs::MIRROR_RENDER_MODE, renderSide); - } else { - _entities.render(RenderArgs::DEFAULT_RENDER_MODE, renderSide); + + RenderArgs::DebugFlags renderDebugFlags = 0; + RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE; + + if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) { + renderDebugFlags |= RenderArgs::RENDER_DEBUG_HULLS; } + if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { + renderDebugFlags |= RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP; + } + if (theCamera.getMode() == CAMERA_MODE_MIRROR) { + renderMode = RenderArgs::MIRROR_RENDER_MODE; + } + _entities.render(renderMode, renderSide, renderDebugFlags); } // render JS/scriptable overlays diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9b9e93a4c9..43c63eb383 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -549,6 +549,11 @@ Menu::Menu() { statsRenderer.data(), SLOT(toggleShowInjectedStreams())); + + QMenu* physicsOptionsMenu = developerMenu->addMenu("Physics"); + addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned); + addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls); + QMenu* helpMenu = addMenu("Help"); addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 5a162d31bc..2c4e2b809f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -187,6 +187,8 @@ namespace MenuOption { const QString OnlyDisplayTopTen = "Only Display Top Ten"; const QString PackageModel = "Package Model..."; const QString Pair = "Pair"; + const QString PhysicsShowOwned = "Highlight Simulation Ownership"; + const QString PhysicsShowHulls = "Draw Collision Hulls"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString Preferences = "Preferences..."; const QString Quit = "Quit"; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c744ec0165..5141ef3437 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -383,7 +383,9 @@ void EntityTreeRenderer::leaveAllEntities() { _lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE); } } -void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) { +void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, + RenderArgs::RenderSide renderSide, + RenderArgs::DebugFlags renderDebugFlags) { if (_tree && !_shuttingDown) { Model::startScene(renderSide); @@ -391,8 +393,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R _viewState->getShadowViewFrustum() : _viewState->getCurrentViewFrustum(); RenderArgs args = { this, frustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - + renderDebugFlags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; _tree->lockForRead(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 8f720e5e48..20534c3e2b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -58,7 +58,8 @@ public: virtual void init(); virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE, - RenderArgs::RenderSide renderSide = RenderArgs::MONO); + RenderArgs::RenderSide renderSide = RenderArgs::MONO, + RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE); virtual const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem); virtual const Model* getModelForEntityItem(const EntityItem* entityItem); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 25922bed10..b9bf1d39a8 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -119,12 +119,14 @@ void RenderableModelEntityItem::render(RenderArgs* args) { glm::vec3 dimensions = getDimensions(); float size = glm::length(dimensions); - auto nodeList = DependencyManager::get(); // XXX for debugging - const QUuid& myNodeID = nodeList->getSessionUUID(); // XXX for debugging + bool highlightSimulationOwnership = false; + if (args->_debugFlags & RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP) { + auto nodeList = DependencyManager::get(); + const QUuid& myNodeID = nodeList->getSessionUUID(); + highlightSimulationOwnership = (getSimulatorID() == myNodeID); + } - if (drawAsModel - && getSimulatorID() != myNodeID // XXX for debugging - ) { + if (drawAsModel && !highlightSimulationOwnership) { remapTextures(); glPushMatrix(); { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 03ff2f1a79..5552013ca2 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1085,6 +1085,7 @@ const float MIN_ALIGNMENT_DOT = 0.999999f; const float MIN_VELOCITY_DELTA = 0.01f; const float MIN_DAMPING_DELTA = 0.001f; const float MIN_GRAVITY_DELTA = 0.001f; +const float MIN_ACCELERATION_DELTA = 0.001f; const float MIN_SPIN_DELTA = 0.0003f; void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index ae40cbfa15..346d7c43f6 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -164,9 +164,11 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) { return false; } -void OctreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) { +void OctreeRenderer::render(RenderArgs::RenderMode renderMode, + RenderArgs::RenderSide renderSide, + RenderArgs::DebugFlags renderDebugFlags) { RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + renderDebugFlags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (_tree) { _tree->lockForRead(); _tree->recurseTreeWithOperation(renderOperation, &args); diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index 4ee0865243..ca0914723f 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -52,7 +52,8 @@ public: /// render the content of the octree virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE, - RenderArgs::RenderSide renderSide = RenderArgs::MONO); + RenderArgs::RenderSide renderSide = RenderArgs::MONO, + RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE); ViewFrustum* getViewFrustum() const { return _viewFrustum; } void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index fe82af6b3c..3508570d6a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1947,14 +1947,14 @@ bool Model::renderInScene(float alpha, RenderArgs* args) { return false; } - if (args->_renderMode == RenderArgs::DEBUG_RENDER_MODE && _renderCollisionHull == false) { + if (args->_debugFlags == RenderArgs::RENDER_DEBUG_HULLS && _renderCollisionHull == false) { // turning collision hull rendering on _renderCollisionHull = true; _nextGeometry = _collisionGeometry; _saveNonCollisionGeometry = _geometry; updateGeometry(); simulate(0.0, true); - } else if (args->_renderMode != RenderArgs::DEBUG_RENDER_MODE && _renderCollisionHull == true) { + } else if (args->_debugFlags != RenderArgs::RENDER_DEBUG_HULLS && _renderCollisionHull == true) { // turning collision hull rendering off _renderCollisionHull = false; _nextGeometry = _saveNonCollisionGeometry; diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 116fc430c2..bc3e2edb6d 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -17,16 +17,23 @@ class OctreeRenderer; class RenderArgs { public: - enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, DEBUG_RENDER_MODE }; + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE }; enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT }; + enum DebugFlags { + RENDER_DEBUG_NONE=0, + RENDER_DEBUG_HULLS=1, + RENDER_DEBUG_SIMULATION_OWNERSHIP=2 + }; + OctreeRenderer* _renderer; ViewFrustum* _viewFrustum; float _sizeScale; int _boundaryLevelAdjust; RenderMode _renderMode; RenderSide _renderSide; + DebugFlags _debugFlags; int _elementsTouched; int _itemsRendered; From b23427a3c805ae5225d5db721c46925c0959faa3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Apr 2015 10:32:47 -0700 Subject: [PATCH 346/401] hook up menu-items to control debug rendering of collision hulls and owned simulations --- interface/src/Application.cpp | 7 ++++--- interface/src/ui/overlays/Overlays.cpp | 9 ++++++--- interface/src/ui/overlays/Overlays.h | 3 ++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c6c9514cc2..c279a345ef 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3104,14 +3104,15 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... entities..."); - RenderArgs::DebugFlags renderDebugFlags = 0; + RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE; RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE; if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) { - renderDebugFlags |= RenderArgs::RENDER_DEBUG_HULLS; + renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_HULLS); } if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { - renderDebugFlags |= RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP; + renderDebugFlags = + (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP); } if (theCamera.getMode() == CAMERA_MODE_MIRROR) { renderMode = RenderArgs::MIRROR_RENDER_MODE; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 191f3f4a99..a9eb9184dd 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -90,7 +90,7 @@ void Overlays::renderHUD() { RenderArgs args = { NULL, Application::getInstance()->getViewFrustum(), lodManager->getOctreeSizeScale(), lodManager->getBoundaryLevelAdjust(), - RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, + RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; foreach(Overlay* thisOverlay, _overlaysHUD) { @@ -108,7 +108,10 @@ void Overlays::renderHUD() { } } -void Overlays::renderWorld(bool drawFront, RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) { +void Overlays::renderWorld(bool drawFront, + RenderArgs::RenderMode renderMode, + RenderArgs::RenderSide renderSide, + RenderArgs::DebugFlags renderDebugFlags) { QReadLocker lock(&_lock); if (_overlaysWorld.size() == 0) { return; @@ -125,7 +128,7 @@ void Overlays::renderWorld(bool drawFront, RenderArgs::RenderMode renderMode, Re RenderArgs args = { NULL, Application::getInstance()->getDisplayViewFrustum(), lodManager->getOctreeSizeScale(), lodManager->getBoundaryLevelAdjust(), - renderMode, renderSide, + renderMode, renderSide, renderDebugFlags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 42227d04f6..04e306097b 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -54,7 +54,8 @@ public: void init(); void update(float deltatime); void renderWorld(bool drawFront, RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE, - RenderArgs::RenderSide renderSide = RenderArgs::MONO); + RenderArgs::RenderSide renderSide = RenderArgs::MONO, + RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE); void renderHUD(); public slots: From 0b1df891af1de70df9838de1aef1fbcde76afc9f Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 27 Apr 2015 10:43:20 -0700 Subject: [PATCH 347/401] Backporting visual work from branch --- interface/resources/qml/LoginDialog.qml | 9 +- interface/resources/qml/MessageDialog.qml | 2 - interface/resources/qml/VrMenu.qml | 127 ++++++++++------- interface/resources/qml/controls/Button.qml | 3 +- interface/resources/qml/controls/CheckBox.qml | 16 +++ interface/resources/qml/controls/Dialog.qml | 129 ++++++------------ .../resources/qml/controls/DialogBase.qml | 74 ++++++++++ .../resources/qml/controls/FontAwesome.qml | 4 +- .../resources/qml/controls/IconButton.qml | 24 ---- .../resources/qml/controls/MenuButton.qml | 5 - interface/resources/qml/controls/Slider.qml | 8 ++ interface/resources/qml/controls/Spacer.qml | 11 ++ interface/resources/qml/controls/SpinBox.qml | 15 ++ interface/resources/qml/controls/Text.qml | 6 +- .../resources/qml/controls/TextAndSlider.qml | 24 ++++ .../resources/qml/controls/TextAndSpinBox.qml | 26 ++++ interface/resources/qml/controls/TextArea.qml | 8 +- interface/resources/qml/controls/TextEdit.qml | 6 +- .../resources/qml/controls/TextHeader.qml | 9 ++ .../resources/qml/controls/TextInput.qml | 44 +++--- .../qml/controls/TextInputAndButton.qml | 40 ++++++ interface/resources/qml/styles/Border.qml | 13 +- .../resources/qml/styles/ButtonStyle.qml | 5 +- .../resources/qml/styles/HifiConstants.qml | 61 +++++++++ .../resources/qml/styles/HifiPalette.qml | 10 +- .../resources/qml/styles/IconButtonStyle.qml | 11 +- .../resources/qml/styles/MenuButtonStyle.qml | 22 --- 27 files changed, 466 insertions(+), 246 deletions(-) create mode 100644 interface/resources/qml/controls/CheckBox.qml create mode 100644 interface/resources/qml/controls/DialogBase.qml delete mode 100644 interface/resources/qml/controls/IconButton.qml delete mode 100644 interface/resources/qml/controls/MenuButton.qml create mode 100644 interface/resources/qml/controls/Slider.qml create mode 100644 interface/resources/qml/controls/Spacer.qml create mode 100644 interface/resources/qml/controls/SpinBox.qml create mode 100644 interface/resources/qml/controls/TextAndSlider.qml create mode 100644 interface/resources/qml/controls/TextAndSpinBox.qml create mode 100644 interface/resources/qml/controls/TextHeader.qml create mode 100644 interface/resources/qml/controls/TextInputAndButton.qml create mode 100644 interface/resources/qml/styles/HifiConstants.qml delete mode 100644 interface/resources/qml/styles/MenuButtonStyle.qml diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index b3b926bbe3..1e02683c57 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -5,9 +5,8 @@ import "controls" import "styles" Dialog { + HifiConstants { id: hifi } title: "Login" - HifiPalette { id: hifiPalette } - SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } objectName: "LoginDialog" height: 512 width: 384 @@ -117,7 +116,7 @@ Dialog { width: 192 height: 64 anchors.horizontalCenter: parent.horizontalCenter - color: hifiPalette.hifiBlue + color: hifi.colors.hifiBlue border.width: 0 radius: 10 @@ -160,7 +159,7 @@ Dialog { text:"Create Account" font.pointSize: 12 font.bold: true - color: hifiPalette.hifiBlue + color: hifi.colors.hifiBlue MouseArea { anchors.fill: parent @@ -177,7 +176,7 @@ Dialog { verticalAlignment: Text.AlignVCenter font.pointSize: 12 text: "Recover Password" - color: hifiPalette.hifiBlue + color: hifi.colors.hifiBlue MouseArea { anchors.fill: parent diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml index f469e33c30..a2a5ba9304 100644 --- a/interface/resources/qml/MessageDialog.qml +++ b/interface/resources/qml/MessageDialog.qml @@ -18,8 +18,6 @@ Dialog { onImplicitHeightChanged: root.height = implicitHeight onImplicitWidthChanged: root.width = implicitWidth - SystemPalette { id: palette } - function calculateImplicitWidth() { if (buttons.visibleChildren.length < 2) return; diff --git a/interface/resources/qml/VrMenu.qml b/interface/resources/qml/VrMenu.qml index 8c4aaafb3b..7de66de23c 100644 --- a/interface/resources/qml/VrMenu.qml +++ b/interface/resources/qml/VrMenu.qml @@ -7,12 +7,19 @@ import "styles" Hifi.VrMenu { id: root + HifiConstants { id: hifi } + anchors.fill: parent + objectName: "VrMenu" + enabled: false opacity: 0.0 + property int animationDuration: 200 - HifiPalette { id: hifiPalette } + property var models: [] + property var columns: [] + z: 10000 onEnabledChanged: { @@ -22,7 +29,7 @@ Hifi.VrMenu { opacity = enabled ? 1.0 : 0.0 if (enabled) { forceActiveFocus() - } + } } // The actual animator @@ -41,10 +48,6 @@ Hifi.VrMenu { if (!visible) reset(); } - - property var models: [] - property var columns: [] - property var menuBuilder: Component { Border { Component.onCompleted: { @@ -58,10 +61,20 @@ Hifi.VrMenu { y = lastMousePosition.y - height / 2; } } - SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } - border.color: hifiPalette.hifiBlue - color: sysPalette.window + border.color: hifi.colors.hifiBlue + color: hifi.colors.window property int menuDepth +/* + MouseArea { +// Rectangle { anchors.fill: parent; color: "#7f0000FF"; visible: enabled } + anchors.fill: parent + onClicked: { + while (parent.menuDepth != root.models.length - 1) { + root.popColumn() + } + } + } +*/ ListView { spacing: 6 @@ -71,12 +84,11 @@ Hifi.VrMenu { anchors.margins: outerMargin id: listView height: root.height - currentIndex: -1 onCountChanged: { recalculateSize() - } - + } + function recalculateSize() { var newHeight = 0 var newWidth = minWidth; @@ -87,11 +99,11 @@ Hifi.VrMenu { parent.height = newHeight + outerMargin * 2; parent.width = newWidth + outerMargin * 2 } - + highlight: Rectangle { width: listView.minWidth - 32; height: 32 - color: sysPalette.highlight + color: hifi.colors.hifiBlue y: (listView.currentItem) ? listView.currentItem.y : 0; x: 32 Behavior on y { @@ -101,10 +113,8 @@ Hifi.VrMenu { } } } - - property int columnIndex: root.models.length - 1 - model: root.models[columnIndex] + model: root.models[menuDepth] delegate: Loader { id: loader sourceComponent: root.itemBuilder @@ -120,12 +130,6 @@ Hifi.VrMenu { value: modelData when: loader.status == Loader.Ready } - Binding { - target: loader.item - property: "listViewIndex" - value: index - when: loader.status == Loader.Ready - } Binding { target: loader.item property: "listView" @@ -133,26 +137,24 @@ Hifi.VrMenu { when: loader.status == Loader.Ready } } - } - } } - + property var itemBuilder: Component { Text { - SystemPalette { id: sp; colorGroup: SystemPalette.Active } id: thisText x: 32 property var source property var root - property var listViewIndex property var listView text: typedText() height: implicitHeight width: implicitWidth - color: source.enabled ? "black" : "gray" - + color: source.enabled ? hifi.colors.text : hifi.colors.disabledText + enabled: source.enabled + + onImplicitWidthChanged: { if (listView) { listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64); @@ -163,15 +165,27 @@ Hifi.VrMenu { FontAwesome { visible: source.type == 1 && source.checkable x: -32 - text: (source.type == 1 && source.checked) ? "\uF05D" : "\uF10C" + text: checkText(); + color: parent.color + function checkText() { + if (source.type != 1) { + return; + } + // FIXME this works for native QML menus but I don't think it will + // for proxied QML menus + if (source.exclusiveGroup) { + return source.checked ? "\uF05D" : "\uF10C" + } + return source.checked ? "\uF046" : "\uF096" + } } - + FontAwesome { visible: source.type == 2 - x: listView.width - 64 + x: listView.width - 32 - (hifi.layout.spacing * 2) text: "\uF0DA" + color: parent.color } - function typedText() { switch(source.type) { @@ -200,38 +214,53 @@ Hifi.VrMenu { interval: 1000 onTriggered: parent.select(); } - onEntered: { - if (source.type == 2 && enabled) { - timer.start() - } - } - onExited: { - timer.stop() - } + /* + * Uncomment below to have menus auto-popup + * + * FIXME if we enabled timer based menu popup, either the timer has + * to be very very short or after auto popup there has to be a small + * amount of time, or a test if the mouse has moved before a click + * will be accepted, otherwise it's too easy to accidently click on + * something immediately after the auto-popup appears underneath your + * cursor + * + */ + //onEntered: { + // if (source.type == 2 && enabled) { + // timer.start() + // } + //} + //onExited: { + // timer.stop() + //} onClicked: { select(); } function select() { timer.stop(); - listView.currentIndex = listViewIndex - parent.root.selectItem(parent.source); + var popped = false; + while (columns.length - 1 > listView.parent.menuDepth) { + popColumn(); + popped = true; + } + + if (!popped || source.type != 1) { + parent.root.selectItem(parent.source); + } } } } } - - function lastColumn() { return columns[root.columns.length - 1]; } - + function pushColumn(items) { models.push(items) if (columns.length) { var oldColumn = lastColumn(); - oldColumn.enabled = false; - oldColumn.opacity = 0.5; + //oldColumn.enabled = false } var newColumn = menuBuilder.createObject(root); columns.push(newColumn); diff --git a/interface/resources/qml/controls/Button.qml b/interface/resources/qml/controls/Button.qml index 215e0542f7..989d5b579c 100644 --- a/interface/resources/qml/controls/Button.qml +++ b/interface/resources/qml/controls/Button.qml @@ -5,6 +5,5 @@ import "." import "../styles" Original.Button { - style: ButtonStyle { - } + style: ButtonStyle { } } diff --git a/interface/resources/qml/controls/CheckBox.qml b/interface/resources/qml/controls/CheckBox.qml new file mode 100644 index 0000000000..fe836a0e89 --- /dev/null +++ b/interface/resources/qml/controls/CheckBox.qml @@ -0,0 +1,16 @@ +import QtQuick.Controls 1.3 as Original +import QtQuick.Controls.Styles 1.3 +import "../styles" +import "." +Original.CheckBox { + text: "Check Box" + style: CheckBoxStyle { + indicator: FontAwesome { + text: control.checked ? "\uf046" : "\uf096" + } + label: Text { + text: control.text + } + } + +} \ No newline at end of file diff --git a/interface/resources/qml/controls/Dialog.qml b/interface/resources/qml/controls/Dialog.qml index d722d5264a..629813d3b5 100644 --- a/interface/resources/qml/controls/Dialog.qml +++ b/interface/resources/qml/controls/Dialog.qml @@ -11,28 +11,21 @@ import "../styles" * Examine the QML ApplicationWindow.qml source for how it does this * */ -Item { +DialogBase { id: root - - HifiPalette { id: hifiPalette } - SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } + HifiConstants { id: hifi } + // FIXME better placement via a window manager x: parent ? parent.width / 2 - width / 2 : 0 y: parent ? parent.height / 2 - height / 2 : 0 - property int animationDuration: 400 property bool destroyOnInvisible: false property bool destroyOnCloseButton: true property bool resizable: false + + property int animationDuration: hifi.effects.fadeInDuration property int minX: 256 property int minY: 256 - property int topMargin: root.height - clientBorder.height + 8 - property int margins: 8 - property string title - property int titleSize: titleBorder.height + 12 - property string frameColor: hifiPalette.hifiBlue - property string backgroundColor: sysPalette.window - property string headerBackgroundColor: sysPalette.dark - clip: true + readonly property int topMargin: root.height - clientBorder.height + hifi.layout.spacing /* * Support for animating the dialog in and out. @@ -44,7 +37,8 @@ Item { // visibility, so that we can do animations in both directions. Because // visibility and enabled are boolean flags, they cannot be animated. So when // enabled is change, we modify a property that can be animated, like scale or - // opacity. + // opacity, and then when the target animation value is reached, we can + // modify the visibility onEnabledChanged: { scale = enabled ? 1.0 : 0.0 } @@ -57,13 +51,13 @@ Item { } } - // We remove any load the dialog might have on the QML by toggling it's - // visibility based on the state of the animated property + // Once we're scaled to 0, disable the dialog's visibility onScaleChanged: { visible = (scale != 0.0); } - - // Some dialogs should be destroyed when they become invisible, so handle that + + // Some dialogs should be destroyed when they become invisible, + // so handle that onVisibleChanged: { if (!visible && destroyOnInvisible) { destroy(); @@ -91,6 +85,7 @@ Item { MouseArea { id: sizeDrag + enabled: root.resizable property int startX property int startY anchors.right: parent.right @@ -103,7 +98,7 @@ Item { startY = mouseY } onPositionChanged: { - if (pressed && root.resizable) { + if (pressed) { root.deltaSize((mouseX - startX), (mouseY - startY)) startX = mouseX startY = mouseY @@ -111,83 +106,41 @@ Item { } } - /* - * Window decorations, with a title bar and frames - */ - Border { - id: windowBorder - anchors.fill: parent - border.color: root.frameColor - color: root.backgroundColor + MouseArea { + id: titleDrag + x: root.titleX + y: root.titleY + width: root.titleWidth + height: root.titleHeight - Border { - id: titleBorder - height: 48 + drag { + target: root + minimumX: 0 + minimumY: 0 + maximumX: root.parent ? root.parent.width - root.width : 0 + maximumY: root.parent ? root.parent.height - root.height : 0 + } + + Row { + id: windowControls + anchors.bottom: parent.bottom + anchors.top: parent.top anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - border.color: root.frameColor - color: root.headerBackgroundColor - - Text { - id: titleText - // FIXME move all constant colors to our own palette class HifiPalette - color: "white" - text: root.title - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - anchors.fill: parent - } - - MouseArea { - id: titleDrag - anchors.right: closeButton.left - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.top: parent.top - anchors.rightMargin: 4 - drag { - target: root - minimumX: 0 - minimumY: 0 - maximumX: root.parent ? root.parent.width - root.width : 0 - maximumY: root.parent ? root.parent.height - root.height : 0 - } - } - Image { - id: closeButton - x: 360 - height: 16 + anchors.rightMargin: hifi.layout.spacing + FontAwesome { + id: icon anchors.verticalCenter: parent.verticalCenter - width: 16 - anchors.right: parent.right - anchors.rightMargin: 12 - source: "../../styles/close.svg" + size: root.titleHeight - hifi.layout.spacing * 2 + color: "red" + text: "\uf00d" MouseArea { + anchors.margins: hifi.layout.spacing / 2 anchors.fill: parent onClicked: { root.close(); } } } - } // header border - - Border { - id: clientBorder - border.color: root.frameColor - // FIXME move all constant colors to our own palette class HifiPalette - color: "#00000000" - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: titleBorder.bottom - anchors.topMargin: -titleBorder.border.width - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - clip: true - } // client border - } // window border - + } + } } diff --git a/interface/resources/qml/controls/DialogBase.qml b/interface/resources/qml/controls/DialogBase.qml new file mode 100644 index 0000000000..e5f0a8f0d1 --- /dev/null +++ b/interface/resources/qml/controls/DialogBase.qml @@ -0,0 +1,74 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import "." +import "../styles" + +Item { + id: root + HifiConstants { id: hifi } + implicitHeight: 512 + implicitWidth: 512 + property string title + property int titleSize: titleBorder.height + 12 + property string frameColor: hifi.colors.hifiBlue + property string backgroundColor: hifi.colors.dialogBackground + property bool active: false + + property alias titleBorder: titleBorder + readonly property alias titleX: titleBorder.x + readonly property alias titleY: titleBorder.y + readonly property alias titleWidth: titleBorder.width + readonly property alias titleHeight: titleBorder.height + + property alias clientBorder: clientBorder + readonly property real clientX: clientBorder.x + hifi.styles.borderWidth + readonly property real clientY: clientBorder.y + hifi.styles.borderWidth + readonly property real clientWidth: clientBorder.width - hifi.styles.borderWidth * 2 + readonly property real clientHeight: clientBorder.height - hifi.styles.borderWidth * 2 + + /* + * Window decorations, with a title bar and frames + */ + Border { + id: windowBorder + anchors.fill: parent + border.color: root.frameColor + color: "#00000000" + + Border { + id: titleBorder + height: hifi.layout.windowTitleHeight + anchors.right: parent.right + anchors.left: parent.left + border.color: root.frameColor + clip: true + color: root.active ? + hifi.colors.activeWindow.headerBackground : + hifi.colors.inactiveWindow.headerBackground + + Text { + id: titleText + color: root.active ? + hifi.colors.activeWindow.headerText : + hifi.colors.inactiveWindow.headerText + text: root.title + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + } + } // header border + + Border { + id: clientBorder + border.color: root.frameColor + color: root.backgroundColor + anchors.bottom: parent.bottom + anchors.top: titleBorder.bottom + anchors.topMargin: -titleBorder.border.width + anchors.right: parent.right + anchors.left: parent.left + clip: true + } // client border + } // window border + +} diff --git a/interface/resources/qml/controls/FontAwesome.qml b/interface/resources/qml/controls/FontAwesome.qml index e975c0342b..50d7e96fb5 100644 --- a/interface/resources/qml/controls/FontAwesome.qml +++ b/interface/resources/qml/controls/FontAwesome.qml @@ -8,9 +8,9 @@ Text { property int size: 32 width: size height: size + font.pixelSize: size verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter + horizontalAlignment: Text.AlignLeft font.family: iconFont.name - font.pointSize: 18 } diff --git a/interface/resources/qml/controls/IconButton.qml b/interface/resources/qml/controls/IconButton.qml deleted file mode 100644 index 346865aacb..0000000000 --- a/interface/resources/qml/controls/IconButton.qml +++ /dev/null @@ -1,24 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.3 -import QtQuick.Window 2.2 -import QtQuick.Controls.Styles 1.3 - -Button { - text: "Text" - style: ButtonStyle { - background: Item { anchors.fill: parent } - label: Text { - id: icon - width: height - verticalAlignment: Text.AlignVCenter - renderType: Text.NativeRendering - font.family: iconFont.name - font.pointSize: 18 - property alias unicode: icon.text - FontLoader { id: iconFont; source: "/fonts/fontawesome-webfont.ttf"; } - text: control.text - color: control.enabled ? "white" : "dimgray" - } - } -} - diff --git a/interface/resources/qml/controls/MenuButton.qml b/interface/resources/qml/controls/MenuButton.qml deleted file mode 100644 index 740995a199..0000000000 --- a/interface/resources/qml/controls/MenuButton.qml +++ /dev/null @@ -1,5 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.3 as Original -import "../styles" -import "../controls" - diff --git a/interface/resources/qml/controls/Slider.qml b/interface/resources/qml/controls/Slider.qml new file mode 100644 index 0000000000..ace20f1e68 --- /dev/null +++ b/interface/resources/qml/controls/Slider.qml @@ -0,0 +1,8 @@ +import QtQuick.Controls 1.3 as Original +import QtQuick.Controls.Styles 1.3 + +import "../styles" +import "." + +Original.Slider { +} diff --git a/interface/resources/qml/controls/Spacer.qml b/interface/resources/qml/controls/Spacer.qml new file mode 100644 index 0000000000..3c4f7456d6 --- /dev/null +++ b/interface/resources/qml/controls/Spacer.qml @@ -0,0 +1,11 @@ +import QtQuick 2.4 +import "../styles" + +Item { + id: root + HifiConstants { id: hifi } + property real size: hifi.layout.spacing + property real multiplier: 1.0 + height: size * multiplier + width: size * multiplier +} diff --git a/interface/resources/qml/controls/SpinBox.qml b/interface/resources/qml/controls/SpinBox.qml new file mode 100644 index 0000000000..7e44b9e4a3 --- /dev/null +++ b/interface/resources/qml/controls/SpinBox.qml @@ -0,0 +1,15 @@ + +import QtQuick.Controls 1.3 as Original +import QtQuick.Controls.Styles 1.3 + +import "../styles" +import "." + +Original.SpinBox { + style: SpinBoxStyle { + HifiConstants { id: hifi } + font.family: hifi.fonts.fontFamily + font.pointSize: hifi.fonts.fontSize + } + +} diff --git a/interface/resources/qml/controls/Text.qml b/interface/resources/qml/controls/Text.qml index a9c19e70b4..4f82f2d9e4 100644 --- a/interface/resources/qml/controls/Text.qml +++ b/interface/resources/qml/controls/Text.qml @@ -1,7 +1,9 @@ import QtQuick 2.3 as Original +import "../styles" Original.Text { - font.family: "Helvetica" - font.pointSize: 18 + HifiConstants { id: hifi } + font.family: hifi.fonts.fontFamily + font.pointSize: hifi.fonts.fontSize } diff --git a/interface/resources/qml/controls/TextAndSlider.qml b/interface/resources/qml/controls/TextAndSlider.qml new file mode 100644 index 0000000000..302c096878 --- /dev/null +++ b/interface/resources/qml/controls/TextAndSlider.qml @@ -0,0 +1,24 @@ +import QtQuick 2.3 as Original +import "../styles" +import "." + +Original.Item { + property alias text: label.text + property alias value: slider.value + + Text { + id: label + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + verticalAlignment: Original.Text.AlignVCenter + } + + Slider { + id: slider + width: 120 + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } +} diff --git a/interface/resources/qml/controls/TextAndSpinBox.qml b/interface/resources/qml/controls/TextAndSpinBox.qml new file mode 100644 index 0000000000..a32a36a1f8 --- /dev/null +++ b/interface/resources/qml/controls/TextAndSpinBox.qml @@ -0,0 +1,26 @@ +import QtQuick 2.3 as Original +import "../styles" +import "." + +Original.Item { + property alias text: label.text + property alias value: spinBox.value + + Text { + id: label + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + verticalAlignment: Original.Text.AlignVCenter + text: "Minimum HMD FPS" + } + SpinBox { + id: spinBox + width: 120 + maximumValue: 240 + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + +} diff --git a/interface/resources/qml/controls/TextArea.qml b/interface/resources/qml/controls/TextArea.qml index dfa177bcb6..a86e76620a 100644 --- a/interface/resources/qml/controls/TextArea.qml +++ b/interface/resources/qml/controls/TextArea.qml @@ -1,7 +1,9 @@ -import QtQuick 2.3 as Original +import QtQuick.Controls 2.3 as Original +import "../styles" Original.TextArea { - font.family: "Helvetica" - font.pointSize: 18 + HifiConstants { id: hifi } + font.family: hifi.fonts.fontFamily + font.pointSize: hifi.fonts.fontSize } diff --git a/interface/resources/qml/controls/TextEdit.qml b/interface/resources/qml/controls/TextEdit.qml index 28551bb171..b59b20a3d6 100644 --- a/interface/resources/qml/controls/TextEdit.qml +++ b/interface/resources/qml/controls/TextEdit.qml @@ -1,7 +1,9 @@ import QtQuick 2.3 as Original +import "../styles" Original.TextEdit { - font.family: "Helvetica" - font.pointSize: 18 + HifiConstants { id: hifi } + font.family: hifi.fonts.fontFamily + font.pointSize: hifi.fonts.fontSize } diff --git a/interface/resources/qml/controls/TextHeader.qml b/interface/resources/qml/controls/TextHeader.qml new file mode 100644 index 0000000000..9ce1da4ac2 --- /dev/null +++ b/interface/resources/qml/controls/TextHeader.qml @@ -0,0 +1,9 @@ +import "." +import "../styles" + +Text { + HifiConstants { id: hifi } + color: hifi.colors.hifiBlue + font.pointSize: hifi.fonts.headerPointSize + font.bold: true +} diff --git a/interface/resources/qml/controls/TextInput.qml b/interface/resources/qml/controls/TextInput.qml index 8ce3d85d81..ceaca0c073 100644 --- a/interface/resources/qml/controls/TextInput.qml +++ b/interface/resources/qml/controls/TextInput.qml @@ -1,34 +1,36 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 +import QtQuick 2.3 as Original +import "../styles" +import "." -TextInput { - SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } +Original.TextInput { + id: root + HifiConstants { id: hifi } property string helperText - font.family: "Helvetica" - font.pointSize: 18 - width: 256 - height: 64 - color: myPalette.text + height: hifi.layout.rowHeight clip: true - verticalAlignment: TextInput.AlignVCenter + color: hifi.colors.text + verticalAlignment: Original.TextInput.AlignVCenter + font.family: hifi.fonts.fontFamily + font.pointSize: hifi.fonts.fontSize - onTextChanged: { - if (text == "") { - helperText.visible = true; - } else { - helperText.visible = false; - } + + Original.Rectangle { + // Render the rectangle as background + z: -1 + anchors.fill: parent + color: hifi.colors.inputBackground } Text { - id: helperText anchors.fill: parent font.pointSize: parent.font.pointSize font.family: parent.font.family - verticalAlignment: TextInput.AlignVCenter - text: parent.helperText - color: myPalette.dark - clip: true + verticalAlignment: parent.verticalAlignment + horizontalAlignment: parent.horizontalAlignment + text: root.helperText + color: hifi.colors.hintText + visible: !root.text } } + diff --git a/interface/resources/qml/controls/TextInputAndButton.qml b/interface/resources/qml/controls/TextInputAndButton.qml new file mode 100644 index 0000000000..60e9001d72 --- /dev/null +++ b/interface/resources/qml/controls/TextInputAndButton.qml @@ -0,0 +1,40 @@ +import QtQuick 2.3 as Original +import "../styles" +import "." + +Original.Item { + id: root + HifiConstants { id: hifi } + height: hifi.layout.rowHeight + property string text + property string helperText + property string buttonText + property int buttonWidth: 0 + property alias input: input + property alias button: button + signal clicked() + + TextInput { + id: input + text: root.text + helperText: root.helperText + anchors.left: parent.left + anchors.right: button.left + anchors.rightMargin: 8 + anchors.bottom: parent.bottom + anchors.top: parent.top + } + + Button { + id: button + clip: true + width: root.buttonWidth ? root.buttonWidth : implicitWidth + text: root.buttonText + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.top: parent.top + onClicked: root.clicked() + } +} + + diff --git a/interface/resources/qml/styles/Border.qml b/interface/resources/qml/styles/Border.qml index 7d38e7d277..ae6bce9e39 100644 --- a/interface/resources/qml/styles/Border.qml +++ b/interface/resources/qml/styles/Border.qml @@ -1,11 +1,12 @@ import QtQuick 2.3 Rectangle { - SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - property int margin: 5 - color: myPalette.window - border.color: myPalette.dark - border.width: 5 - radius: border.width * 2 + HifiConstants { id: hifi } + implicitHeight: 64 + implicitWidth: 64 + color: hifi.colors.window + border.color: hifi.colors.hifiBlue + border.width: hifi.styles.borderWidth + radius: hifi.styles.borderRadius } diff --git a/interface/resources/qml/styles/ButtonStyle.qml b/interface/resources/qml/styles/ButtonStyle.qml index 8d866390a0..bcb167f4dc 100644 --- a/interface/resources/qml/styles/ButtonStyle.qml +++ b/interface/resources/qml/styles/ButtonStyle.qml @@ -4,7 +4,7 @@ import "." import "../controls" OriginalStyles.ButtonStyle { - Original.SystemPalette { id: myPalette; colorGroup: Original.SystemPalette.Active } + HifiConstants { id: hifi } padding { top: 8 left: 12 @@ -15,10 +15,9 @@ OriginalStyles.ButtonStyle { anchors.fill: parent } label: Text { - renderType: Original.Text.NativeRendering verticalAlignment: Original.Text.AlignVCenter horizontalAlignment: Original.Text.AlignHCenter text: control.text - color: control.enabled ? myPalette.text : myPalette.dark + color: control.enabled ? hifi.colors.text : hifi.colors.disabledText } } diff --git a/interface/resources/qml/styles/HifiConstants.qml b/interface/resources/qml/styles/HifiConstants.qml new file mode 100644 index 0000000000..d24e9ca9be --- /dev/null +++ b/interface/resources/qml/styles/HifiConstants.qml @@ -0,0 +1,61 @@ +import QtQuick 2.4 + +Item { + SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } + readonly property alias colors: colors + readonly property alias layout: layout + readonly property alias fonts: fonts + readonly property alias styles: styles + readonly property alias effects: effects + + Item { + id: colors + readonly property color hifiBlue: "#0e7077" + readonly property color window: sysPalette.window + readonly property color dialogBackground: sysPalette.window + //readonly property color dialogBackground: "#00000000" + readonly property color inputBackground: "white" + readonly property color background: sysPalette.dark + readonly property color text: sysPalette.text + readonly property color disabledText: "gray" + readonly property color hintText: sysPalette.dark + readonly property color light: sysPalette.light + readonly property alias activeWindow: activeWindow + readonly property alias inactiveWindow: inactiveWindow + QtObject { + id: activeWindow + readonly property color headerBackground: "white" + readonly property color headerText: "black" + } + QtObject { + id: inactiveWindow + readonly property color headerBackground: "gray" + readonly property color headerText: "black" + } + } + + QtObject { + id: fonts + readonly property real headerPointSize: 24 + readonly property string fontFamily: "Helvetica" + readonly property real fontSize: 18 + } + + QtObject { + id: layout + property int spacing: 8 + property int rowHeight: 40 + property int windowTitleHeight: 48 + } + + QtObject { + id: styles + readonly property int borderWidth: 5 + readonly property int borderRadius: borderWidth * 2 + } + + QtObject { + id: effects + readonly property int fadeInDuration: 400 + } +} diff --git a/interface/resources/qml/styles/HifiPalette.qml b/interface/resources/qml/styles/HifiPalette.qml index 46ef0ef14e..421fa2c75d 100644 --- a/interface/resources/qml/styles/HifiPalette.qml +++ b/interface/resources/qml/styles/HifiPalette.qml @@ -1,5 +1,11 @@ import QtQuick 2.4 -QtObject { +Item { property string hifiBlue: "#0e7077" -} \ No newline at end of file + property alias colors: colorsObj + + Item { + id: colorsObj + property string hifiRed: "red" + } +} diff --git a/interface/resources/qml/styles/IconButtonStyle.qml b/interface/resources/qml/styles/IconButtonStyle.qml index b341e5d6dd..812cd493b0 100644 --- a/interface/resources/qml/styles/IconButtonStyle.qml +++ b/interface/resources/qml/styles/IconButtonStyle.qml @@ -1,15 +1,10 @@ ButtonStyle { background: Item { anchors.fill: parent } - label: Text { + label: FontAwesome { id: icon - width: height - verticalAlignment: Text.AlignVCenter - renderType: Text.NativeRendering - font.family: iconFont.name font.pointSize: 18 - property alias unicode: icon.text - FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; } + property alias unicode: text text: control.text - color: control.enabled ? "white" : "dimgray" + color: control.enabled ? hifi.colors.text : hifi.colors.disabledText } } diff --git a/interface/resources/qml/styles/MenuButtonStyle.qml b/interface/resources/qml/styles/MenuButtonStyle.qml deleted file mode 100644 index fd21e88d86..0000000000 --- a/interface/resources/qml/styles/MenuButtonStyle.qml +++ /dev/null @@ -1,22 +0,0 @@ -import QtQuick 2.4 -import QtQuick.Controls.Styles 1.3 -import "../controls" -import "." - -ButtonStyle { - HifiPalette { id: hifiPalette } - padding { - top: 2 - left: 4 - right: 4 - bottom: 2 - } - background: Item {} - label: Text { - renderType: Text.NativeRendering - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - text: control.text - color: control.enabled ? "yellow" : "brown" - } -} From 8278f52a7978858a27b6117c804f9a477199eaf7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Apr 2015 10:59:51 -0700 Subject: [PATCH 348/401] cleanups --- libraries/physics/src/EntityMotionState.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c722336ca2..4c61503d49 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -219,7 +219,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& simulatorID = _entity->getSimulatorID(); - if (simulatorID != myNodeID /* && !simulatorID.isNull() */) { + if (simulatorID != myNodeID) { // some other Node owns the simulating of this, so don't broadcast the results of local simulation. return false; } @@ -302,13 +302,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); - // if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { - // // the entity is moving and no node has claimed simulation ownership. try to claim it. - // setShouldClaimSimulationOwnership(true); - // } - if (getShouldClaimSimulationOwnership()) { - // _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); setShouldClaimSimulationOwnership(false); } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { From e14b4c6ad4b9299f4b52d2da4676c7052ea8c10b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Apr 2015 11:01:48 -0700 Subject: [PATCH 349/401] cleanups --- libraries/physics/src/PhysicsEngine.cpp | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 6d0c9c878a..27ea816440 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -467,16 +467,6 @@ void PhysicsEngine::computeCollisionEvents() { if (type == CONTACT_EVENT_TYPE_END) { ContactMap::iterator iterToDelete = contactItr; ++contactItr; - - // const ContactKey& contactKey = (*iterToDelete).first; - // const ObjectMotionState* objectMotionStateA = static_cast(contactKey._a); - // const ObjectMotionState* objectMotionStateB = static_cast(contactKey._b); - // const btCollisionObject* objectA = - // objectMotionStateA ? static_cast(objectMotionStateA->getRigidBody()) : NULL; - // const btCollisionObject* objectB = - // objectMotionStateB ? static_cast(objectMotionStateB->getRigidBody()) : NULL; - // doOwnershipInfection(objectA, objectB); - _contactMap.erase(iterToDelete); } else { ++contactItr; @@ -600,17 +590,10 @@ void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { assert(motionState); btRigidBody* body = motionState->getRigidBody(); - // activate this before deleting it so that anything resting on it will begin to fall. - // - // body->activate(); - // - // motionState->setShouldClaimSimulationOwnership(true); - // computeCollisionEvents(); - // + // wake up anything touching this object EntityItem* entityItem = motionState ? motionState->getEntity() : NULL; bump(entityItem); - if (body) { const btCollisionShape* shape = body->getCollisionShape(); _dynamicsWorld->removeRigidBody(body); From d55d467d3f19e70492e8de3c0886591429744ca4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 27 Apr 2015 11:35:57 -0700 Subject: [PATCH 350/401] Tweaking VR menu for PR --- interface/resources/qml/VrMenu.qml | 22 +++++++++++++++++-- interface/src/Application.cpp | 9 +++++--- interface/src/Menu.cpp | 2 +- libraries/ui/src/{HifiMenu.cpp => VrMenu.cpp} | 14 +++++++----- libraries/ui/src/{HifiMenu.h => VrMenu.h} | 10 ++++----- tests/ui/src/main.cpp | 2 +- 6 files changed, 42 insertions(+), 17 deletions(-) rename libraries/ui/src/{HifiMenu.cpp => VrMenu.cpp} (93%) rename libraries/ui/src/{HifiMenu.h => VrMenu.h} (83%) diff --git a/interface/resources/qml/VrMenu.qml b/interface/resources/qml/VrMenu.qml index 7de66de23c..01714e9ebe 100644 --- a/interface/resources/qml/VrMenu.qml +++ b/interface/resources/qml/VrMenu.qml @@ -94,6 +94,9 @@ Hifi.VrMenu { var newWidth = minWidth; for (var i = 0; i < children.length; ++i) { var item = children[i]; + if (!item.visible) { + continue + } newHeight += item.height } parent.height = newHeight + outerMargin * 2; @@ -152,8 +155,23 @@ Hifi.VrMenu { height: implicitHeight width: implicitWidth color: source.enabled ? hifi.colors.text : hifi.colors.disabledText - enabled: source.enabled - + enabled: source.enabled && source.visible + // FIXME uncommenting this line results in menus that have blank spots + // rather than having the correct size + // visible: source.visible + + onListViewChanged: { + if (listView) { + listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64); + listView.recalculateSize(); + } + } + + onVisibleChanged: { + if (listView) { + listView.recalculateSize(); + } + } onImplicitWidthChanged: { if (listView) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5fd3cc48ab..2550651a34 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include #include @@ -1327,13 +1327,16 @@ void Application::keyPressEvent(QKeyEvent* event) { } } + +//#define VR_MENU_ONLY_IN_HMD + void Application::keyReleaseEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Alt && _altPressed && _window->isActiveWindow()) { -#ifndef DEBUG +#ifdef VR_MENU_ONLY_IN_HMD if (OculusManager::isConnected()) { #endif VrMenu::toggle(); -#ifndef DEBUG +#ifdef VR_MENU_ONLY_IN_HMD } #endif } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 67fae46b33..42670c2979 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include "Application.h" #include "AccountManager.h" diff --git a/libraries/ui/src/HifiMenu.cpp b/libraries/ui/src/VrMenu.cpp similarity index 93% rename from libraries/ui/src/HifiMenu.cpp rename to libraries/ui/src/VrMenu.cpp index 854f0d6eb2..e0fa296857 100644 --- a/libraries/ui/src/HifiMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -1,5 +1,5 @@ // -// HifiMenu.cpp +// VrMenu.cpp // // Created by Bradley Austin Davis on 2015/04/21 // Copyright 2015 High Fidelity, Inc. @@ -8,11 +8,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "HifiMenu.h" +#include "VrMenu.h" #include #include // Binds together a Qt Action or Menu with the QML Menu or MenuItem +// +// TODO On reflection, it may be pointless to use the UUID. Perhaps +// simply creating the bidirectional link pointing to both the widget +// and qml object and inject the pointer into both objects class MenuUserData : public QObjectUserData { static const int USER_DATA_ID; @@ -69,7 +73,7 @@ VrMenu::VrMenu(QQuickItem* parent) : QQuickItem(parent) { } // QML helper functions -QObject* addMenu(QObject* parent, const QString & text) { +QObject* addMenu(QObject* parent, const QString& text) { // FIXME add more checking here to ensure no name conflicts QVariant returnedValue; QMetaObject::invokeMethod(parent, "addMenu", Qt::DirectConnection, @@ -94,7 +98,7 @@ QObject* addItem(QObject* parent, const QString& text) { return result; } -const QObject* VrMenu::findMenuObject(const QString & menuOption) const { +const QObject* VrMenu::findMenuObject(const QString& menuOption) const { if (menuOption.isEmpty()) { return _rootMenu; } @@ -102,7 +106,7 @@ const QObject* VrMenu::findMenuObject(const QString & menuOption) const { return result; } -QObject* VrMenu::findMenuObject(const QString & menuOption) { +QObject* VrMenu::findMenuObject(const QString& menuOption) { if (menuOption.isEmpty()) { return _rootMenu; } diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/VrMenu.h similarity index 83% rename from libraries/ui/src/HifiMenu.h rename to libraries/ui/src/VrMenu.h index 43af05a426..7fe0d33cc4 100644 --- a/libraries/ui/src/HifiMenu.h +++ b/libraries/ui/src/VrMenu.h @@ -1,5 +1,5 @@ // -// HifiMenu.h +// VrMenu.h // // Created by Bradley Austin Davis on 2015/04/21 // Copyright 2015 High Fidelity, Inc. @@ -9,8 +9,8 @@ // #pragma once -#ifndef hifi_HifiMenu_h -#define hifi_HifiMenu_h +#ifndef hifi_VrMenu_h +#define hifi_VrMenu_h #include #include @@ -20,7 +20,7 @@ #include #include "OffscreenUi.h" -// FIXME rename the compilation files to VrMenu.h and VrMenu.cpp after upstream pull requests are merged. +// FIXME break up the rendering code (VrMenu) and the code for mirroring a Widget based menu in QML class VrMenu : public QQuickItem { Q_OBJECT HIFI_QML_DECL_LAMBDA @@ -45,4 +45,4 @@ protected: friend class MenuUserData; }; -#endif // hifi_HifiMenu_h +#endif // hifi_VrMenu_h diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 192bfd928b..ae8375717e 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -35,7 +35,7 @@ #include #include "MessageDialog.h" -#include "HifiMenu.h" +#include "VrMenu.h" class RateCounter { std::vector times; From 76ce34a74b3d4243d5a8d2b17c12f43e4e2422ef Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 27 Apr 2015 11:41:10 -0700 Subject: [PATCH 351/401] Scanning for code style --- interface/src/ui/MarketplaceDialog.cpp | 4 ++-- interface/src/ui/MarketplaceDialog.h | 4 ++-- libraries/ui/src/VrMenu.cpp | 2 +- tests/ui/src/main.cpp | 18 +++++++++--------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/interface/src/ui/MarketplaceDialog.cpp b/interface/src/ui/MarketplaceDialog.cpp index f37f71ef54..b9c640054c 100644 --- a/interface/src/ui/MarketplaceDialog.cpp +++ b/interface/src/ui/MarketplaceDialog.cpp @@ -15,10 +15,10 @@ HIFI_QML_DEF(MarketplaceDialog) -MarketplaceDialog::MarketplaceDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { +MarketplaceDialog::MarketplaceDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) { } -bool MarketplaceDialog::navigationRequested(const QString & url) { +bool MarketplaceDialog::navigationRequested(const QString& url) { qDebug() << url; if (Application::getInstance()->canAcceptURL(url)) { if (Application::getInstance()->acceptURL(url)) { diff --git a/interface/src/ui/MarketplaceDialog.h b/interface/src/ui/MarketplaceDialog.h index 241d4a7131..2440c3e07c 100644 --- a/interface/src/ui/MarketplaceDialog.h +++ b/interface/src/ui/MarketplaceDialog.h @@ -20,9 +20,9 @@ class MarketplaceDialog : public OffscreenQmlDialog HIFI_QML_DECL public: - MarketplaceDialog(QQuickItem *parent = 0); + MarketplaceDialog(QQuickItem* parent = nullptr); - Q_INVOKABLE bool navigationRequested(const QString & url); + Q_INVOKABLE bool navigationRequested(const QString& url); }; diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index e0fa296857..04c2cb0b30 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -50,7 +50,7 @@ const int MenuUserData::USER_DATA_ID = QObject::registerUserData(); HIFI_QML_DEF_LAMBDA(VrMenu, [&](QQmlContext* context, QObject* newItem) { auto offscreenUi = DependencyManager::get(); - QObject * rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); + QObject* rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); Q_ASSERT(rootMenu); static_cast(newItem)->setRootMenu(rootMenu); context->setContextProperty("rootMenu", rootMenu); diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index ae8375717e..aaca2efa2a 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -234,12 +234,12 @@ public: }; public: - MenuConstants(QObject * parent = nullptr) : QObject(parent) { + MenuConstants(QObject* parent = nullptr) : QObject(parent) { } }; -const QString & getQmlDir() { +const QString& getQmlDir() { static QString dir; if (dir.isEmpty()) { QDir path(__FILE__); @@ -250,7 +250,7 @@ const QString & getQmlDir() { return dir; } -const QString & getTestQmlDir() { +const QString& getTestQmlDir() { static QString dir; if (dir.isEmpty()) { QDir path(__FILE__); @@ -265,7 +265,7 @@ const QString & getTestQmlDir() { class QTestWindow : public QWindow, private QOpenGLFunctions { Q_OBJECT - QOpenGLContext * _context{ nullptr }; + QOpenGLContext* _context{ nullptr }; QSize _size; bool _altPressed{ false }; RateCounter fps; @@ -273,7 +273,7 @@ class QTestWindow : public QWindow, private QOpenGLFunctions { int testQmlTexture{ 0 }; public: - QObject * rootMenu; + QObject* rootMenu; QTestWindow() { _timer.setInterval(1); @@ -304,7 +304,7 @@ public: initializeOpenGLFunctions(); { - QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); logger->initialize(); // initializes in the current context, i.e. ctx logger->enableMessages(); connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { @@ -396,12 +396,12 @@ private: protected: - void resizeEvent(QResizeEvent * ev) override { + void resizeEvent(QResizeEvent* ev) override { resizeWindow(ev->size()); } - void keyPressEvent(QKeyEvent *event) { + void keyPressEvent(QKeyEvent* event) { _altPressed = Qt::Key_Alt == event->key(); switch (event->key()) { case Qt::Key_L: @@ -432,7 +432,7 @@ protected: } } - void moveEvent(QMoveEvent *event) { + void moveEvent(QMoveEvent* event) { static qreal oldPixelRatio = 0.0; if (devicePixelRatio() != oldPixelRatio) { oldPixelRatio = devicePixelRatio(); From 2e5049a190e2278c8867ecc4afde620499f9e640 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Apr 2015 12:20:01 -0700 Subject: [PATCH 352/401] fix bug caused by no-longer reusing a variable --- libraries/physics/src/EntityMotionState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 4c61503d49..6338736a19 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -111,7 +111,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { glm::vec3 av; getAngularVelocity(av); - _entity->setAngularVelocity(v); + _entity->setAngularVelocity(av); _entity->setLastSimulated(usecTimestampNow()); From ca16d37ce5fe70dd62cc24eafb5049a781bba73e Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Mon, 27 Apr 2015 12:46:34 -0700 Subject: [PATCH 353/401] Mac testing --- interface/resources/qml/VrMenu.qml | 42 +++++++++++++++++------------- libraries/ui/src/OffscreenUi.cpp | 2 +- tests/render-utils/src/main.cpp | 2 +- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/interface/resources/qml/VrMenu.qml b/interface/resources/qml/VrMenu.qml index 01714e9ebe..4bbcb9c498 100644 --- a/interface/resources/qml/VrMenu.qml +++ b/interface/resources/qml/VrMenu.qml @@ -108,7 +108,7 @@ Hifi.VrMenu { height: 32 color: hifi.colors.hifiBlue y: (listView.currentItem) ? listView.currentItem.y : 0; - x: 32 + x: (listView.currentItem) ? listView.currentItem.height : 0; Behavior on y { NumberAnimation { duration: 100 @@ -132,6 +132,12 @@ Hifi.VrMenu { property: "source" value: modelData when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "border" + value: listView.parent + when: loader.status == Loader.Ready } Binding { target: loader.item @@ -147,10 +153,11 @@ Hifi.VrMenu { property var itemBuilder: Component { Text { id: thisText - x: 32 + x: height property var source property var root property var listView + property var border text: typedText() height: implicitHeight width: implicitWidth @@ -167,12 +174,6 @@ Hifi.VrMenu { } } - onVisibleChanged: { - if (listView) { - listView.recalculateSize(); - } - } - onImplicitWidthChanged: { if (listView) { listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64); @@ -182,12 +183,13 @@ Hifi.VrMenu { FontAwesome { visible: source.type == 1 && source.checkable - x: -32 + x: -parent.height + size: parent.height text: checkText(); color: parent.color function checkText() { - if (source.type != 1) { - return; + if (!source || source.type != 1) { + return ""; } // FIXME this works for native QML menus but I don't think it will // for proxied QML menus @@ -199,6 +201,7 @@ Hifi.VrMenu { } FontAwesome { + size: parent.height visible: source.type == 2 x: listView.width - 32 - (hifi.layout.spacing * 2) text: "\uF0DA" @@ -206,14 +209,17 @@ Hifi.VrMenu { } function typedText() { - switch(source.type) { - case 2: - return source.title; - case 1: - return source.text; - case 0: - return "-----" + if (source) { + switch(source.type) { + case 2: + return source.title; + case 1: + return source.text; + case 0: + return "-----" + } } + return "" } MouseArea { diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 5db7349a02..8ba7b514e4 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -124,9 +124,9 @@ void OffscreenUi::resize(const QSize& newSize) { if (_quickWindow) { _quickWindow->setGeometry(QRect(QPoint(), newSize)); + _quickWindow->contentItem()->setSize(newSize); } - _quickWindow->contentItem()->setSize(newSize); // Update our members if (_rootItem) { diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 5e45bf23a2..0ba7416b28 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -205,7 +205,7 @@ void QTestWindow::renderText() { { size.x + QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x + QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, { QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, - }; + }; QString str = QString::fromWCharArray(EXAMPLE_TEXT); for (int i = 0; i < 4; ++i) { From 31e57584229073de2296967b3b68601b05a36bd6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 27 Apr 2015 13:04:59 -0700 Subject: [PATCH 354/401] namechange updateObjectEasy()-->updateBodyEasy() --- libraries/physics/src/EntityMotionState.cpp | 2 +- libraries/physics/src/EntityMotionState.h | 2 +- libraries/physics/src/ObjectMotionState.h | 3 ++- libraries/physics/src/PhysicsEngine.cpp | 10 +++++----- libraries/physics/src/PhysicsEngine.h | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 74096a3f45..a7245c32d4 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -138,7 +138,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { #endif } -void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { +void EntityMotionState::updateBodyEasy(uint32_t flags, uint32_t step) { if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY | EntityItem::DIRTY_PHYSICS_NO_WAKE)) { if (flags & EntityItem::DIRTY_POSITION) { _sentPosition = getObjectPosition() - ObjectMotionState::getWorldOffset(); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index b3323cafec..98d05a0420 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -49,7 +49,7 @@ public: virtual void setWorldTransform(const btTransform& worldTrans); // these relay incoming values to the RigidBody - virtual void updateObjectEasy(uint32_t flags, uint32_t step); + virtual void updateBodyEasy(uint32_t flags, uint32_t step); virtual void updateBodyMaterialProperties(); virtual void updateBodyVelocities(); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 049e3c6a37..7c00eedd09 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -69,7 +69,8 @@ public: void resetMeasuredBodyAcceleration(); // An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine - virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0; + virtual void updateBodyEasy(uint32_t flags, uint32_t frame) = 0; + virtual void updateBodyMaterialProperties() = 0; virtual void updateBodyVelocities() = 0; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 0f3d677017..603aef731c 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -173,9 +173,9 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { if (flags & HARD_DIRTY_PHYSICS_FLAGS) { // a HARD update requires the body be pulled out of physics engine, changed, then reinserted // but it also handles all EASY changes - bool success = updateObjectHard(body, motionState, flags); + bool success = updateBodyHard(body, motionState, flags); if (!success) { - // NOTE: since updateObjectHard() failed we know that motionState has been removed + // NOTE: since updateBodyHard() failed we know that motionState has been removed // from simulation and body has been deleted. Depending on what else has changed // we might need to remove motionState altogether... if (flags & EntityItem::DIRTY_VELOCITY) { @@ -195,7 +195,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { } else if (flags) { // an EASY update does NOT require that the body be pulled out of physics engine // hence the MotionState has all the knowledge and authority to perform the update. - motionState->updateObjectEasy(flags, _numSubsteps); + motionState->updateBodyEasy(flags, _numSubsteps); } if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { motionState->resetMeasuredBodyAcceleration(); @@ -608,7 +608,7 @@ void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { } // private -bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { +bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { MotionType newType = motionState->computeObjectMotionType(); // pull body out of physics engine @@ -653,7 +653,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio } bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS; if (easyUpdate) { - motionState->updateObjectEasy(flags, _numSubsteps); + motionState->updateBodyEasy(flags, _numSubsteps); } // update the motion parameters diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index a005c0f4f9..4f931d939a 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -100,7 +100,7 @@ private: void doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB); // return 'true' of update was successful - bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); + bool updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); btClock _clock; From 1ef58139a40160a854ee555ccaaff8f760385826 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 Apr 2015 15:07:32 -0700 Subject: [PATCH 355/401] fix bug in parsing root element data --- libraries/octree/src/Octree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index b1e92e2140..059c0e5bbc 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -380,9 +380,9 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch } // if this is the root, and there is more data to read, allow it to read it's element data... - if (destinationElement == _rootElement && rootElementHasData() && (bytesLeftToRead - bytesRead) > 0) { + if (destinationElement == _rootElement && rootElementHasData() && bytesLeftToRead > 0) { // tell the element to read the subsequent data - int rootDataSize = _rootElement->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead - bytesRead, args); + int rootDataSize = _rootElement->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args); bytesRead += rootDataSize; bytesLeftToRead -= rootDataSize; } From 2f36cd0fb0c80766f310f87f1420ec2847b4a3b6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Apr 2015 15:30:17 -0700 Subject: [PATCH 356/401] make it so assignment-clients runnings scripts can rez entities --- domain-server/src/DomainServer.cpp | 20 +++++++++++++++---- domain-server/src/PendingAssignedNodeData.cpp | 9 ++++++--- domain-server/src/PendingAssignedNodeData.h | 13 ++++++++++-- libraries/networking/src/Assignment.cpp | 6 +++++- libraries/networking/src/NodeData.h | 10 ++++++++++ 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d7cd7ec47d..14dea70c5c 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -504,7 +504,11 @@ void DomainServer::populateStaticScriptedAssignmentsFromSettings() { Assignment::AgentType, scriptPool); scriptAssignment->setPayload(scriptURL.toUtf8()); - + + // we want a script added by the domain owner to be able to do what it wants with entities. + scriptAssignment->setCanRez(true); + scriptAssignment->setCanAdjustLocks(true); + // add it to static hash so we know we have to keep giving it back out addStaticAssignmentToAssignmentHash(scriptAssignment); } @@ -675,6 +679,12 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock nodeData->setAssignmentUUID(matchingQueuedAssignment->getUUID()); nodeData->setWalletUUID(pendingAssigneeData->getWalletUUID()); + // always allow assignment clients to create and destroy entities + nodeData->setCanAdjustLocks(true); + nodeData->setCanRez(true); + newNode->setCanAdjustLocks(true); + newNode->setCanRez(true); + // now that we've pulled the wallet UUID and added the node to our list, delete the pending assignee data delete pendingAssigneeData; } @@ -1052,7 +1062,9 @@ void DomainServer::readAvailableDatagrams() { // add the information for that deployed assignment to the hash of pending assigned nodes PendingAssignedNodeData* pendingNodeData = new PendingAssignedNodeData(assignmentToDeploy->getUUID(), - requestAssignment.getWalletUUID()); + requestAssignment.getWalletUUID(), + true, true + ); _pendingAssignedNodes.insert(uniqueAssignment.getUUID(), pendingNodeData); } else { if (requestAssignment.getType() != Assignment::AgentType @@ -2119,10 +2131,10 @@ SharedAssignmentPointer DomainServer::deployableAssignmentForRequest(const Assig Assignment* assignment = sharedAssignment->data(); bool requestIsAllTypes = requestAssignment.getType() == Assignment::AllTypes; bool assignmentTypesMatch = assignment->getType() == requestAssignment.getType(); - bool nietherHasPool = assignment->getPool().isEmpty() && requestAssignment.getPool().isEmpty(); + bool neitherHasPool = assignment->getPool().isEmpty() && requestAssignment.getPool().isEmpty(); bool assignmentPoolsMatch = assignment->getPool() == requestAssignment.getPool(); - if ((requestIsAllTypes || assignmentTypesMatch) && (nietherHasPool || assignmentPoolsMatch)) { + if ((requestIsAllTypes || assignmentTypesMatch) && (neitherHasPool || assignmentPoolsMatch)) { // remove the assignment from the queue SharedAssignmentPointer deployableAssignment = _unfulfilledAssignments.takeAt(sharedAssignment diff --git a/domain-server/src/PendingAssignedNodeData.cpp b/domain-server/src/PendingAssignedNodeData.cpp index 21b3aa4ca4..c4b47fd254 100644 --- a/domain-server/src/PendingAssignedNodeData.cpp +++ b/domain-server/src/PendingAssignedNodeData.cpp @@ -11,9 +11,12 @@ #include "PendingAssignedNodeData.h" -PendingAssignedNodeData::PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID) : +PendingAssignedNodeData::PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID, + bool canAdjustLocks, bool canRez) : _assignmentUUID(assignmentUUID), - _walletUUID(walletUUID) + _walletUUID(walletUUID), + _canAdjustLocks(canAdjustLocks), + _canRez(canRez) { -} \ No newline at end of file +} diff --git a/domain-server/src/PendingAssignedNodeData.h b/domain-server/src/PendingAssignedNodeData.h index 93d99a6f8f..17f94d2225 100644 --- a/domain-server/src/PendingAssignedNodeData.h +++ b/domain-server/src/PendingAssignedNodeData.h @@ -18,16 +18,25 @@ class PendingAssignedNodeData : public QObject { Q_OBJECT public: - PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID); + PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID, bool canAdjustLocks, bool canRez); void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } const QUuid& getAssignmentUUID() const { return _assignmentUUID; } void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; } const QUuid& getWalletUUID() const { return _walletUUID; } + + void setCanAdjustLocks(bool canAdjustLocks) { _canAdjustLocks = canAdjustLocks; } + bool getCanAdjustLocks() { return _canAdjustLocks; } + + void setCanRez(bool canRez) { _canRez = canRez; } + bool getCanRez() { return _canRez; } + private: QUuid _assignmentUUID; QUuid _walletUUID; + bool _canAdjustLocks = false; /// will this node be allowed to adjust locks on entities? + bool _canRez = false; /// will this node be allowed to rez in new entities? }; -#endif // hifi_PendingAssignedNodeData_h \ No newline at end of file +#endif // hifi_PendingAssignedNodeData_h diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 944041730e..560bce3b91 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -153,6 +153,8 @@ QDataStream& operator<<(QDataStream &out, const Assignment& assignment) { if (assignment._command == Assignment::RequestCommand) { out << assignment._walletUUID; } + + out << assignment._canAdjustLocks << assignment._canRez; return out; } @@ -167,6 +169,8 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { if (assignment._command == Assignment::RequestCommand) { in >> assignment._walletUUID; } - + + in >> assignment._canAdjustLocks >> assignment._canRez; + return in; } diff --git a/libraries/networking/src/NodeData.h b/libraries/networking/src/NodeData.h index b865e444a9..e5e7925280 100644 --- a/libraries/networking/src/NodeData.h +++ b/libraries/networking/src/NodeData.h @@ -26,8 +26,18 @@ public: QMutex& getMutex() { return _mutex; } + void setCanAdjustLocks(bool canAdjustLocks) { _canAdjustLocks = canAdjustLocks; } + bool getCanAdjustLocks() { return _canAdjustLocks; } + + void setCanRez(bool canRez) { _canRez = canRez; } + bool getCanRez() { return _canRez; } + private: QMutex _mutex; + +protected: + bool _canAdjustLocks = false; /// will this node be allowed to adjust locks on entities? + bool _canRez = false; /// will this node be allowed to rez in new entities? }; #endif // hifi_NodeData_h From fd28baac8c713446163a7b1e5e877e709e3c90ef Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 27 Apr 2015 15:42:20 -0700 Subject: [PATCH 357/401] Working on message box and addressbar tweaks --- interface/resources/qml/AddressBarDialog.qml | 31 ++++++---- interface/resources/qml/MessageDialog.qml | 60 +++++++------------ .../resources/qml/controls/DialogBase.qml | 6 +- 3 files changed, 45 insertions(+), 52 deletions(-) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 8d2439e5b8..e12452472a 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -4,12 +4,16 @@ import "controls" import "styles" Dialog { + id: root + HifiConstants { id: hifi } + title: "Go to..." objectName: "AddressBarDialog" - height: 128 - width: 512 + contentImplicitWidth: addressBarDialog.implicitWidth + contentImplicitHeight: addressBarDialog.implicitHeight destroyOnCloseButton: false + onVisibleChanged: { if (!visible) { reset(); @@ -21,6 +25,11 @@ Dialog { addressLine.forceActiveFocus(); } } + onParentChanged: { + if (enabled && visible) { + addressLine.forceActiveFocus(); + } + } function reset() { addressLine.text = "" @@ -29,24 +38,26 @@ Dialog { AddressBarDialog { id: addressBarDialog - // The client area - anchors.fill: parent - anchors.margins: parent.margins - anchors.topMargin: parent.topMargin + x: root.clientX + y: root.clientY + implicitWidth: 512 + implicitHeight: border.height + hifi.layout.spacing * 4 + Border { + id: border height: 64 anchors.left: parent.left - anchors.leftMargin: 0 + anchors.leftMargin: hifi.layout.spacing * 2 anchors.right: goButton.left - anchors.rightMargin: 8 + anchors.rightMargin: hifi.layout.spacing anchors.verticalCenter: parent.verticalCenter TextInput { id: addressLine anchors.fill: parent helperText: "domain, location, @user, /x,y,z" - anchors.margins: 8 + anchors.margins: hifi.layout.spacing onAccepted: { event.accepted addressBarDialog.loadAddress(addressLine.text) @@ -59,7 +70,7 @@ Dialog { width: 32 height: 32 anchors.right: parent.right - anchors.rightMargin: 8 + anchors.rightMargin: hifi.layout.spacing * 2 source: "../images/address-bar-submit.svg" anchors.verticalCenter: parent.verticalCenter diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml index a2a5ba9304..02f1e4716f 100644 --- a/interface/resources/qml/MessageDialog.qml +++ b/interface/resources/qml/MessageDialog.qml @@ -3,71 +3,51 @@ import QtQuick 2.2 import QtQuick.Controls 1.2 import QtQuick.Dialogs 1.2 import "controls" +import "styles" Dialog { id: root - property real spacing: 8 - property real outerSpacing: 16 - + HifiConstants { id: hifi } + property real spacing: hifi.layout.spacing + property real outerSpacing: hifi.layout.spacing * 2 destroyOnCloseButton: true destroyOnInvisible: true - implicitHeight: content.implicitHeight + outerSpacing * 2 + 48 - implicitWidth: Math.min(200, Math.max(mainText.implicitWidth, content.buttonsRowImplicitWidth) + outerSpacing * 2); + contentImplicitWidth: content.implicitWidth + contentImplicitHeight: content.implicitHeight - onImplicitHeightChanged: root.height = implicitHeight - onImplicitWidthChanged: root.width = implicitWidth - - function calculateImplicitWidth() { - if (buttons.visibleChildren.length < 2) - return; - var calcWidth = 0; - for (var i = 0; i < buttons.visibleChildren.length; ++i) { - calcWidth += Math.max(100, buttons.visibleChildren[i].implicitWidth) + root.spacing - } - content.buttonsRowImplicitWidth = outerSpacing + calcWidth + 48 - } - Component.onCompleted: { enabled = true } - - onEnabledChanged: { - if (enabled) { - root.forceActiveFocus(); + + onParentChanged: { + if (visible && enabled) { + forceActiveFocus(); } } Hifi.MessageDialog { id: content clip: true - anchors.fill: parent - anchors.topMargin: parent.topMargin + root.outerSpacing - anchors.leftMargin: parent.margins + root.outerSpacing - anchors.rightMargin: parent.margins + root.outerSpacing - anchors.bottomMargin: parent.margins + root.outerSpacing - implicitHeight: contentColumn.implicitHeight + outerSpacing * 2 - implicitWidth: Math.max(mainText.implicitWidth, buttonsRowImplicitWidth); - property real buttonsRowImplicitWidth: Screen.pixelDensity * 50 - onImplicitWidthChanged: root.width = implicitWidth + x: root.clientX + y: root.clientY + implicitHeight: contentColumn.implicitHeight + outerSpacing * 2 + implicitWidth: mainText.implicitWidth + outerSpacing * 2 Component.onCompleted: { root.title = title } - + onTitleChanged: { root.title = title } - + Column { + anchors.fill: parent + anchors.margins: 8 id: contentColumn spacing: root.outerSpacing - anchors { - top: parent.top - left: parent.left - right: parent.right - } Item { width: parent.width @@ -83,7 +63,7 @@ Dialog { horizontalAlignment: Text.AlignLeft color: iconColor() text: iconSymbol() - + function iconSymbol() { switch (content.icon) { case Hifi.MessageDialog.Information: @@ -262,7 +242,6 @@ Dialog { onClicked: content.click(StandardButton.Help) visible: content.standardButtons & StandardButton.Help } - onVisibleChildrenChanged: root.calculateImplicitWidth() } } @@ -319,6 +298,7 @@ Dialog { ] } + Keys.onPressed: { if (event.modifiers === Qt.ControlModifier) switch (event.key) { diff --git a/interface/resources/qml/controls/DialogBase.qml b/interface/resources/qml/controls/DialogBase.qml index e5f0a8f0d1..050237c184 100644 --- a/interface/resources/qml/controls/DialogBase.qml +++ b/interface/resources/qml/controls/DialogBase.qml @@ -6,13 +6,15 @@ import "../styles" Item { id: root HifiConstants { id: hifi } - implicitHeight: 512 - implicitWidth: 512 + implicitHeight: contentImplicitHeight + titleBorder.height + hifi.styles.borderWidth + implicitWidth: contentImplicitWidth + hifi.styles.borderWidth * 2 property string title property int titleSize: titleBorder.height + 12 property string frameColor: hifi.colors.hifiBlue property string backgroundColor: hifi.colors.dialogBackground property bool active: false + property real contentImplicitWidth: 800 + property real contentImplicitHeight: 800 property alias titleBorder: titleBorder readonly property alias titleX: titleBorder.x From 32f91a86e7c924f5090d8232b216a80ad0add3be Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Apr 2015 15:43:47 -0700 Subject: [PATCH 358/401] remove some unneeded code --- domain-server/src/DomainServer.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 14dea70c5c..5090978a72 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -505,10 +505,6 @@ void DomainServer::populateStaticScriptedAssignmentsFromSettings() { scriptPool); scriptAssignment->setPayload(scriptURL.toUtf8()); - // we want a script added by the domain owner to be able to do what it wants with entities. - scriptAssignment->setCanRez(true); - scriptAssignment->setCanAdjustLocks(true); - // add it to static hash so we know we have to keep giving it back out addStaticAssignmentToAssignmentHash(scriptAssignment); } From 1beaf18d1baf096bec57aff78c70397fb76d1597 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 27 Apr 2015 16:00:23 -0700 Subject: [PATCH 359/401] Prevent the login dialog from spawning the address bar on enter keys --- interface/resources/qml/LoginDialog.qml | 28 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index 1e02683c57..5653dfc7a1 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -60,9 +60,6 @@ Dialog { anchors.margins: 8 KeyNavigation.tab: password KeyNavigation.backtab: password - onAccepted: { - password.forceActiveFocus() - } } } @@ -78,13 +75,6 @@ Dialog { anchors.margins: 8 KeyNavigation.tab: username KeyNavigation.backtab: username - onAccepted: { - if (username.text == "") { - username.forceActiveFocus() - } else { - loginDialog.login(username.text, password.text) - } - } onFocusChanged: { if (password.focus) { password.selectAll() @@ -187,4 +177,22 @@ Dialog { } } } + Keys.onPressed: { + switch(event.key) { + case Qt.Key_Enter: + case Qt.Key_Return: + if (username.activeFocus) { + event.accepted = true + password.forceActiveFocus() + } else if (password.activeFocus) { + event.accepted = true + if (username.text == "") { + username.forceActiveFocus() + } else { + loginDialog.login(username.text, password.text) + } + } + break; + } + } } From ec2f54b90a8af45abafae32ac21d434ce2b4fbc3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Apr 2015 16:02:52 -0700 Subject: [PATCH 360/401] add a macro to recursively correctly handle resources --- cmake/macros/AddResourcesToOSXBundle.cmake | 40 ++++++++++++++++++++++ interface/CMakeLists.txt | 17 ++++----- 2 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 cmake/macros/AddResourcesToOSXBundle.cmake diff --git a/cmake/macros/AddResourcesToOSXBundle.cmake b/cmake/macros/AddResourcesToOSXBundle.cmake new file mode 100644 index 0000000000..113f751731 --- /dev/null +++ b/cmake/macros/AddResourcesToOSXBundle.cmake @@ -0,0 +1,40 @@ +# +# AddResourcesToOSXBundle.cmake +# cmake/macros +# +# Created by Stephen Birarda on 04/27/15. +# Copyright 2015 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 +# + +macro(_RECURSIVELY_SET_PACKAGE_LOCATION _PATH) + # enumerate the items + foreach(_ITEM ${ARGN}) + + if (IS_DIRECTORY "${_ITEM}") + # recurse into the directory and check for more resources + file(GLOB _DIR_CONTENTS "${_ITEM}/*") + + # figure out the path for this directory and then call ourselves to recurse into it + get_filename_component(_ITEM_PATH ${_ITEM} NAME) + _recursively_set_package_location("${_PATH}/${_ITEM_PATH}" ${_DIR_CONTENTS}) + else () + # add any files in the root to the resources folder directly + SET_SOURCE_FILES_PROPERTIES(${_ITEM} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources${_PATH}") + list(APPEND DISCOVERED_RESOURCES ${_ITEM}) + endif () + + endforeach() +endmacro(_RECURSIVELY_SET_PACKAGE_LOCATION _PATH) + +macro(ADD_RESOURCES_TO_OS_X_BUNDLE _RSRC_FOLDER) + + # GLOB the resource directory + file(GLOB _ROOT_ITEMS "${_RSRC_FOLDER}/*") + + # recursively enumerate from the root items + _recursively_set_package_location("" ${_ROOT_ITEMS}) + +endmacro(ADD_RESOURCES_TO_OS_X_BUNDLE _RSRC_FOLDER) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index b4e0e3a244..9e282f4725 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -88,18 +88,15 @@ if (APPLE) # set where in the bundle to put the resources file SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - # grab the directories in resources and put them in the right spot in Resources - file(GLOB RESOURCE_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/resources" "${CMAKE_CURRENT_SOURCE_DIR}/resources/*") - foreach(DIR ${RESOURCE_SUBDIRS}) - if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/resources/${DIR}") - FILE(GLOB DIR_CONTENTS "resources/${DIR}/*") - SET_SOURCE_FILES_PROPERTIES(${DIR_CONTENTS} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/${DIR}") + set(DISCOVERED_RESOURCES "") - SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${DIR_CONTENTS}") - endif() - endforeach() + # use the add_resources_to_os_x_bundle macro to recurse into resources + add_resources_to_os_x_bundle("${CMAKE_CURRENT_SOURCE_DIR}/resources") - SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME}") + # append the discovered resources to our list of interface sources + list(APPEND INTERFACE_SRCS ${DISCOVERED_RESOURCES}) + + set(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME}") endif() # create the executable, make it a bundle on OS X From 62a421361ce243d654aec339366f0dd0751ec41b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 Apr 2015 16:58:34 -0700 Subject: [PATCH 361/401] fix crash in scripts using useAvatar methods --- interface/src/avatar/MyAvatar.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4e09f57267..cd7bedc19e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -987,6 +987,13 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { } void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "useFullAvatarURL", Qt::BlockingQueuedConnection, + Q_ARG(const QUrl&, fullAvatarURL), + Q_ARG(const QString&, modelName)); + return; + } + _useFullAvatar = true; if (_fullAvatarURLFromPreferences != fullAvatarURL) { @@ -1019,6 +1026,15 @@ void MyAvatar::useBodyURL(const QUrl& bodyURL, const QString& 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) { From 10b59350630553a500c912aa9d57f23c6a303787 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 27 Apr 2015 18:11:19 -0700 Subject: [PATCH 362/401] Let QML take care of more of the height/width stuff --- interface/resources/qml/VrMenu.qml | 335 +++++++++++++---------------- 1 file changed, 152 insertions(+), 183 deletions(-) diff --git a/interface/resources/qml/VrMenu.qml b/interface/resources/qml/VrMenu.qml index 4bbcb9c498..01a726d2ba 100644 --- a/interface/resources/qml/VrMenu.qml +++ b/interface/resources/qml/VrMenu.qml @@ -50,6 +50,7 @@ Hifi.VrMenu { property var menuBuilder: Component { Border { + HifiConstants { id: hifi } Component.onCompleted: { menuDepth = root.models.length - 1 if (menuDepth == 0) { @@ -64,213 +65,181 @@ Hifi.VrMenu { border.color: hifi.colors.hifiBlue color: hifi.colors.window property int menuDepth -/* - MouseArea { -// Rectangle { anchors.fill: parent; color: "#7f0000FF"; visible: enabled } - anchors.fill: parent - onClicked: { - while (parent.menuDepth != root.models.length - 1) { - root.popColumn() - } - } - } -*/ + implicitHeight: listView.implicitHeight + 16 + implicitWidth: listView.implicitWidth + 16 - ListView { - spacing: 6 - property int outerMargin: 8 - property real minWidth: 0 - anchors.fill: parent - anchors.margins: outerMargin + Column { id: listView - height: root.height - - onCountChanged: { - recalculateSize() + property real minWidth: 0 + anchors { + top: parent.top + topMargin: 8 + left: parent.left + leftMargin: 8 + right: parent.right + rightMargin: 8 } - function recalculateSize() { - var newHeight = 0 - var newWidth = minWidth; - for (var i = 0; i < children.length; ++i) { - var item = children[i]; - if (!item.visible) { - continue - } - newHeight += item.height + Repeater { + model: root.models[menuDepth] + delegate: Loader { + id: loader + sourceComponent: root.itemBuilder + Binding { + target: loader.item + property: "root" + value: root + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "source" + value: modelData + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "border" + value: listView.parent + when: loader.status == Loader.Ready + } + Binding { + target: loader.item + property: "listView" + value: listView + when: loader.status == Loader.Ready + } } - parent.height = newHeight + outerMargin * 2; - parent.width = newWidth + outerMargin * 2 - } - - highlight: Rectangle { - width: listView.minWidth - 32; - height: 32 - color: hifi.colors.hifiBlue - y: (listView.currentItem) ? listView.currentItem.y : 0; - x: (listView.currentItem) ? listView.currentItem.height : 0; - Behavior on y { - NumberAnimation { - duration: 100 - easing.type: Easing.InOutQuint - } - } - } - - model: root.models[menuDepth] - delegate: Loader { - id: loader - sourceComponent: root.itemBuilder - Binding { - target: loader.item - property: "root" - value: root - when: loader.status == Loader.Ready - } - Binding { - target: loader.item - property: "source" - value: modelData - when: loader.status == Loader.Ready - } - Binding { - target: loader.item - property: "border" - value: listView.parent - when: loader.status == Loader.Ready - } - Binding { - target: loader.item - property: "listView" - value: listView - when: loader.status == Loader.Ready - } } } } } property var itemBuilder: Component { - Text { - id: thisText - x: height + Item { property var source property var root property var listView property var border - text: typedText() - height: implicitHeight - width: implicitWidth - color: source.enabled ? hifi.colors.text : hifi.colors.disabledText - enabled: source.enabled && source.visible + implicitHeight: row.implicitHeight + 4 + implicitWidth: row.implicitWidth + label.height // FIXME uncommenting this line results in menus that have blank spots // rather than having the correct size // visible: source.visible - - onListViewChanged: { - if (listView) { - listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64); - listView.recalculateSize(); + Row { + id: row + spacing: 4 + anchors { + top: parent.top + topMargin: 2 } - } + FontAwesome { + id: check + size: label.height + text: checkText() + color: label.color + function checkText() { + if (!source || source.type != 1 || !source.checkable) { + return ""; + } - onImplicitWidthChanged: { - if (listView) { - listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64); - listView.recalculateSize(); - } - } - - FontAwesome { - visible: source.type == 1 && source.checkable - x: -parent.height - size: parent.height - text: checkText(); - color: parent.color - function checkText() { - if (!source || source.type != 1) { - return ""; - } - // FIXME this works for native QML menus but I don't think it will - // for proxied QML menus - if (source.exclusiveGroup) { - return source.checked ? "\uF05D" : "\uF10C" - } - return source.checked ? "\uF046" : "\uF096" - } - } - - FontAwesome { - size: parent.height - visible: source.type == 2 - x: listView.width - 32 - (hifi.layout.spacing * 2) - text: "\uF0DA" - color: parent.color - } - - function typedText() { - if (source) { - switch(source.type) { - case 2: - return source.title; - case 1: - return source.text; - case 0: - return "-----" + // FIXME this works for native QML menus but I don't think it will + // for proxied QML menus + if (source.exclusiveGroup) { + return source.checked ? "\uF05D" : "\uF10C" + } + return source.checked ? "\uF046" : "\uF096" } } - return "" - } + Text { + id: label + text: typedText() + color: source.enabled ? hifi.colors.text : hifi.colors.disabledText + enabled: source.enabled && source.visible + function typedText() { + if (source) { + switch(source.type) { + case 2: + return source.title; + case 1: + return source.text; + case 0: + return "-----" + } + } + return "" + } + } + } // row + + FontAwesome { + anchors { + top: row.top + } + id: tag + size: label.height + width: implicitWidth + visible: source.type == 2 + x: listView.width - width - 4 + text: "\uF0DA" + color: label.color + } - MouseArea { - id: mouseArea - acceptedButtons: Qt.LeftButton - anchors.left: parent.left - anchors.leftMargin: -32 - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: parent.top - anchors.topMargin: 0 - width: listView.width - hoverEnabled: true - Timer { - id: timer - interval: 1000 - onTriggered: parent.select(); - } - /* - * Uncomment below to have menus auto-popup - * - * FIXME if we enabled timer based menu popup, either the timer has - * to be very very short or after auto popup there has to be a small - * amount of time, or a test if the mouse has moved before a click - * will be accepted, otherwise it's too easy to accidently click on - * something immediately after the auto-popup appears underneath your - * cursor - * - */ - //onEntered: { - // if (source.type == 2 && enabled) { - // timer.start() - // } - //} - //onExited: { - // timer.stop() - //} - onClicked: { - select(); - } - function select() { - timer.stop(); - var popped = false; - while (columns.length - 1 > listView.parent.menuDepth) { - popColumn(); - popped = true; - } + MouseArea { + anchors { + top: parent.top + bottom: parent.bottom + left: parent.left + right: tag.right + } + acceptedButtons: Qt.LeftButton + hoverEnabled: true + Rectangle { + id: highlight + visible: false + anchors.fill: parent + color: "#7f0e7077" + } + Timer { + id: timer + interval: 1000 + onTriggered: parent.select(); + } + onEntered: { + /* + * Uncomment below to have menus auto-popup + * + * FIXME if we enabled timer based menu popup, either the timer has + * to be very very short or after auto popup there has to be a small + * amount of time, or a test if the mouse has moved before a click + * will be accepted, otherwise it's too easy to accidently click on + * something immediately after the auto-popup appears underneath your + * cursor + * + */ + //if (source.type == 2 && enabled) { + // timer.start() + //} + highlight.visible = source.enabled + } + onExited: { + timer.stop() + highlight.visible = false + } + onClicked: { + select(); + } + function select() { + //timer.stop(); + var popped = false; + while (columns.length - 1 > listView.parent.menuDepth) { + popColumn(); + popped = true; + } - if (!popped || source.type != 1) { - parent.root.selectItem(parent.source); - } + if (!popped || source.type != 1) { + parent.root.selectItem(parent.source); + } } } } From 6f441e3490d3c43925b9faf071676e690d51e2f7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Apr 2015 19:07:53 -0700 Subject: [PATCH 363/401] if our Node isn't allowed to create entities in this domain, don't try. --- .../entities/src/EntityScriptingInterface.cpp | 17 +++++++++++++---- libraries/entities/src/EntityTree.cpp | 8 ++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 04da26a1ff..1dbd67f3b2 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -16,6 +16,7 @@ #include "LightEntityItem.h" #include "ModelEntityItem.h" #include "ZoneEntityItem.h" +#include "EntitiesLogging.h" EntityScriptingInterface::EntityScriptingInterface() : @@ -78,19 +79,27 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro EntityItemProperties propertiesWithSimID = properties; - EntityItemID id(NEW_ENTITY, creatorTokenID, false ); + EntityItemID id(NEW_ENTITY, creatorTokenID, false); // If we have a local entity tree set, then also update it. + bool success = true; if (_entityTree) { _entityTree->lockForWrite(); EntityItem* entity = _entityTree->addEntity(id, propertiesWithSimID); - // This Node is creating a new object. If it's in motion, set this Node as the simulator. - setSimId(propertiesWithSimID, entity); + if (entity) { + // This Node is creating a new object. If it's in motion, set this Node as the simulator. + setSimId(propertiesWithSimID, entity); + } else { + qCDebug(entities) << "script failed to add new Entity to local Octree"; + success = false; + } _entityTree->unlock(); } // queue the packet - queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID); + if (success) { + queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID); + } return id; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a63a7ef7c3..436339b3fe 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -192,6 +192,14 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItem* result = NULL; + if (getIsClient()) { + // if our Node isn't allowed to create entities in this domain, don't try. + auto nodeList = DependencyManager::get(); + if (!nodeList->getThisNodeCanRez()) { + return NULL; + } + } + // NOTE: This method is used in the client and the server tree. In the client, it's possible to create EntityItems // that do not yet have known IDs. In the server tree however we don't want to have entities without known IDs. bool recordCreationTime = false; From 19ca543c2c9ab177e5343f88d8595307a00ddd23 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 27 Apr 2015 19:07:53 -0700 Subject: [PATCH 364/401] Cleaning up code and tweaking menu layout --- interface/resources/qml/InterfaceMenu.qml | 1073 --------------------- interface/resources/qml/MessageDialog.qml | 1 - interface/resources/qml/TestMenu.qml | 115 +++ interface/resources/qml/VrMenu.qml | 17 +- libraries/ui/src/OffscreenUi.cpp | 1 - tests/ui/src/main.cpp | 6 +- 6 files changed, 128 insertions(+), 1085 deletions(-) delete mode 100644 interface/resources/qml/InterfaceMenu.qml create mode 100644 interface/resources/qml/TestMenu.qml diff --git a/interface/resources/qml/InterfaceMenu.qml b/interface/resources/qml/InterfaceMenu.qml deleted file mode 100644 index 2a5ed8d212..0000000000 --- a/interface/resources/qml/InterfaceMenu.qml +++ /dev/null @@ -1,1073 +0,0 @@ -import QtQuick 2.4 -import QtQuick.Controls 1.3 -import Hifi 1.0 - -// Currently for testing a pure QML replacement menu -Item { - Item { - objectName: "AllActions" - Action { - id: aboutApp - objectName: "HifiAction_" + MenuConstants.AboutApp - text: qsTr("About Interface") - } - - // - // File Menu - // - Action { - id: login - objectName: "HifiAction_" + MenuConstants.Login - text: qsTr("Login") - } - Action { - id: quit - objectName: "HifiAction_" + MenuConstants.Quit - text: qsTr("Quit") - //shortcut: StandardKey.Quit - shortcut: "Ctrl+Q" - } - - // Scripts - Action { - id: loadScript - objectName: "HifiAction_" + MenuConstants.LoadScript - text: qsTr("Open and Run Script File...") - shortcut: "Ctrl+O" - onTriggered: { - console.log("Shortcut ctrl+o hit"); - } - } - Action { - id: loadScriptURL - objectName: "HifiAction_" + MenuConstants.LoadScriptURL - text: qsTr("Open and Run Script from URL...") - shortcut: "Ctrl+Shift+O" - } - Action { - id: reloadAllScripts - objectName: "HifiAction_" + MenuConstants.ReloadAllScripts - text: qsTr("Reload All Scripts") - } - Action { - id: runningScripts - objectName: "HifiAction_" + MenuConstants.RunningScripts - text: qsTr("Running Scripts") - } - Action { - id: stopAllScripts - objectName: "HifiAction_" + MenuConstants.StopAllScripts - text: qsTr("Stop All Scripts") - } - - // Locations - Action { - id: bookmarkLocation - objectName: "HifiAction_" + MenuConstants.BookmarkLocation - text: qsTr("Bookmark Location") - } - Action { - id: bookmarks - objectName: "HifiAction_" + MenuConstants.Bookmarks - text: qsTr("Bookmarks") - } - Action { - id: addressBar - objectName: "HifiAction_" + MenuConstants.AddressBar - text: qsTr("Show Address Bar") - } - - // - // Edit menu - // - Action { - id: undo - text: "Undo" - shortcut: StandardKey.Undo - } - - Action { - id: redo - text: "Redo" - shortcut: StandardKey.Redo - } - - Action { - id: animations - objectName: "HifiAction_" + MenuConstants.Animations - text: qsTr("Animations...") - } - Action { - id: attachments - objectName: "HifiAction_" + MenuConstants.Attachments - text: qsTr("Attachments...") - } - - // - // Tools menu - // - Action { - id: scriptEditor - objectName: "HifiAction_" + MenuConstants.ScriptEditor - text: qsTr("Script Editor...") - } - Action { - id: controlWithSpeech - objectName: "HifiAction_" + MenuConstants.ControlWithSpeech - text: qsTr("Control With Speech") - } - Action { - id: chat - objectName: "HifiAction_" + MenuConstants.Chat - text: qsTr("Chat...") - } - Action { - id: addRemoveFriends - objectName: "HifiAction_" + MenuConstants.AddRemoveFriends - text: qsTr("Add/Remove Friends...") - } - ExclusiveGroup { - Action { - id: visibleToEveryone - objectName: "HifiAction_" + MenuConstants.VisibleToEveryone - text: qsTr("Everyone") - } - Action { - id: visibleToFriends - objectName: "HifiAction_" + MenuConstants.VisibleToFriends - text: qsTr("Friends") - } - Action { - id: visibleToNoOne - objectName: "HifiAction_" + MenuConstants.VisibleToNoOne - text: qsTr("No one") - } - } - Action { - id: toolWindow - objectName: "HifiAction_" + MenuConstants.ToolWindow - text: qsTr("Tool Window") - } - Action { - id: javascriptConsole - objectName: "HifiAction_" + MenuConstants.JavascriptConsole - text: qsTr("Console...") - } - Action { - id: resetSensors - objectName: "HifiAction_" + MenuConstants.ResetSensors - text: qsTr("Reset Sensors") - } - - - - - - - - - - - - - Action { - id: alignForearmsWithWrists - objectName: "HifiAction_" + MenuConstants.AlignForearmsWithWrists - text: qsTr("Align Forearms with Wrists") - checkable: true - } - Action { - id: alternateIK - objectName: "HifiAction_" + MenuConstants.AlternateIK - text: qsTr("Alternate IK") - checkable: true - } - Action { - id: ambientOcclusion - objectName: "HifiAction_" + MenuConstants.AmbientOcclusion - text: qsTr("Ambient Occlusion") - checkable: true - } - Action { - id: atmosphere - objectName: "HifiAction_" + MenuConstants.Atmosphere - text: qsTr("Atmosphere") - } - Action { - id: audioNoiseReduction - objectName: "HifiAction_" + MenuConstants.AudioNoiseReduction - text: qsTr("Audio Noise Reduction") - checkable: true - } - Action { - id: audioScope - objectName: "HifiAction_" + MenuConstants.AudioScope - text: qsTr("Show Scope") - checkable: true - } - ExclusiveGroup { - Action { - id: audioScopeFiveFrames - objectName: "HifiAction_" + MenuConstants.AudioScopeFiveFrames - text: qsTr("Five") - checkable: true - checked: true - } - Action { - id: audioScopeFiftyFrames - objectName: "HifiAction_" + MenuConstants.AudioScopeFiftyFrames - text: qsTr("Fifty") - checkable: true - } - Action { - id: audioScopeTwentyFrames - objectName: "HifiAction_" + MenuConstants.AudioScopeTwentyFrames - text: qsTr("Twenty") - checkable: true - } - } - Action { - id: audioScopePause - objectName: "HifiAction_" + MenuConstants.AudioScopePause - text: qsTr("Pause Scope") - checkable: true - } - Action { - id: audioStats - objectName: "HifiAction_" + MenuConstants.AudioStats - text: qsTr("Audio Stats") - checkable: true - } - Action { - id: audioStatsShowInjectedStreams - objectName: "HifiAction_" + MenuConstants.AudioStatsShowInjectedStreams - text: qsTr("Audio Stats Show Injected Streams") - checkable: true - } - Action { - id: bandwidthDetails - objectName: "HifiAction_" + MenuConstants.BandwidthDetails - text: qsTr("Bandwidth Details") - checkable: true - } - Action { - id: blueSpeechSphere - objectName: "HifiAction_" + MenuConstants.BlueSpeechSphere - text: qsTr("Blue Sphere While Speaking") - checkable: true - } - Action { - id: cascadedShadows - objectName: "HifiAction_" + MenuConstants.CascadedShadows - text: qsTr("Cascaded") - } - Action { - id: cachesSize - objectName: "HifiAction_" + MenuConstants.CachesSize - text: qsTr("RAM Caches Size") - } - Action { - id: collisions - objectName: "HifiAction_" + MenuConstants.Collisions - text: qsTr("Collisions") - } - Action { - id: copyAddress - objectName: "HifiAction_" + MenuConstants.CopyAddress - text: qsTr("Copy Address to Clipboard") - } - Action { - id: copyPath - objectName: "HifiAction_" + MenuConstants.CopyPath - text: qsTr("Copy Path to Clipboard") - } - Action { - id: decreaseAvatarSize - objectName: "HifiAction_" + MenuConstants.DecreaseAvatarSize - text: qsTr("Decrease Avatar Size") - } - Action { - id: deleteBookmark - objectName: "HifiAction_" + MenuConstants.DeleteBookmark - text: qsTr("Delete Bookmark...") - } - Action { - id: disableActivityLogger - objectName: "HifiAction_" + MenuConstants.DisableActivityLogger - text: qsTr("Disable Activity Logger") - } - Action { - id: disableLightEntities - objectName: "HifiAction_" + MenuConstants.DisableLightEntities - text: qsTr("Disable Light Entities") - } - Action { - id: disableNackPackets - objectName: "HifiAction_" + MenuConstants.DisableNackPackets - text: qsTr("Disable NACK Packets") - } - Action { - id: diskCacheEditor - objectName: "HifiAction_" + MenuConstants.DiskCacheEditor - text: qsTr("Disk Cache Editor") - } - Action { - id: displayHands - objectName: "HifiAction_" + MenuConstants.DisplayHands - text: qsTr("Show Hand Info") - } - Action { - id: displayHandTargets - objectName: "HifiAction_" + MenuConstants.DisplayHandTargets - text: qsTr("Show Hand Targets") - } - Action { - id: displayModelBounds - objectName: "HifiAction_" + MenuConstants.DisplayModelBounds - text: qsTr("Display Model Bounds") - } - Action { - id: displayModelTriangles - objectName: "HifiAction_" + MenuConstants.DisplayModelTriangles - text: qsTr("Display Model Triangles") - } - Action { - id: displayModelElementChildProxies - objectName: "HifiAction_" + MenuConstants.DisplayModelElementChildProxies - text: qsTr("Display Model Element Children") - } - Action { - id: displayModelElementProxy - objectName: "HifiAction_" + MenuConstants.DisplayModelElementProxy - text: qsTr("Display Model Element Bounds") - } - Action { - id: displayDebugTimingDetails - objectName: "HifiAction_" + MenuConstants.DisplayDebugTimingDetails - text: qsTr("Display Timing Details") - } - Action { - id: dontDoPrecisionPicking - objectName: "HifiAction_" + MenuConstants.DontDoPrecisionPicking - text: qsTr("Don't Do Precision Picking") - } - Action { - id: dontFadeOnOctreeServerChanges - objectName: "HifiAction_" + MenuConstants.DontFadeOnOctreeServerChanges - text: qsTr("Don't Fade In/Out on Octree Server Changes") - } - Action { - id: dontRenderEntitiesAsScene - objectName: "HifiAction_" + MenuConstants.DontRenderEntitiesAsScene - text: qsTr("Don't Render Entities as Scene") - } - Action { - id: echoLocalAudio - objectName: "HifiAction_" + MenuConstants.EchoLocalAudio - text: qsTr("Echo Local Audio") - } - Action { - id: echoServerAudio - objectName: "HifiAction_" + MenuConstants.EchoServerAudio - text: qsTr("Echo Server Audio") - } - Action { - id: editEntitiesHelp - objectName: "HifiAction_" + MenuConstants.EditEntitiesHelp - text: qsTr("Edit Entities Help...") - } - Action { - id: enable3DTVMode - objectName: "HifiAction_" + MenuConstants.Enable3DTVMode - text: qsTr("Enable 3DTV Mode") - } - Action { - id: enableCharacterController - objectName: "HifiAction_" + MenuConstants.EnableCharacterController - text: qsTr("Enable avatar collisions") - } - Action { - id: enableGlowEffect - objectName: "HifiAction_" + MenuConstants.EnableGlowEffect - text: qsTr("Enable Glow Effect (Warning: Poor Oculus Performance)") - } - Action { - id: enableVRMode - objectName: "HifiAction_" + MenuConstants.EnableVRMode - text: qsTr("Enable VR Mode") - } - Action { - id: expandMyAvatarSimulateTiming - objectName: "HifiAction_" + MenuConstants.ExpandMyAvatarSimulateTiming - text: qsTr("Expand /myAvatar/simulation") - } - Action { - id: expandMyAvatarTiming - objectName: "HifiAction_" + MenuConstants.ExpandMyAvatarTiming - text: qsTr("Expand /myAvatar") - } - Action { - id: expandOtherAvatarTiming - objectName: "HifiAction_" + MenuConstants.ExpandOtherAvatarTiming - text: qsTr("Expand /otherAvatar") - } - Action { - id: expandPaintGLTiming - objectName: "HifiAction_" + MenuConstants.ExpandPaintGLTiming - text: qsTr("Expand /paintGL") - } - Action { - id: expandUpdateTiming - objectName: "HifiAction_" + MenuConstants.ExpandUpdateTiming - text: qsTr("Expand /update") - } - Action { - id: faceshift - objectName: "HifiAction_" + MenuConstants.Faceshift - text: qsTr("Faceshift") - } - Action { - id: filterSixense - objectName: "HifiAction_" + MenuConstants.FilterSixense - text: qsTr("Smooth Sixense Movement") - } - Action { - id: firstPerson - objectName: "HifiAction_" + MenuConstants.FirstPerson - text: qsTr("First Person") - } - Action { - id: frameTimer - objectName: "HifiAction_" + MenuConstants.FrameTimer - text: qsTr("Show Timer") - } - Action { - id: fullscreen - objectName: "HifiAction_" + MenuConstants.Fullscreen - text: qsTr("Fullscreen") - } - Action { - id: fullscreenMirror - objectName: "HifiAction_" + MenuConstants.FullscreenMirror - text: qsTr("Fullscreen Mirror") - } - Action { - id: glowWhenSpeaking - objectName: "HifiAction_" + MenuConstants.GlowWhenSpeaking - text: qsTr("Glow When Speaking") - } - Action { - id: namesAboveHeads - objectName: "HifiAction_" + MenuConstants.NamesAboveHeads - text: qsTr("Names Above Heads") - } - Action { - id: goToUser - objectName: "HifiAction_" + MenuConstants.GoToUser - text: qsTr("Go To User") - } - Action { - id: hMDTools - objectName: "HifiAction_" + MenuConstants.HMDTools - text: qsTr("HMD Tools") - } - Action { - id: increaseAvatarSize - objectName: "HifiAction_" + MenuConstants.IncreaseAvatarSize - text: qsTr("Increase Avatar Size") - } - Action { - id: keyboardMotorControl - objectName: "HifiAction_" + MenuConstants.KeyboardMotorControl - text: qsTr("Enable Keyboard Motor Control") - } - Action { - id: leapMotionOnHMD - objectName: "HifiAction_" + MenuConstants.LeapMotionOnHMD - text: qsTr("Leap Motion on HMD") - } - Action { - id: loadRSSDKFile - objectName: "HifiAction_" + MenuConstants.LoadRSSDKFile - text: qsTr("Load .rssdk file") - } - Action { - id: lodTools - objectName: "HifiAction_" + MenuConstants.LodTools - text: qsTr("LOD Tools") - } - Action { - id: log - objectName: "HifiAction_" + MenuConstants.Log - text: qsTr("Log") - } - Action { - id: lowVelocityFilter - objectName: "HifiAction_" + MenuConstants.LowVelocityFilter - text: qsTr("Low Velocity Filter") - } - Action { - id: mirror - objectName: "HifiAction_" + MenuConstants.Mirror - text: qsTr("Mirror") - } - Action { - id: muteAudio - objectName: "HifiAction_" + MenuConstants.MuteAudio - text: qsTr("Mute Microphone") - } - Action { - id: muteEnvironment - objectName: "HifiAction_" + MenuConstants.MuteEnvironment - text: qsTr("Mute Environment") - } - Action { - id: noFaceTracking - objectName: "HifiAction_" + MenuConstants.NoFaceTracking - text: qsTr("None") - } - Action { - id: noShadows - objectName: "HifiAction_" + MenuConstants.NoShadows - text: qsTr("None") - } - Action { - id: octreeStats - objectName: "HifiAction_" + MenuConstants.OctreeStats - text: qsTr("Entity Statistics") - } - Action { - id: offAxisProjection - objectName: "HifiAction_" + MenuConstants.OffAxisProjection - text: qsTr("Off-Axis Projection") - } - Action { - id: onlyDisplayTopTen - objectName: "HifiAction_" + MenuConstants.OnlyDisplayTopTen - text: qsTr("Only Display Top Ten") - } - Action { - id: packageModel - objectName: "HifiAction_" + MenuConstants.PackageModel - text: qsTr("Package Model...") - } - Action { - id: pair - objectName: "HifiAction_" + MenuConstants.Pair - text: qsTr("Pair") - } - Action { - id: pipelineWarnings - objectName: "HifiAction_" + MenuConstants.PipelineWarnings - text: qsTr("Log Render Pipeline Warnings") - } - Action { - id: preferences - objectName: "HifiAction_" + MenuConstants.Preferences - text: qsTr("Preferences...") - } - Action { - id: renderBoundingCollisionShapes - objectName: "HifiAction_" + MenuConstants.RenderBoundingCollisionShapes - text: qsTr("Show Bounding Collision Shapes") - checkable: true - } - Action { - id: renderFocusIndicator - objectName: "HifiAction_" + MenuConstants.RenderFocusIndicator - text: qsTr("Show Eye Focus") - checkable: true - } - Action { - id: renderHeadCollisionShapes - objectName: "HifiAction_" + MenuConstants.RenderHeadCollisionShapes - text: qsTr("Show Head Collision Shapes") - checkable: true - } - Action { - id: renderLookAtVectors - objectName: "HifiAction_" + MenuConstants.RenderLookAtVectors - text: qsTr("Show Look-at Vectors") - checkable: true - } - Action { - id: renderSkeletonCollisionShapes - objectName: "HifiAction_" + MenuConstants.RenderSkeletonCollisionShapes - text: qsTr("Show Skeleton Collision Shapes") - checkable: true - } - ExclusiveGroup { - Action { - id: renderTargetFramerateUnlimited - objectName: "HifiAction_" + MenuConstants.RenderTargetFramerateUnlimited - text: qsTr("Unlimited") - checked: true - checkable: true - } - Action { - id: renderTargetFramerate60 - objectName: "HifiAction_" + MenuConstants.RenderTargetFramerate60 - text: qsTr("60") - checkable: true - } - Action { - id: renderTargetFramerate50 - objectName: "HifiAction_" + MenuConstants.RenderTargetFramerate50 - text: qsTr("50") - checkable: true - } - Action { - id: renderTargetFramerate40 - objectName: "HifiAction_" + MenuConstants.RenderTargetFramerate40 - text: qsTr("40") - checkable: true - } - Action { - id: renderTargetFramerate30 - objectName: "HifiAction_" + MenuConstants.RenderTargetFramerate30 - text: qsTr("30") - checkable: true - } - } - Action { - id: renderTargetFramerateVSyncOn - objectName: "HifiAction_" + MenuConstants.RenderTargetFramerateVSyncOn - text: qsTr("V-Sync On") - checkable: true - } - Action { - id: renderResolution - objectName: "HifiAction_" + MenuConstants.RenderResolution - text: qsTr("Scale Resolution") - } - ExclusiveGroup { - Action { - id: renderResolutionOne - objectName: "HifiAction_" + MenuConstants.RenderResolutionOne - text: qsTr("1") - checkable: true - checked: true - } - Action { - id: renderResolutionTwoThird - objectName: "HifiAction_" + MenuConstants.RenderResolutionTwoThird - text: qsTr("2/3") - checkable: true - } - Action { - id: renderResolutionHalf - objectName: "HifiAction_" + MenuConstants.RenderResolutionHalf - text: qsTr("1/2") - checkable: true - } - Action { - id: renderResolutionThird - objectName: "HifiAction_" + MenuConstants.RenderResolutionThird - text: qsTr("1/3") - checkable: true - } - Action { - id: renderResolutionQuarter - objectName: "HifiAction_" + MenuConstants.RenderResolutionQuarter - text: qsTr("1/4") - checkable: true - } - } - Action { - id: renderAmbientLight - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight - text: qsTr("Ambient Light") - } - ExclusiveGroup { - Action { - id: renderAmbientLightGlobal - objectName: "HifiAction_" + MenuConstants.RenderAmbientLightGlobal - text: qsTr("Global") - checked: true - checkable: true - } - Action { - id: renderAmbientLight0 - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight0 - text: qsTr("OLD_TOWN_SQUARE") - checkable: true - } - Action { - id: renderAmbientLight1 - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight1 - text: qsTr("GRACE_CATHEDRAL") - checkable: true - } - Action { - id: renderAmbientLight2 - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight2 - text: qsTr("EUCALYPTUS_GROVE") - checkable: true - } - Action { - id: renderAmbientLight3 - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight3 - text: qsTr("ST_PETERS_BASILICA") - checkable: true - } - Action { - id: renderAmbientLight4 - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight4 - text: qsTr("UFFIZI_GALLERY") - checkable: true - } - Action { - id: renderAmbientLight5 - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight5 - text: qsTr("GALILEOS_TOMB") - checkable: true - } - Action { - id: renderAmbientLight6 - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight6 - text: qsTr("VINE_STREET_KITCHEN") - checkable: true - } - Action { - id: renderAmbientLight7 - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight7 - text: qsTr("BREEZEWAY") - checkable: true - } - Action { - id: renderAmbientLight8 - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight8 - text: qsTr("CAMPUS_SUNSET") - checkable: true - } - Action { - id: renderAmbientLight9 - objectName: "HifiAction_" + MenuConstants.RenderAmbientLight9 - text: qsTr("FUNSTON_BEACH_SUNSET") - checkable: true - } - } - Action { - id: resetAvatarSize - objectName: "HifiAction_" + MenuConstants.ResetAvatarSize - text: qsTr("Reset Avatar Size") - } - Action { - id: runTimingTests - objectName: "HifiAction_" + MenuConstants.RunTimingTests - text: qsTr("Run Timing Tests") - } - Action { - id: scriptedMotorControl - objectName: "HifiAction_" + MenuConstants.ScriptedMotorControl - text: qsTr("Enable Scripted Motor Control") - } - Action { - id: showBordersEntityNodes - objectName: "HifiAction_" + MenuConstants.ShowBordersEntityNodes - text: qsTr("Show Entity Nodes") - } - Action { - id: showIKConstraints - objectName: "HifiAction_" + MenuConstants.ShowIKConstraints - text: qsTr("Show IK Constraints") - } - Action { - id: simpleShadows - objectName: "HifiAction_" + MenuConstants.SimpleShadows - text: qsTr("Simple") - } - Action { - id: sixenseEnabled - objectName: "HifiAction_" + MenuConstants.SixenseEnabled - text: qsTr("Enable Hydra Support") - } - Action { - id: sixenseMouseInput - objectName: "HifiAction_" + MenuConstants.SixenseMouseInput - text: qsTr("Enable Sixense Mouse Input") - } - Action { - id: sixenseLasers - objectName: "HifiAction_" + MenuConstants.SixenseLasers - text: qsTr("Enable Sixense UI Lasers") - } - Action { - id: shiftHipsForIdleAnimations - objectName: "HifiAction_" + MenuConstants.ShiftHipsForIdleAnimations - text: qsTr("Shift hips for idle animations") - } - Action { - id: stars - objectName: "HifiAction_" + MenuConstants.Stars - text: qsTr("Stars") - } - Action { - id: stats - objectName: "HifiAction_" + MenuConstants.Stats - text: qsTr("Stats") - } - Action { - id: stereoAudio - objectName: "HifiAction_" + MenuConstants.StereoAudio - text: qsTr("Stereo Audio (disables spatial sound)") - } - Action { - id: suppressShortTimings - objectName: "HifiAction_" + MenuConstants.SuppressShortTimings - text: qsTr("Suppress Timings Less than 10ms") - } - Action { - id: testPing - objectName: "HifiAction_" + MenuConstants.TestPing - text: qsTr("Test Ping") - } - Action { - id: transmitterDrive - objectName: "HifiAction_" + MenuConstants.TransmitterDrive - text: qsTr("Transmitter Drive") - } - Action { - id: turnWithHead - objectName: "HifiAction_" + MenuConstants.TurnWithHead - text: qsTr("Turn using Head") - } - Action { - id: useAudioForMouth - objectName: "HifiAction_" + MenuConstants.UseAudioForMouth - text: qsTr("Use Audio for Mouth") - } - Action { - id: useCamera - objectName: "HifiAction_" + MenuConstants.UseCamera - text: qsTr("Use Camera") - } - Action { - id: velocityFilter - objectName: "HifiAction_" + MenuConstants.VelocityFilter - text: qsTr("Velocity Filter") - } - Action { - id: wireframe - objectName: "HifiAction_" + MenuConstants.Wireframe - text: qsTr("Wireframe") - } - } - - Menu { - objectName: "rootMenu"; - Menu { - title: "File" - MenuItem { - action: login - } - MenuItem { - action: aboutApp - } - MenuSeparator {} MenuItem { text: "Scripts"; enabled: false } - MenuItem { action: loadScript; } - MenuItem { action: loadScriptURL; } - MenuItem { action: stopAllScripts; } - MenuItem { action: reloadAllScripts; } - MenuItem { action: runningScripts; } - MenuSeparator {} MenuItem { text: "Locations"; enabled: false } - MenuItem { action: addressBar; } - MenuItem { action: copyAddress; } - MenuItem { action: copyPath; } - MenuSeparator {} - MenuItem { action: quit; } - } - Menu { - title: "Edit" - MenuItem { action: preferences; } - MenuItem { action: animations; } - } - Menu { - title: "Tools" - MenuItem { action: scriptEditor; } - MenuItem { action: controlWithSpeech; } - MenuItem { action: chat; } - MenuItem { action: addRemoveFriends; } - Menu { - title: "I Am Visible To" - MenuItem { action: visibleToEveryone; } - MenuItem { action: visibleToFriends; } - MenuItem { action: visibleToNoOne; } - } - MenuItem { action: toolWindow; } - MenuItem { action: javascriptConsole; } - MenuItem { action: resetSensors; } - MenuItem { action: packageModel; } - } - Menu { - title: "Avatar" - Menu { - title: "Size" - MenuItem { action: increaseAvatarSize; } - MenuItem { action: decreaseAvatarSize; } - MenuItem { action: resetAvatarSize; } - } - MenuItem { action: keyboardMotorControl; } - MenuItem { action: scriptedMotorControl; } - MenuItem { action: namesAboveHeads; } - MenuItem { action: glowWhenSpeaking; } - MenuItem { action: blueSpeechSphere; } - MenuItem { action: enableCharacterController; } - MenuItem { action: shiftHipsForIdleAnimations; } - } - Menu { - title: "View" - MenuItem { action: fullscreen; } - MenuItem { action: firstPerson; } - MenuItem { action: mirror; } - MenuItem { action: fullscreenMirror; } - MenuItem { action: hMDTools; } - MenuItem { action: enableVRMode; } - MenuItem { action: enable3DTVMode; } - MenuItem { action: showBordersEntityNodes; } - MenuItem { action: offAxisProjection; } - MenuItem { action: turnWithHead; } - MenuItem { action: stats; } - MenuItem { action: log; } - MenuItem { action: bandwidthDetails; } - MenuItem { action: octreeStats; } - } - Menu { - title: "Developer" - Menu { - title: "Render" - MenuItem { action: atmosphere; } - MenuItem { action: ambientOcclusion; } - MenuItem { action: dontFadeOnOctreeServerChanges; } - Menu { - title: "Ambient Light" - MenuItem { action: renderAmbientLightGlobal; } - MenuItem { action: renderAmbientLight0; } - MenuItem { action: renderAmbientLight1; } - MenuItem { action: renderAmbientLight2; } - MenuItem { action: renderAmbientLight3; } - MenuItem { action: renderAmbientLight4; } - MenuItem { action: renderAmbientLight5; } - MenuItem { action: renderAmbientLight6; } - MenuItem { action: renderAmbientLight7; } - MenuItem { action: renderAmbientLight8; } - MenuItem { action: renderAmbientLight9; } - } - Menu { - title: "Shadows" - MenuItem { action: noShadows; } - MenuItem { action: simpleShadows; } - MenuItem { action: cascadedShadows; } - } - Menu { - title: "Framerate" - MenuItem { action: renderTargetFramerateUnlimited; } - MenuItem { action: renderTargetFramerate60; } - MenuItem { action: renderTargetFramerate50; } - MenuItem { action: renderTargetFramerate40; } - MenuItem { action: renderTargetFramerate30; } - } - MenuItem { action: renderTargetFramerateVSyncOn; } - Menu { - title: "Scale Resolution" - MenuItem { action: renderResolutionOne; } - MenuItem { action: renderResolutionTwoThird; } - MenuItem { action: renderResolutionHalf; } - MenuItem { action: renderResolutionThird; } - MenuItem { action: renderResolutionQuarter; } - } - MenuItem { action: stars; } - MenuItem { action: enableGlowEffect; } - MenuItem { action: wireframe; } - MenuItem { action: lodTools; } - } - Menu { - title: "Avatar" - Menu { - title: "Face Tracking" - MenuItem { action: noFaceTracking; } - MenuItem { action: faceshift; } - MenuItem { action: useCamera; } - MenuItem { action: useAudioForMouth; } - MenuItem { action: velocityFilter; } - } - MenuItem { action: renderSkeletonCollisionShapes; } - MenuItem { action: renderHeadCollisionShapes; } - MenuItem { action: renderBoundingCollisionShapes; } - MenuItem { action: renderLookAtVectors; } - MenuItem { action: renderFocusIndicator; } - } - Menu { - title: "Hands" - MenuItem { action: alignForearmsWithWrists; } - MenuItem { action: alternateIK; } - MenuItem { action: displayHands; } - MenuItem { action: displayHandTargets; } - MenuItem { action: showIKConstraints; } - Menu { - title: "Sixense" - MenuItem { action: sixenseEnabled; } - MenuItem { action: filterSixense; } - MenuItem { action: lowVelocityFilter; } - MenuItem { action: sixenseMouseInput; } - MenuItem { action: sixenseLasers; } - } - Menu { - title: "Leap Motion" - MenuItem { action: leapMotionOnHMD; } - } - MenuItem { action: loadRSSDKFile; } - } - Menu { - title: "Network" - MenuItem { action: disableNackPackets; } - MenuItem { action: disableActivityLogger; } - MenuItem { action: cachesSize; } - MenuItem { action: diskCacheEditor; } - } - Menu { - title: "Timing and Stats" - Menu { - title: "Performance Timer" - MenuItem { action: displayDebugTimingDetails; } - MenuItem { action: onlyDisplayTopTen; } - MenuItem { action: expandUpdateTiming; } - MenuItem { action: expandMyAvatarTiming; } - MenuItem { action: expandMyAvatarSimulateTiming; } - MenuItem { action: expandOtherAvatarTiming; } - MenuItem { action: expandPaintGLTiming; } - } - MenuItem { action: testPing; } - MenuItem { action: frameTimer; } - MenuItem { action: runTimingTests; } - MenuItem { action: pipelineWarnings; } - MenuItem { action: suppressShortTimings; } - } - Menu { - title: "Audio" - MenuItem { action: audioNoiseReduction; } - MenuItem { action: echoServerAudio; } - MenuItem { action: echoLocalAudio; } - MenuItem { action: stereoAudio; } - MenuItem { action: muteAudio; } - MenuItem { action: muteEnvironment; } - Menu { - title: "Audio Scope" - MenuItem { action: audioScope; } - MenuItem { action: audioScopePause; } - MenuSeparator {} MenuItem { text: "Audio Scope"; enabled: false; } - MenuItem { action: audioScopeFiveFrames; } - MenuItem { action: audioScopeTwentyFrames; } - MenuItem { action: audioScopeFiftyFrames; } - } - MenuItem { action: audioStats; } - MenuItem { action: audioStatsShowInjectedStreams; } - } - } - Menu { - title: "Help" - MenuItem { action: editEntitiesHelp; } - MenuItem { action: aboutApp; } - } - } -} diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml index 02f1e4716f..dd410b8070 100644 --- a/interface/resources/qml/MessageDialog.qml +++ b/interface/resources/qml/MessageDialog.qml @@ -325,7 +325,6 @@ Dialog { case Qt.Key_Enter: case Qt.Key_Return: - console.log("Accepting"); event.accepted = true content.accept() break diff --git a/interface/resources/qml/TestMenu.qml b/interface/resources/qml/TestMenu.qml new file mode 100644 index 0000000000..5aff18b421 --- /dev/null +++ b/interface/resources/qml/TestMenu.qml @@ -0,0 +1,115 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.3 +import Hifi 1.0 + +// Currently for testing a pure QML replacement menu +Item { + Item { + objectName: "AllActions" + Action { + id: aboutApp + objectName: "HifiAction_" + MenuConstants.AboutApp + text: qsTr("About Interface") + } + + // + // File Menu + // + Action { + id: login + objectName: "HifiAction_" + MenuConstants.Login + text: qsTr("Login") + } + Action { + id: quit + objectName: "HifiAction_" + MenuConstants.Quit + text: qsTr("Quit") + //shortcut: StandardKey.Quit + shortcut: "Ctrl+Q" + } + + + // + // Edit menu + // + Action { + id: undo + text: "Undo" + shortcut: StandardKey.Undo + } + + Action { + id: redo + text: "Redo" + shortcut: StandardKey.Redo + } + + Action { + id: animations + objectName: "HifiAction_" + MenuConstants.Animations + text: qsTr("Animations...") + } + Action { + id: attachments + text: qsTr("Attachments...") + } + Action { + id: explode + text: qsTr("Explode on quit") + checkable: true + checked: true + } + Action { + id: freeze + text: qsTr("Freeze on quit") + checkable: true + checked: false + } + ExclusiveGroup { + Action { + id: visibleToEveryone + objectName: "HifiAction_" + MenuConstants.VisibleToEveryone + text: qsTr("Everyone") + checkable: true + checked: true + } + Action { + id: visibleToFriends + objectName: "HifiAction_" + MenuConstants.VisibleToFriends + text: qsTr("Friends") + checkable: true + } + Action { + id: visibleToNoOne + objectName: "HifiAction_" + MenuConstants.VisibleToNoOne + text: qsTr("No one") + checkable: true + } + } + } + + Menu { + objectName: "rootMenu"; + Menu { + title: "File" + MenuItem { action: login } + MenuItem { action: explode } + MenuItem { action: freeze } + MenuItem { action: quit } + } + Menu { + title: "Tools" + Menu { + title: "I Am Visible To" + MenuItem { action: visibleToEveryone } + MenuItem { action: visibleToFriends } + MenuItem { action: visibleToNoOne } + } + MenuItem { action: animations } + } + Menu { + title: "Help" + MenuItem { action: aboutApp } + } + } +} diff --git a/interface/resources/qml/VrMenu.qml b/interface/resources/qml/VrMenu.qml index 01a726d2ba..d81d79aa0b 100644 --- a/interface/resources/qml/VrMenu.qml +++ b/interface/resources/qml/VrMenu.qml @@ -128,13 +128,16 @@ Hifi.VrMenu { // visible: source.visible Row { id: row - spacing: 4 + spacing: 2 anchors { top: parent.top topMargin: 2 } + Spacer { size: 4 } FontAwesome { id: check + verticalAlignment: Text.AlignVCenter + y: 2 size: label.height text: checkText() color: label.color @@ -191,6 +194,7 @@ Hifi.VrMenu { bottom: parent.bottom left: parent.left right: tag.right + rightMargin: -4 } acceptedButtons: Qt.LeftButton hoverEnabled: true @@ -263,23 +267,22 @@ Hifi.VrMenu { function popColumn() { if (columns.length > 0) { var curColumn = columns.pop(); - console.log(curColumn); curColumn.visible = false; curColumn.destroy(); models.pop(); - } - + } + if (columns.length == 0) { enabled = false; return; - } + } curColumn = lastColumn(); curColumn.enabled = true; curColumn.opacity = 1.0; curColumn.forceActiveFocus(); } - + function selectItem(source) { switch (source.type) { case 2: @@ -317,7 +320,7 @@ Hifi.VrMenu { root.popColumn(); } else { root.enabled = false; - } + } } } } diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 8ba7b514e4..d9c7cd890d 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -426,7 +426,6 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::functionfindChild(name); } if (item) { - qDebug() << "Turning item " << !item->isEnabled(); item->setEnabled(!item->isEnabled()); } } diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index aaca2efa2a..a5bc50b288 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -348,7 +348,7 @@ public: #else offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); offscreenUi->load(QUrl("TestRoot.qml")); - offscreenUi->load(QUrl("InterfaceMenu.qml")); + offscreenUi->load(QUrl("TestMenu.qml")); // Requires a root menu to have been loaded before it can load VrMenu::load(); #endif @@ -470,7 +470,7 @@ void QTestWindow::renderQml() { const char * LOG_FILTER_RULES = R"V0G0N( -*.debug=false +hifi.offscreen.focus.debug=false qt.quick.mouse.debug=false )V0G0N"; @@ -484,7 +484,7 @@ qt.quick.mouse.debug=false int main(int argc, char** argv) { QGuiApplication app(argc, argv); -// QLoggingCategory::setFilterRules(LOG_FILTER_RULES); + QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QTestWindow window; app.exec(); return 0; From d6eb04c3b07d8b1c613138720a39606bebd363bf Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 27 Apr 2015 21:43:57 -0700 Subject: [PATCH 365/401] Fix audio-driven mouth viewed by others --- interface/src/avatar/Head.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index b84fd23614..41c2e9b54c 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -73,20 +73,20 @@ void Head::reset() { } void Head::simulate(float deltaTime, bool isMine, bool billboard) { + // Update audio trailing average for rendering facial animations + const float AUDIO_AVERAGING_SECS = 0.05f; + const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; + _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f)); + + if (_longTermAverageLoudness == -1.0) { + _longTermAverageLoudness = _averageLoudness; + } else { + _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f)); + } + if (isMine) { MyAvatar* myAvatar = static_cast(_owningAvatar); - // Update audio trailing average for rendering facial animations - const float AUDIO_AVERAGING_SECS = 0.05f; - const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; - _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f)); - - if (_longTermAverageLoudness == -1.0) { - _longTermAverageLoudness = _averageLoudness; - } else { - _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f)); - } - // Only use face trackers when not playing back a recording. if (!myAvatar->isPlaying()) { FaceTracker* faceTracker = Application::getInstance()->getActiveFaceTracker(); From b0eccc40c27b0cb8a87af5186393ca663058f960 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 27 Apr 2015 22:58:09 -0700 Subject: [PATCH 366/401] Fix crash cause when Menu::instance() is before offscreen ui startup --- interface/src/Application.cpp | 3 +++ interface/src/Menu.cpp | 20 +++++++++++++++----- libraries/ui/src/VrMenu.cpp | 26 +++++++++++++++++++------- libraries/ui/src/VrMenu.h | 3 ++- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f1825b2c4a..3b2173f05e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -767,6 +767,7 @@ void Application::initializeUi() { AddressBarDialog::registerType(); LoginDialog::registerType(); MessageDialog::registerType(); + VrMenu::registerType(); auto offscreenUi = DependencyManager::get(); offscreenUi->create(_glWidget->context()->contextHandle()); @@ -775,6 +776,8 @@ void Application::initializeUi() { offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); offscreenUi->load("Root.qml"); offscreenUi->load("RootMenu.qml"); + VrMenu::load(); + VrMenu::executeQueuedLambdas(); offscreenUi->setMouseTranslator([this](const QPointF& p){ if (OculusManager::isConnected()) { glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p)); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c467658fc4..868fa9270c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -975,7 +975,9 @@ bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) { - VrMenu::instance()->addMenu(menu); + VrMenu::executeOrQueue([=](VrMenu* vrMenu) { + vrMenu->addMenu(menu); + }); _backMap[menu] = this; } @@ -997,18 +999,24 @@ void MenuWrapper::addSeparator() { void MenuWrapper::addAction(QAction* action) { _realMenu->addAction(action); - VrMenu::instance()->addAction(_realMenu, action); + VrMenu::executeOrQueue([=](VrMenu* vrMenu) { + vrMenu->addAction(_realMenu, action); + }); } QAction* MenuWrapper::addAction(const QString& menuName) { QAction* action = _realMenu->addAction(menuName); - VrMenu::instance()->addAction(_realMenu, action); + VrMenu::executeOrQueue([=](VrMenu* vrMenu) { + vrMenu->addAction(_realMenu, action); + }); return action; } QAction* MenuWrapper::addAction(const QString& menuName, const QObject* receiver, const char* member, const QKeySequence& shortcut) { QAction* action = _realMenu->addAction(menuName, receiver, member, shortcut); - VrMenu::instance()->addAction(_realMenu, action); + VrMenu::executeOrQueue([=](VrMenu* vrMenu) { + vrMenu->addAction(_realMenu, action); + }); return action; } @@ -1018,7 +1026,9 @@ void MenuWrapper::removeAction(QAction* action) { void MenuWrapper::insertAction(QAction* before, QAction* action) { _realMenu->insertAction(before, action); - VrMenu::instance()->insertAction(before, action); + VrMenu::executeOrQueue([=](VrMenu* vrMenu) { + vrMenu->insertAction(before, action); + }); } QHash MenuWrapper::_backMap; diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index 04c2cb0b30..5c0f8fb732 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -42,7 +42,7 @@ private: qmlObject->setUserData(USER_DATA_ID, this); qmlObject->setObjectName(uuid.toString()); // Make sure we can find it again in the future - Q_ASSERT(VrMenu::instance()->findMenuObject(uuid.toString())); + Q_ASSERT(VrMenu::_instance->findMenuObject(uuid.toString())); } }; @@ -57,14 +57,25 @@ HIFI_QML_DEF_LAMBDA(VrMenu, [&](QQmlContext* context, QObject* newItem) { }); VrMenu* VrMenu::_instance{ nullptr }; +static QQueue> queuedLambdas; -VrMenu* VrMenu::instance() { - if (!_instance) { - VrMenu::registerType(); - VrMenu::load(); - Q_ASSERT(_instance); +void VrMenu::executeOrQueue(std::function f) { + if (_instance) { + foreach(std::function priorLambda, queuedLambdas) { + priorLambda(_instance); + } + f(_instance); + } else { + queuedLambdas.push_back(f); } - return _instance; +} + +void VrMenu::executeQueuedLambdas() { + Q_ASSERT(_instance); + foreach(std::function f, queuedLambdas) { + f(_instance); + } + queuedLambdas.clear(); } VrMenu::VrMenu(QQuickItem* parent) : QQuickItem(parent) { @@ -72,6 +83,7 @@ VrMenu::VrMenu(QQuickItem* parent) : QQuickItem(parent) { this->setEnabled(false); } + // QML helper functions QObject* addMenu(QObject* parent, const QString& text) { // FIXME add more checking here to ensure no name conflicts diff --git a/libraries/ui/src/VrMenu.h b/libraries/ui/src/VrMenu.h index 7fe0d33cc4..06a16588af 100644 --- a/libraries/ui/src/VrMenu.h +++ b/libraries/ui/src/VrMenu.h @@ -26,7 +26,8 @@ class VrMenu : public QQuickItem { HIFI_QML_DECL_LAMBDA public: - static VrMenu* instance(); + static void executeOrQueue(std::function f); + static void executeQueuedLambdas(); VrMenu(QQuickItem* parent = nullptr); void addMenu(QMenu* menu); void addAction(QMenu* parent, QAction* action); From 897e47e8e6946feb9883b1712c646d9ae8a10e39 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 27 Apr 2015 23:17:56 -0700 Subject: [PATCH 367/401] Removing debug hack to load resources from source folder --- libraries/shared/src/PathUtils.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 47e5659c60..84c8ae4939 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -19,19 +19,10 @@ QString& PathUtils::resourcesPath() { -#ifdef DEBUG - static QString staticResourcePath; - if (staticResourcePath.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - staticResourcePath = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; - } -#else #ifdef Q_OS_MAC static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/"; #else static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/"; -#endif #endif return staticResourcePath; From d1d1830b2f811ae181b7055a82bab7878ef85afb Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 28 Apr 2015 00:26:24 -0700 Subject: [PATCH 368/401] Importing peferred dialog look from browser branch --- interface/resources/qml/controls/Dialog.qml | 12 +++++++ .../resources/qml/controls/DialogBase.qml | 32 ++++++++++++++++--- .../resources/qml/controls/TextInput.qml | 4 +-- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/controls/Dialog.qml b/interface/resources/qml/controls/Dialog.qml index 629813d3b5..46add1dc07 100644 --- a/interface/resources/qml/controls/Dialog.qml +++ b/interface/resources/qml/controls/Dialog.qml @@ -92,6 +92,7 @@ DialogBase { anchors.bottom: parent.bottom width: 16 height: 16 + z: 1000 hoverEnabled: true onPressed: { startX = mouseX @@ -143,4 +144,15 @@ DialogBase { } } } + + Keys.onPressed: { + switch(event.key) { + case Qt.Key_W: + if (event.modifiers == Qt.ControlModifier) { + event.accepted = true + enabled = false + } + break; + } + } } diff --git a/interface/resources/qml/controls/DialogBase.qml b/interface/resources/qml/controls/DialogBase.qml index 050237c184..a6616fc731 100644 --- a/interface/resources/qml/controls/DialogBase.qml +++ b/interface/resources/qml/controls/DialogBase.qml @@ -22,11 +22,13 @@ Item { readonly property alias titleWidth: titleBorder.width readonly property alias titleHeight: titleBorder.height + // readonly property real borderWidth: hifi.styles.borderWidth + readonly property real borderWidth: 0 property alias clientBorder: clientBorder - readonly property real clientX: clientBorder.x + hifi.styles.borderWidth - readonly property real clientY: clientBorder.y + hifi.styles.borderWidth - readonly property real clientWidth: clientBorder.width - hifi.styles.borderWidth * 2 - readonly property real clientHeight: clientBorder.height - hifi.styles.borderWidth * 2 + readonly property real clientX: clientBorder.x + borderWidth + readonly property real clientY: clientBorder.y + borderWidth + readonly property real clientWidth: clientBorder.width - borderWidth * 2 + readonly property real clientHeight: clientBorder.height - borderWidth * 2 /* * Window decorations, with a title bar and frames @@ -35,6 +37,7 @@ Item { id: windowBorder anchors.fill: parent border.color: root.frameColor + border.width: 0 color: "#00000000" Border { @@ -43,11 +46,13 @@ Item { anchors.right: parent.right anchors.left: parent.left border.color: root.frameColor + border.width: 0 clip: true color: root.active ? hifi.colors.activeWindow.headerBackground : hifi.colors.inactiveWindow.headerBackground + Text { id: titleText color: root.active ? @@ -60,8 +65,26 @@ Item { } } // header border + // These two rectangles hide the curves between the title area + // and the client area + Rectangle { + y: titleBorder.height - titleBorder.radius + height: titleBorder.radius + width: titleBorder.width + color: titleBorder.color + visible: borderWidth == 0 + } + + Rectangle { + y: titleBorder.height + width: clientBorder.width + height: clientBorder.radius + color: clientBorder.color + } + Border { id: clientBorder + border.width: 0 border.color: root.frameColor color: root.backgroundColor anchors.bottom: parent.bottom @@ -69,7 +92,6 @@ Item { anchors.topMargin: -titleBorder.border.width anchors.right: parent.right anchors.left: parent.left - clip: true } // client border } // window border diff --git a/interface/resources/qml/controls/TextInput.qml b/interface/resources/qml/controls/TextInput.qml index ceaca0c073..d533c67bd6 100644 --- a/interface/resources/qml/controls/TextInput.qml +++ b/interface/resources/qml/controls/TextInput.qml @@ -13,14 +13,14 @@ Original.TextInput { font.family: hifi.fonts.fontFamily font.pointSize: hifi.fonts.fontSize - +/* Original.Rectangle { // Render the rectangle as background z: -1 anchors.fill: parent color: hifi.colors.inputBackground } - +*/ Text { anchors.fill: parent font.pointSize: parent.font.pointSize From 4911aa58bc9c526d5a973f45406002da73fddbbd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Apr 2015 17:02:32 +0200 Subject: [PATCH 369/401] Fix Model setURL with delayload Without this condition the model stays in a state where the geometry is downloaded but not referenced That way, another call to setURL with update the geometry reference instead of returning. --- libraries/render-utils/src/Model.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index fe82af6b3c..14cb2e5c55 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1047,7 +1047,7 @@ int Model::getLastFreeJointIndex(int jointIndex) const { void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bool delayLoad) { // don't recreate the geometry if it's the same URL - if (_url == url) { + if (_url == url && _geometry && _geometry->getURL() == url) { return; } _url = url; From b7263eeacf0a93b81d6c1dec1a6cad10b4b5d0d5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Apr 2015 17:05:38 +0200 Subject: [PATCH 370/401] Added a more efficient convexHullContains to Model New version computes each submesh's bounding box once and checks against it before checking against triangles. --- libraries/render-utils/src/Model.cpp | 55 ++++++++++++++++++++++++++++ libraries/render-utils/src/Model.h | 1 + 2 files changed, 56 insertions(+) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 14cb2e5c55..0d9423218e 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -573,6 +573,61 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g return intersectedSomething; } +bool Model::convexHullContains(glm::vec3 point) { + // if we aren't active, we can't compute that yet... + if (!isActive()) { + return false; + } + + // extents is the entity relative, scaled, centered extents of the entity + glm::vec3 position = _translation; + glm::mat4 rotation = glm::mat4_cast(_rotation); + glm::mat4 translation = glm::translate(position); + glm::mat4 modelToWorldMatrix = translation * rotation; + glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); + + Extents modelExtents = getMeshExtents(); // NOTE: unrotated + + glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; + glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the ray picking in the model frame of reference + AABox modelFrameBox(corner, dimensions); + + glm::vec3 modelFramePoint = glm::vec3(worldToModelMatrix * glm::vec4(point, 1.0f)); + + // we can use the AABox's ray intersection by mapping our origin and direction into the model frame + // and testing intersection there. + if (modelFrameBox.contains(modelFramePoint)){ + if (!_calculatedMeshTrianglesValid) { + recalculateMeshBoxes(true); + } + + // If we are inside the models box, then consider the submeshes... + int subMeshIndex = 0; + foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { + if (subMeshBox.contains(point)) { + bool insideMesh = true; + // To be inside the sub mesh, we need to be behind every triangles' planes + const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; + foreach (const Triangle& triangle, meshTriangles) { + if (!isPointBehindTrianglesPlane(point, triangle.v0, triangle.v1, triangle.v2)) { + // it's not behind at least one so we bail + insideMesh = false; + break; + } + + } + if (insideMesh) { + // It's inside this mesh, return true. + return true; + } + } + subMeshIndex++; + } + } + // It wasn't in any mesh, return false. + return false; +} + // TODO: we seem to call this too often when things haven't actually changed... look into optimizing this void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 1559e73e61..10f294dc7c 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -213,6 +213,7 @@ public: bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false); + bool convexHullContains(glm::vec3 point); protected: QSharedPointer _geometry; From fe0bd456e10d462767489da9355b1a8aaa447136 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Apr 2015 17:07:40 +0200 Subject: [PATCH 371/401] Zones now use Models instead of FBXGeometries --- .../src/RenderableZoneEntityItem.cpp | 70 ++++++++++++++----- .../src/RenderableZoneEntityItem.h | 13 +++- 2 files changed, 65 insertions(+), 18 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index e4c56dc419..d61e3c02f7 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -18,39 +18,77 @@ EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, cons return new RenderableZoneEntityItem(entityID, properties); } -bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& properties) { +template +void RenderableZoneEntityItem::changeProperties(Lambda setNewProperties) { QString oldShapeURL = getCompoundShapeURL(); - bool somethingChanged = ZoneEntityItem::setProperties(properties); - if (somethingChanged && oldShapeURL != getCompoundShapeURL()) { - _compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); + glm::vec3 oldPosition = getPosition(), oldDimensions = getDimensions(); + glm::quat oldRotation = getRotation(); + + setNewProperties(); + + if (oldShapeURL != getCompoundShapeURL()) { + if (!_model) { + _model = getModel(); + _needsInitialSimulation = true; + } + _model->setURL(getCompoundShapeURL(), QUrl(), true, true); } + if (oldPosition != getPosition() || + oldRotation != getRotation() || + oldDimensions != getDimensions()) { + _needsInitialSimulation = true; + } +} + +bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + changeProperties([&]() { + somethingChanged = this->ZoneEntityItem::setProperties(properties); + }); return somethingChanged; } int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { - QString oldShapeURL = getCompoundShapeURL(); - int bytesRead = ZoneEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead, - args, propertyFlags, overwriteLocalData); - if (oldShapeURL != getCompoundShapeURL()) { - _compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); - } + int bytesRead = 0; + changeProperties([&]() { + bytesRead = ZoneEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead, + args, propertyFlags, overwriteLocalData); + }); return bytesRead; } +Model* RenderableZoneEntityItem::getModel() { + Model* model = new Model(); + model->init(); + return model; +} + +void RenderableZoneEntityItem::initialSimulation() { + _model->setScaleToFit(true, getDimensions()); + _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); + _model->setRotation(getRotation()); + _model->setTranslation(getPosition()); + _model->simulate(0.0f); + _needsInitialSimulation = false; +} + bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { if (getShapeType() != SHAPE_TYPE_COMPOUND) { return EntityItem::contains(point); } - if (!_compoundShapeModel && hasCompoundShapeURL()) { - const_cast(this)->_compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); + + if (_model && !_model->isActive() && hasCompoundShapeURL()) { + // Since we have a delayload, we need to update the geometry if it has been downloaded + _model->setURL(getCompoundShapeURL(), QUrl(), true); } - if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) { - const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry(); - glm::vec3 meshDimensions = geometry.getUnscaledMeshExtents().maximum - geometry.getUnscaledMeshExtents().minimum; - return geometry.convexHullContains(worldToEntity(point) * meshDimensions); + if (_model && _model->isActive() && EntityItem::contains(point)) { + if (_needsInitialSimulation) { + const_cast(this)->initialSimulation(); + } + return _model->convexHullContains(point); } return false; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 8d8d8b4b3f..8a75a048d1 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -12,6 +12,7 @@ #ifndef hifi_RenderableZoneEntityItem_h #define hifi_RenderableZoneEntityItem_h +#include #include class NetworkGeometry; @@ -21,7 +22,9 @@ public: static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - ZoneEntityItem(entityItemID, properties) + ZoneEntityItem(entityItemID, properties), + _model(NULL), + _needsInitialSimulation(true) { } virtual bool setProperties(const EntityItemProperties& properties); @@ -32,8 +35,14 @@ public: virtual bool contains(const glm::vec3& point) const; private: + Model* getModel(); + void initialSimulation(); - QSharedPointer _compoundShapeModel; + template + void changeProperties(Lambda functor); + + Model* _model; + bool _needsInitialSimulation; }; #endif // hifi_RenderableZoneEntityItem_h \ No newline at end of file From ab9d81b5e2f569bf61c8ab3f1c4bd63bbf19cb1b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Apr 2015 18:09:09 +0200 Subject: [PATCH 372/401] Correct comments --- libraries/render-utils/src/GeometryCache.h | 2 +- libraries/render-utils/src/Model.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 37156a6c71..8ccbb65dbb 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -324,7 +324,7 @@ public: const FBXGeometry& getFBXGeometry() const { return _geometry; } const QVector& getMeshes() const { return _meshes; } -// + QVector getJointMappings(const AnimationPointer& animation); virtual void setLoadPriority(const QPointer& owner, float priority); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0d9423218e..8ed1728e0a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -589,13 +589,13 @@ bool Model::convexHullContains(glm::vec3 point) { Extents modelExtents = getMeshExtents(); // NOTE: unrotated glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; - glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the ray picking in the model frame of reference + glm::vec3 corner = -(dimensions * _registrationPoint); AABox modelFrameBox(corner, dimensions); glm::vec3 modelFramePoint = glm::vec3(worldToModelMatrix * glm::vec4(point, 1.0f)); - // we can use the AABox's ray intersection by mapping our origin and direction into the model frame - // and testing intersection there. + // we can use the AABox's contains() by mapping our point into the model frame + // and testing there. if (modelFrameBox.contains(modelFramePoint)){ if (!_calculatedMeshTrianglesValid) { recalculateMeshBoxes(true); From 38ba0ab3526d8b87890d2b9e0d38ed41ff7b426d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:18:00 -0700 Subject: [PATCH 373/401] remove useless added code --- domain-server/src/DomainServer.cpp | 6 +----- domain-server/src/PendingAssignedNodeData.cpp | 7 ++----- domain-server/src/PendingAssignedNodeData.h | 10 +--------- libraries/networking/src/Assignment.cpp | 4 ---- libraries/networking/src/NodeData.h | 10 ---------- 5 files changed, 4 insertions(+), 33 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 5090978a72..1ddf1cb7db 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -676,8 +676,6 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock nodeData->setWalletUUID(pendingAssigneeData->getWalletUUID()); // always allow assignment clients to create and destroy entities - nodeData->setCanAdjustLocks(true); - nodeData->setCanRez(true); newNode->setCanAdjustLocks(true); newNode->setCanRez(true); @@ -1058,9 +1056,7 @@ void DomainServer::readAvailableDatagrams() { // add the information for that deployed assignment to the hash of pending assigned nodes PendingAssignedNodeData* pendingNodeData = new PendingAssignedNodeData(assignmentToDeploy->getUUID(), - requestAssignment.getWalletUUID(), - true, true - ); + requestAssignment.getWalletUUID()); _pendingAssignedNodes.insert(uniqueAssignment.getUUID(), pendingNodeData); } else { if (requestAssignment.getType() != Assignment::AgentType diff --git a/domain-server/src/PendingAssignedNodeData.cpp b/domain-server/src/PendingAssignedNodeData.cpp index c4b47fd254..be24498d70 100644 --- a/domain-server/src/PendingAssignedNodeData.cpp +++ b/domain-server/src/PendingAssignedNodeData.cpp @@ -11,12 +11,9 @@ #include "PendingAssignedNodeData.h" -PendingAssignedNodeData::PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID, - bool canAdjustLocks, bool canRez) : +PendingAssignedNodeData::PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID) : _assignmentUUID(assignmentUUID), - _walletUUID(walletUUID), - _canAdjustLocks(canAdjustLocks), - _canRez(canRez) + _walletUUID(walletUUID) { } diff --git a/domain-server/src/PendingAssignedNodeData.h b/domain-server/src/PendingAssignedNodeData.h index 17f94d2225..9daa7822c3 100644 --- a/domain-server/src/PendingAssignedNodeData.h +++ b/domain-server/src/PendingAssignedNodeData.h @@ -18,7 +18,7 @@ class PendingAssignedNodeData : public QObject { Q_OBJECT public: - PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID, bool canAdjustLocks, bool canRez); + PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID); void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } const QUuid& getAssignmentUUID() const { return _assignmentUUID; } @@ -26,17 +26,9 @@ public: void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; } const QUuid& getWalletUUID() const { return _walletUUID; } - void setCanAdjustLocks(bool canAdjustLocks) { _canAdjustLocks = canAdjustLocks; } - bool getCanAdjustLocks() { return _canAdjustLocks; } - - void setCanRez(bool canRez) { _canRez = canRez; } - bool getCanRez() { return _canRez; } - private: QUuid _assignmentUUID; QUuid _walletUUID; - bool _canAdjustLocks = false; /// will this node be allowed to adjust locks on entities? - bool _canRez = false; /// will this node be allowed to rez in new entities? }; #endif // hifi_PendingAssignedNodeData_h diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 560bce3b91..027cf8aba5 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -153,8 +153,6 @@ QDataStream& operator<<(QDataStream &out, const Assignment& assignment) { if (assignment._command == Assignment::RequestCommand) { out << assignment._walletUUID; } - - out << assignment._canAdjustLocks << assignment._canRez; return out; } @@ -170,7 +168,5 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { in >> assignment._walletUUID; } - in >> assignment._canAdjustLocks >> assignment._canRez; - return in; } diff --git a/libraries/networking/src/NodeData.h b/libraries/networking/src/NodeData.h index e5e7925280..b865e444a9 100644 --- a/libraries/networking/src/NodeData.h +++ b/libraries/networking/src/NodeData.h @@ -26,18 +26,8 @@ public: QMutex& getMutex() { return _mutex; } - void setCanAdjustLocks(bool canAdjustLocks) { _canAdjustLocks = canAdjustLocks; } - bool getCanAdjustLocks() { return _canAdjustLocks; } - - void setCanRez(bool canRez) { _canRez = canRez; } - bool getCanRez() { return _canRez; } - private: QMutex _mutex; - -protected: - bool _canAdjustLocks = false; /// will this node be allowed to adjust locks on entities? - bool _canRez = false; /// will this node be allowed to rez in new entities? }; #endif // hifi_NodeData_h From 8db46d859eb21a6f1ab40a7f8cefbbef0d2f4678 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:19:45 -0700 Subject: [PATCH 374/401] formatting --- domain-server/src/PendingAssignedNodeData.h | 1 - libraries/networking/src/Assignment.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/domain-server/src/PendingAssignedNodeData.h b/domain-server/src/PendingAssignedNodeData.h index 9daa7822c3..f2cac41607 100644 --- a/domain-server/src/PendingAssignedNodeData.h +++ b/domain-server/src/PendingAssignedNodeData.h @@ -25,7 +25,6 @@ public: void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; } const QUuid& getWalletUUID() const { return _walletUUID; } - private: QUuid _assignmentUUID; QUuid _walletUUID; diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 027cf8aba5..944041730e 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -167,6 +167,6 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { if (assignment._command == Assignment::RequestCommand) { in >> assignment._walletUUID; } - + return in; } From be8764424ef58576254f564fbef42658d1166929 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:20:38 -0700 Subject: [PATCH 375/401] formatting --- libraries/networking/src/Assignment.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 944041730e..a17ea8efd1 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -170,3 +170,5 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { return in; } + + From eb36bf3aa02a2d12607787b77d7f113d4c8a17ee Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:23:00 -0700 Subject: [PATCH 376/401] formatting --- libraries/networking/src/Assignment.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index a17ea8efd1..944041730e 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -170,5 +170,3 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { return in; } - - From dc0b033101e0493c1389ebec828e7286fa171517 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:23:19 -0700 Subject: [PATCH 377/401] formatting --- libraries/networking/src/Assignment.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 944041730e..d93d1a15f1 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -170,3 +170,4 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { return in; } + From a1da96e9714023692f9fb4310f1c0391ca509d88 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:23:30 -0700 Subject: [PATCH 378/401] formatting --- libraries/networking/src/Assignment.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index d93d1a15f1..944041730e 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -170,4 +170,3 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { return in; } - From 30e78a37cd3c801a990450b6f60375011313cbed Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:26:03 -0700 Subject: [PATCH 379/401] formatting --- domain-server/src/PendingAssignedNodeData.h | 1 + 1 file changed, 1 insertion(+) diff --git a/domain-server/src/PendingAssignedNodeData.h b/domain-server/src/PendingAssignedNodeData.h index f2cac41607..60878d4244 100644 --- a/domain-server/src/PendingAssignedNodeData.h +++ b/domain-server/src/PendingAssignedNodeData.h @@ -31,3 +31,4 @@ private: }; #endif // hifi_PendingAssignedNodeData_h + From 436fe03d105886d769c0d8a7f966994238854578 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:26:20 -0700 Subject: [PATCH 380/401] formatting --- domain-server/src/PendingAssignedNodeData.h | 1 - 1 file changed, 1 deletion(-) diff --git a/domain-server/src/PendingAssignedNodeData.h b/domain-server/src/PendingAssignedNodeData.h index 60878d4244..f2cac41607 100644 --- a/domain-server/src/PendingAssignedNodeData.h +++ b/domain-server/src/PendingAssignedNodeData.h @@ -31,4 +31,3 @@ private: }; #endif // hifi_PendingAssignedNodeData_h - From 7aa2013473481063471135ad363f2c81efa7c873 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:26:39 -0700 Subject: [PATCH 381/401] formatting --- domain-server/src/PendingAssignedNodeData.h | 1 + 1 file changed, 1 insertion(+) diff --git a/domain-server/src/PendingAssignedNodeData.h b/domain-server/src/PendingAssignedNodeData.h index f2cac41607..60878d4244 100644 --- a/domain-server/src/PendingAssignedNodeData.h +++ b/domain-server/src/PendingAssignedNodeData.h @@ -31,3 +31,4 @@ private: }; #endif // hifi_PendingAssignedNodeData_h + From 49783c1550498630b649f93c55e2a44889e7b02d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:28:17 -0700 Subject: [PATCH 382/401] formatting --- domain-server/src/PendingAssignedNodeData.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/domain-server/src/PendingAssignedNodeData.h b/domain-server/src/PendingAssignedNodeData.h index 60878d4244..93d99a6f8f 100644 --- a/domain-server/src/PendingAssignedNodeData.h +++ b/domain-server/src/PendingAssignedNodeData.h @@ -30,5 +30,4 @@ private: QUuid _walletUUID; }; -#endif // hifi_PendingAssignedNodeData_h - +#endif // hifi_PendingAssignedNodeData_h \ No newline at end of file From e6da5ea711743925868bcdaa26e79e8f78eeccdb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 09:28:42 -0700 Subject: [PATCH 383/401] formatting --- domain-server/src/PendingAssignedNodeData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/PendingAssignedNodeData.cpp b/domain-server/src/PendingAssignedNodeData.cpp index be24498d70..21b3aa4ca4 100644 --- a/domain-server/src/PendingAssignedNodeData.cpp +++ b/domain-server/src/PendingAssignedNodeData.cpp @@ -16,4 +16,4 @@ PendingAssignedNodeData::PendingAssignedNodeData(const QUuid& assignmentUUID, co _walletUUID(walletUUID) { -} +} \ No newline at end of file From f9c0493c61a56498ca4ae7de6d5e76bd1ba2089f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 10:23:08 -0700 Subject: [PATCH 384/401] when a login is completed, reset the node list in order to force a re-connection to the domain-server (thereby giving the interface any new rights it deserves, such as the ability to edit entities) --- libraries/networking/src/NodeList.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 76f66420bf..1e24b3f1a9 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -58,6 +58,9 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned // handle ICE signal from DS so connection is attempted immediately connect(&_domainHandler, &DomainHandler::requestICEConnectionAttempt, this, &NodeList::handleICEConnectionToDomainServer); + + // clear out NodeList when login is finished + connect(&AccountManager::getInstance(), &AccountManager::loginComplete , this, &NodeList::reset); // clear our NodeList when logout is requested connect(&AccountManager::getInstance(), &AccountManager::logoutComplete , this, &NodeList::reset); From 25753524852679e317fe790282c635196eb33309 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 28 Apr 2015 12:51:01 -0700 Subject: [PATCH 385/401] Attempting to resolve possible crash case for scripts playing sounds --- libraries/script-engine/src/ScriptAudioInjector.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptAudioInjector.cpp b/libraries/script-engine/src/ScriptAudioInjector.cpp index a9cf40558c..2ec30ad4dd 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.cpp +++ b/libraries/script-engine/src/ScriptAudioInjector.cpp @@ -13,8 +13,12 @@ #include "ScriptAudioInjector.h" QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in) { + // The AudioScriptingInterface::playSound method can return null, so we need to account for that. + if (!in) { + return QScriptValue(QScriptValue::NullValue); + } + // when the script goes down we want to cleanup the injector - QObject::connect(engine, &QScriptEngine::destroyed, in, &ScriptAudioInjector::stopInjectorImmediately, Qt::DirectConnection); From 28ad80936aadd2b29072e7ead391395567225536 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 13:21:14 -0700 Subject: [PATCH 386/401] assignment-client shouldn't try to save contents of its nonexistent address bar. interface still needs to save the address. --- interface/src/Application.cpp | 1 + libraries/networking/src/AddressManager.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 68a542d4dd..1e3e6cfd9e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -465,6 +465,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : addressManager->setOrientationGetter(getOrientationForPath); connect(addressManager.data(), &AddressManager::rootPlaceNameChanged, this, &Application::updateWindowTitle); + connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); #ifdef _WIN32 WSADATA WsaData; diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 73aaa63844..9b99c236b3 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -35,7 +35,6 @@ AddressManager::AddressManager() : _positionGetter(NULL), _orientationGetter(NULL) { - connect(qApp, &QCoreApplication::aboutToQuit, this, &AddressManager::storeCurrentAddress); } bool AddressManager::isConnected() { From 512a10902348f7bcbe58e49416a5a84d980d75e9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Apr 2015 13:48:51 -0700 Subject: [PATCH 387/401] add call to perror() to get OS level error details on failed backups --- libraries/octree/src/OctreePersistThread.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index 9c7a43b12d..210d074001 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -285,6 +285,7 @@ void OctreePersistThread::restoreFromMostRecentBackup() { qCDebug(octree) << "DONE restoring backup file " << mostRecentBackupFileName << "to" << _filename << "..."; } else { qCDebug(octree) << "ERROR while restoring backup file " << mostRecentBackupFileName << "to" << _filename << "..."; + perror("ERROR while restoring backup file"); } } else { qCDebug(octree) << "NO BEST backup file found."; @@ -366,6 +367,7 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) { qCDebug(octree) << "DONE rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; } else { qCDebug(octree) << "ERROR in rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; + perror("ERROR in rolling backup file"); } } } @@ -425,6 +427,7 @@ void OctreePersistThread::backup() { rule.lastBackup = now; // only record successful backup in this case. } else { qCDebug(octree) << "ERROR in backing up persist file..."; + perror("ERROR in backing up persist file"); } } else { qCDebug(octree) << "persist file " << _filename << " does not exist. " << From 9576ad19a7f78001ec5f90df899190f6d931d128 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 28 Apr 2015 10:52:46 -0700 Subject: [PATCH 388/401] Move "Stereo Audio" option into developerMenu.js And rename it "Stereo Input" to better relect what it does. --- examples/utilities/tools/developerMenuItems.js | 12 ++++++++++++ interface/src/Menu.cpp | 2 -- interface/src/Menu.h | 1 - libraries/audio-client/src/AudioClient.h | 8 +++----- libraries/audio/src/AbstractAudioInterface.h | 2 ++ .../script-engine/src/AudioScriptingInterface.cpp | 6 +++++- .../script-engine/src/AudioScriptingInterface.h | 2 ++ 7 files changed, 24 insertions(+), 9 deletions(-) diff --git a/examples/utilities/tools/developerMenuItems.js b/examples/utilities/tools/developerMenuItems.js index 58b5149307..ace2b032e2 100644 --- a/examples/utilities/tools/developerMenuItems.js +++ b/examples/utilities/tools/developerMenuItems.js @@ -13,6 +13,7 @@ var createdRenderMenu = false; var createdGeneratedAudioMenu = false; +var createdStereoInputMenuItem = false; var DEVELOPER_MENU = "Developer"; @@ -28,6 +29,7 @@ var AUDIO_SOURCE_INJECT = "Generated Audio"; var AUDIO_SOURCE_MENU = AUDIO_MENU + " > Generated Audio Source"; var AUDIO_SOURCE_PINK_NOISE = "Pink Noise"; var AUDIO_SOURCE_SINE_440 = "Sine 440hz"; +var AUDIO_STEREO_INPUT = "Stereo Input"; function setupMenus() { @@ -78,6 +80,10 @@ function setupMenus() { Audio.selectPinkNoise(); createdGeneratedAudioMenu = true; } + if (!Menu.menuItemExists(AUDIO_MENU, AUDIO_STEREO_INPUT)) { + Menu.addMenuItem({ menuName: AUDIO_MENU, menuItemName: AUDIO_STEREO_INPUT, isCheckable: true, isChecked: false }); + createdStereoInputMenuItem = true; + } } Menu.menuItemEvent.connect(function (menuItem) { @@ -99,6 +105,8 @@ Menu.menuItemEvent.connect(function (menuItem) { } else if (menuItem == AUDIO_SOURCE_SINE_440 && !createdGeneratedAudioMenu) { Audio.selectSine440(); Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, false); + } else if (menuItem == AUDIO_STEREO_INPUT) { + Audio.setStereoInput(Menu.isOptionChecked(AUDIO_STEREO_INPUT)) } }); @@ -125,6 +133,10 @@ function scriptEnding() { Menu.removeMenuItem(AUDIO_MENU, AUDIO_SOURCE_INJECT); Menu.removeMenu(AUDIO_SOURCE_MENU); } + + if (createdStereoInputMenuItem) { + Menu.removeMenuItem(AUDIO_MENU, AUDIO_STEREO_INPUT); + } } setupMenus(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 43c63eb383..4548ccd586 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -485,8 +485,6 @@ Menu::Menu() { audioIO.data(), SLOT(toggleServerEcho())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio, 0, false, audioIO.data(), SLOT(toggleLocalEcho())); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false, - audioIO.data(), SLOT(toggleStereoInput())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteAudio, Qt::CTRL | Qt::Key_M, false, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 2c4e2b809f..fd0c230c17 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -238,7 +238,6 @@ namespace MenuOption { const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations"; const QString Stars = "Stars"; const QString Stats = "Stats"; - const QString StereoAudio = "Stereo Audio (disables spatial sound)"; const QString StopAllScripts = "Stop All Scripts"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString TestPing = "Test Ping"; diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index bb145a209f..9d10184d13 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -108,8 +108,6 @@ public: bool isMuted() { return _muted; } - void setIsStereoInput(bool isStereoInput); - const AudioIOStats& getStats() const { return _stats; } float getInputRingBufferMsecsAvailable() const; @@ -146,14 +144,14 @@ public slots: virtual void enableAudioSourceInject(bool enable); virtual void selectAudioSourcePinkNoise(); virtual void selectAudioSourceSine440(); - + + virtual void setIsStereoInput(bool stereo); + void toggleAudioNoiseReduction() { _isNoiseGateEnabled = !_isNoiseGateEnabled; } void toggleLocalEcho() { _shouldEchoLocally = !_shouldEchoLocally; } void toggleServerEcho() { _shouldEchoToServer = !_shouldEchoToServer; } - void toggleStereoInput() { setIsStereoInput(!_isStereoInput); } - void processReceivedSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer); void sendMuteEnvironmentPacket(); diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 9649d11ad2..a5855d75d1 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -31,6 +31,8 @@ public slots: virtual void enableAudioSourceInject(bool enable) = 0; virtual void selectAudioSourcePinkNoise() = 0; virtual void selectAudioSourceSine440() = 0; + + virtual void setIsStereoInput(bool stereo) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index 8bcc4a20cf..e210ee6f6e 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -89,4 +89,8 @@ void AudioScriptingInterface::selectSine440() { } } - +void AudioScriptingInterface::setStereoInput(bool stereo) { + if (_localAudioInterface) { + _localAudioInterface->setIsStereoInput(stereo); + } +} diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 9d02b8c9a1..bbc9a57db8 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -32,6 +32,8 @@ protected: Q_INVOKABLE void injectGeneratedNoise(bool inject); Q_INVOKABLE void selectPinkNoise(); Q_INVOKABLE void selectSine440(); + + Q_INVOKABLE void setStereoInput(bool stereo); signals: void mutedByMixer(); From 342d3576c96b62d98fbd2f436c49836ca0accc74 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Tue, 28 Apr 2015 14:46:39 -0700 Subject: [PATCH 389/401] Added ability to check if an avatar is within specified range of a position from javascript --- libraries/avatars/src/AvatarHashMap.cpp | 11 +++++++++++ libraries/avatars/src/AvatarHashMap.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index ae3a8c3e5c..d389846796 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -55,6 +55,17 @@ bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) { return !avatarWithDisplayName(displayName).isNull(); } +bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range) { + foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) { + glm::vec3 avatarPosition = sharedAvatar->getPosition(); + float distance = glm::distance(avatarPosition, position); + if (distance < range) { + return true; + } + } + return false; +} + AvatarWeakPointer AvatarHashMap::avatarWithDisplayName(const QString& displayName) { foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) { if (sharedAvatar->getDisplayName() == displayName) { diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index b59559e78c..b7d40e2acc 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -20,6 +20,7 @@ #include #include "AvatarData.h" +#include typedef QSharedPointer AvatarSharedPointer; typedef QWeakPointer AvatarWeakPointer; @@ -36,6 +37,7 @@ public: public slots: void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer& mixerWeakPointer); bool containsAvatarWithDisplayName(const QString& displayName); + bool isAvatarInRange(const glm::vec3 & position, const float range); AvatarWeakPointer avatarWithDisplayName(const QString& displayname); private slots: From bfbad539e06a3881cf850cd9bcc4c7c0a0eeb786 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Apr 2015 14:54:58 -0700 Subject: [PATCH 390/401] hack test --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index cd7bedc19e..e588cb69f1 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -166,7 +166,7 @@ void MyAvatar::simulate(float deltaTime) { if (_scale != _targetScale) { float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; setScale(scale); - Application::getInstance()->getCamera()->setScale(scale); + //Application::getInstance()->getCamera()->setScale(scale); } { From aec0bd16930adcb82d22beb6aa48a2bb9c98fe0e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Apr 2015 16:26:17 -0700 Subject: [PATCH 391/401] dont change camera scale with avatar scale --- interface/src/avatar/MyAvatar.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e588cb69f1..60a760b2a8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -166,7 +166,6 @@ void MyAvatar::simulate(float deltaTime) { if (_scale != _targetScale) { float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; setScale(scale); - //Application::getInstance()->getCamera()->setScale(scale); } { From 664d1264653261f6ccee8049c50f1160eaf95d72 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Apr 2015 16:34:33 -0700 Subject: [PATCH 392/401] remove scale from Camera class since it was only used by avatar and was causing problems with no obvious benefit --- interface/src/Camera.cpp | 5 ++--- interface/src/Camera.h | 5 +---- interface/src/avatar/MyAvatar.cpp | 2 -- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index e334fd7c65..6c6d165e7d 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -55,7 +55,6 @@ Camera::Camera() : _farClip(DEFAULT_FAR_CLIP), // default _hmdPosition(), _hmdRotation(), - _scale(1.0f), _isKeepLookingAt(false), _lookingAt(0.0f, 0.0f, 0.0f) { @@ -94,8 +93,8 @@ void Camera::setHmdRotation(const glm::quat& hmdRotation) { } float Camera::getFarClip() const { - return (_scale * _farClip < std::numeric_limits::max()) - ? _scale * _farClip + return (_farClip < std::numeric_limits::max()) + ? _farClip : std::numeric_limits::max() - 1; } diff --git a/interface/src/Camera.h b/interface/src/Camera.h index 7c6951b920..10572d3513 100644 --- a/interface/src/Camera.h +++ b/interface/src/Camera.h @@ -54,7 +54,6 @@ public: void setFarClip(float f); void setEyeOffsetPosition(const glm::vec3& p) { _eyeOffsetPosition = p; } void setEyeOffsetOrientation(const glm::quat& o) { _eyeOffsetOrientation = o; } - void setScale(const float s) { _scale = s; } glm::quat getRotation() const { return _rotation * _hmdRotation; } const glm::vec3& getHmdPosition() const { return _hmdPosition; } @@ -63,11 +62,10 @@ public: CameraMode getMode() const { return _mode; } float getFieldOfView() const { return _fieldOfView; } float getAspectRatio() const { return _aspectRatio; } - float getNearClip() const { return _scale * _nearClip; } + float getNearClip() const { return _nearClip; } float getFarClip() const; const glm::vec3& getEyeOffsetPosition() const { return _eyeOffsetPosition; } const glm::quat& getEyeOffsetOrientation() const { return _eyeOffsetOrientation; } - float getScale() const { return _scale; } public slots: QString getModeString() const; void setModeString(const QString& mode); @@ -107,7 +105,6 @@ private: glm::quat _rotation; glm::vec3 _hmdPosition; glm::quat _hmdRotation; - float _scale; bool _isKeepLookingAt; glm::vec3 _lookingAt; }; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 60a760b2a8..557d630ebf 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -672,8 +672,6 @@ void MyAvatar::loadData() { _leanScale = loadSetting(settings, "leanScale", 0.05f); _targetScale = loadSetting(settings, "scale", 1.0f); setScale(_scale); - Application::getInstance()->getCamera()->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 From f2dcacffd025a465333efdd4fd818b1af3767cef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Apr 2015 09:47:19 -0700 Subject: [PATCH 393/401] show avatar data receive rate by default with display name --- interface/src/avatar/Avatar.cpp | 16 ++++++++++++++-- libraries/avatars/src/AvatarData.cpp | 17 ++++++++++++----- libraries/avatars/src/AvatarData.h | 13 ++++++++----- libraries/avatars/src/AvatarHashMap.cpp | 4 ++-- libraries/shared/src/SimpleMovingAverage.cpp | 6 +++--- libraries/shared/src/SimpleMovingAverage.h | 7 +++++-- 6 files changed, 44 insertions(+), 19 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b3439317d8..94589623bf 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -581,7 +581,8 @@ void Avatar::renderBillboard() { glm::vec2 texCoordTopLeft(0.0f, 0.0f); glm::vec2 texCoordBottomRight(1.0f, 1.0f); - DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); + DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, + glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); glPopMatrix(); @@ -709,11 +710,22 @@ void Avatar::renderDisplayName() { glm::vec4(0.2f, 0.2f, 0.2f, _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA)); glm::vec4 color(0.93f, 0.93f, 0.93f, _displayNameAlpha); + + // optionally render timing stats for this avatar with the display name + QString renderedDisplayName = _displayName; + + const float BYTES_PER_KILOBYTE = 1000.0f; + float kilobytesPerSecond = getAverageBytesReceivedPerSecond() / BYTES_PER_KILOBYTE; + + renderedDisplayName += QString(" - (%1 KBps, %2 Hz)") + .arg(QString::number(kilobytesPerSecond, 'f', 2)) + .arg(getReceiveRate()); + QByteArray ba = _displayName.toLocal8Bit(); const char* text = ba.data(); glDisable(GL_POLYGON_OFFSET_FILL); - textRenderer(DISPLAYNAME)->draw(text_x, text_y, text, color); + textRenderer(DISPLAYNAME)->draw(text_x, text_y, renderedDisplayName, color); glPopMatrix(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a8d2c209c3..f0e4eb118b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -58,11 +58,11 @@ AvatarData::AvatarData() : _billboard(), _errorLogExpiry(0), _owningAvatarMixer(), - _lastUpdateTimer(), _velocity(0.0f), _targetVelocity(0.0f), _localAABox(DEFAULT_LOCAL_AABOX_CORNER, DEFAULT_LOCAL_AABOX_SCALE) { + } AvatarData::~AvatarData() { @@ -268,9 +268,6 @@ bool AvatarData::shouldLogError(const quint64& now) { // read data in packet starting at byte offset and return number of bytes parsed int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { - // reset the last heard timer since we have new data for this AvatarData - _lastUpdateTimer.restart(); - // lazily allocate memory for HeadData in case we're not an Avatar instance if (!_headData) { _headData = new HeadData(this); @@ -555,7 +552,17 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { } } // numJoints * 8 bytes - return sourceBuffer - startPosition; + int numBytesRead = sourceBuffer - startPosition; + _averageBytesReceived.updateAverage(numBytesRead); + return numBytesRead; +} + +int AvatarData::getAverageBytesReceivedPerSecond() const { + return lrint(_averageBytesReceived.getAverageSampleValuePerSecond()); +} + +int AvatarData::getReceiveRate() const { + return lrint(1.0f / _averageBytesReceived.getEventDeltaAverage()); } bool AvatarData::hasReferential() { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 58e9c42c3c..0aa911112a 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -46,9 +46,9 @@ typedef unsigned long long quint64; #include #include -#include - #include +#include +#include #include "AABox.h" #include "HandData.h" @@ -293,11 +293,13 @@ public: Node* getOwningAvatarMixer() { return _owningAvatarMixer.data(); } void setOwningAvatarMixer(const QWeakPointer& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; } - QElapsedTimer& getLastUpdateTimer() { return _lastUpdateTimer; } - const AABox& getLocalAABox() const { return _localAABox; } const Referential* getReferential() const { return _referential; } + int getUsecsSinceLastUpdate() const { return _averageBytesReceived.getUsecsSinceLastEvent(); } + int getAverageBytesReceivedPerSecond() const; + int getReceiveRate() const; + void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; } glm::vec3 getTargetVelocity() const { return _targetVelocity; } @@ -382,7 +384,6 @@ protected: quint64 _errorLogExpiry; ///< time in future when to log an error QWeakPointer _owningAvatarMixer; - QElapsedTimer _lastUpdateTimer; PlayerPointer _player; @@ -395,6 +396,8 @@ protected: AABox _localAABox; + SimpleMovingAverage _averageBytesReceived {}; + private: // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&); diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index ae3a8c3e5c..3e913acbd7 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -25,11 +25,11 @@ AvatarHash::iterator AvatarHashMap::erase(const AvatarHash::iterator& iterator) return _avatarHash.erase(iterator); } -const qint64 AVATAR_SILENCE_THRESHOLD_MSECS = 5 * 1000; +const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * 1000 * 1000; bool AvatarHashMap::shouldKillAvatar(const AvatarSharedPointer& sharedAvatar) { return (sharedAvatar->getOwningAvatarMixer() == NULL - || sharedAvatar->getLastUpdateTimer().elapsed() > AVATAR_SILENCE_THRESHOLD_MSECS); + || sharedAvatar->getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS); } void AvatarHashMap::processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer& mixerWeakPointer) { diff --git a/libraries/shared/src/SimpleMovingAverage.cpp b/libraries/shared/src/SimpleMovingAverage.cpp index 90a9509c91..1d2574ecbf 100644 --- a/libraries/shared/src/SimpleMovingAverage.cpp +++ b/libraries/shared/src/SimpleMovingAverage.cpp @@ -52,9 +52,9 @@ void SimpleMovingAverage::reset() { float SimpleMovingAverage::getEventDeltaAverage() const { return (ONE_MINUS_WEIGHTING * _eventDeltaAverage) + - (WEIGHTING * ((usecTimestampNow() - _lastEventTimestamp) / 1000000.0f)); + (WEIGHTING * ((usecTimestampNow() - _lastEventTimestamp) / 1000000.0f )); } -float SimpleMovingAverage::getAverageSampleValuePerSecond() const { - return _average * (1.0f / getEventDeltaAverage()); +uint64_t SimpleMovingAverage::getUsecsSinceLastEvent() const { + return usecTimestampNow() - _lastEventTimestamp; } diff --git a/libraries/shared/src/SimpleMovingAverage.h b/libraries/shared/src/SimpleMovingAverage.h index 3eec9d5be8..4233411466 100644 --- a/libraries/shared/src/SimpleMovingAverage.h +++ b/libraries/shared/src/SimpleMovingAverage.h @@ -25,8 +25,11 @@ public: int getSampleCount() const { return _numSamples; }; float getAverage() const { return _average; }; - float getEventDeltaAverage() const; - float getAverageSampleValuePerSecond() const; + float getEventDeltaAverage() const; // returned in microseconds + float getAverageSampleValuePerSecond() const { return _average * (1.0f / getEventDeltaAverage()); } + + uint64_t getUsecsSinceLastEvent() const; + private: int _numSamples; uint64_t _lastEventTimestamp; From f9a25d7089483b0ff5804a058d757df80556a355 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Apr 2015 10:13:18 -0700 Subject: [PATCH 394/401] add Menu option to toggle Avatar receive stats --- interface/src/Menu.cpp | 7 ++++--- interface/src/Menu.h | 1 + interface/src/avatar/Avatar.cpp | 16 +++++++++------- interface/src/avatar/AvatarManager.h | 11 +++++++++-- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 868fa9270c..23f69b5e5b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -285,9 +285,6 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, - 0); // QML Qt::Key_Slash); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats); addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L, @@ -397,6 +394,10 @@ Menu::Menu() { QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true); ddeFiltering->setVisible(false); #endif + + auto avatarManager = DependencyManager::get(); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false, + avatarManager.data(), SLOT(setShouldShowReceiveStats(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderHeadCollisionShapes); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 5b2d1430a6..62b6ac5656 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -147,6 +147,7 @@ namespace MenuOption { const QString AudioScopeTwentyFrames = "Twenty"; const QString AudioStats = "Audio Stats"; const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams"; + const QString AvatarReceiveStats = "Show Receive Stats"; const QString BandwidthDetails = "Bandwidth Details"; const QString BlueSpeechSphere = "Blue Sphere While Speaking"; const QString BookmarkLocation = "Bookmark Location"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 94589623bf..05f834255c 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -713,14 +713,16 @@ void Avatar::renderDisplayName() { // optionally render timing stats for this avatar with the display name QString renderedDisplayName = _displayName; - - const float BYTES_PER_KILOBYTE = 1000.0f; - float kilobytesPerSecond = getAverageBytesReceivedPerSecond() / BYTES_PER_KILOBYTE; - renderedDisplayName += QString(" - (%1 KBps, %2 Hz)") - .arg(QString::number(kilobytesPerSecond, 'f', 2)) - .arg(getReceiveRate()); - + if (DependencyManager::get()->shouldShowReceiveStats()) { + const float BYTES_PER_KILOBYTE = 1000.0f; + float kilobytesPerSecond = getAverageBytesReceivedPerSecond() / BYTES_PER_KILOBYTE; + + renderedDisplayName += QString(" - (%1 KBps, %2 Hz)") + .arg(QString::number(kilobytesPerSecond, 'f', 2)) + .arg(getReceiveRate()); + } + QByteArray ba = _displayName.toLocal8Bit(); const char* text = ba.data(); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 1a833c5106..3c7f7296fe 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -40,7 +40,9 @@ public: void renderAvatars(RenderArgs::RenderMode renderMode, bool postLighting = false, bool selfAvatarOnly = false); void clearOtherAvatars(); - + + bool shouldShowReceiveStats() const { return _shouldShowReceiveStats; } + class LocalLight { public: glm::vec3 color; @@ -49,7 +51,10 @@ public: Q_INVOKABLE void setLocalLights(const QVector& localLights); Q_INVOKABLE QVector getLocalLights() const; - + +public slots: + void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } + private: AvatarManager(QObject* parent = 0); AvatarManager(const AvatarManager& other); @@ -67,6 +72,8 @@ private: quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate. QVector _localLights; + + bool _shouldShowReceiveStats = false; }; Q_DECLARE_METATYPE(AvatarManager::LocalLight) From c52426385dbfd8252891b4842296d2363f9f5eaa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Apr 2015 18:20:54 -0700 Subject: [PATCH 395/401] code review comments for #4713 --- libraries/avatars/src/AvatarHashMap.cpp | 3 ++- libraries/shared/src/SimpleMovingAverage.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 3e913acbd7..a78d91fc43 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -11,6 +11,7 @@ #include #include +#include #include "AvatarLogging.h" #include "AvatarHashMap.h" @@ -25,7 +26,7 @@ AvatarHash::iterator AvatarHashMap::erase(const AvatarHash::iterator& iterator) return _avatarHash.erase(iterator); } -const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * 1000 * 1000; +const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND; bool AvatarHashMap::shouldKillAvatar(const AvatarSharedPointer& sharedAvatar) { return (sharedAvatar->getOwningAvatarMixer() == NULL diff --git a/libraries/shared/src/SimpleMovingAverage.cpp b/libraries/shared/src/SimpleMovingAverage.cpp index 1d2574ecbf..e1c9a27390 100644 --- a/libraries/shared/src/SimpleMovingAverage.cpp +++ b/libraries/shared/src/SimpleMovingAverage.cpp @@ -52,7 +52,7 @@ void SimpleMovingAverage::reset() { float SimpleMovingAverage::getEventDeltaAverage() const { return (ONE_MINUS_WEIGHTING * _eventDeltaAverage) + - (WEIGHTING * ((usecTimestampNow() - _lastEventTimestamp) / 1000000.0f )); + (WEIGHTING * ((usecTimestampNow() - _lastEventTimestamp) / 1000000.0f)); } uint64_t SimpleMovingAverage::getUsecsSinceLastEvent() const { From 1995fa6a5ee53fe3d58e8cb8179372334114f811 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Apr 2015 18:21:15 -0700 Subject: [PATCH 396/401] fix return value comment in SimpleMovingAverage --- libraries/shared/src/SimpleMovingAverage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/SimpleMovingAverage.h b/libraries/shared/src/SimpleMovingAverage.h index 4233411466..194a078194 100644 --- a/libraries/shared/src/SimpleMovingAverage.h +++ b/libraries/shared/src/SimpleMovingAverage.h @@ -25,7 +25,7 @@ public: int getSampleCount() const { return _numSamples; }; float getAverage() const { return _average; }; - float getEventDeltaAverage() const; // returned in microseconds + float getEventDeltaAverage() const; // returned in seconds float getAverageSampleValuePerSecond() const { return _average * (1.0f / getEventDeltaAverage()); } uint64_t getUsecsSinceLastEvent() const; From 61b4025526e798318f226912f26e5bbff46832fb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Apr 2015 09:33:23 -0700 Subject: [PATCH 397/401] remove the uneeded curly braces for default ctor --- libraries/avatars/src/AvatarData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 0aa911112a..6a11f94cb6 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -396,7 +396,7 @@ protected: AABox _localAABox; - SimpleMovingAverage _averageBytesReceived {}; + SimpleMovingAverage _averageBytesReceived; private: // privatize the copy constructor and assignment operator so they cannot be called From 8b9236a18dee96ffdc1c22d67c762231aa5661ff Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Wed, 29 Apr 2015 09:44:22 -0700 Subject: [PATCH 398/401] added grab.js script, which allows users to grab and fling physical objects --- examples/grab.js | 223 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 examples/grab.js diff --git a/examples/grab.js b/examples/grab.js new file mode 100644 index 0000000000..eca457f0b2 --- /dev/null +++ b/examples/grab.js @@ -0,0 +1,223 @@ +var isGrabbing = false; +var grabbedEntity = null; +var prevMouse = {}; +var deltaMouse = { + z: 0 +} +var entityProps; +var box, box2, ground; +var baseMoveFactor = .001; +var finalMoveMultiplier; +var avatarEntityDistance; +var camYaw, dv; +var prevPosition; +var newPosition; +var flingVelocity; +var flingMultiplier = 10; +var moveUpDown = false; +var savedGravity; + +var DROP_DISTANCE = 5.0; +var DROP_COLOR = { + red: 200, + green: 200, + blue: 200 +}; +var DROP_WIDTH = 4; + + +var autoBox = false; +if (autoBox) { + setUpTestObjects(); +} + +var dropLine = Overlays.addOverlay("line3d", { + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: DROP_COLOR, + alpha: 1, + visible: false, + lineWidth: DROP_WIDTH +}); + + +function mousePressEvent(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var intersection = Entities.findRayIntersection(pickRay); + if (intersection.intersects && intersection.properties.collisionsWillMove) { + grabbedEntity = intersection.entityID; + var props = Entities.getEntityProperties(grabbedEntity) + prevPosition = props.position; + isGrabbing = true; + savedGravity = props.gravity; + Overlays.editOverlay(dropLine, { + visible: true + }); + Entities.editEntity(grabbedEntity, { + gravity: { + x: 0, + y: 0, + z: 0 + } + }); + //We need to store entity's current gravity, and then disable it while we move + + } + +} + + +function mouseReleaseEvent() { + if (isGrabbing) { + flingObject(); + Entities.editEntity(grabbedEntity, { + gravity: savedGravity + }); + } + isGrabbing = false; + Overlays.editOverlay(dropLine, { + visible: false + }); +} + +function flingObject() { + //calculate velocity to give object base on current and previous position + entityProps = Entities.getEntityProperties(grabbedEntity); + + flingVelocity = Vec3.subtract(entityProps.position, prevPosition); + flingVelocity = Vec3.multiply(flingMultiplier, flingVelocity); + flingVelocity.y = 0; + Entities.editEntity(grabbedEntity, { + velocity: flingVelocity + }); +} + +function mouseMoveEvent(event) { + if (isGrabbing) { + entityProps = Entities.getEntityProperties(grabbedEntity); + prevPosition = entityProps.position; + avatarEntityDistance = Vec3.distance(MyAvatar.position, entityProps.position); + finalMoveMultiplier = baseMoveFactor * Math.pow(avatarEntityDistance, 1.5); + deltaMouse.x = event.x - prevMouse.x; + if (!moveUpDown) { + deltaMouse.z = event.y - prevMouse.y; + } else { + deltaMouse.y = (event.y - prevMouse.y) * -1; + } + finalMoveMultiplier = baseMoveFactor * Math.pow(avatarEntityDistance, 1.5); + deltaMouse = Vec3.multiply(deltaMouse, finalMoveMultiplier); + camYaw = Quat.safeEulerAngles(Camera.getOrientation()).y; + dv = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, camYaw, 0), deltaMouse); + newPosition = Vec3.sum(entityProps.position, dv); + Entities.editEntity(grabbedEntity, { + position: newPosition + }); + Overlays.editOverlay(dropLine, { + start: newPosition, + end: Vec3.sum(newPosition, { + x: 0, + y: -DROP_DISTANCE, + z: 0 + }) + }); + } + prevMouse.x = event.x; + prevMouse.y = event.y; +} + +function keyReleaseEvent(event) { + if (event.text === "SHIFT") { + moveUpDown = false; + } +} + +function keyPressEvent(event) { + if (event.text === "SHIFT") { + moveUpDown = true; + } +} + +function cleanup() { + Entities.deleteEntity(box); + Entities.deleteEntity(box2); + Entities.deleteEntity(ground); +} + +function setUpTestObjects() { + var distance = 4; + box = Entities.addEntity({ + type: 'Box', + position: Vec3.sum(MyAvatar.position, Vec3.multiply(distance, Quat.getFront(Camera.getOrientation()))), + dimensions: { + x: .5, + y: .5, + z: .5 + }, + color: { + red: 200, + green: 50, + blue: 192 + }, + collisionsWillMove: true, + gravity: { + x: 0, + y: -1, + z: 0 + } + }); + + box2 = Entities.addEntity({ + type: 'Box', + position: Vec3.sum(MyAvatar.position, Vec3.multiply(distance + 1, Quat.getFront(Camera.getOrientation()))), + dimensions: { + x: .5, + y: .5, + z: .5 + }, + color: { + red: 200, + green: 50, + blue: 192 + }, + collisionsWillMove: true, + gravity: { + x: 0, + y: -1, + z: 0 + } + }); + + ground = Entities.addEntity({ + type: 'Box', + position: { + x: MyAvatar.position.x, + y: MyAvatar.position.y - 5, + z: MyAvatar.position.z + }, + dimensions: { + x: 100, + y: 2, + z: 100 + }, + color: { + red: 20, + green: 200, + blue: 50 + } + }); +} + +Controller.mouseMoveEvent.connect(mouseMoveEvent); +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseReleaseEvent.connect(mouseReleaseEvent); +Controller.keyPressEvent.connect(keyPressEvent); +Controller.keyReleaseEvent.connect(keyReleaseEvent); +Script.scriptEnding.connect(cleanup); \ No newline at end of file From 489fbaac5765e6b68e821a6b40557b361df02dfa Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Wed, 29 Apr 2015 09:45:58 -0700 Subject: [PATCH 399/401] added grab.js to defaultScripts.js --- examples/defaultScripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 05ffb0bd3f..a5c086fc44 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -18,3 +18,4 @@ Script.load("lobby.js"); Script.load("notifications.js"); Script.load("look.js"); Script.load("users.js"); +Script.load("grab.js"); From 36a26ad416077bfae082f50cd5224a7a1d6bd6ea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Apr 2015 09:58:54 -0700 Subject: [PATCH 400/401] update BUILD.md for new OpenSSL req --- BUILD.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD.md b/BUILD.md index 0de8d32b82..a5ee32262f 100644 --- a/BUILD.md +++ b/BUILD.md @@ -2,8 +2,8 @@ * [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.12.2 * [Qt](http://www.qt.io/download-open-source) ~> 5.4.1 -* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g - * IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability. +* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1m + * IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities. * [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional) ####CMake External Project Dependencies From e933ab2e84d3a59eae9bca0deca33170133e9d65 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Apr 2015 09:59:20 -0700 Subject: [PATCH 401/401] update win required version of OpenSSL --- BUILD_WIN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 80b8c35502..169077ed78 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -71,7 +71,7 @@ Your system may already have several versions of the OpenSSL DLL's (ssleay32.dll To prevent these problems, install OpenSSL yourself. Download the following binary packages [from this website](http://slproweb.com/products/Win32OpenSSL.html): * Visual C++ 2008 Redistributables -* Win32 OpenSSL v1.0.1L +* Win32 OpenSSL v1.0.1m Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.