From 2a597eb7154d99679da744c7282e2326371d1afc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 20 Feb 2018 17:00:28 -0800 Subject: [PATCH 01/97] use QCoreApplication for oven when headless version is used --- tools/oven/src/BakerCLI.cpp | 19 +++++--- tools/oven/src/BakerCLI.h | 6 +-- tools/oven/src/DomainBaker.cpp | 6 +-- tools/oven/src/Oven.cpp | 62 +++++++------------------- tools/oven/src/Oven.h | 23 +++------- tools/oven/src/OvenCLIApplication.cpp | 49 ++++++++++++++++++++ tools/oven/src/OvenCLIApplication.h | 27 +++++++++++ tools/oven/src/OvenGUIApplication.cpp | 19 ++++++++ tools/oven/src/OvenGUIApplication.h | 33 ++++++++++++++ tools/oven/src/main.cpp | 13 ++++-- tools/oven/src/ui/BakeWidget.cpp | 5 +-- tools/oven/src/ui/DomainBakeWidget.cpp | 11 +++-- tools/oven/src/ui/ModelBakeWidget.cpp | 11 +++-- tools/oven/src/ui/SkyboxBakeWidget.cpp | 9 ++-- 14 files changed, 193 insertions(+), 100 deletions(-) create mode 100644 tools/oven/src/OvenCLIApplication.cpp create mode 100644 tools/oven/src/OvenCLIApplication.h create mode 100644 tools/oven/src/OvenGUIApplication.cpp create mode 100644 tools/oven/src/OvenGUIApplication.h diff --git a/tools/oven/src/BakerCLI.cpp b/tools/oven/src/BakerCLI.cpp index 5af65c4dc0..f5af5455fb 100644 --- a/tools/oven/src/BakerCLI.cpp +++ b/tools/oven/src/BakerCLI.cpp @@ -14,13 +14,14 @@ #include #include +#include "OvenCLIApplication.h" #include "ModelBakingLoggingCategory.h" -#include "Oven.h" #include "BakerCLI.h" #include "FBXBaker.h" #include "TextureBaker.h" -BakerCLI::BakerCLI(Oven* parent) : QObject(parent) { +BakerCLI::BakerCLI(OvenCLIApplication* parent) : QObject(parent) { + } void BakerCLI::bakeFile(QUrl inputUrl, const QString& outputPath, const QString& type) { @@ -50,14 +51,18 @@ void BakerCLI::bakeFile(QUrl inputUrl, const QString& outputPath, const QString& // create our appropiate baker if (isFBX) { - _baker = std::unique_ptr { new FBXBaker(inputUrl, []() -> QThread* { return qApp->getNextWorkerThread(); }, outputPath) }; - _baker->moveToThread(qApp->getNextWorkerThread()); + _baker = std::unique_ptr { + new FBXBaker(inputUrl, + []() -> QThread* { return Oven::instance().getNextWorkerThread(); }, + outputPath) + }; + _baker->moveToThread(Oven::instance().getNextWorkerThread()); } else if (isSupportedImage) { _baker = std::unique_ptr { new TextureBaker(inputUrl, image::TextureUsage::CUBE_TEXTURE, outputPath) }; - _baker->moveToThread(qApp->getNextWorkerThread()); + _baker->moveToThread(Oven::instance().getNextWorkerThread()); } else { qCDebug(model_baking) << "Failed to determine baker type for file" << inputUrl; - QApplication::exit(OVEN_STATUS_CODE_FAIL); + QCoreApplication::exit(OVEN_STATUS_CODE_FAIL); } // invoke the bake method on the baker thread @@ -81,5 +86,5 @@ void BakerCLI::handleFinishedBaker() { errorFile.close(); } } - QApplication::exit(exitCode); + QCoreApplication::exit(exitCode); } diff --git a/tools/oven/src/BakerCLI.h b/tools/oven/src/BakerCLI.h index 7d362eb898..4f5b6607b0 100644 --- a/tools/oven/src/BakerCLI.h +++ b/tools/oven/src/BakerCLI.h @@ -18,7 +18,7 @@ #include #include "Baker.h" -#include "Oven.h" +#include "OvenCLIApplication.h" static const int OVEN_STATUS_CODE_SUCCESS { 0 }; static const int OVEN_STATUS_CODE_FAIL { 1 }; @@ -27,10 +27,10 @@ static const int OVEN_STATUS_CODE_ABORT { 2 }; static const QString OVEN_ERROR_FILENAME = "errors.txt"; class BakerCLI : public QObject { - Q_OBJECT + Q_OBJECT public: - BakerCLI(Oven* parent); + BakerCLI(OvenCLIApplication* parent); void bakeFile(QUrl inputUrl, const QString& outputPath, const QString& type = QString::null); private slots: diff --git a/tools/oven/src/DomainBaker.cpp b/tools/oven/src/DomainBaker.cpp index edc2492e82..28ede982a0 100644 --- a/tools/oven/src/DomainBaker.cpp +++ b/tools/oven/src/DomainBaker.cpp @@ -201,7 +201,7 @@ void DomainBaker::enumerateEntities() { } QSharedPointer baker { new FBXBaker(modelURL, []() -> QThread* { - return qApp->getNextWorkerThread(); + return Oven::instance().getNextWorkerThread(); }, _contentOutputPath + subDirName + "/baked", _contentOutputPath + subDirName + "/original"), &FBXBaker::deleteLater }; @@ -214,7 +214,7 @@ void DomainBaker::enumerateEntities() { // move the baker to the baker thread // and kickoff the bake - baker->moveToThread(qApp->getNextWorkerThread()); + baker->moveToThread(Oven::instance().getNextWorkerThread()); QMetaObject::invokeMethod(baker.data(), "bake"); // keep track of the total number of baking entities @@ -285,7 +285,7 @@ void DomainBaker::bakeSkybox(QUrl skyboxURL, QJsonValueRef entity) { _skyboxBakers.insert(skyboxURL, skyboxBaker); // move the baker to a worker thread and kickoff the bake - skyboxBaker->moveToThread(qApp->getNextWorkerThread()); + skyboxBaker->moveToThread(Oven::instance().getNextWorkerThread()); QMetaObject::invokeMethod(skyboxBaker.data(), "bake"); // keep track of the total number of baking entities diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index 69d2ef84ce..e8d4c01f63 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -11,33 +11,15 @@ #include #include -#include #include -#include "ui/OvenMainWindow.h" #include "Oven.h" -#include "BakerCLI.h" -static const QString OUTPUT_FOLDER = "/Users/birarda/code/hifi/lod/test-oven/export"; +Oven* Oven::_staticInstance { nullptr }; -static const QString CLI_INPUT_PARAMETER = "i"; -static const QString CLI_OUTPUT_PARAMETER = "o"; -static const QString CLI_TYPE_PARAMETER = "t"; - -Oven::Oven(int argc, char* argv[]) : - QApplication(argc, argv) -{ - // parse the command line parameters - QCommandLineParser parser; - - parser.addOptions({ - { CLI_INPUT_PARAMETER, "Path to file that you would like to bake.", "input" }, - { CLI_OUTPUT_PARAMETER, "Path to folder that will be used as output.", "output" }, - { CLI_TYPE_PARAMETER, "Type of asset.", "type" } - }); - parser.addHelpOption(); - parser.process(*this); +Oven::Oven() { + _staticInstance = this; // enable compression in image library image::setColorTexturesCompressionEnabled(true); @@ -47,41 +29,27 @@ Oven::Oven(int argc, char* argv[]) : // setup our worker threads setupWorkerThreads(QThread::idealThreadCount()); - - // check if we were passed any command line arguments that would tell us just to run without the GUI - if (parser.isSet(CLI_INPUT_PARAMETER) || parser.isSet(CLI_OUTPUT_PARAMETER)) { - if (parser.isSet(CLI_INPUT_PARAMETER) && parser.isSet(CLI_OUTPUT_PARAMETER)) { - BakerCLI* cli = new BakerCLI(this); - QUrl inputUrl(QDir::fromNativeSeparators(parser.value(CLI_INPUT_PARAMETER))); - QUrl outputUrl(QDir::fromNativeSeparators(parser.value(CLI_OUTPUT_PARAMETER))); - QString type = parser.isSet(CLI_TYPE_PARAMETER) ? parser.value(CLI_TYPE_PARAMETER) : QString::null; - cli->bakeFile(inputUrl, outputUrl.toString(), type); - } else { - parser.showHelp(); - QApplication::quit(); - } - } else { - // setup the GUI - _mainWindow = new OvenMainWindow; - _mainWindow->show(); - } } Oven::~Oven() { - // cleanup the worker threads - for (auto i = 0; i < _workerThreads.size(); ++i) { - _workerThreads[i]->quit(); - _workerThreads[i]->wait(); + // quit and wait on the worker threads + for (auto& thread : _workerThreads) { + thread->quit(); + thread->wait(); } + + _staticInstance = nullptr; } void Oven::setupWorkerThreads(int numWorkerThreads) { + _workerThreads.reserve(numWorkerThreads); + for (auto i = 0; i < numWorkerThreads; ++i) { // setup a worker thread yet and add it to our concurrent vector - auto newThread = new QThread(this); + auto newThread = std::unique_ptr { new QThread }; newThread->setObjectName("Oven Worker Thread " + QString::number(i + 1)); - _workerThreads.push_back(newThread); + _workerThreads.push_back(std::move(newThread)); } } @@ -92,13 +60,13 @@ QThread* Oven::getNextWorkerThread() { // (for the FBX Baker Thread to have room), and cycle through them to hand a usable running thread back to our callers. auto nextIndex = ++_nextWorkerThreadIndex; - auto nextThread = _workerThreads[nextIndex % _workerThreads.size()]; + auto& nextThread = _workerThreads[nextIndex % _workerThreads.size()]; // start the thread if it isn't running yet if (!nextThread->isRunning()) { nextThread->start(); } - return nextThread; + return nextThread.get(); } diff --git a/tools/oven/src/Oven.h b/tools/oven/src/Oven.h index 928ba4eb11..443def5cb1 100644 --- a/tools/oven/src/Oven.h +++ b/tools/oven/src/Oven.h @@ -12,27 +12,15 @@ #ifndef hifi_Oven_h #define hifi_Oven_h -#include - -#include - #include -#if defined(qApp) -#undef qApp -#endif -#define qApp (static_cast(QCoreApplication::instance())) - -class OvenMainWindow; - -class Oven : public QApplication { - Q_OBJECT +class Oven { public: - Oven(int argc, char* argv[]); + Oven(); ~Oven(); - OvenMainWindow* getMainWindow() const { return _mainWindow; } + static Oven& instance() { return *_staticInstance; } QThread* getNextWorkerThread(); @@ -40,11 +28,12 @@ private: void setupWorkerThreads(int numWorkerThreads); void setupFBXBakerThread(); - OvenMainWindow* _mainWindow; - QList _workerThreads; + std::vector> _workerThreads; std::atomic _nextWorkerThreadIndex; int _numWorkerThreads; + + static Oven* _staticInstance; }; diff --git a/tools/oven/src/OvenCLIApplication.cpp b/tools/oven/src/OvenCLIApplication.cpp new file mode 100644 index 0000000000..38d9963eeb --- /dev/null +++ b/tools/oven/src/OvenCLIApplication.cpp @@ -0,0 +1,49 @@ +// +// OvenCLIApplication.cpp +// tools/oven/src +// +// Created by Stephen Birarda on 2/20/18. +// Copyright 2018 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 "BakerCLI.h" + +#include "OvenCLIApplication.h" + +static const QString CLI_INPUT_PARAMETER = "i"; +static const QString CLI_OUTPUT_PARAMETER = "o"; +static const QString CLI_TYPE_PARAMETER = "t"; + +OvenCLIApplication::OvenCLIApplication(int argc, char* argv[]) : + QCoreApplication(argc, argv) +{ + // parse the command line parameters + QCommandLineParser parser; + + parser.addOptions({ + { CLI_INPUT_PARAMETER, "Path to file that you would like to bake.", "input" }, + { CLI_OUTPUT_PARAMETER, "Path to folder that will be used as output.", "output" }, + { CLI_TYPE_PARAMETER, "Type of asset.", "type" } + }); + + parser.addHelpOption(); + parser.process(*this); + + if (parser.isSet(CLI_INPUT_PARAMETER) && parser.isSet(CLI_OUTPUT_PARAMETER)) { + BakerCLI* cli = new BakerCLI(this); + QUrl inputUrl(QDir::fromNativeSeparators(parser.value(CLI_INPUT_PARAMETER))); + QUrl outputUrl(QDir::fromNativeSeparators(parser.value(CLI_OUTPUT_PARAMETER))); + QString type = parser.isSet(CLI_TYPE_PARAMETER) ? parser.value(CLI_TYPE_PARAMETER) : QString::null; + cli->bakeFile(inputUrl, outputUrl.toString(), type); + } else { + parser.showHelp(); + QCoreApplication::quit(); + } + +} diff --git a/tools/oven/src/OvenCLIApplication.h b/tools/oven/src/OvenCLIApplication.h new file mode 100644 index 0000000000..5d81166f69 --- /dev/null +++ b/tools/oven/src/OvenCLIApplication.h @@ -0,0 +1,27 @@ +// +// OvenCLIApplication.h +// tools/oven/src +// +// Created by Stephen Birarda on 2/20/18. +// Copyright 2018 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_OvenCLIApplication_h +#define hifi_OvenCLIApplication_h + +#include + +#include "Oven.h" + +class OvenCLIApplication : public QCoreApplication, public Oven { + Q_OBJECT +public: + OvenCLIApplication(int argc, char* argv[]); + + static OvenCLIApplication* instance() { return dynamic_cast(QCoreApplication::instance()); } +}; + +#endif // hifi_OvenCLIApplication_h diff --git a/tools/oven/src/OvenGUIApplication.cpp b/tools/oven/src/OvenGUIApplication.cpp new file mode 100644 index 0000000000..33dc375634 --- /dev/null +++ b/tools/oven/src/OvenGUIApplication.cpp @@ -0,0 +1,19 @@ +// +// OvenGUIApplication.cpp +// tools/src/oven +// +// Created by Stephen Birarda on 2/20/18. +// Copyright 2018 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 "OvenGUIApplication.h" + +OvenGUIApplication::OvenGUIApplication(int argc, char* argv[]) : + QApplication(argc, argv) +{ + // setup the GUI + _mainWindow.show(); +} diff --git a/tools/oven/src/OvenGUIApplication.h b/tools/oven/src/OvenGUIApplication.h new file mode 100644 index 0000000000..7f5bbf3eaf --- /dev/null +++ b/tools/oven/src/OvenGUIApplication.h @@ -0,0 +1,33 @@ +// +// OvenGUIApplication.h +// tools/oven/src +// +// Created by Stephen Birarda on 2/20/18. +// Copyright 2018 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_OvenGUIApplication_h +#define hifi_OvenGUIApplication_h + +#include + +#include "ui/OvenMainWindow.h" + +#include "Oven.h" + +class OvenGUIApplication : public QApplication, public Oven { + Q_OBJECT +public: + OvenGUIApplication(int argc, char* argv[]); + + static OvenGUIApplication* instance() { return dynamic_cast(QApplication::instance()); } + + OvenMainWindow* getMainWindow() { return &_mainWindow; } +private: + OvenMainWindow _mainWindow; +}; + +#endif // hifi_OvenGUIApplication_h diff --git a/tools/oven/src/main.cpp b/tools/oven/src/main.cpp index 788470b75e..062cc63a0d 100644 --- a/tools/oven/src/main.cpp +++ b/tools/oven/src/main.cpp @@ -8,7 +8,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -#include "Oven.h" +#include "OvenCLIApplication.h" +#include "OvenGUIApplication.h" #include @@ -19,6 +20,12 @@ int main (int argc, char** argv) { // init the settings interface so we can save and load settings Setting::init(); - Oven app(argc, argv); - return app.exec(); + // figure out if we're launching our GUI application or just the simple command line interface + if (argc > 1) { + OvenCLIApplication app { argc, argv }; + return app.exec(); + } else { + OvenGUIApplication app { argc, argv }; + return app.exec(); + } } diff --git a/tools/oven/src/ui/BakeWidget.cpp b/tools/oven/src/ui/BakeWidget.cpp index 9fb8f2f880..22e1b1aaf9 100644 --- a/tools/oven/src/ui/BakeWidget.cpp +++ b/tools/oven/src/ui/BakeWidget.cpp @@ -11,8 +11,7 @@ #include -#include "../Oven.h" -#include "OvenMainWindow.h" +#include "../OvenGUIApplication.h" #include "BakeWidget.h" @@ -28,7 +27,7 @@ BakeWidget::~BakeWidget() { auto it = _bakers.begin(); while (it != _bakers.end()) { auto resultRow = it->second; - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); resultsWindow->changeStatusForRow(resultRow, "Cancelled"); diff --git a/tools/oven/src/ui/DomainBakeWidget.cpp b/tools/oven/src/ui/DomainBakeWidget.cpp index 41452c7283..bf79319458 100644 --- a/tools/oven/src/ui/DomainBakeWidget.cpp +++ b/tools/oven/src/ui/DomainBakeWidget.cpp @@ -21,8 +21,7 @@ #include #include -#include "../Oven.h" -#include "OvenMainWindow.h" +#include "../OvenGUIApplication.h" #include "DomainBakeWidget.h" @@ -223,14 +222,14 @@ void DomainBakeWidget::bakeButtonClicked() { connect(domainBaker.get(), &DomainBaker::bakeProgress, this, &DomainBakeWidget::handleBakerProgress); // move the baker to the next available Oven worker thread - auto nextThread = qApp->getNextWorkerThread(); + auto nextThread = Oven::instance().getNextWorkerThread(); domainBaker->moveToThread(nextThread); // kickoff the domain baker on its thread QMetaObject::invokeMethod(domainBaker.get(), "bake"); // add a pending row to the results window to show that this bake is in process - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); auto resultsRowName = _domainNameLineEdit->text().isEmpty() ? fileToBakeURL.fileName() : _domainNameLineEdit->text(); auto resultsRow = resultsWindow->addPendingResultRow(resultsRowName, outputDirectory); @@ -250,7 +249,7 @@ void DomainBakeWidget::handleBakerProgress(int baked, int total) { auto resultRow = it->second; // grab the results window, don't force it to be brought to the top - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(false); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(false); int percentage = roundf(float(baked) / float(total) * 100.0f); @@ -269,7 +268,7 @@ void DomainBakeWidget::handleFinishedBaker() { if (it != _bakers.end()) { auto resultRow = it->second; - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); if (baker->hasErrors()) { auto errors = baker->getErrors(); diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index 7963b3f3c4..61eea55917 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -21,8 +21,7 @@ #include #include -#include "../Oven.h" -#include "OvenMainWindow.h" +#include "../OvenGUIApplication.h" #include "ModelBakeWidget.h" @@ -208,12 +207,12 @@ void ModelBakeWidget::bakeButtonClicked() { // everything seems to be in place, kick off a bake for this model now auto baker = std::unique_ptr { new FBXBaker(modelToBakeURL, []() -> QThread* { - return qApp->getNextWorkerThread(); + return Oven::instance().getNextWorkerThread(); }, bakedOutputDirectory.absolutePath(), originalOutputDirectory.absolutePath()) }; // move the baker to the FBX baker thread - baker->moveToThread(qApp->getNextWorkerThread()); + baker->moveToThread(Oven::instance().getNextWorkerThread()); // invoke the bake method on the baker thread QMetaObject::invokeMethod(baker.get(), "bake"); @@ -222,7 +221,7 @@ void ModelBakeWidget::bakeButtonClicked() { connect(baker.get(), &FBXBaker::finished, this, &ModelBakeWidget::handleFinishedBaker); // add a pending row to the results window to show that this bake is in process - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); auto resultsRow = resultsWindow->addPendingResultRow(modelToBakeURL.fileName(), outputDirectory); // keep a unique_ptr to this baker @@ -244,7 +243,7 @@ void ModelBakeWidget::handleFinishedBaker() { if (it != _bakers.end()) { auto resultRow = it->second; - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); if (baker->hasErrors()) { resultsWindow->changeStatusForRow(resultRow, baker->getErrors().join("\n")); diff --git a/tools/oven/src/ui/SkyboxBakeWidget.cpp b/tools/oven/src/ui/SkyboxBakeWidget.cpp index cbaaa5ec0a..369b06c39f 100644 --- a/tools/oven/src/ui/SkyboxBakeWidget.cpp +++ b/tools/oven/src/ui/SkyboxBakeWidget.cpp @@ -21,8 +21,7 @@ #include #include -#include "../Oven.h" -#include "OvenMainWindow.h" +#include "../OvenGUIApplication.h" #include "SkyboxBakeWidget.h" @@ -184,7 +183,7 @@ void SkyboxBakeWidget::bakeButtonClicked() { }; // move the baker to a worker thread - baker->moveToThread(qApp->getNextWorkerThread()); + baker->moveToThread(Oven::instance().getNextWorkerThread()); // invoke the bake method on the baker thread QMetaObject::invokeMethod(baker.get(), "bake"); @@ -193,7 +192,7 @@ void SkyboxBakeWidget::bakeButtonClicked() { connect(baker.get(), &TextureBaker::finished, this, &SkyboxBakeWidget::handleFinishedBaker); // add a pending row to the results window to show that this bake is in process - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); auto resultsRow = resultsWindow->addPendingResultRow(skyboxToBakeURL.fileName(), outputDirectory); // keep a unique_ptr to this baker @@ -211,7 +210,7 @@ void SkyboxBakeWidget::handleFinishedBaker() { if (it != _bakers.end()) { auto resultRow = it->second; - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); if (baker->hasErrors()) { resultsWindow->changeStatusForRow(resultRow, baker->getErrors().join("\n")); From d4061c172ef8cb795b4b8409312ae1d41865686b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 20 Feb 2018 17:27:40 -0800 Subject: [PATCH 02/97] quit all threads before waiting on them (CR) --- tools/oven/src/Oven.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index e8d4c01f63..650683e1f0 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -32,9 +32,12 @@ Oven::Oven() { } Oven::~Oven() { - // quit and wait on the worker threads + // quit all worker threads and wait on them for (auto& thread : _workerThreads) { thread->quit(); + } + + for (auto& thread: _workerThreads) { thread->wait(); } From 79f5d0cee21161054b12d220b28d1d4bac546887 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 20 Feb 2018 18:49:38 -0800 Subject: [PATCH 03/97] include memory for unique_ptr in Oven --- tools/oven/src/Oven.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/oven/src/Oven.h b/tools/oven/src/Oven.h index 443def5cb1..effebb472e 100644 --- a/tools/oven/src/Oven.h +++ b/tools/oven/src/Oven.h @@ -13,6 +13,7 @@ #define hifi_Oven_h #include +#include class Oven { From 63e2084395a1de52bcd83264598cd3dea71ceb61 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Thu, 22 Feb 2018 17:29:06 -0800 Subject: [PATCH 04/97] Add a Q_DECLARE_METATYPE in TextureCache. There was a missing declaration that was causing an assert in the Qt meta-object system on startup in debug builds: Q_DECLARE_METATYPE(QWeakPointer) Bug fixed by Clement. --- libraries/model-networking/src/model-networking/TextureCache.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index ffa3150b43..f817c5eff9 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -133,6 +133,8 @@ private: using NetworkTexturePointer = QSharedPointer; +Q_DECLARE_METATYPE(QWeakPointer) + /// Stores cached textures, including render-to-texture targets. class TextureCache : public ResourceCache, public Dependency { Q_OBJECT From f9de255fa7d294c08452591b2c81fa1471d87bca Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 23 Feb 2018 20:07:09 +0300 Subject: [PATCH 05/97] FB12523 - HMD: Commerce specific disabled preview is not dismissed when user leaves page without entering credentials --- .../resources/qml/hifi/commerce/wallet/PassphraseModal.qml | 4 ++++ scripts/system/marketplaces/marketplaces.js | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index f1692acb3d..1fa9054d69 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -69,6 +69,10 @@ Item { hoverEnabled: true; } + Component.onDestruction: { + sendSignalToParent({method: 'maybeEnableHmdPreview'}); + } + // This will cause a bug -- if you bring up passphrase selection in HUD mode while // in HMD while having HMD preview enabled, then move, then finish passphrase selection, // HMD preview will stay off. diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 631b5e97ac..bb31d718e2 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -115,13 +115,15 @@ var selectionDisplay = null; // for gridTool.js to ignore var filterText; // Used for updating Purchases QML var onWalletScreen = false; + var onCommerceScreen = false; + function onScreenChanged(type, url) { onMarketplaceScreen = type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1; var onWalletScreenNow = url.indexOf(MARKETPLACE_WALLET_QML_PATH) !== -1; - onCommerceScreen = type === "QML" && (url.indexOf(MARKETPLACE_CHECKOUT_QML_PATH) !== -1 || url === MARKETPLACE_PURCHASES_QML_PATH + var onCommerceScreenNow = type === "QML" && (url.indexOf(MARKETPLACE_CHECKOUT_QML_PATH) !== -1 || url === MARKETPLACE_PURCHASES_QML_PATH || url.indexOf(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH) !== -1); - if (!onWalletScreenNow && onWalletScreen) { // exiting wallet screen + if ((!onWalletScreenNow && onWalletScreen) || (!onCommerceScreenNow && onCommerceScreen)) { // exiting wallet or commerce screen if (isHmdPreviewDisabledBySecurity) { DesktopPreviewProvider.setPreviewDisabledReason("USER"); Menu.setIsOptionChecked("Disable Preview", false); @@ -129,6 +131,7 @@ var selectionDisplay = null; // for gridTool.js to ignore } } + onCommerceScreen = onCommerceScreenNow; onWalletScreen = onWalletScreenNow; wireEventBridge(onMarketplaceScreen || onCommerceScreen || onWalletScreen); From b56f755034bcd578cf4c2e6419531d6ef24a317c Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 23 Feb 2018 15:10:49 -0800 Subject: [PATCH 06/97] material reflection --- interface/src/ui/overlays/ModelOverlay.cpp | 4 + .../src/avatars-renderer/Avatar.cpp | 4 + .../src/RenderableModelEntityItem.cpp | 4 + .../src/RenderableShapeEntityItem.cpp | 8 +- libraries/gpu/src/gpu/Texture.cpp | 10 -- libraries/gpu/src/gpu/Texture.h | 7 +- libraries/graphics-scripting/CMakeLists.txt | 2 +- .../src/graphics-scripting/Forward.h | 43 +++++- .../src/graphics-scripting/ScriptableMesh.cpp | 58 ++++++++ .../graphics-scripting/ScriptableModel.cpp | 124 ++++++++++++++++++ .../src/graphics-scripting/ScriptableModel.h | 7 +- libraries/graphics/src/graphics/Material.h | 1 + .../src/model-networking/MaterialCache.cpp | 7 + .../src/model-networking/TextureCache.cpp | 4 +- .../render-utils/src/CauterizedModel.cpp | 2 + libraries/render-utils/src/Model.cpp | 8 ++ 16 files changed, 272 insertions(+), 21 deletions(-) diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index ffcc18032c..47dd8f45f9 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -671,5 +671,9 @@ scriptable::ScriptableModelBase ModelOverlay::getScriptableModel() { } auto result = _model->getScriptableModel(); result.objectID = getID(); + { + std::lock_guard lock(_materialsLock); + result.appendMaterials(_materials); + } return result; } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 25ddfba670..db20f9144d 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1801,5 +1801,9 @@ scriptable::ScriptableModelBase Avatar::getScriptableModel() { } auto result = _skeletonModel->getScriptableModel(); result.objectID = getSessionUUID(); + { + std::lock_guard lock(_materialsLock); + result.appendMaterials(_materials); + } return result; } \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index f3c99cde2d..5c95d1e556 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -970,6 +970,10 @@ scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScript auto result = _model->getScriptableModel(); result.objectID = getEntity()->getID(); + { + std::lock_guard lock(_materialsLock); + result.appendMaterials(_materials); + } return result; } diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 22cd98b08a..e5cbfdb59d 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -169,8 +169,12 @@ scriptable::ScriptableModelBase ShapeEntityRenderer::getScriptableModel() { auto geometryCache = DependencyManager::get(); auto geometryShape = geometryCache->getShapeForEntityShape(_shape); glm::vec3 vertexColor; - if (_materials["0"].top().material) { - vertexColor = _materials["0"].top().material->getAlbedo(); + { + std::lock_guard lock(_materialsLock); + result.appendMaterials(_materials); + if (_materials["0"].top().material) { + vertexColor = _materials["0"].top().material->getAlbedo(); + } } if (auto mesh = geometryCache->meshFromShape(geometryShape, vertexColor)) { result.objectID = getEntity()->getID(); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 4a588c3c84..ed9505766b 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -868,16 +868,6 @@ void SphericalHarmonics::evalFromTexture(const Texture& texture) { // TextureSource -TextureSource::TextureSource() { -} - -TextureSource::~TextureSource() { -} - -void TextureSource::reset(const QUrl& url) { - _imageUrl = url; -} - void TextureSource::resetTexture(gpu::TexturePointer texture) { _gpuTexture = texture; } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index ad3dc5fada..a03b894e0d 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -647,13 +647,11 @@ typedef std::vector TextureViews; // It provides the mechanism to create a texture using a customizable TextureLoader class TextureSource { public: - TextureSource(); - ~TextureSource(); + TextureSource(const QUrl& url, int type = 0) : _imageUrl(url), _type(type) {} const QUrl& getUrl() const { return _imageUrl; } const gpu::TexturePointer getGPUTexture() const { return _gpuTexture; } - - void reset(const QUrl& url); + int getType() const { return _type; } void resetTexture(gpu::TexturePointer texture); @@ -662,6 +660,7 @@ public: protected: gpu::TexturePointer _gpuTexture; QUrl _imageUrl; + int _type { 0 }; }; typedef std::shared_ptr< TextureSource > TextureSourcePointer; diff --git a/libraries/graphics-scripting/CMakeLists.txt b/libraries/graphics-scripting/CMakeLists.txt index ad8055b647..0f59fb41f8 100644 --- a/libraries/graphics-scripting/CMakeLists.txt +++ b/libraries/graphics-scripting/CMakeLists.txt @@ -1,4 +1,4 @@ set(TARGET_NAME graphics-scripting) setup_hifi_library() -link_hifi_libraries(shared networking graphics fbx model-networking script-engine) +link_hifi_libraries(shared networking graphics fbx image model-networking script-engine) include_hifi_library_headers(gpu) diff --git a/libraries/graphics-scripting/src/graphics-scripting/Forward.h b/libraries/graphics-scripting/src/graphics-scripting/Forward.h index 94a96446a0..b07c25ee02 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/Forward.h +++ b/libraries/graphics-scripting/src/graphics-scripting/Forward.h @@ -6,9 +6,14 @@ #include #include #include +#include #include #include + +#include "graphics/Material.h" +#include "graphics/TextureMap.h" + namespace graphics { class Mesh; } @@ -31,6 +36,38 @@ namespace scriptable { using ModelProviderPointer = std::shared_ptr; using WeakModelProviderPointer = std::weak_ptr; + class ScriptableMaterial { + public: + ScriptableMaterial() {} + ScriptableMaterial(const graphics::MaterialLayer& materialLayer); + ScriptableMaterial(const ScriptableMaterial& material) { *this = material; } + ScriptableMaterial& operator=(const ScriptableMaterial& material); + + QString name; + QString model; + float opacity; + float roughness; + float metallic; + float scattering; + bool unlit; + glm::vec3 emissive; + glm::vec3 albedo; + QString emissiveMap; + QString albedoMap; + QString opacityMap; + QString metallicMap; + QString specularMap; + QString roughnessMap; + QString glossMap; + QString normalMap; + QString bumpMap; + QString occlusionMap; + QString lightmapMap; + QString scatteringMap; + quint16 priority; + }; + typedef QHash> MultiMaterialMap; + class ScriptableMeshBase : public QObject { Q_OBJECT public: @@ -55,6 +92,8 @@ namespace scriptable { WeakModelProviderPointer provider; QUuid objectID; // spatially nestable ID QVector meshes; + MultiMaterialMap materials; + QVector materialNames; ScriptableModelBase(QObject* parent = nullptr) : QObject(parent) {} ScriptableModelBase(const ScriptableModelBase& other) : QObject(other.parent()) { *this = other; } @@ -63,9 +102,11 @@ namespace scriptable { void append(const ScriptableMeshBase& mesh); void append(scriptable::WeakMeshPointer mesh); + void appendMaterial(const graphics::MaterialLayer& material, int shapeID, std::string materialName); + void appendMaterials(const std::unordered_map& materialsToAppend); + void appendMaterialNames(const std::vector& names); // TODO: in future containers for these could go here // QVariantMap shapes; - // QVariantMap materials; // QVariantMap armature; }; diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp index 76741947fd..7da69fcad2 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp @@ -554,6 +554,57 @@ namespace { qScriptValueToSequence(array, result); } + QScriptValue qVectorScriptableMaterialToScriptValue(QScriptEngine* engine, const QVector& vector) { + return qScriptValueFromSequence(engine, vector); + } + + void qVectorScriptableMaterialFromScriptValue(const QScriptValue& array, QVector& result) { + qScriptValueToSequence(array, result); + } + + QScriptValue scriptableMaterialToScriptValue(QScriptEngine* engine, const scriptable::ScriptableMaterial &material) { + QScriptValue obj = engine->newObject(); + obj.setProperty("name", material.name); + obj.setProperty("model", material.model); + obj.setProperty("opacity", material.opacity); + obj.setProperty("roughness", material.roughness); + obj.setProperty("metallic", material.metallic); + obj.setProperty("scattering", material.scattering); + obj.setProperty("unlit", material.unlit); + obj.setProperty("emissive", vec3toScriptValue(engine, material.emissive)); + obj.setProperty("albedo", vec3toScriptValue(engine, material.albedo)); + obj.setProperty("emissiveMap", material.emissiveMap); + obj.setProperty("albedoMap", material.albedoMap); + obj.setProperty("opacityMap", material.opacityMap); + obj.setProperty("metallicMap", material.metallicMap); + obj.setProperty("specularMap", material.specularMap); + obj.setProperty("roughnessMap", material.roughnessMap); + obj.setProperty("glossMap", material.glossMap); + obj.setProperty("normalMap", material.normalMap); + obj.setProperty("bumpMap", material.bumpMap); + obj.setProperty("occlusionMap", material.occlusionMap); + obj.setProperty("lightmapMap", material.lightmapMap); + obj.setProperty("scatteringMap", material.scatteringMap); + obj.setProperty("priority", material.priority); + return obj; + } + + void scriptableMaterialFromScriptValue(const QScriptValue &object, scriptable::ScriptableMaterial& material) { + // No need to convert from QScriptValue to ScriptableMaterial + } + + QScriptValue multiMaterialMapToScriptValue(QScriptEngine* engine, const scriptable::MultiMaterialMap& map) { + QScriptValue obj = engine->newObject(); + for (auto key : map.keys()) { + obj.setProperty(key, qVectorScriptableMaterialToScriptValue(engine, map[key])); + } + return obj; + } + + void multiMaterialMapFromScriptValue(const QScriptValue& map, scriptable::MultiMaterialMap& result) { + // No need to convert from QScriptValue to MultiMaterialMap + } + QVector metaTypeIds{ qRegisterMetaType("uint32"), qRegisterMetaType("scriptable::uint32"), @@ -562,6 +613,9 @@ namespace { qRegisterMetaType(), qRegisterMetaType(), qRegisterMetaType(), + qRegisterMetaType(), + qRegisterMetaType>(), + qRegisterMetaType() }; } @@ -570,11 +624,15 @@ namespace scriptable { qScriptRegisterSequenceMetaType>(engine); qScriptRegisterSequenceMetaType>(engine); qScriptRegisterSequenceMetaType>(engine); + qScriptRegisterSequenceMetaType>(engine); qScriptRegisterMetaType(engine, qVectorUInt32ToScriptValue, qVectorUInt32FromScriptValue); qScriptRegisterMetaType(engine, modelPointerToScriptValue, modelPointerFromScriptValue); qScriptRegisterMetaType(engine, meshPointerToScriptValue, meshPointerFromScriptValue); qScriptRegisterMetaType(engine, meshPartPointerToScriptValue, meshPartPointerFromScriptValue); + qScriptRegisterMetaType(engine, scriptableMaterialToScriptValue, scriptableMaterialFromScriptValue); + qScriptRegisterMetaType(engine, qVectorScriptableMaterialToScriptValue, qVectorScriptableMaterialFromScriptValue); + qScriptRegisterMetaType(engine, multiMaterialMapToScriptValue, multiMaterialMapFromScriptValue); return metaTypeIds.size(); } diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp index 8ceb7de6a2..9a4bfe60b6 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp @@ -14,14 +14,115 @@ #include +#include "graphics/Material.h" + +#include "image/Image.h" + // #define SCRIPTABLE_MESH_DEBUG 1 +scriptable::ScriptableMaterial& scriptable::ScriptableMaterial::operator=(const scriptable::ScriptableMaterial& material) { + name = material.name; + model = material.model; + opacity = material.opacity; + roughness = material.roughness; + metallic = material.metallic; + scattering = material.scattering; + unlit = material.unlit; + emissive = material.emissive; + albedo = material.albedo; + emissiveMap = material.emissiveMap; + albedoMap = material.albedoMap; + opacityMap = material.opacityMap; + metallicMap = material.metallicMap; + specularMap = material.specularMap; + roughnessMap = material.roughnessMap; + glossMap = material.glossMap; + normalMap = material.normalMap; + bumpMap = material.bumpMap; + occlusionMap = material.occlusionMap; + lightmapMap = material.lightmapMap; + scatteringMap = material.scatteringMap; + priority = material.priority; + + return *this; +} + +scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer& materialLayer) : + name(materialLayer.material->getName().c_str()), + model(materialLayer.material->getModel().c_str()), + opacity(materialLayer.material->getOpacity()), + roughness(materialLayer.material->getRoughness()), + metallic(materialLayer.material->getMetallic()), + scattering(materialLayer.material->getScattering()), + unlit(materialLayer.material->isUnlit()), + emissive(materialLayer.material->getEmissive()), + albedo(materialLayer.material->getAlbedo()), + priority(materialLayer.priority) +{ + auto map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP); + if (map && map->getTextureSource()) { + emissiveMap = map->getTextureSource()->getUrl().toString(); + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP); + if (map && map->getTextureSource()) { + albedoMap = map->getTextureSource()->getUrl().toString(); + if (map->useAlphaChannel()) { + opacityMap = albedoMap; + } + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP); + if (map && map->getTextureSource()) { + if (map->getTextureSource()->getType() == image::TextureUsage::Type::METALLIC_TEXTURE) { + metallicMap = map->getTextureSource()->getUrl().toString(); + } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::SPECULAR_TEXTURE) { + specularMap = map->getTextureSource()->getUrl().toString(); + } + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP); + if (map && map->getTextureSource()) { + if (map->getTextureSource()->getType() == image::TextureUsage::Type::ROUGHNESS_TEXTURE) { + roughnessMap = map->getTextureSource()->getUrl().toString(); + } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::GLOSS_TEXTURE) { + glossMap = map->getTextureSource()->getUrl().toString(); + } + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP); + if (map && map->getTextureSource()) { + if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) { + normalMap = map->getTextureSource()->getUrl().toString(); + } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::BUMP_TEXTURE) { + bumpMap = map->getTextureSource()->getUrl().toString(); + } + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP); + if (map && map->getTextureSource()) { + occlusionMap = map->getTextureSource()->getUrl().toString(); + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP); + if (map && map->getTextureSource()) { + lightmapMap = map->getTextureSource()->getUrl().toString(); + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP); + if (map && map->getTextureSource()) { + scatteringMap = map->getTextureSource()->getUrl().toString(); + } +} + scriptable::ScriptableModelBase& scriptable::ScriptableModelBase::operator=(const scriptable::ScriptableModelBase& other) { provider = other.provider; objectID = other.objectID; for (const auto& mesh : other.meshes) { append(mesh); } + materials = other.materials; + materialNames = other.materialNames; return *this; } @@ -34,6 +135,8 @@ scriptable::ScriptableModelBase::~ScriptableModelBase() { m.strongMesh.reset(); } meshes.clear(); + materials.clear(); + materialNames.clear(); } void scriptable::ScriptableModelBase::append(scriptable::WeakMeshPointer mesh) { @@ -47,6 +150,27 @@ void scriptable::ScriptableModelBase::append(const ScriptableMeshBase& mesh) { meshes << mesh; } +void scriptable::ScriptableModelBase::appendMaterial(const graphics::MaterialLayer& material, int shapeID, std::string materialName) { + materials[QString::number(shapeID)].push_back(ScriptableMaterial(material)); + materials["mat::" + QString::fromStdString(materialName)].push_back(ScriptableMaterial(material)); +} + +void scriptable::ScriptableModelBase::appendMaterials(const std::unordered_map& materialsToAppend) { + auto materialsToAppendCopy = materialsToAppend; + for (auto& multiMaterial : materialsToAppendCopy) { + while (!multiMaterial.second.empty()) { + materials[QString(multiMaterial.first.c_str())].push_back(ScriptableMaterial(multiMaterial.second.top())); + multiMaterial.second.pop(); + } + } +} + +void scriptable::ScriptableModelBase::appendMaterialNames(const std::vector& names) { + for (auto& name : names) { + materialNames.append(QString::fromStdString(name)); + } +} + QString scriptable::ScriptableModel::toString() const { return QString("[ScriptableModel%1%2 numMeshes=%3]") .arg(objectID.isNull() ? "" : " objectID="+objectID.toString()) diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h index 4ed1cc9554..9dc4c6f1ca 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h @@ -19,6 +19,8 @@ namespace scriptable { Q_PROPERTY(QUuid objectID MEMBER objectID CONSTANT) Q_PROPERTY(uint32 numMeshes READ getNumMeshes) Q_PROPERTY(QVector meshes READ getMeshes) + Q_PROPERTY(scriptable::MultiMaterialMap materials READ getMaterials) + Q_PROPERTY(QVector materialNames READ getMaterialNames) ScriptableModel(QObject* parent = nullptr) : ScriptableModelBase(parent) {} ScriptableModel(const ScriptableModel& other) : ScriptableModelBase(other) {} @@ -28,7 +30,6 @@ namespace scriptable { Q_INVOKABLE scriptable::ScriptableModelPointer cloneModel(const QVariantMap& options = QVariantMap()); // TODO: in future accessors for these could go here // QVariantMap shapes; - // QVariantMap materials; // QVariantMap armature; QVector getMeshes(); @@ -37,6 +38,8 @@ namespace scriptable { return QPointer(qobject_cast(this)); } + scriptable::MultiMaterialMap getMaterials() { return materials; } + QVector getMaterialNames() { return materialNames; } // QScriptEngine-specific wrappers Q_INVOKABLE uint32 mapAttributeValues(QScriptValue callback); @@ -51,3 +54,5 @@ Q_DECLARE_METATYPE(scriptable::WeakMeshPointer) Q_DECLARE_METATYPE(scriptable::ScriptableModelPointer) Q_DECLARE_METATYPE(scriptable::ScriptableModelBase) Q_DECLARE_METATYPE(scriptable::ScriptableModelBasePointer) +Q_DECLARE_METATYPE(scriptable::ScriptableMaterial) +Q_DECLARE_METATYPE(scriptable::MultiMaterialMap) diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 632cf99391..f34f68c04a 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -358,6 +358,7 @@ public: const std::string& getName() { return _name; } + const std::string& getModel() { return _model; } void setModel(const std::string& model) { _model = model; } protected: diff --git a/libraries/model-networking/src/model-networking/MaterialCache.cpp b/libraries/model-networking/src/model-networking/MaterialCache.cpp index 8d9d6571f8..85f2f43652 100644 --- a/libraries/model-networking/src/model-networking/MaterialCache.cpp +++ b/libraries/model-networking/src/model-networking/MaterialCache.cpp @@ -11,6 +11,8 @@ #include "QJsonDocument" #include "QJsonArray" +#include "RegisteredMetaTypes.h" + NetworkMaterialResource::NetworkMaterialResource(const QUrl& url) : Resource(url) {} @@ -39,6 +41,11 @@ bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3& color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble()); return true; } + } else if (array.isObject()) { + bool toReturn; + isSRGB = true; + color = vec3FromVariant(array.toObject(), toReturn); + return toReturn; } return false; } diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3a29139ee7..9b12c34f87 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -291,7 +291,7 @@ _type(), _sourceIsKTX(false), _maxNumPixels(100) { - _textureSource = std::make_shared(); + _textureSource = std::make_shared(url); _lowestRequestedMipLevel = 0; _loaded = true; } @@ -303,7 +303,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, image::TextureUsage::Type type, _sourceIsKTX(url.path().endsWith(".ktx")), _maxNumPixels(maxNumPixels) { - _textureSource = std::make_shared(); + _textureSource = std::make_shared(url, (int)type); _lowestRequestedMipLevel = 0; _shouldFailOnRedirect = !_sourceIsKTX; diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 54dfd96a00..5685a85349 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -57,6 +57,7 @@ void CauterizedModel::createVisibleRenderItemSet() { Q_ASSERT(_modelMeshRenderItems.isEmpty()); _modelMeshRenderItems.clear(); + _modelMeshMaterialNames.clear(); _modelMeshRenderItemShapes.clear(); Transform transform; @@ -81,6 +82,7 @@ void CauterizedModel::createVisibleRenderItemSet() { for (int partIndex = 0; partIndex < numParts; partIndex++) { auto ptr = std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::static_pointer_cast(ptr); + _modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName()); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 6d735497c0..f55b3c598d 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -629,12 +629,20 @@ scriptable::ScriptableModelBase Model::getScriptableModel() { const FBXGeometry& geometry = getFBXGeometry(); int numberOfMeshes = geometry.meshes.size(); + int shapeID = 0; for (int i = 0; i < numberOfMeshes; i++) { const FBXMesh& fbxMesh = geometry.meshes.at(i); if (auto mesh = fbxMesh._mesh) { result.append(mesh); + + int numParts = (int)mesh->getNumParts(); + for (int partIndex = 0; partIndex < numParts; partIndex++) { + result.appendMaterial(graphics::MaterialLayer(getGeometry()->getShapeMaterial(shapeID), 0), shapeID, _modelMeshMaterialNames[shapeID]); + shapeID++; + } } } + result.appendMaterialNames(_modelMeshMaterialNames); return result; } From b81f69d97a7aabaf2f6dc50e573dad7cb065fd45 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 23 Feb 2018 18:40:16 -0800 Subject: [PATCH 07/97] WIP - recursive tests. --- tools/auto-tester/src/Test.cpp | 13 +++++++------ tools/auto-tester/src/Test.h | 1 + tools/auto-tester/src/ui/AutoTester.cpp | 4 ++++ tools/auto-tester/src/ui/AutoTester.h | 1 + tools/auto-tester/src/ui/AutoTester.ui | 21 +++++++++++++++++---- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 816eac7fbd..931a940760 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -319,11 +319,12 @@ void Test::createRecursiveScript() { return; } - QFile allTestsFilename(topLevelDirectory + "/" + "allTests.js"); + const QString recursiveTestsFilename("testRecursive.js"); + QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { messageBox.critical(0, "Internal Error", - "Failed to create \"allTests.js\" in directory \"" + topLevelDirectory + "\"" + "Failed to create \"" + recursiveTestsFilename + "\" in directory \"" + topLevelDirectory + "\"" ); exit(-1); @@ -335,9 +336,6 @@ void Test::createRecursiveScript() { textStream << "var autoTester = Script.require(\"https://github.com/highfidelity/hifi_tests/blob/master/tests/utils/autoTester.js?raw=true\");" << endl; textStream << "autoTester.enableRecursive();" << endl << endl; - // The main will call each test after the previous test is completed - // This is implemented with an interval timer that periodically tests if a - // running test has increment a testNumber variable that it received as an input. QVector testPathnames; // First test if top-level folder has a test.js file @@ -371,7 +369,7 @@ void Test::createRecursiveScript() { } if (testPathnames.length() <= 0) { - messageBox.information(0, "Failure", "No \"test.js\" files found"); + messageBox.information(0, "Failure", "No \"" + TEST_FILENAME + "\" files found"); allTestsFilename.close(); return; } @@ -383,6 +381,9 @@ void Test::createRecursiveScript() { messageBox.information(0, "Success", "Script has been created"); } +void Test::createRecursiveScriptsRecursively() { +} + void Test::createTest() { // Rename files sequentially, as ExpectedResult_1.jpeg, ExpectedResult_2.jpg and so on // Any existing expected result images will be deleted diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 3177df4d47..3da5badb6d 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -26,6 +26,7 @@ public: void evaluateTests(bool interactiveMode, QProgressBar* progressBar); void evaluateTestsRecursively(bool interactiveMode, QProgressBar* progressBar); void createRecursiveScript(); + void createRecursiveScriptsRecursively(); void createTest(); void deleteOldSnapshots(); diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 2834ff81e0..18eef13e6e 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -30,6 +30,10 @@ void AutoTester::on_createRecursiveScriptButton_clicked() { test.createRecursiveScript(); } +void AutoTester::on_createRecursiveScriptsRecursivelyButton_clicked() { + test.createRecursiveScriptsRecursively(); +} + void AutoTester::on_createTestButton_clicked() { test.createTest(); } diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index 35f609a89d..d25969589b 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -24,6 +24,7 @@ private slots: void on_evaluateTestsButton_clicked(); void on_evaluateTestsRecursivelyButton_clicked(); void on_createRecursiveScriptButton_clicked(); + void on_createRecursiveScriptsRecursivelyButton_clicked(); void on_createTestButton_clicked(); void on_deleteOldSnapshotsButton_clicked(); void on_closeButton_clicked(); diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index d06255acf6..0d142ec43e 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -17,7 +17,7 @@ - 190 + 20 300 220 40 @@ -31,7 +31,7 @@ 360 - 130 + 210 220 40 @@ -112,7 +112,7 @@ 360 - 240 + 270 220 40 @@ -121,6 +121,19 @@ Delete Old Snapshots + + + + 360 + 140 + 220 + 40 + + + + Create Recursive Scripts Recursively + + @@ -145,4 +158,4 @@ - \ No newline at end of file + From 9f9214e808df300810b2eb7b610262caa137656e Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 1 Mar 2018 09:33:48 -0800 Subject: [PATCH 08/97] getting back the RC65 version for a few files --- interface/resources/qml/Stats.qml | 6 +--- interface/src/ui/Stats.cpp | 31 +------------------ interface/src/ui/Stats.h | 2 -- .../system/libraries/entitySelectionTool.js | 5 ++- 4 files changed, 4 insertions(+), 40 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index a12bd4b2c0..4626d9bcda 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -257,11 +257,7 @@ Item { id: octreeCol spacing: 4; x: 4; y: 4; StatText { - text: "Render Engine: " + root.engineFrameTime.toFixed(1) + " ms" - } - StatText { - visible: root.expanded - text: root.renderEngineStats + text: "Engine: " + root.engineFrameTime.toFixed(1) + " ms" } StatText { text: "Batch: " + root.batchFrameTime.toFixed(1) + " ms" diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index ff42ed09e7..80f57bfe0e 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -482,7 +482,7 @@ void Stats::updateStats(bool force) { float dt = (float)itr.value().getMovingAverage() / (float)USECS_PER_MSEC; _gameUpdateStats = QString("/idle/update = %1 ms").arg(dt); - QVector categories = { "devices", "physics", "otherAvatars", "MyAvatar", "pickManager", "postUpdateLambdas", "misc" }; + QVector categories = { "devices", "physics", "otherAvatars", "MyAvatar", "misc" }; for (int32_t j = 0; j < categories.size(); ++j) { QString recordKey = "/idle/update/" + categories[j]; itr = allRecords.find(recordKey); @@ -502,39 +502,10 @@ void Stats::updateStats(bool force) { _gameUpdateStats = ""; emit gameUpdateStatsChanged(); } - - itr = allRecords.find("/paintGL/display/EngineRun/Engine"); - std::priority_queue renderEngineStats; - if (itr != allRecords.end()) { - float dt = (float)itr.value().getMovingAverage() / (float)USECS_PER_MSEC; - _renderEngineStats = QString("/render = %1 ms").arg(dt); - - QVector categories = { "RenderMainView", "SecondaryCameraJob", "UpdateScene"}; - for (int32_t j = 0; j < categories.size(); ++j) { - QString recordKey = "/paintGL/display/EngineRun/Engine/" + categories[j]; - itr = allRecords.find(recordKey); - if (itr != allRecords.end()) { - float dt = (float)itr.value().getMovingAverage() / (float)USECS_PER_MSEC; - QString message = QString("\n %1 = %2").arg(categories[j]).arg(dt); - renderEngineStats.push(SortableStat(message, dt)); - } - } - while (!renderEngineStats.empty()) { - SortableStat stat = renderEngineStats.top(); - _renderEngineStats += stat.message; - renderEngineStats.pop(); - } - emit renderEngineStatsChanged(); - } else if (_renderEngineStats != "") { - _renderEngineStats = ""; - emit renderEngineStatsChanged(); - } } else if (_showGameUpdateStats) { _showGameUpdateStats = false; _gameUpdateStats = ""; - _renderEngineStats = ""; emit gameUpdateStatsChanged(); - emit renderEngineStatsChanged(); } } diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index e5fc0beaf6..af3189f20b 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -106,7 +106,6 @@ class Stats : public QQuickItem { STATS_PROPERTY(QString, lodStatus, QString()) STATS_PROPERTY(QString, timingStats, QString()) STATS_PROPERTY(QString, gameUpdateStats, QString()) - STATS_PROPERTY(QString, renderEngineStats, QString()) STATS_PROPERTY(int, serverElements, 0) STATS_PROPERTY(int, serverInternal, 0) STATS_PROPERTY(int, serverLeaves, 0) @@ -240,7 +239,6 @@ signals: void localLeavesChanged(); void timingStatsChanged(); void gameUpdateStatsChanged(); - void renderEngineStatsChanged(); void glContextSwapchainMemoryChanged(); void qmlTextureMemoryChanged(); void texturePendingTransfersChanged(); diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index a419e9d49c..8a07ff0d20 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1322,9 +1322,8 @@ SelectionDisplay = (function() { isActiveTool(handleScaleRTFCube) || isActiveTool(handleStretchXSphere) || isActiveTool(handleStretchYSphere) || isActiveTool(handleStretchZSphere)); - var showOutlineForZone = (SelectionManager.selections.length === 1 && - typeof SelectionManager.savedProperties[SelectionManager.selections[0]] !== "undefined" && - SelectionManager.savedProperties[SelectionManager.selections[0]].type === "Zone"); + var showOutlineForZone = (SelectionManager.selections.length === 1 && + SelectionManager.savedProperties[SelectionManager.selections[0]].type === "Zone"); that.setHandleScaleEdgeVisible(showOutlineForZone || (!isActiveTool(handleRotatePitchRing) && !isActiveTool(handleRotateYawRing) && !isActiveTool(handleRotateRollRing))); From 5440f62860ae8ca02943e1f9d27f5b80f99b6963 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 1 Mar 2018 10:46:47 -0800 Subject: [PATCH 09/97] fixing a bad key /pipeline pair --- libraries/render-utils/src/RenderPipelines.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index b3a1d40257..84a144e6db 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -592,8 +592,8 @@ void initForwardPipelines(ShapePlumber& plumber, const render::ShapePipeline::Ba Key::Builder().withMaterial().withSkinned().withTangents().withDualQuatSkinned(), skinModelNormalMapDualQuatVertex, modelNormalMapPixel, nullptr, nullptr); addPipeline( - Key::Builder().withMaterial().withSkinned(), - skinModelDualQuatVertex, modelSpecularMapPixel, nullptr, nullptr); + Key::Builder().withMaterial().withSkinned().withSpecular().withDualQuatSkinned(), + skinModelDualQuatVertex, modelSpecularMapPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withSkinned().withTangents().withSpecular().withDualQuatSkinned(), skinModelNormalMapDualQuatVertex, modelNormalSpecularMapPixel, nullptr, nullptr); From 8cae20f53de82ffe9a49c917bec62966e382ead6 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 1 Mar 2018 11:03:18 -0800 Subject: [PATCH 10/97] adding stereo checkbox to audio settings --- interface/resources/qml/hifi/audio/Audio.qml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index eab1e40af0..fc308100a8 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -112,6 +112,7 @@ Rectangle { // mute is in its own row RowLayout { + spacing: (margins.sizeCheckBox - 10.5) * 3; AudioControls.CheckBox { id: muteMic text: qsTr("Mute microphone"); @@ -123,6 +124,16 @@ Rectangle { checked = Qt.binding(function() { return AudioScriptingInterface.muted; }); // restore binding } } + + AudioControls.CheckBox { + id: stereoMic + spacing: muteMic.spacing; + text: qsTr("Enable stereo"); + checked: false; + onClicked: { + Audio.setIsStereoInput(checked); + } + } } RowLayout { From 4b572eda6bc93e89ae3e0debfe32a09615eb5e49 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 1 Mar 2018 11:05:40 -0800 Subject: [PATCH 11/97] changing Name --- interface/resources/qml/hifi/audio/Audio.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index fc308100a8..f7dde336c8 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -128,7 +128,7 @@ Rectangle { AudioControls.CheckBox { id: stereoMic spacing: muteMic.spacing; - text: qsTr("Enable stereo"); + text: qsTr("Stereo"); checked: false; onClicked: { Audio.setIsStereoInput(checked); From 2a1c22e7a5eb53548d0f901cfb3e9143e1c6c7ef Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Mar 2018 11:10:45 -0800 Subject: [PATCH 12/97] "Create Test" copies (and renames) images from snapshot folder to the corresponding test folder. --- tools/auto-tester/src/Test.cpp | 68 ++++++++++++++++++++++------------ tools/auto-tester/src/Test.h | 4 +- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 931a940760..357fc7b296 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -17,8 +17,6 @@ #include Test::Test() { - snapshotFilenameFormat = QRegularExpression("hifi-snap-by-.*-on-\\d\\d\\d\\d-\\d\\d-\\d\\d_\\d\\d-\\d\\d-\\d\\d.jpg"); - expectedImageFilenameFormat = QRegularExpression("ExpectedImage_\\d+.jpg"); mismatchWindow.setModal(true); @@ -387,16 +385,16 @@ void Test::createRecursiveScriptsRecursively() { void Test::createTest() { // Rename files sequentially, as ExpectedResult_1.jpeg, ExpectedResult_2.jpg and so on // Any existing expected result images will be deleted - QString pathToImageDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); - if (pathToImageDirectory == "") { + QString imageSourceDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); + if (imageSourceDirectory == "") { return; } - QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(pathToImageDirectory); + QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(imageSourceDirectory); int i = 1; foreach (QString currentFilename, sortedImageFilenames) { - QString fullCurrentFilename = pathToImageDirectory + "/" + currentFilename; + QString fullCurrentFilename = imageSourceDirectory + "/" + currentFilename; if (isInExpectedImageFilenameFormat(currentFilename)) { if (!QFile::remove(fullCurrentFilename)) { messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); @@ -408,22 +406,15 @@ void Test::createTest() { messageBox.critical(0, "Error", "More than 100,000 images not supported"); exit(-1); } - QString newFilename = "ExpectedImage_" + QString::number(i-1).rightJustified(5, '0') + ".jpg"; - QString fullNewFileName = pathToImageDirectory + "/" + newFilename; + QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".jpg"; + QString imageDestinationDirectory = getImageDestinationDirectory(currentFilename); + QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; - if (!imageDirectory.rename(fullCurrentFilename, newFilename)) { - if (!QFile::exists(fullCurrentFilename)) { - messageBox.critical(0, "Error", "Could not rename file: " + fullCurrentFilename + " to: " + newFilename + "\n" - + fullCurrentFilename + " not found" - + "\nTest creation aborted" - ); - exit(-1); - } else { - messageBox.critical(0, "Error", "Could not rename file: " + fullCurrentFilename + " to: " + newFilename + "\n" - + "unknown error" + "\nTest creation aborted" - ); - exit(-1); - } + try { + QFile::copy(fullCurrentFilename, fullNewFileName); + } catch (...) { + messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); + exit(-1); } ++i; } @@ -475,9 +466,40 @@ QStringList Test::createListOfAllJPEGimagesInDirectory(QString pathToImageDirect return imageDirectory.entryList(nameFilters, QDir::Files, QDir::Name); } -// Use regular expressions to check if files are in specific format +// Snapshots are files in the following format: +// Filename contains no periods (excluding period before exception +// Filename (i.e. without extension) contains _tests_ (this is based on all test scripts being within the tests folder +// Last 5 characters in filename are digits +// Extension is jpg bool Test::isInSnapshotFilenameFormat(QString filename) { - return (snapshotFilenameFormat.match(filename).hasMatch()); + QStringList filenameParts = filename.split("."); + + bool filnameHasNoPeriods = (filenameParts.size() == 2); + bool contains_tests = filenameParts[0].contains("_tests_"); + + bool last5CharactersAreDigits; + filenameParts[0].right(5).toInt(&last5CharactersAreDigits, 10); + + bool extensionIsJPG = filenameParts[1] == "jpg"; + + return (filnameHasNoPeriods && contains_tests && last5CharactersAreDigits && extensionIsJPG); +} + +// For a file named "D_GitHub_hifi-tests_tests_content_entity_zone_create_0.jpg", the test directory is +// D:/GitHub/hifi-tests/tests/content/entity/zone/create +// This method assumes the filename is in the correct format +// The final part of the filename is the image number. This is checked for sanity +QString Test::getImageDestinationDirectory(QString filename) { + QString filenameWithoutExtension = filename.split(".")[0]; + QStringList filenameParts = filenameWithoutExtension.split("_"); + + QString result = filenameParts[0] + ":"; + + for (int i = 1; i < filenameParts.length() - 1; ++i) { + result += "/" + filenameParts[i]; + } + + return result; } bool Test::isInExpectedImageFilenameFormat(QString filename) { diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 3da5badb6d..55fb7229d1 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -46,6 +46,8 @@ public: bool isAValidDirectory(QString pathname); + QString getImageDestinationDirectory(QString filename); + private: const QString TEST_FILENAME { "test.js" }; const QString TEST_RESULTS_FOLDER { "TestResults" }; @@ -55,14 +57,12 @@ private: QDir imageDirectory; - QRegularExpression snapshotFilenameFormat; QRegularExpression expectedImageFilenameFormat; MismatchWindow mismatchWindow; ImageComparer imageComparer; - QString testResultsFolderPath { "" }; int index { 1 }; }; From b2c7ddbd056813131fdad8a0c5da05bc1f125f77 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Thu, 15 Feb 2018 14:52:16 -0500 Subject: [PATCH 13/97] [Case 4315] Particle System Tab has additional color picker support (details below). * Adds 3 additional keys/properties to hifi-entity-ui's specification support for color pickers. * layoutType: This correlates to colpick's layout property. This is expected to be a string. Valid values are those supported by colpick, see colpick.js for additional details. * Within hifi-entity-ui, if this value isn't specified the default is "hex" as was previously hard coded. * layoutColorScheme: This correlates to colpicks's colorScheme property. This is expected to be a string. Valid values are those supported by colpick, see colpick.js for additional details. * Within hifi-entity-ui, if this value isn't specified the default is "dark" as was previously hard coded. * useSubmitButton: This correlates to colpick's submit property. This is expected to be a boolean. See colpick.js for additional details. * Within hifi-entity-ui, if this value isn't specified the default is true as was previously hard coded. * Amends particleExplorer.js color picker descriptors to make use of the new keys to bring the color pickers within the Particle Tab inline with the appearance of the Properties Tab color pickers submitted within PR #12241 which don't utilize the OK button. Changes Committed: modified: scripts/system/particle_explorer/hifi-entity-ui.js modified: scripts/system/particle_explorer/particleExplorer.js --- .../particle_explorer/hifi-entity-ui.js | 5 +++-- .../particle_explorer/particleExplorer.js | 20 +++++++++++++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/scripts/system/particle_explorer/hifi-entity-ui.js b/scripts/system/particle_explorer/hifi-entity-ui.js index 720aaee4d9..05b6ba6f75 100644 --- a/scripts/system/particle_explorer/hifi-entity-ui.js +++ b/scripts/system/particle_explorer/hifi-entity-ui.js @@ -439,8 +439,9 @@ HifiEntityUI.prototype = { $colPickContainer.colpick({ - colorScheme: 'dark', - layout: 'hex', + colorScheme: (group.layoutColorScheme === undefined ? 'dark' : group.layoutColorScheme), + layout: (group.layoutType === undefined ? 'hex' : group.layoutType), + submit: (group.useSubmitButton === undefined ? true : group.useSubmitButton), color: { r: domArray[0].value, g: domArray[1].value, diff --git a/scripts/system/particle_explorer/particleExplorer.js b/scripts/system/particle_explorer/particleExplorer.js index 971798828f..3598f30ee0 100644 --- a/scripts/system/particle_explorer/particleExplorer.js +++ b/scripts/system/particle_explorer/particleExplorer.js @@ -236,7 +236,10 @@ red: 255, green: 255, blue: 255 - } + }, + layoutType: "hex", + layoutColorScheme: "dark", + useSubmitButton: false }, { type: "Row" @@ -249,7 +252,10 @@ red: 0, green: 0, blue: 0 - } + }, + layoutType: "hex", + layoutColorScheme: "dark", + useSubmitButton: false }, { type: "Row" @@ -262,7 +268,10 @@ red: 255, green: 255, blue: 255 - } + }, + layoutType: "hex", + layoutColorScheme: "dark", + useSubmitButton: false }, { type: "Row" @@ -275,7 +284,10 @@ red: 255, green: 255, blue: 255 - } + }, + layoutType: "hex", + layoutColorScheme: "dark", + useSubmitButton: false }, { type: "Row" From fde1ca62620e162c4804e6da8ab01f3ff0aa6256 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Thu, 22 Feb 2018 14:49:15 -0500 Subject: [PATCH 14/97] [Case 4315] Ensures that Particle Tab Color Pickers obey colpick visual styling. Changes Committed: modified: scripts/system/particle_explorer/particleExplorer.html --- scripts/system/particle_explorer/particleExplorer.html | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/particle_explorer/particleExplorer.html b/scripts/system/particle_explorer/particleExplorer.html index 48cd4afa06..ab4c249cc3 100644 --- a/scripts/system/particle_explorer/particleExplorer.html +++ b/scripts/system/particle_explorer/particleExplorer.html @@ -27,6 +27,7 @@ + From 0f2cf8ea85b32e2d5121a42b7cbe232ebe5575a5 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Mar 2018 14:24:20 -0800 Subject: [PATCH 15/97] Re-implemented shadow controls. --- .../dialogs/GraphicsPreferencesDialog.qml | 19 ------ interface/src/Menu.cpp | 16 +++-- interface/src/Menu.h | 2 + .../src/RenderableEntityItem.cpp | 8 ++- .../src/RenderableEntityItem.h | 1 + .../src/RenderableModelEntityItem.cpp | 4 ++ .../src/RenderableZoneEntityItem.cpp | 1 + libraries/entities/src/EntityItem.cpp | 27 ++++++++ libraries/entities/src/EntityItem.h | 5 ++ .../entities/src/EntityItemProperties.cpp | 13 ++++ libraries/entities/src/EntityItemProperties.h | 2 + .../src/EntityItemPropertiesDefaults.h | 1 + libraries/entities/src/EntityPropertyFlags.h | 10 +-- .../entities/src/KeyLightPropertyGroup.cpp | 31 +++++++-- .../entities/src/KeyLightPropertyGroup.h | 2 + libraries/graphics/src/graphics/Light.cpp | 9 ++- libraries/graphics/src/graphics/Light.h | 5 ++ .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- .../render-utils/src/CauterizedModel.cpp | 5 +- .../src/DeferredLightingEffect.cpp | 18 ++++-- .../render-utils/src/DeferredLightingEffect.h | 2 +- .../render-utils/src/MeshPartPayload.cpp | 13 +++- libraries/render-utils/src/MeshPartPayload.h | 4 +- libraries/render-utils/src/Model.cpp | 63 +++++++++++++------ libraries/render-utils/src/Model.h | 6 ++ .../render-utils/src/RenderShadowTask.cpp | 14 ++++- libraries/render-utils/src/RenderShadowTask.h | 2 +- scripts/system/html/entityProperties.html | 44 ++++++------- scripts/system/html/js/entityProperties.js | 32 +++++++++- 30 files changed, 269 insertions(+), 95 deletions(-) delete mode 100644 interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml diff --git a/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml deleted file mode 100644 index d95bafd0a9..0000000000 --- a/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml +++ /dev/null @@ -1,19 +0,0 @@ -import QtQuick 2.5 -import Qt.labs.settings 1.0 - -import "../../dialogs" - -PreferencesDialog { - id: root - objectName: "GraphicsPreferencesDialog" - title: "Graphics Settings" - showCategories: ["Graphics"] - property var settings: Settings { - category: root.objectName - property alias x: root.x - property alias y: root.y - property alias width: root.width - property alias height: root.height - } -} - diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8c0ac584c5..ca6f7a31d1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -43,6 +43,7 @@ #include "ui/StandAloneJSConsole.h" #include "InterfaceLogging.h" #include "LocationBookmarks.h" +#include "DeferredLightingEffect.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) #include "SpeechRecognizer.h" @@ -360,11 +361,16 @@ Menu::Menu() { // Developer menu ---------------------------------- MenuWrapper* developerMenu = addMenu("Developer", "Developer"); - // Developer > Graphics... - action = addActionToQMenuAndActionHash(developerMenu, "Graphics..."); - connect(action, &QAction::triggered, [] { - qApp->showDialog(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"), - QString("hifi/tablet/TabletGraphicsPreferences.qml"), "GraphicsPreferencesDialog"); + // Developer > Graphics + MenuWrapper* graphicsOptionsMenu = developerMenu->addMenu("Render"); + action = addCheckableActionToQMenuAndActionHash(graphicsOptionsMenu, MenuOption::Shadows, 0, true); + connect(action, &QAction::triggered, [action] { + DependencyManager::get()->setShadowMapEnabled(action->isChecked()); + }); + + action = addCheckableActionToQMenuAndActionHash(graphicsOptionsMenu, MenuOption::AmbientOcclusion, 0, false); + connect(action, &QAction::triggered, [action] { + DependencyManager::get()->setAmbientOcclusionEnabled(action->isChecked()); }); // Developer > UI >>> diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 34588535ec..1d37b74ffe 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -204,6 +204,8 @@ namespace MenuOption { const QString WorldAxes = "World Axes"; const QString DesktopTabletToToolbar = "Desktop Tablet Becomes Toolbar"; const QString HMDTabletToToolbar = "HMD Tablet Becomes Toolbar"; + const QString Shadows = "Shadows"; + const QString AmbientOcclusion = "AmbientOcclusion"; } #endif // hifi_Menu_h diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index d3c9f3d4bd..c33b87e5cf 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -164,7 +164,12 @@ ItemKey EntityRenderer::getKey() { return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); } - return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + // This allows shapes to cast shadows + if (_canCastShadow) { + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).withShadowCaster(); + } else { + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + } } uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) { @@ -377,6 +382,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa _moving = entity->isMovingRelativeToParent(); _visible = entity->getVisible(); + _canCastShadow = entity->getCanCastShadow(); _cauterized = entity->getCauterized(); _needsRenderUpdate = false; }); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index d34a1127ae..ada57c8ab0 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -129,6 +129,7 @@ protected: bool _isFading{ _entitiesShouldFadeFunction() }; bool _prevIsTransparent { false }; bool _visible { false }; + bool _canCastShadow { false }; bool _cauterized { false }; bool _moving { false }; bool _needsRenderUpdate { false }; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 5f926d1bb9..b7c5caf8ee 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1395,6 +1395,10 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce } // TODO? early exit here when not visible? + if (model->canCastShadow() != _canCastShadow) { + model->setCanCastShadow(_canCastShadow, scene, viewTaskBits, false); + } + if (_needsCollisionGeometryUpdate) { setCollisionMeshKey(entity->getCollisionMeshKey()); _needsCollisionGeometryUpdate = false; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 34703804cd..322c91e3d3 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -330,6 +330,7 @@ void ZoneEntityRenderer::updateKeySunFromEntity(const TypedEntityPointer& entity sunLight->setColor(ColorUtils::toVec3(_keyLightProperties.getColor())); sunLight->setIntensity(_keyLightProperties.getIntensity()); sunLight->setDirection(entity->getTransform().getRotation() * _keyLightProperties.getDirection()); + sunLight->setCastShadows(_keyLightProperties.getCastShadows()); } void ZoneEntityRenderer::updateAmbientLightFromEntity(const TypedEntityPointer& entity) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ec0bdbd2ae..f77d8a59c3 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -91,6 +91,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_REGISTRATION_POINT; requestedProperties += PROP_ANGULAR_DAMPING; requestedProperties += PROP_VISIBLE; + requestedProperties += PROP_CAN_CAST_SHADOW; requestedProperties += PROP_COLLISIONLESS; requestedProperties += PROP_COLLISION_MASK; requestedProperties += PROP_DYNAMIC; @@ -249,6 +250,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, getVisible()); + APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, getCanCastShadow()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONLESS, getCollisionless()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, getCollisionMask()); APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, getDynamic()); @@ -799,6 +801,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, setAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); + READ_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); READ_ENTITY_PROPERTY(PROP_COLLISIONLESS, bool, setCollisionless); READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, setCollisionMask); READ_ENTITY_PROPERTY(PROP_DYNAMIC, bool, setDynamic); @@ -1234,6 +1237,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularDamping, getAngularDamping); COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRenderAlpha, getLocalRenderAlpha); COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(canCastShadow, getCanCastShadow); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionless, getCollisionless); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionMask, getCollisionMask); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dynamic, getDynamic); @@ -1346,6 +1350,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(canCastShadow, setCanCastShadow); SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); // Certifiable Properties @@ -2723,6 +2728,28 @@ void EntityItem::setVisible(bool value) { } } +bool EntityItem::getCanCastShadow() const { + bool result; + withReadLock([&] { + result = _canCastShadow; + }); + return result; +} + +void EntityItem::setCanCastShadow(bool value) { + bool changed = false; + withWriteLock([&] { + if (_canCastShadow != value) { + changed = true; + _canCastShadow = value; + } + }); + + if (changed) { + emit requestRenderUpdate(); + } +} + bool EntityItem::isChildOfMyAvatar() const { QUuid ancestorID = findAncestorOfType(NestableType::Avatar); return !ancestorID.isNull() && (ancestorID == Physics::getSessionUUID() || ancestorID == AVATAR_SELF_ID); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index b12417c496..d08c5514e9 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -274,6 +274,10 @@ public: bool getVisible() const; void setVisible(bool value); + + bool getCanCastShadow() const; + void setCanCastShadow(bool value); + inline bool isVisible() const { return getVisible(); } inline bool isInvisible() const { return !getVisible(); } @@ -551,6 +555,7 @@ protected: glm::vec3 _registrationPoint { ENTITY_ITEM_DEFAULT_REGISTRATION_POINT }; float _angularDamping { ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING }; bool _visible { ENTITY_ITEM_DEFAULT_VISIBLE }; + bool _canCastShadow{ ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW }; bool _collisionless { ENTITY_ITEM_DEFAULT_COLLISIONLESS }; uint8_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; bool _dynamic { ENTITY_ITEM_DEFAULT_DYNAMIC }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index a2724c4cbf..2eca612fc2 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -316,6 +316,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible); + CHECK_PROPERTY_CHANGE(PROP_CAN_CAST_SHADOW, canCastShadow); CHECK_PROPERTY_CHANGE(PROP_REGISTRATION_POINT, registrationPoint); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping); @@ -490,6 +491,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_VELOCITY, angularVelocity); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CAN_CAST_SHADOW, canCastShadow); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONLESS, collisionless); COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISIONLESS, collisionless, ignoreForCollisions, getCollisionless()); // legacy support COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_MASK, collisionMask); @@ -751,6 +753,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, glmVec3, setAngularVelocity); COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping); COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible); + COPY_PROPERTY_FROM_QSCRIPTVALUE(canCastShadow, bool, setCanCastShadow); COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor); COPY_PROPERTY_FROM_QSCRIPTVALUE(colorSpread, xColor, setColorSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(colorStart, xColor, setColorStart); @@ -922,6 +925,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(angularVelocity); COPY_PROPERTY_IF_CHANGED(angularDamping); COPY_PROPERTY_IF_CHANGED(visible); + COPY_PROPERTY_IF_CHANGED(canCastShadow); COPY_PROPERTY_IF_CHANGED(color); COPY_PROPERTY_IF_CHANGED(colorSpread); COPY_PROPERTY_IF_CHANGED(colorStart); @@ -1094,6 +1098,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue std::call_once(initMap, [](){ ADD_PROPERTY_TO_MAP(PROP_VISIBLE, Visible, visible, bool); + ADD_PROPERTY_TO_MAP(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool); ADD_PROPERTY_TO_MAP(PROP_POSITION, Position, position, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_DIMENSIONS, Dimensions, dimensions, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_ROTATION, Rotation, rotation, glm::quat); @@ -1187,6 +1192,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor); ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float); ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_DIRECTION, KeyLightDirection, keyLightDirection, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_CAST_SHADOW, KeyLightCastShadows, keyLightCastShadows, bool); + ADD_PROPERTY_TO_MAP(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray); ADD_PROPERTY_TO_MAP(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t); @@ -1412,6 +1419,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, properties.getAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, properties.getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, properties.getVisible()); + APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, properties.getCanCastShadow()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONLESS, properties.getCollisionless()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, properties.getCollisionMask()); APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, properties.getDynamic()); @@ -1784,6 +1792,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, glm::vec3, setAngularVelocity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONLESS, bool, setCollisionless); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_MASK, uint8_t, setCollisionMask); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DYNAMIC, bool, setDynamic); @@ -2053,6 +2062,7 @@ void EntityItemProperties::markAllChanged() { _angularDampingChanged = true; _nameChanged = true; _visibleChanged = true; + _canCastShadowChanged = true; _colorChanged = true; _alphaChanged = true; _modelURLChanged = true; @@ -2250,6 +2260,9 @@ QList EntityItemProperties::listChangedProperties() { if (visibleChanged()) { out += "visible"; } + if (canCastShadowChanged()) { + out += "canCastShadow"; + } if (rotationChanged()) { out += "rotation"; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 36ca47291c..0838bb937a 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -117,6 +117,7 @@ public: // bool _fooChanged { false }; DEFINE_PROPERTY(PROP_VISIBLE, Visible, visible, bool, ENTITY_ITEM_DEFAULT_VISIBLE); + DEFINE_PROPERTY(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool, ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW); DEFINE_PROPERTY_REF_WITH_SETTER(PROP_POSITION, Position, position, glm::vec3, ENTITY_ITEM_ZERO_VEC3); DEFINE_PROPERTY_REF(PROP_DIMENSIONS, Dimensions, dimensions, glm::vec3, ENTITY_ITEM_DEFAULT_DIMENSIONS); DEFINE_PROPERTY_REF(PROP_ROTATION, Rotation, rotation, glm::quat, ENTITY_ITEM_DEFAULT_ROTATION); @@ -426,6 +427,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, Velocity, velocity, "in meters"); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Name, name, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Visible, visible, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, CanCastShadow, canCastShadow, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Rotation, rotation, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Density, density, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Gravity, gravity, ""); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index eb09a64628..0e0c2994cd 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -46,6 +46,7 @@ const quint32 ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION = 0; const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f; const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; const bool ENTITY_ITEM_DEFAULT_VISIBLE = true; +const bool ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW { true }; const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString(""); const quint64 ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP = 0; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index b65d5d1a3f..07908fe6cf 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -20,6 +20,7 @@ enum EntityPropertyList { // these properties are supported by the EntityItem base class PROP_VISIBLE, + PROP_CAN_CAST_SHADOW, PROP_POSITION, PROP_DIMENSIONS, PROP_ROTATION, @@ -205,6 +206,11 @@ enum EntityPropertyList { PROP_HAZE_MODE, + PROP_KEYLIGHT_COLOR, + PROP_KEYLIGHT_INTENSITY, + PROP_KEYLIGHT_DIRECTION, + PROP_KEYLIGHT_CAST_SHADOW, + PROP_HAZE_RANGE, PROP_HAZE_COLOR, PROP_HAZE_GLARE_COLOR, @@ -254,10 +260,6 @@ enum EntityPropertyList { // Aliases/Piggyback properties for Zones. These properties intentionally reuse the enum values for // 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_DIRECTION = PROP_EXPONENT, - PROP_SKYBOX_COLOR = PROP_ANIMATION_URL, PROP_SKYBOX_URL = PROP_ANIMATION_FPS, diff --git a/libraries/entities/src/KeyLightPropertyGroup.cpp b/libraries/entities/src/KeyLightPropertyGroup.cpp index c476b4c23c..e0b6ae6e96 100644 --- a/libraries/entities/src/KeyLightPropertyGroup.cpp +++ b/libraries/entities/src/KeyLightPropertyGroup.cpp @@ -21,6 +21,7 @@ const xColor KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR = { 255, 255, 255 }; const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY = 1.0f; const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY = 0.5f; const glm::vec3 KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION = { 0.0f, -1.0f, 0.0f }; +const bool KeyLightPropertyGroup::DEFAULT_KEYLIGHT_CAST_SHADOWS { false }; void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { @@ -28,23 +29,27 @@ void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desired COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_COLOR, KeyLight, keyLight, Color, color); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_INTENSITY, KeyLight, keyLight, Intensity, intensity); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_DIRECTION, KeyLight, keyLight, Direction, direction); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_CAST_SHADOW, KeyLight, keyLight, CastShadows, castShadows); } void KeyLightPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, color, xColor, setColor); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, intensity, float, setIntensity); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, direction, glmVec3, setDirection); - + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, castShadows, bool, setCastShadows); + // legacy property support COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightColor, xColor, setColor, getColor); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightIntensity, float, setIntensity, getIntensity); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightDirection, glmVec3, setDirection, getDirection); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightCastShadows, bool, setCastShadows, getCastShadows); } void KeyLightPropertyGroup::merge(const KeyLightPropertyGroup& other) { COPY_PROPERTY_IF_CHANGED(color); COPY_PROPERTY_IF_CHANGED(intensity); COPY_PROPERTY_IF_CHANGED(direction); + COPY_PROPERTY_IF_CHANGED(castShadows); } void KeyLightPropertyGroup::debugDump() const { @@ -52,6 +57,7 @@ void KeyLightPropertyGroup::debugDump() const { qCDebug(entities) << " color:" << getColor(); // << "," << getColor()[1] << "," << getColor()[2]; qCDebug(entities) << " intensity:" << getIntensity(); qCDebug(entities) << " direction:" << getDirection(); + qCDebug(entities) << " castShadows:" << getCastShadows(); } void KeyLightPropertyGroup::listChangedProperties(QList& out) { @@ -64,6 +70,9 @@ void KeyLightPropertyGroup::listChangedProperties(QList& out) { if (directionChanged()) { out << "keyLight-direction"; } + if (castShadowsChanged()) { + out << "keyLight-castShadows"; + } } bool KeyLightPropertyGroup::appendToEditPacket(OctreePacketData* packetData, @@ -78,12 +87,13 @@ bool KeyLightPropertyGroup::appendToEditPacket(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, getColor()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, getIntensity()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, getDirection()); - + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, getCastShadows()); + return true; } bool KeyLightPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt, - int& processedBytes) { + int& processedBytes) { int bytesRead = 0; bool overwriteLocalData = true; @@ -92,11 +102,13 @@ bool KeyLightPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFl READ_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, xColor, setColor); READ_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, float, setIntensity); READ_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, glm::vec3, setDirection); - + READ_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, bool, setCastShadows); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_COLOR, Color); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_INTENSITY, Intensity); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_DIRECTION, Direction); - + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_CAST_SHADOW, CastShadows); + processedBytes += bytesRead; Q_UNUSED(somethingChanged); @@ -108,6 +120,7 @@ void KeyLightPropertyGroup::markAllChanged() { _colorChanged = true; _intensityChanged = true; _directionChanged = true; + _castShadowsChanged = true; } EntityPropertyFlags KeyLightPropertyGroup::getChangedProperties() const { @@ -116,7 +129,8 @@ EntityPropertyFlags KeyLightPropertyGroup::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, color); CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_INTENSITY, intensity); CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_DIRECTION, direction); - + CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_CAST_SHADOW, castShadows); + return changedProperties; } @@ -124,6 +138,7 @@ void KeyLightPropertyGroup::getProperties(EntityItemProperties& properties) cons COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, Color, getColor); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, Intensity, getIntensity); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, Direction, getDirection); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, CastShadows, getCastShadows); } bool KeyLightPropertyGroup::setProperties(const EntityItemProperties& properties) { @@ -132,6 +147,7 @@ bool KeyLightPropertyGroup::setProperties(const EntityItemProperties& properties SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, Color, color, setColor); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, Intensity, intensity, setIntensity); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, Direction, direction, setDirection); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, CastShadows, castShadows, setCastShadows); return somethingChanged; } @@ -142,6 +158,7 @@ EntityPropertyFlags KeyLightPropertyGroup::getEntityProperties(EncodeBitstreamPa requestedProperties += PROP_KEYLIGHT_COLOR; requestedProperties += PROP_KEYLIGHT_INTENSITY; requestedProperties += PROP_KEYLIGHT_DIRECTION; + requestedProperties += PROP_KEYLIGHT_CAST_SHADOW; return requestedProperties; } @@ -159,6 +176,7 @@ void KeyLightPropertyGroup::appendSubclassData(OctreePacketData* packetData, Enc APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, getColor()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, getIntensity()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, getDirection()); + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, getCastShadows()); } int KeyLightPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, @@ -172,6 +190,7 @@ int KeyLightPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* READ_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, xColor, setColor); READ_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, float, setIntensity); READ_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, glm::vec3, setDirection); + READ_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, bool, setCastShadows); return bytesRead; } diff --git a/libraries/entities/src/KeyLightPropertyGroup.h b/libraries/entities/src/KeyLightPropertyGroup.h index f33ebb282d..5e13a6afa6 100644 --- a/libraries/entities/src/KeyLightPropertyGroup.h +++ b/libraries/entities/src/KeyLightPropertyGroup.h @@ -78,10 +78,12 @@ public: static const float DEFAULT_KEYLIGHT_INTENSITY; static const float DEFAULT_KEYLIGHT_AMBIENT_INTENSITY; static const glm::vec3 DEFAULT_KEYLIGHT_DIRECTION; + static const bool DEFAULT_KEYLIGHT_CAST_SHADOWS; DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, Color, color, xColor, DEFAULT_KEYLIGHT_COLOR); DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, Intensity, intensity, float, DEFAULT_KEYLIGHT_INTENSITY); DEFINE_PROPERTY_REF(PROP_KEYLIGHT_DIRECTION, Direction, direction, glm::vec3, DEFAULT_KEYLIGHT_DIRECTION); + DEFINE_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, CastShadows, castShadows, bool, DEFAULT_KEYLIGHT_CAST_SHADOWS); }; #endif // hifi_KeyLightPropertyGroup_h diff --git a/libraries/graphics/src/graphics/Light.cpp b/libraries/graphics/src/graphics/Light.cpp index 9da14fec4f..76d8a6030a 100755 --- a/libraries/graphics/src/graphics/Light.cpp +++ b/libraries/graphics/src/graphics/Light.cpp @@ -65,6 +65,14 @@ const Vec3& Light::getDirection() const { return _lightSchemaBuffer->volume.direction; } +void Light::setCastShadows(const bool castShadows) { + _castShadows = castShadows; +} + +bool Light::getCastShadows() const { + return _castShadows; +} + void Light::setColor(const Color& color) { _lightSchemaBuffer.edit().irradiance.color = color; updateLightRadius(); @@ -132,7 +140,6 @@ void Light::setSpotExponent(float exponent) { _lightSchemaBuffer.edit().irradiance.falloffSpot = exponent; } - void Light::setAmbientIntensity(float intensity) { _ambientSchemaBuffer.edit().intensity = intensity; } diff --git a/libraries/graphics/src/graphics/Light.h b/libraries/graphics/src/graphics/Light.h index e6ef1e35c5..bb9fb3e5b9 100755 --- a/libraries/graphics/src/graphics/Light.h +++ b/libraries/graphics/src/graphics/Light.h @@ -103,6 +103,9 @@ public: void setDirection(const Vec3& direction); const Vec3& getDirection() const; + void setCastShadows(const bool castShadows); + bool getCastShadows() const; + void setOrientation(const Quat& orientation); const glm::quat& getOrientation() const { return _transform.getRotation(); } @@ -191,6 +194,8 @@ protected: void updateLightRadius(); + bool _castShadows{ false }; + }; typedef std::shared_ptr< Light > LightPointer; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 5c202fa70c..a83924ee58 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::MaterialEntities); + return static_cast(EntityVersion::ShadowControl); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::RemovedJurisdictions); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index e9fe232335..98a9087d37 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -230,7 +230,8 @@ enum class EntityVersion : PacketVersion { ZoneLightInheritModes = 82, ZoneStageRemoved, SoftEntities, - MaterialEntities + MaterialEntities, + ShadowControl }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 6806b41647..fdb57dace7 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -214,6 +214,7 @@ void CauterizedModel::updateRenderItems() { bool isWireframe = self->isWireframe(); bool isVisible = self->isVisible(); + bool canCastShadow = self->canCastShadow(); bool isLayeredInFront = self->isLayeredInFront(); bool isLayeredInHUD = self->isLayeredInHUD(); bool enableCauterization = self->getEnableCauterization(); @@ -231,7 +232,7 @@ void CauterizedModel::updateRenderItems() { bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, - isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) { + isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, canCastShadow, enableCauterization](CauterizedMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions, cauterizedMeshState.clusterDualQuaternions); @@ -273,7 +274,7 @@ void CauterizedModel::updateRenderItems() { data.updateTransformForCauterizedMesh(renderTransform); data.setEnableCauterization(enableCauterization); - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::TAG_BITS_ALL); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, render::ItemKey::TAG_BITS_ALL); data.setLayer(isLayeredInFront, isLayeredInHUD); data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); }); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e2c0073d2f..665e767c7c 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -537,15 +537,25 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, auto keyLight = lightAndShadow.first; - graphics::LightPointer keyAmbientLight; + graphics::LightPointer ambientLight; if (lightStage && lightStage->_currentFrame._ambientLights.size()) { - keyAmbientLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front()); + ambientLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front()); } - bool hasAmbientMap = (keyAmbientLight != nullptr); + bool hasAmbientMap = (ambientLight != nullptr); // Setup the global directional pass pipeline { - if (deferredLightingEffect->_shadowMapEnabled) { + // Check if keylight casts shadows + bool keyLightCastShadows { false }; + + if (lightStage && lightStage->_currentFrame._sunLights.size()) { + graphics::LightPointer keyLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front()); + if (keyLight) { + keyLightCastShadows = keyLight->getCastShadows(); + } + } + + if (deferredLightingEffect->_shadowMapEnabled && keyLightCastShadows) { // If the keylight has an ambient Map then use the Skybox version of the pass // otherwise use the ambient sphere version diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 1b776e6409..ce7ecacbbe 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -61,7 +61,7 @@ public: private: DeferredLightingEffect() = default; - bool _shadowMapEnabled{ false }; + bool _shadowMapEnabled{ true }; // note that this value is overwritten in the ::configure method bool _ambientOcclusionEnabled{ false }; graphics::MeshPointer _pointLightMesh; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2637d24d67..98ecc4c941 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -77,7 +77,7 @@ void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); } -void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled) { +void MeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) { ItemKey::Builder builder; builder.withTypeShape(); @@ -91,6 +91,10 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, builder.withLayered(); } + if (canCastShadow) { + builder.withShadowCaster(); + } + if (isGroupCulled) { builder.withSubMetaCulled(); } @@ -328,7 +332,8 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render _worldBound.transform(boundTransform); } -void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled) { +// Note that this method is called for models but not for shapes +void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) { ItemKey::Builder builder; builder.withTypeShape(); @@ -342,6 +347,10 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tag builder.withLayered(); } + if (canCastShadow) { + builder.withShadowCaster(); + } + if (isGroupCulled) { builder.withSubMetaCulled(); } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 3ad222d90c..087550345d 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -32,7 +32,7 @@ public: typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - virtual void updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled = false); + virtual void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false); virtual void updateMeshPart(const std::shared_ptr& drawMesh, int partIndex); @@ -92,7 +92,7 @@ public: void notifyLocationChanged() override; - void updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled = false) override; + void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false) override; // matrix palette skinning void updateClusterBuffer(const std::vector& clusterMatrices); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 12d6659849..593780709a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -104,6 +104,7 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : _snappedToRegistrationPoint(false), _url(HTTP_INVALID_COM), _isVisible(true), + _canCastShadow(false), _blendNumber(0), _appliedBlendNumber(0), _isWireframe(false) @@ -270,6 +271,7 @@ void Model::updateRenderItems() { bool isWireframe = self->isWireframe(); bool isVisible = self->isVisible(); + bool canCastShadow = self->canCastShadow(); uint8_t viewTagBits = self->getViewTagBits(); bool isLayeredInFront = self->isLayeredInFront(); bool isLayeredInHUD = self->isLayeredInHUD(); @@ -288,7 +290,7 @@ void Model::updateRenderItems() { transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, invalidatePayloadShapeKey, isWireframe, isVisible, - viewTagBits, isLayeredInFront, + canCastShadow, viewTagBits, isLayeredInFront, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); @@ -313,7 +315,7 @@ void Model::updateRenderItems() { } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); }); @@ -773,46 +775,66 @@ void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, bool isLayeredInFront = _isLayeredInFront; bool isLayeredInHUD = _isLayeredInHUD; - + bool canCastShadow = _canCastShadow; render::Transaction transaction; foreach (auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); }); } scene->enqueueTransaction(transaction); } } +void Model::setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled) { + if (_canCastShadow != canCastShadow) { + _canCastShadow = canCastShadow; + + bool isVisible = _isVisible; + bool isLayeredInFront = _isLayeredInFront; + bool isLayeredInHUD = _isLayeredInHUD; + + render::Transaction transaction; + foreach (auto item, _modelMeshRenderItemsMap.keys()) { + transaction.updateItem(item, + [isVisible, viewTagBits, canCastShadow, isLayeredInFront, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { + data.updateKey(isVisible, viewTagBits, canCastShadow, isLayeredInFront || isLayeredInHUD, isGroupCulled); + }); + } + + scene->enqueueTransaction(transaction); + } +} void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene) { if (_isLayeredInFront != isLayeredInFront) { _isLayeredInFront = isLayeredInFront; bool isVisible = _isVisible; + bool canCastShadow = _canCastShadow; uint8_t viewTagBits = _viewTagBits; bool isLayeredInHUD = _isLayeredInHUD; bool isGroupCulled = _isGroupCulled; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } @@ -825,22 +847,23 @@ void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& sce _isLayeredInHUD = isLayeredInHUD; bool isVisible = _isVisible; + bool canCastShadow = _canCastShadow; uint8_t viewTagBits = _viewTagBits; bool isLayeredInFront = _isLayeredInFront; bool isGroupCulled = _isGroupCulled; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } @@ -1650,15 +1673,16 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par uint8_t viewTagBits = getViewTagBits(); bool layeredInFront = isLayeredInFront(); bool layeredInHUD = isLayeredInHUD(); + bool canCastShadow = _canCastShadow; bool wireframe = isWireframe(); auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = _useDualQuaternionSkinning; - transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow, invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) { data.addMaterial(material); // if the material changed, we might need to update our item key or shape key - data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits); data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning); }); } @@ -1676,15 +1700,16 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string uint8_t viewTagBits = getViewTagBits(); bool layeredInFront = isLayeredInFront(); bool layeredInHUD = isLayeredInHUD(); + bool canCastShadow = _canCastShadow; bool wireframe = isWireframe(); auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = _useDualQuaternionSkinning; - transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow, invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) { data.removeMaterial(material); // if the material changed, we might need to update our item key or shape key - data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits); data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning); }); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 9c98ac2b8b..2b14a7c055 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -88,6 +88,10 @@ public: // new Scene/Engine rendering support void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled); + + bool canCastShadow() const { return _canCastShadow; } + void setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled); + void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene); void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene); bool needsFixupInScene() const; @@ -403,6 +407,8 @@ protected: bool _isVisible; uint8_t _viewTagBits{ render::ItemKey::TAG_BITS_ALL }; + bool _canCastShadow; + gpu::Buffers _blendedVertexBuffers; QVector > > _dilatedTextures; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index e8963c2e4e..ce4bf01dcf 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -218,7 +218,10 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende const auto setupOutput = task.addJob("ShadowSetup"); const auto queryResolution = setupOutput.getN(2); // Fetch and cull the items from the scene - static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask); + + // Enable models to not cast shadows (otherwise, models will always cast shadows) + static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask).withShadowCaster(); + const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterFilter, queryResolution).asVarying(); const auto shadowSelection = task.addJob("FetchShadowTree", fetchInput); const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying(); @@ -297,8 +300,14 @@ void RenderShadowSetup::setSlopeBias(int cascadeIndex, float value) { } void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) { + // Abort all jobs if not casting shadows auto lightStage = renderContext->_scene->getStage(); assert(lightStage); + if (!lightStage->getCurrentKeyLight() || !lightStage->getCurrentKeyLight()->getCastShadows()) { + renderContext->taskFlow.abortTask(); + return; + } + // Cache old render args RenderArgs* args = renderContext->args; @@ -378,12 +387,13 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) { auto lightStage = renderContext->_scene->getStage(); assert(lightStage); + // Cache old render args RenderArgs* args = renderContext->args; const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow && _cascadeIndexgetCascadeCount()) { - output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask); + output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask).withShadowCaster(); // Set the keylight render args auto& cascade = globalShadow->getCascade(_cascadeIndex); diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 7f127a558c..98b70c0c9f 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -38,7 +38,7 @@ class RenderShadowTaskConfig : public render::Task::Config::Persistent { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty) public: - RenderShadowTaskConfig() : render::Task::Config::Persistent(QStringList() << "Render" << "Engine" << "Shadows", false) {} + RenderShadowTaskConfig() : render::Task::Config::Persistent(QStringList() << "Render" << "Engine" << "Shadows", true) {} signals: void dirty(); diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index c53a2fa5bd..d6710238fb 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -42,25 +42,28 @@ -
+
+ +
@@ -293,7 +296,6 @@
-
BehaviorM @@ -365,8 +367,6 @@
- -
LightM @@ -400,7 +400,6 @@
-
ModelM @@ -484,7 +483,6 @@
-
ZoneM @@ -532,6 +530,10 @@
+
+ + +
Skybox @@ -676,7 +678,7 @@ min="-1000" max="50000" step="10"> -
+
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 2b29fbf041..4db9bd00c6 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -616,6 +616,8 @@ function loaded() { var elShape = document.getElementById("property-shape"); + var elCanCastShadow = document.getElementById("property-can-cast-shadow"); + var elLightSpotLight = document.getElementById("property-light-spot-light"); var elLightColor = document.getElementById("property-light-color"); var elLightColorRed = document.getElementById("property-light-color-red"); @@ -687,6 +689,8 @@ function loaded() { var elZoneKeyLightDirectionX = document.getElementById("property-zone-key-light-direction-x"); var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y"); + var elZoneKeyLightCastShadows = document.getElementById("property-zone-key-light-cast-shadows"); + // Skybox var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit"); var elZoneSkyboxModeDisabled = document.getElementById("property-zone-skybox-mode-disabled"); @@ -844,7 +848,6 @@ function loaded() { elLocked.checked = properties.locked; - elName.value = properties.name; elVisible.checked = properties.visible; @@ -1011,6 +1014,12 @@ function loaded() { properties.color.green + "," + properties.color.blue + ")"; } + if (properties.type === "Model" || + properties.type === "Shape" || properties.type === "Box" || properties.type === "Sphere") { + + elCanCastShadow.checked = properties.canCastShadow; + } + if (properties.type === "Model") { elModelURL.value = properties.modelURL; elShapeType.value = properties.shapeType; @@ -1060,7 +1069,6 @@ function loaded() { elLightFalloffRadius.value = properties.falloffRadius.toFixed(1); elLightExponent.value = properties.exponent.toFixed(2); elLightCutoff.value = properties.cutoff.toFixed(2); - } else if (properties.type === "Zone") { // Key light elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit'); @@ -1076,6 +1084,8 @@ function loaded() { elZoneKeyLightDirectionX.value = properties.keyLight.direction.x.toFixed(2); elZoneKeyLightDirectionY.value = properties.keyLight.direction.y.toFixed(2); + elZoneKeyLightCastShadows.checked = properties.keyLight.castShadows; + // Skybox elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit'); elZoneSkyboxModeDisabled.checked = (properties.skyboxMode === 'disabled'); @@ -1139,13 +1149,15 @@ function loaded() { // Show/hide sections as required showElements(document.getElementsByClassName('skybox-section'), elZoneSkyboxModeEnabled.checked); + showElements(document.getElementsByClassName('keylight-section'), elZoneKeyLightModeEnabled.checked); + showElements(document.getElementsByClassName('ambient-section'), elZoneAmbientLightModeEnabled.checked); + showElements(document.getElementsByClassName('haze-section'), elZoneHazeModeEnabled.checked); - } else if (properties.type === "PolyVox") { elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2); elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2); @@ -1176,6 +1188,15 @@ function loaded() { elMaterialMappingRot.value = properties.materialMappingRot.toFixed(2); } + // Only these types can cast a shadow + if (properties.type === "Model" || + properties.type === "Shape" || properties.type === "Box" || properties.type === "Sphere") { + + showElements(document.getElementsByClassName('can-cast-shadow-section'), true); + } else { + showElements(document.getElementsByClassName('can-cast-shadow-section'), false); + } + if (properties.locked) { disableProperties(); elLocked.removeAttribute('disabled'); @@ -1432,6 +1453,8 @@ function loaded() { elShape.addEventListener('change', createEmitTextPropertyUpdateFunction('shape')); + elCanCastShadow.addEventListener('change', createEmitCheckedPropertyUpdateFunction('canCastShadow')); + elImageURL.addEventListener('change', createImageURLUpdateFunction('textures')); elWebSourceURL.addEventListener('change', createEmitTextPropertyUpdateFunction('sourceUrl')); @@ -1590,6 +1613,9 @@ function loaded() { elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction); elZoneKeyLightDirectionY.addEventListener('change', zoneKeyLightDirectionChangeFunction); + elZoneKeyLightCastShadows.addEventListener('change', + createEmitGroupCheckedPropertyUpdateFunction('keyLight', 'castShadows')); + // Skybox var skyboxModeChanged = createZoneComponentModeChangedFunction('skyboxMode', elZoneSkyboxModeInherit, elZoneSkyboxModeDisabled, elZoneSkyboxModeEnabled); From b50044fb2b667a8a2d98ca7b3cee864870894c0a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 2 Mar 2018 13:15:27 +1300 Subject: [PATCH 16/97] Remove deprecated Window.openFileChanged() signal from API --- interface/src/scripting/WindowScriptingInterface.cpp | 1 - interface/src/scripting/WindowScriptingInterface.h | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 12b20566ed..e0a008b25e 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -259,7 +259,6 @@ void WindowScriptingInterface::browseAsync(const QString& title, const QString& setPreviousBrowseLocation(QFileInfo(result).absolutePath()); } emit browseChanged(result); - emit openFileChanged(result); // Deprecated signal; to be removed in due course. }); } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 67fdea0bc5..5a30f44856 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -179,7 +179,6 @@ public slots: * Prompt the user to choose a file. Displays a non-modal dialog that navigates the directory tree. A * {@link Window.browseChanged|browseChanged} signal is emitted when a file is chosen; no signal is emitted if the user * cancels the dialog. - * @deprecated A deprecated {@link Window.openFileChanged|openFileChanged} signal is also emitted when a file is chosen. * @function Window.browseAsync * @param {string} title="" - The title to display at the top of the dialog. * @param {string} directory="" - The initial directory to start browsing at. @@ -660,15 +659,6 @@ signals: */ void browseChanged(QString filename); - /**jsdoc - * Triggered when the user chooses a file in a {@link Window.browseAsync|browseAsync} dialog. - * @function Window.openFileChanged - * @deprecated This signal is being replaced with {@link Window.browseChanged|browseChanged} and will be removed. - * @param {string} filename - The path and name of the file the user chose in the dialog. - * @returns {Signal} - */ - void openFileChanged(QString filename); - /**jsdoc * Triggered when the user OKs a {@link Window.promptAsync|promptAsync} dialog. * @function Window.promptTextChanged From 70bdedc4b398293d30168666517f34904573cef3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 1 Mar 2018 16:37:19 -0800 Subject: [PATCH 17/97] Fix Edit -> Export Entities exporting gzipped json We were not respecting the doGzip flag. --- libraries/octree/src/Octree.cpp | 21 +++++++++++--------- libraries/octree/src/Octree.h | 4 ++-- libraries/octree/src/OctreePersistThread.cpp | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 334299185e..7e0c82506b 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1778,7 +1778,7 @@ bool Octree::writeToFile(const char* fileName, const OctreeElementPointer& eleme return success; } -bool Octree::toJSON(QJsonDocument* doc, const OctreeElementPointer& element) { +bool Octree::toJSONDocument(QJsonDocument* doc, const OctreeElementPointer& element) { QVariantMap entityDescription; OctreeElementPointer top; @@ -1804,18 +1804,22 @@ bool Octree::toJSON(QJsonDocument* doc, const OctreeElementPointer& element) { return true; } -bool Octree::toGzippedJSON(QByteArray* data, const OctreeElementPointer& element) { +bool Octree::toJSON(QByteArray* data, const OctreeElementPointer& element, bool doGzip) { QJsonDocument doc; - if (!toJSON(&doc, element)) { + if (!toJSONDocument(&doc, element)) { qCritical("Failed to convert Entities to QVariantMap while converting to json."); return false; } - QByteArray jsonData = doc.toJson(); + if (doGzip) { + QByteArray jsonData = doc.toJson(); - if (!gzip(jsonData, *data, -1)) { - qCritical("Unable to gzip data while saving to json."); - return false; + if (!gzip(jsonData, *data, -1)) { + qCritical("Unable to gzip data while saving to json."); + return false; + } + } else { + *data = doc.toJson(); } return true; @@ -1825,7 +1829,7 @@ bool Octree::writeToJSONFile(const char* fileName, const OctreeElementPointer& e qCDebug(octree, "Saving JSON SVO to file %s...", fileName); QByteArray jsonDataForFile; - if (!toGzippedJSON(&jsonDataForFile)) { + if (!toJSON(&jsonDataForFile, element, doGzip)) { return false; } @@ -1837,7 +1841,6 @@ bool Octree::writeToJSONFile(const char* fileName, const OctreeElementPointer& e qCritical("Could not write to JSON description of entities."); } - return success; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index cb281593b1..c4c4508138 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -284,8 +284,8 @@ public: void loadOctreeFile(const char* fileName); // Octree exporters - bool toJSON(QJsonDocument* doc, const OctreeElementPointer& element = nullptr); - bool toGzippedJSON(QByteArray* data, const OctreeElementPointer& element = nullptr); + bool toJSONDocument(QJsonDocument* doc, const OctreeElementPointer& element = nullptr); + bool toJSON(QByteArray* data, const OctreeElementPointer& element = nullptr, bool doGzip = false); bool writeToFile(const char* filename, const OctreeElementPointer& element = nullptr, QString persistAsFileType = "json.gz"); bool writeToJSONFile(const char* filename, const OctreeElementPointer& element = nullptr, bool doGzip = false); virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index 23d6b6c2aa..7c5b7eb45c 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -341,7 +341,7 @@ void OctreePersistThread::sendLatestEntityDataToDS() { const DomainHandler& domainHandler = nodeList->getDomainHandler(); QByteArray data; - if (_tree->toGzippedJSON(&data)) { + if (_tree->toJSON(&data, nullptr, true)) { auto message = NLPacketList::create(PacketType::OctreeDataPersist, QByteArray(), true, true); message->write(data); nodeList->sendPacketList(std::move(message), domainHandler.getSockAddr()); From 7107e1539ffa735b7fc90e7b09c694da0f4d3d70 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 2 Mar 2018 13:45:31 +1300 Subject: [PATCH 18/97] Remove deprecated Window.location.protocolVersion() function from API --- libraries/networking/src/AddressManager.cpp | 4 ---- libraries/networking/src/AddressManager.h | 9 --------- 2 files changed, 13 deletions(-) diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 9296f61ad3..4965a5baaa 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -46,10 +46,6 @@ AddressManager::AddressManager() : } -QString AddressManager::protocolVersion() { - return protocolVersionsSignatureBase64(); -} - bool AddressManager::isConnected() { return DependencyManager::get()->getDomainHandler().isConnected(); } diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 6c9f06d2dd..1b550df693 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -71,15 +71,6 @@ class AddressManager : public QObject, public Dependency { Q_PROPERTY(QString domainID READ getDomainID) Q_PROPERTY(QString domainId READ getDomainID) public: - - /**jsdoc - * Get Interface's protocol version. - * @function location.protocolVersion - * @returns {string} A string uniquely identifying the version of the metaverse protocol that Interface is using. - * @deprecated This function is deprecated and will be removed. Use {@link Window.protocolSignature} instead. - */ - Q_INVOKABLE QString protocolVersion(); - using PositionGetter = std::function; using OrientationGetter = std::function; From a66125fbb781af8faf8fa1cef32628974291e5b0 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 1 Mar 2018 16:56:51 -0800 Subject: [PATCH 19/97] scriptablematerial -> scriptablemateriallayer --- .../src/graphics-scripting/Forward.h | 17 ++++-- .../GraphicsScriptingInterface.cpp | 26 ++++++--- .../graphics-scripting/ScriptableModel.cpp | 57 ++++++++++--------- .../src/graphics-scripting/ScriptableModel.h | 5 +- libraries/graphics/src/graphics/Material.h | 4 +- 5 files changed, 68 insertions(+), 41 deletions(-) diff --git a/libraries/graphics-scripting/src/graphics-scripting/Forward.h b/libraries/graphics-scripting/src/graphics-scripting/Forward.h index 650e4104e7..3d710b41b4 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/Forward.h +++ b/libraries/graphics-scripting/src/graphics-scripting/Forward.h @@ -39,7 +39,7 @@ namespace scriptable { class ScriptableMaterial { public: ScriptableMaterial() {} - ScriptableMaterial(const graphics::MaterialLayer& materialLayer); + ScriptableMaterial(const graphics::MaterialPointer& material); ScriptableMaterial(const ScriptableMaterial& material) { *this = material; } ScriptableMaterial& operator=(const ScriptableMaterial& material); @@ -64,9 +64,18 @@ namespace scriptable { QString occlusionMap; QString lightmapMap; QString scatteringMap; + }; + class ScriptableMaterialLayer { + public: + ScriptableMaterialLayer() {} + ScriptableMaterialLayer(const graphics::MaterialLayer& materialLayer) : material(materialLayer.material), priority(materialLayer.priority) {} + ScriptableMaterialLayer(const ScriptableMaterialLayer& materialLayer) { *this = materialLayer; } + ScriptableMaterialLayer& operator=(const ScriptableMaterialLayer& materialLayer); + + ScriptableMaterial material; quint16 priority; }; - typedef QHash> MultiMaterialMap; + typedef QHash> MultiMaterialMap; class ScriptableMeshBase : public QObject { Q_OBJECT @@ -92,7 +101,7 @@ namespace scriptable { WeakModelProviderPointer provider; QUuid objectID; // spatially nestable ID QVector meshes; - MultiMaterialMap materials; + MultiMaterialMap materialLayers; QVector materialNames; ScriptableModelBase(QObject* parent = nullptr) : QObject(parent) {} @@ -102,7 +111,7 @@ namespace scriptable { void append(const ScriptableMeshBase& mesh); void append(scriptable::WeakMeshPointer mesh); - void appendMaterial(const graphics::MaterialLayer& material, int shapeID, std::string materialName); + void appendMaterial(const graphics::MaterialLayer& materialLayer, int shapeID, std::string materialName); void appendMaterials(const std::unordered_map& materialsToAppend); void appendMaterialNames(const std::vector& names); // TODO: in future containers for these could go here diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp index ff0170f07d..20b54b02c9 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp @@ -298,7 +298,8 @@ namespace { qRegisterMetaType(), qRegisterMetaType(), qRegisterMetaType(), - qRegisterMetaType>(), + qRegisterMetaType(), + qRegisterMetaType>(), qRegisterMetaType(), qRegisterMetaType(), }; @@ -338,11 +339,11 @@ namespace scriptable { ); } - QScriptValue qVectorScriptableMaterialToScriptValue(QScriptEngine* engine, const QVector& vector) { + QScriptValue qVectorScriptableMaterialLayerToScriptValue(QScriptEngine* engine, const QVector& vector) { return qScriptValueFromSequence(engine, vector); } - void qVectorScriptableMaterialFromScriptValue(const QScriptValue& array, QVector& result) { + void qVectorScriptableMaterialLayerFromScriptValue(const QScriptValue& array, QVector& result) { qScriptValueToSequence(array, result); } @@ -369,7 +370,6 @@ namespace scriptable { obj.setProperty("occlusionMap", material.occlusionMap); obj.setProperty("lightmapMap", material.lightmapMap); obj.setProperty("scatteringMap", material.scatteringMap); - obj.setProperty("priority", material.priority); return obj; } @@ -377,10 +377,21 @@ namespace scriptable { // No need to convert from QScriptValue to ScriptableMaterial } + QScriptValue scriptableMaterialLayerToScriptValue(QScriptEngine* engine, const scriptable::ScriptableMaterialLayer &materialLayer) { + QScriptValue obj = engine->newObject(); + obj.setProperty("material", scriptableMaterialToScriptValue(engine, materialLayer.material)); + obj.setProperty("priority", materialLayer.priority); + return obj; + } + + void scriptableMaterialLayerFromScriptValue(const QScriptValue &object, scriptable::ScriptableMaterialLayer& materialLayer) { + // No need to convert from QScriptValue to ScriptableMaterialLayer + } + QScriptValue multiMaterialMapToScriptValue(QScriptEngine* engine, const scriptable::MultiMaterialMap& map) { QScriptValue obj = engine->newObject(); for (auto key : map.keys()) { - obj.setProperty(key, qVectorScriptableMaterialToScriptValue(engine, map[key])); + obj.setProperty(key, qVectorScriptableMaterialLayerToScriptValue(engine, map[key])); } return obj; } @@ -405,7 +416,7 @@ namespace scriptable { void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) { qScriptRegisterSequenceMetaType>(engine); - qScriptRegisterSequenceMetaType>(engine); + qScriptRegisterSequenceMetaType>(engine); scriptable::registerQPointerMetaType(engine); scriptable::registerQPointerMetaType(engine); @@ -417,7 +428,8 @@ void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) { scriptable::registerDebugEnum(engine, gpu::DIMENSIONS); qScriptRegisterMetaType(engine, scriptable::scriptableMaterialToScriptValue, scriptable::scriptableMaterialFromScriptValue); - qScriptRegisterMetaType(engine, scriptable::qVectorScriptableMaterialToScriptValue, scriptable::qVectorScriptableMaterialFromScriptValue); + qScriptRegisterMetaType(engine, scriptable::scriptableMaterialLayerToScriptValue, scriptable::scriptableMaterialLayerFromScriptValue); + qScriptRegisterMetaType(engine, scriptable::qVectorScriptableMaterialLayerToScriptValue, scriptable::qVectorScriptableMaterialLayerFromScriptValue); qScriptRegisterMetaType(engine, scriptable::multiMaterialMapToScriptValue, scriptable::multiMaterialMapFromScriptValue); Q_UNUSED(metaTypeIds); diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp index a713d42012..c65764a225 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp @@ -42,29 +42,27 @@ scriptable::ScriptableMaterial& scriptable::ScriptableMaterial::operator=(const occlusionMap = material.occlusionMap; lightmapMap = material.lightmapMap; scatteringMap = material.scatteringMap; - priority = material.priority; return *this; } -scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer& materialLayer) : - name(materialLayer.material->getName().c_str()), - model(materialLayer.material->getModel().c_str()), - opacity(materialLayer.material->getOpacity()), - roughness(materialLayer.material->getRoughness()), - metallic(materialLayer.material->getMetallic()), - scattering(materialLayer.material->getScattering()), - unlit(materialLayer.material->isUnlit()), - emissive(materialLayer.material->getEmissive()), - albedo(materialLayer.material->getAlbedo()), - priority(materialLayer.priority) +scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPointer& material) : + name(material->getName().c_str()), + model(material->getModel().c_str()), + opacity(material->getOpacity()), + roughness(material->getRoughness()), + metallic(material->getMetallic()), + scattering(material->getScattering()), + unlit(material->isUnlit()), + emissive(material->getEmissive()), + albedo(material->getAlbedo()) { - auto map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP); + auto map = material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP); if (map && map->getTextureSource()) { emissiveMap = map->getTextureSource()->getUrl().toString(); } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP); if (map && map->getTextureSource()) { albedoMap = map->getTextureSource()->getUrl().toString(); if (map->useAlphaChannel()) { @@ -72,7 +70,7 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer } } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP); if (map && map->getTextureSource()) { if (map->getTextureSource()->getType() == image::TextureUsage::Type::METALLIC_TEXTURE) { metallicMap = map->getTextureSource()->getUrl().toString(); @@ -81,7 +79,7 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer } } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP); if (map && map->getTextureSource()) { if (map->getTextureSource()->getType() == image::TextureUsage::Type::ROUGHNESS_TEXTURE) { roughnessMap = map->getTextureSource()->getUrl().toString(); @@ -90,7 +88,7 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer } } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP); if (map && map->getTextureSource()) { if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) { normalMap = map->getTextureSource()->getUrl().toString(); @@ -99,29 +97,36 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer } } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP); if (map && map->getTextureSource()) { occlusionMap = map->getTextureSource()->getUrl().toString(); } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP); if (map && map->getTextureSource()) { lightmapMap = map->getTextureSource()->getUrl().toString(); } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP); if (map && map->getTextureSource()) { scatteringMap = map->getTextureSource()->getUrl().toString(); } } +scriptable::ScriptableMaterialLayer& scriptable::ScriptableMaterialLayer::operator=(const scriptable::ScriptableMaterialLayer& materialLayer) { + material = materialLayer.material; + priority = materialLayer.priority; + + return *this; +} + scriptable::ScriptableModelBase& scriptable::ScriptableModelBase::operator=(const scriptable::ScriptableModelBase& other) { provider = other.provider; objectID = other.objectID; for (const auto& mesh : other.meshes) { append(mesh); } - materials = other.materials; + materialLayers = other.materialLayers; materialNames = other.materialNames; return *this; } @@ -135,7 +140,7 @@ scriptable::ScriptableModelBase::~ScriptableModelBase() { m.strongMesh.reset(); } meshes.clear(); - materials.clear(); + materialLayers.clear(); materialNames.clear(); } @@ -150,16 +155,16 @@ void scriptable::ScriptableModelBase::append(const ScriptableMeshBase& mesh) { meshes << mesh; } -void scriptable::ScriptableModelBase::appendMaterial(const graphics::MaterialLayer& material, int shapeID, std::string materialName) { - materials[QString::number(shapeID)].push_back(ScriptableMaterial(material)); - materials["mat::" + QString::fromStdString(materialName)].push_back(ScriptableMaterial(material)); +void scriptable::ScriptableModelBase::appendMaterial(const graphics::MaterialLayer& materialLayer, int shapeID, std::string materialName) { + materialLayers[QString::number(shapeID)].push_back(ScriptableMaterialLayer(materialLayer)); + materialLayers["mat::" + QString::fromStdString(materialName)].push_back(ScriptableMaterialLayer(materialLayer)); } void scriptable::ScriptableModelBase::appendMaterials(const std::unordered_map& materialsToAppend) { auto materialsToAppendCopy = materialsToAppend; for (auto& multiMaterial : materialsToAppendCopy) { while (!multiMaterial.second.empty()) { - materials[QString(multiMaterial.first.c_str())].push_back(ScriptableMaterial(multiMaterial.second.top())); + materialLayers[QString(multiMaterial.first.c_str())].push_back(ScriptableMaterialLayer(multiMaterial.second.top())); multiMaterial.second.pop(); } } diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h index b1fe29447f..a1278132ca 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h @@ -28,7 +28,7 @@ namespace scriptable { Q_PROPERTY(QUuid objectID MEMBER objectID CONSTANT) Q_PROPERTY(glm::uint32 numMeshes READ getNumMeshes) Q_PROPERTY(ScriptableMeshes meshes READ getMeshes) - Q_PROPERTY(scriptable::MultiMaterialMap materials READ getMaterials) + Q_PROPERTY(scriptable::MultiMaterialMap materialLayers READ getMaterialLayers) Q_PROPERTY(QVector materialNames READ getMaterialNames) public: @@ -43,7 +43,7 @@ namespace scriptable { ScriptableMeshes getMeshes(); const ScriptableMeshes getConstMeshes() const; - scriptable::MultiMaterialMap getMaterials() { return materials; } + scriptable::MultiMaterialMap getMaterialLayers() { return materialLayers; } QVector getMaterialNames() { return materialNames; } public slots: @@ -60,4 +60,5 @@ namespace scriptable { Q_DECLARE_METATYPE(scriptable::ScriptableModelPointer) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(scriptable::ScriptableMaterial) +Q_DECLARE_METATYPE(scriptable::ScriptableMaterialLayer) Q_DECLARE_METATYPE(scriptable::MultiMaterialMap) diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index f34f68c04a..f9e83a0324 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -356,9 +356,9 @@ public: void setTextureTransforms(const Transform& transform); - const std::string& getName() { return _name; } + const std::string& getName() const { return _name; } - const std::string& getModel() { return _model; } + const std::string& getModel() const { return _model; } void setModel(const std::string& model) { _model = model; } protected: From 5bb4023fb5d62869923a2a0f9a1b47383d05c3df Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Mar 2018 19:23:17 -0800 Subject: [PATCH 20/97] First version - can download fixed URL to fixed location. --- tools/auto-tester/CMakeLists.txt | 2 +- tools/auto-tester/src/Test.cpp | 63 +++++++++++++------------ tools/auto-tester/src/Test.h | 7 ++- tools/auto-tester/src/main.cpp | 6 ++- tools/auto-tester/src/ui/AutoTester.cpp | 35 ++++++++++---- tools/auto-tester/src/ui/AutoTester.h | 8 +++- 6 files changed, 76 insertions(+), 45 deletions(-) diff --git a/tools/auto-tester/CMakeLists.txt b/tools/auto-tester/CMakeLists.txt index a875f5676a..a2589bb760 100644 --- a/tools/auto-tester/CMakeLists.txt +++ b/tools/auto-tester/CMakeLists.txt @@ -5,7 +5,7 @@ project(${TARGET_NAME}) SET (CMAKE_AUTOUIC ON) SET (CMAKE_AUTOMOC ON) -setup_hifi_project (Core Widgets) +setup_hifi_project (Core Widgets Network) link_hifi_libraries () # FIX: Qt was built with -reduce-relocations diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 357fc7b296..458ce0838b 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -16,8 +16,13 @@ #include #include +#include "ui/AutoTester.h" +extern AutoTester* autoTester; + Test::Test() { - expectedImageFilenameFormat = QRegularExpression("ExpectedImage_\\d+.jpg"); + QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + EXPECTED_IMAGE_TYPE); + + expectedImageFilenameFormat = QRegularExpression(regex); mismatchWindow.setModal(true); } @@ -178,49 +183,45 @@ void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure te void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { // Get list of JPEG images in folder, sorted by name - QString pathToImageDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); - if (pathToImageDirectory == "") { + QString pathToTestResultsDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); + if (pathToTestResultsDirectory == "") { return; } // Leave if test results folder could not be created - if (!createTestResultsFolderPathIfNeeded(pathToImageDirectory)) { + if (!createTestResultsFolderPathIfNeeded(pathToTestResultsDirectory)) { return; } - QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(pathToImageDirectory); - - // Separate images into two lists. The first is the expected images, the second is the test results + // Create two lists. The first is the test results, the second is the expected images // Images that are in the wrong format are ignored. + + QStringList sortedTestResultsFilenames = createListOfAllJPEGimagesInDirectory(pathToTestResultsDirectory); QStringList expectedImages; QStringList resultImages; - foreach(QString currentFilename, sortedImageFilenames) { - QString fullCurrentFilename = pathToImageDirectory + "/" + currentFilename; - if (isInExpectedImageFilenameFormat(currentFilename)) { - expectedImages << fullCurrentFilename; - } else if (isInSnapshotFilenameFormat(currentFilename)) { + foreach(QString currentFilename, sortedTestResultsFilenames) { + QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename; + if (isInSnapshotFilenameFormat(currentFilename)) { resultImages << fullCurrentFilename; + + QString expectedImageDirectory = getExpectedImageDestinationDirectory(currentFilename); + + // extract the digits at the end of the filename (exluding the file extension) + QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); + + QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + EXPECTED_IMAGE_TYPE; + expectedImages << (expectedImageDirectory + "/" + expectedImageFilename); } } - // The number of images in each list should be identical - if (expectedImages.length() != resultImages.length()) { - messageBox.critical(0, - "Test failed", - "Found " + QString::number(resultImages.length()) + " images in directory" + - "\nExpected to find " + QString::number(expectedImages.length()) + " images" - ); + autoTester->downloadImage(QUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png")); + ////bool success = compareImageLists(expectedImages, resultImages, pathToImageDirectory, interactiveMode, progressBar); - exit(-1); - } - - bool success = compareImageLists(expectedImages, resultImages, pathToImageDirectory, interactiveMode, progressBar); - - if (success) { - messageBox.information(0, "Success", "All images are as expected"); - } else { - messageBox.information(0, "Failure", "One or more images are not as expected"); - } + ////if (success) { + //// messageBox.information(0, "Success", "All images are as expected"); + ////} else { + //// messageBox.information(0, "Failure", "One or more images are not as expected"); + ////} zipAndDeleteTestResultsFolder(); } @@ -407,7 +408,7 @@ void Test::createTest() { exit(-1); } QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".jpg"; - QString imageDestinationDirectory = getImageDestinationDirectory(currentFilename); + QString imageDestinationDirectory = getExpectedImageDestinationDirectory(currentFilename); QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; try { @@ -489,7 +490,7 @@ bool Test::isInSnapshotFilenameFormat(QString filename) { // D:/GitHub/hifi-tests/tests/content/entity/zone/create // This method assumes the filename is in the correct format // The final part of the filename is the image number. This is checked for sanity -QString Test::getImageDestinationDirectory(QString filename) { +QString Test::getExpectedImageDestinationDirectory(QString filename) { QString filenameWithoutExtension = filename.split(".")[0]; QStringList filenameParts = filenameWithoutExtension.split("_"); diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 55fb7229d1..7168a8ef69 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -46,7 +46,7 @@ public: bool isAValidDirectory(QString pathname); - QString getImageDestinationDirectory(QString filename); + QString getExpectedImageDestinationDirectory(QString filename); private: const QString TEST_FILENAME { "test.js" }; @@ -65,6 +65,11 @@ private: QString testResultsFolderPath { "" }; int index { 1 }; + + // Expected images are in the format ExpectedImage_dddd.jpg (d == decimal digit) + const int NUM_DIGITS { 5 }; + const QString EXPECTED_IMAGE_PREFIX { "ExpectedImage_" }; + const QString EXPECTED_IMAGE_TYPE { ".jpg" }; }; #endif // hifi_test_h \ No newline at end of file diff --git a/tools/auto-tester/src/main.cpp b/tools/auto-tester/src/main.cpp index 6e5e06b732..cd0ce22b13 100644 --- a/tools/auto-tester/src/main.cpp +++ b/tools/auto-tester/src/main.cpp @@ -10,11 +10,13 @@ #include #include "ui/AutoTester.h" +AutoTester* autoTester; + int main(int argc, char *argv[]) { QApplication application(argc, argv); - AutoTester autoTester; - autoTester.show(); + autoTester = new AutoTester(); + autoTester->show(); return application.exec(); } diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 18eef13e6e..8d0b0dc6a5 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -12,36 +12,53 @@ AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); - ui.checkBoxInteractiveMode->setChecked(true); - ui.progressBar->setVisible(false); + + test = new Test(); } void AutoTester::on_evaluateTestsButton_clicked() { - test.evaluateTests(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); + ////QUrl imageUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png"); + ////downloader = new Downloader(imageUrl, this); + ////connect(downloader, SIGNAL (downloaded()), this, SLOT (saveImage())); + test->evaluateTests(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); } void AutoTester::on_evaluateTestsRecursivelyButton_clicked() { - test.evaluateTestsRecursively(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); + test->evaluateTestsRecursively(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); } void AutoTester::on_createRecursiveScriptButton_clicked() { - test.createRecursiveScript(); + test->createRecursiveScript(); } void AutoTester::on_createRecursiveScriptsRecursivelyButton_clicked() { - test.createRecursiveScriptsRecursively(); + test->createRecursiveScriptsRecursively(); } void AutoTester::on_createTestButton_clicked() { - test.createTest(); + test->createTest(); } void AutoTester::on_deleteOldSnapshotsButton_clicked() { - test.deleteOldSnapshots(); + test->deleteOldSnapshots(); } void AutoTester::on_closeButton_clicked() { exit(0); -} \ No newline at end of file +} + +void AutoTester::downloadImage(QUrl url) { + downloader = new Downloader(url, this); + + connect(downloader, SIGNAL (downloaded()), this, SLOT (saveImage())); +} + +void AutoTester::saveImage() { + QPixmap image; + image.loadFromData(downloader->downloadedData()); + int er = image.width(); + int df = image.height(); + image.save("D:/Dicom/lll.png"); +} diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index d25969589b..2f6a9bca1e 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -12,6 +12,8 @@ #include #include "ui_AutoTester.h" + +#include "../Downloader.h" #include "../Test.h" class AutoTester : public QMainWindow { @@ -19,6 +21,7 @@ class AutoTester : public QMainWindow { public: AutoTester(QWidget *parent = Q_NULLPTR); + void downloadImage(QUrl url); private slots: void on_evaluateTestsButton_clicked(); @@ -29,10 +32,13 @@ private slots: void on_deleteOldSnapshotsButton_clicked(); void on_closeButton_clicked(); + void saveImage(); + private: Ui::AutoTesterClass ui; - Test test; + Test* test; + Downloader* downloader; }; #endif // hifi_AutoTester_h \ No newline at end of file From 07267f9fe6bd8618b4cf1e6d20b98677693a1946 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Mar 2018 09:13:07 -0800 Subject: [PATCH 21/97] WIP. --- tools/auto-tester/src/Downloader.cpp | 32 +++++++++++++++++ tools/auto-tester/src/Downloader.h | 48 +++++++++++++++++++++++++ tools/auto-tester/src/Test.cpp | 4 ++- tools/auto-tester/src/ui/AutoTester.cpp | 2 +- 4 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 tools/auto-tester/src/Downloader.cpp create mode 100644 tools/auto-tester/src/Downloader.h diff --git a/tools/auto-tester/src/Downloader.cpp b/tools/auto-tester/src/Downloader.cpp new file mode 100644 index 0000000000..030aa95a19 --- /dev/null +++ b/tools/auto-tester/src/Downloader.cpp @@ -0,0 +1,32 @@ +// +// Downloader.cpp +// +// Created by Nissim Hadar on 1 Mar 2018. +// 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 "Downloader.h" + +Downloader::Downloader(QUrl imageUrl, QObject *parent) : QObject(parent) { + connect( + &_networkAccessManager, SIGNAL (finished(QNetworkReply*)), + this, SLOT (fileDownloaded(QNetworkReply*)) + ); + + QNetworkRequest request(imageUrl); + _networkAccessManager.get(request); +} + +void Downloader::fileDownloaded(QNetworkReply* reply) { + _downloadedData = reply->readAll(); + + //emit a signal + reply->deleteLater(); + emit downloaded(); +} + +QByteArray Downloader::downloadedData() const { + return _downloadedData; +} \ No newline at end of file diff --git a/tools/auto-tester/src/Downloader.h b/tools/auto-tester/src/Downloader.h new file mode 100644 index 0000000000..b0ad58fac5 --- /dev/null +++ b/tools/auto-tester/src/Downloader.h @@ -0,0 +1,48 @@ +// +// Downloader.h +// +// Created by Nissim Hadar on 1 Mar 2018. +// 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_downloader_h +#define hifi_downloader_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +class Downloader : public QObject { +Q_OBJECT +public: + explicit Downloader(QUrl imageUrl, QObject *parent = 0); + + QByteArray downloadedData() const; + +signals: + void downloaded(); + + private slots: + void fileDownloaded(QNetworkReply* pReply); + +private: + QNetworkAccessManager _networkAccessManager; + QByteArray _downloadedData; +}; + +#endif // hifi_downloader_h \ No newline at end of file diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 458ce0838b..ee792c0ea4 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -214,7 +214,9 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { } } - autoTester->downloadImage(QUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png")); + ////autoTester->downloadImage(QUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png")); + ////autoTester->downloadImage(QUrl("https://github.com/NissimHadar/hifi_tests/blob/addRecursionToAutotester/tests/content/entity/zone/ambientLightInheritance/ExpectedImage_00000.jpg?raw=true")); + autoTester->downloadImage(QUrl("https://hifi-content.s3.amazonaws.com/nissim/autoTester/resources/ColourBox.jpg")); ////bool success = compareImageLists(expectedImages, resultImages, pathToImageDirectory, interactiveMode, progressBar); ////if (success) { diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 8d0b0dc6a5..5a666aa5eb 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -60,5 +60,5 @@ void AutoTester::saveImage() { image.loadFromData(downloader->downloadedData()); int er = image.width(); int df = image.height(); - image.save("D:/Dicom/lll.png"); + image.save("D:/Dicom/lll.jpg"); } From a5a109e4f1d25a4ff33e7dbd11598eb8e1a63f2b Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 1 Mar 2018 16:40:24 -0800 Subject: [PATCH 22/97] Fix undefined request from JS --- scripts/modules/request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/modules/request.js b/scripts/modules/request.js index c7bf98d815..3516554567 100644 --- a/scripts/modules/request.js +++ b/scripts/modules/request.js @@ -71,7 +71,7 @@ module.exports = { } } httpRequest.open(options.method, options.uri, true); - httpRequest.send(options.body); + httpRequest.send(options.body || null); } }; From 55d8cfd4c154154705576e5703fbaacf3b52c02d Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 2 Mar 2018 10:56:44 -0800 Subject: [PATCH 23/97] make sure dont make audio devices that don't use stereo use stereo --- interface/resources/qml/hifi/audio/Audio.qml | 8 ++++++-- libraries/audio-client/src/AudioClient.cpp | 8 ++++++-- libraries/audio-client/src/AudioClient.h | 2 +- libraries/audio/src/AbstractAudioInterface.h | 2 +- libraries/script-engine/src/AudioScriptingInterface.cpp | 6 ++++-- libraries/script-engine/src/AudioScriptingInterface.h | 2 +- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index f7dde336c8..a9a8a8e5c4 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -128,10 +128,13 @@ Rectangle { AudioControls.CheckBox { id: stereoMic spacing: muteMic.spacing; - text: qsTr("Stereo"); + text: qsTr("use stereo for stereo devices"); checked: false; onClicked: { - Audio.setIsStereoInput(checked); + var success = Audio.setIsStereoInput(checked); + if (!success) { + checked = !checked; + } } } } @@ -215,6 +218,7 @@ Rectangle { text: devicename onPressed: { if (!checked) { + stereoMic.checked = false; AudioScriptingInterface.setInputDevice(info, bar.currentIndex === 1); } } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 8379151d1c..3828304964 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1372,9 +1372,11 @@ void AudioClient::setNoiseReduction(bool enable) { } -void AudioClient::setIsStereoInput(bool isStereoInput) { - if (isStereoInput != _isStereoInput) { +bool AudioClient::setIsStereoInput(bool isStereoInput) { + bool stereoInputChanged = false; + if (isStereoInput != _isStereoInput && _inputDeviceInfo.supportedChannelCounts().contains(2)) { _isStereoInput = isStereoInput; + stereoInputChanged = true; if (_isStereoInput) { _desiredInputFormat.setChannelCount(2); @@ -1394,6 +1396,8 @@ void AudioClient::setIsStereoInput(bool isStereoInput) { // restart the input device switchInputToAudioDevice(_inputDeviceInfo); } + + return stereoInputChanged; } bool AudioClient::outputLocalInjector(const AudioInjectorPointer& injector) { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 0643b8e52a..2c2ddd0342 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -194,7 +194,7 @@ public slots: void toggleMute(); bool isMuted() { return _muted; } - virtual void setIsStereoInput(bool stereo) override; + virtual bool setIsStereoInput(bool stereo) override; void setNoiseReduction(bool isNoiseGateEnabled); bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; } diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 37731c31f7..ba1e733f13 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -41,7 +41,7 @@ public: public slots: virtual bool shouldLoopbackInjectors() { return false; } - virtual void setIsStereoInput(bool stereo) = 0; + virtual bool 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 28bf5ed163..dd8d284c12 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -60,8 +60,10 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(SharedSoundPointer sound } } -void AudioScriptingInterface::setStereoInput(bool stereo) { +bool AudioScriptingInterface::setStereoInput(bool stereo) { + bool stereoInputChanged = false; if (_localAudioInterface) { - _localAudioInterface->setIsStereoInput(stereo); + stereoInputChanged = _localAudioInterface->setIsStereoInput(stereo); } + return stereoInputChanged; } diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 23a0861acd..d46430ccce 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -35,7 +35,7 @@ protected: // FIXME: there is no way to play a positionless sound Q_INVOKABLE ScriptAudioInjector* playSystemSound(SharedSoundPointer sound, const QVector3D& position); - Q_INVOKABLE void setStereoInput(bool stereo); + Q_INVOKABLE bool setStereoInput(bool stereo); signals: void mutedByMixer(); /// the client has been muted by the mixer From 7ce13a3ce745ca53d206917dcbefee7bdf6d5d3c Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 2 Mar 2018 11:06:28 -0800 Subject: [PATCH 24/97] adding comment --- interface/resources/qml/hifi/audio/Audio.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index a9a8a8e5c4..156332579a 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -219,6 +219,7 @@ Rectangle { onPressed: { if (!checked) { stereoMic.checked = false; + Audio.setIsStereoInput(false); // the next selected audio device might not support stereo AudioScriptingInterface.setInputDevice(info, bar.currentIndex === 1); } } From d29adcd000dd5dffc33849c9763008a1f62e78d1 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Mar 2018 16:08:14 -0800 Subject: [PATCH 25/97] Can download multiple images from GitHub. --- tools/auto-tester/src/Test.cpp | 54 +++++++++++++++++++------ tools/auto-tester/src/Test.h | 1 + tools/auto-tester/src/ui/AutoTester.cpp | 36 +++++++++++++---- tools/auto-tester/src/ui/AutoTester.h | 12 +++++- 4 files changed, 81 insertions(+), 22 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index ee792c0ea4..ac10d1ab33 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -188,36 +188,43 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { return; } - // Leave if test results folder could not be created + // Quit if test results folder could not be created if (!createTestResultsFolderPathIfNeeded(pathToTestResultsDirectory)) { return; } // Create two lists. The first is the test results, the second is the expected images + // The expected images are represented as a URL to enabel download from GitHub // Images that are in the wrong format are ignored. QStringList sortedTestResultsFilenames = createListOfAllJPEGimagesInDirectory(pathToTestResultsDirectory); QStringList expectedImages; QStringList resultImages; + + const QString URLPrefix("https://raw.githubusercontent.com"); + const QString githubUser("NissimHadar"); + const QString testsRepo("hifi_tests"); + const QString branch("addRecursionToAutotester"); + foreach(QString currentFilename, sortedTestResultsFilenames) { QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename; if (isInSnapshotFilenameFormat(currentFilename)) { resultImages << fullCurrentFilename; - QString expectedImageDirectory = getExpectedImageDestinationDirectory(currentFilename); + QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); // extract the digits at the end of the filename (exluding the file extension) QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); - QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + EXPECTED_IMAGE_TYPE; - expectedImages << (expectedImageDirectory + "/" + expectedImageFilename); + + QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + expectedImagePartialSourceDirectory + "/" + expectedImageFilename); + expectedImages << imageURLString; } } - ////autoTester->downloadImage(QUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png")); - ////autoTester->downloadImage(QUrl("https://github.com/NissimHadar/hifi_tests/blob/addRecursionToAutotester/tests/content/entity/zone/ambientLightInheritance/ExpectedImage_00000.jpg?raw=true")); - autoTester->downloadImage(QUrl("https://hifi-content.s3.amazonaws.com/nissim/autoTester/resources/ColourBox.jpg")); - ////bool success = compareImageLists(expectedImages, resultImages, pathToImageDirectory, interactiveMode, progressBar); + //autoTester->downloadImage(QUrl("https://raw.githubusercontent.com/NissimHadar/hifi_tests/addRecursionToAutotester/tests/content/entity/zone/ambientLightInheritance/ExpectedImage_00000.jpg")); + + autoTester->downloadImages(expectedImages); ////if (success) { //// messageBox.information(0, "Success", "All images are as expected"); @@ -386,7 +393,7 @@ void Test::createRecursiveScriptsRecursively() { } void Test::createTest() { - // Rename files sequentially, as ExpectedResult_1.jpeg, ExpectedResult_2.jpg and so on + // Rename files sequentially, as ExpectedResult_00000.jpeg, ExpectedResult_00001.jpg and so on // Any existing expected result images will be deleted QString imageSourceDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); if (imageSourceDirectory == "") { @@ -404,9 +411,9 @@ void Test::createTest() { exit(-1); } } else if (isInSnapshotFilenameFormat(currentFilename)) { - const int MAX_IMAGES = 100000; - if (i >= MAX_IMAGES) { - messageBox.critical(0, "Error", "More than 100,000 images not supported"); + const int maxImages = pow(10, NUM_DIGITS); + if (i >= maxImages) { + messageBox.critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported"); exit(-1); } QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".jpg"; @@ -491,7 +498,6 @@ bool Test::isInSnapshotFilenameFormat(QString filename) { // For a file named "D_GitHub_hifi-tests_tests_content_entity_zone_create_0.jpg", the test directory is // D:/GitHub/hifi-tests/tests/content/entity/zone/create // This method assumes the filename is in the correct format -// The final part of the filename is the image number. This is checked for sanity QString Test::getExpectedImageDestinationDirectory(QString filename) { QString filenameWithoutExtension = filename.split(".")[0]; QStringList filenameParts = filenameWithoutExtension.split("_"); @@ -505,6 +511,28 @@ QString Test::getExpectedImageDestinationDirectory(QString filename) { return result; } +// For a file named "D_GitHub_hifi-tests_tests_content_entity_zone_create_0.jpg", the source directory on GitHub +// is ...tests/content/entity/zone/create +// This is used to create the full URL +// This method assumes the filename is in the correct format +QString Test::getExpectedImagePartialSourceDirectory(QString filename) { + QString filenameWithoutExtension = filename.split(".")[0]; + QStringList filenameParts = filenameWithoutExtension.split("_"); + + int i { 0 }; + while (filenameParts[i] != "tests") { + ++i; + } + + QString result = filenameParts[i]; + + for (int j = i + 1; j < filenameParts.length() - 1; ++j) { + result += "/" + filenameParts[j]; + } + + return result; +} + bool Test::isInExpectedImageFilenameFormat(QString filename) { return (expectedImageFilenameFormat.match(filename).hasMatch()); } \ No newline at end of file diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 7168a8ef69..026dbf25f6 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -47,6 +47,7 @@ public: bool isAValidDirectory(QString pathname); QString getExpectedImageDestinationDirectory(QString filename); + QString getExpectedImagePartialSourceDirectory(QString filename); private: const QString TEST_FILENAME { "test.js" }; diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 5a666aa5eb..c3ab88b7f4 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -16,6 +16,8 @@ AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { ui.progressBar->setVisible(false); test = new Test(); + + signalMapper = new QSignalMapper(); } void AutoTester::on_evaluateTestsButton_clicked() { @@ -50,15 +52,35 @@ void AutoTester::on_closeButton_clicked() { } void AutoTester::downloadImage(QUrl url) { - downloader = new Downloader(url, this); + downloaders.emplace_back(new Downloader(url, this)); + connect(downloaders[_index], SIGNAL (downloaded()), signalMapper, SLOT (map())); - connect(downloader, SIGNAL (downloaded()), this, SLOT (saveImage())); + signalMapper->setMapping(downloaders[_index], _index); + + ++_index; } -void AutoTester::saveImage() { +void AutoTester::downloadImages(QStringList listOfURLs) { + _numberOfImagesToDownload = listOfURLs.size(); + _numberOfImagesDownloaded = 0; + _index = 0; + + for (int i = 0; i < _numberOfImagesToDownload; ++i) { + QUrl imageURL(listOfURLs[i]); + downloadImage(imageURL); + } + + connect(signalMapper, SIGNAL (mapped(int)), this, SLOT (saveImage(int))); +} + +void AutoTester::saveImage(int index) { QPixmap image; - image.loadFromData(downloader->downloadedData()); - int er = image.width(); - int df = image.height(); - image.save("D:/Dicom/lll.jpg"); + image.loadFromData(downloaders[index]->downloadedData()); + + int w = image.width(); + int h = image.height(); + + ++_numberOfImagesDownloaded; + + image.save("D:/Dicom/lll_" + QString::number(index) + ".jpg"); } diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index 2f6a9bca1e..5c1f217421 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -11,6 +11,7 @@ #define hifi_AutoTester_h #include +#include #include "ui_AutoTester.h" #include "../Downloader.h" @@ -22,6 +23,7 @@ class AutoTester : public QMainWindow { public: AutoTester(QWidget *parent = Q_NULLPTR); void downloadImage(QUrl url); + void downloadImages(QStringList listOfURLs); private slots: void on_evaluateTestsButton_clicked(); @@ -32,13 +34,19 @@ private slots: void on_deleteOldSnapshotsButton_clicked(); void on_closeButton_clicked(); - void saveImage(); + void saveImage(int index); private: Ui::AutoTesterClass ui; Test* test; - Downloader* downloader; + std::vector downloaders; + + QSignalMapper* signalMapper; + + int _numberOfImagesToDownload; + int _numberOfImagesDownloaded; + int _index; }; #endif // hifi_AutoTester_h \ No newline at end of file From 4b836a2ca9ef0194af2c6f1c03ff96ee7f409fe6 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Mar 2018 16:49:09 -0800 Subject: [PATCH 26/97] Stores downloaded images in correct folder and with correct filenames. --- tools/auto-tester/src/Test.cpp | 11 +++++++---- tools/auto-tester/src/ui/AutoTester.cpp | 17 +++++++++-------- tools/auto-tester/src/ui/AutoTester.h | 11 ++++++++--- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index ac10d1ab33..d30349b395 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -198,7 +198,8 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { // Images that are in the wrong format are ignored. QStringList sortedTestResultsFilenames = createListOfAllJPEGimagesInDirectory(pathToTestResultsDirectory); - QStringList expectedImages; + QStringList expectedImagesURLs; + QStringList expectedImagesFilenames; QStringList resultImages; const QString URLPrefix("https://raw.githubusercontent.com"); @@ -217,14 +218,16 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + EXPECTED_IMAGE_TYPE; + expectedImagesFilenames << expectedImageFilename; + QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + expectedImagePartialSourceDirectory + "/" + expectedImageFilename); - expectedImages << imageURLString; + expectedImagesURLs << imageURLString; } } - //autoTester->downloadImage(QUrl("https://raw.githubusercontent.com/NissimHadar/hifi_tests/addRecursionToAutotester/tests/content/entity/zone/ambientLightInheritance/ExpectedImage_00000.jpg")); + autoTester->downloadImages(expectedImagesURLs, pathToTestResultsDirectory, expectedImagesFilenames); - autoTester->downloadImages(expectedImages); + // Wait for do ////if (success) { //// messageBox.information(0, "Success", "All images are as expected"); diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index c3ab88b7f4..5fd726ad72 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -51,7 +51,7 @@ void AutoTester::on_closeButton_clicked() { exit(0); } -void AutoTester::downloadImage(QUrl url) { +void AutoTester::downloadImage(const QUrl& url) { downloaders.emplace_back(new Downloader(url, this)); connect(downloaders[_index], SIGNAL (downloaded()), signalMapper, SLOT (map())); @@ -60,13 +60,16 @@ void AutoTester::downloadImage(QUrl url) { ++_index; } -void AutoTester::downloadImages(QStringList listOfURLs) { - _numberOfImagesToDownload = listOfURLs.size(); +void AutoTester::downloadImages(const QStringList& URLs, const QString& directoryName, const QStringList& filenames) { + _directoryName = directoryName; + _filenames = filenames; + + _numberOfImagesToDownload = URLs.size(); _numberOfImagesDownloaded = 0; _index = 0; for (int i = 0; i < _numberOfImagesToDownload; ++i) { - QUrl imageURL(listOfURLs[i]); + QUrl imageURL(URLs[i]); downloadImage(imageURL); } @@ -77,10 +80,8 @@ void AutoTester::saveImage(int index) { QPixmap image; image.loadFromData(downloaders[index]->downloadedData()); - int w = image.width(); - int h = image.height(); + + image.save(_directoryName + "/" + _filenames[index]); ++_numberOfImagesDownloaded; - - image.save("D:/Dicom/lll_" + QString::number(index) + ".jpg"); } diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index 5c1f217421..d5bab6d8a4 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -22,8 +22,8 @@ class AutoTester : public QMainWindow { public: AutoTester(QWidget *parent = Q_NULLPTR); - void downloadImage(QUrl url); - void downloadImages(QStringList listOfURLs); + void downloadImage(const QUrl& url); + void downloadImages(const QStringList& URLs, const QString& directoryName, const QStringList& filenames); private slots: void on_evaluateTestsButton_clicked(); @@ -38,10 +38,15 @@ private slots: private: Ui::AutoTesterClass ui; - Test* test; + std::vector downloaders; + // local storage for parameters - folder to store downloaded files in, and a list of their names + QString _directoryName; + QStringList _filenames; + + // Used to enable passing a parameter to slots QSignalMapper* signalMapper; int _numberOfImagesToDownload; From 361b5331bafba0d7862c52c8527a3c3550a91dc8 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Mar 2018 18:09:32 -0800 Subject: [PATCH 27/97] File sizes are wrong, and so is format. --- tools/auto-tester/src/Test.cpp | 101 ++++-------------------- tools/auto-tester/src/Test.h | 11 ++- tools/auto-tester/src/ui/AutoTester.cpp | 23 +++--- tools/auto-tester/src/ui/AutoTester.h | 1 - tools/auto-tester/src/ui/AutoTester.ui | 13 --- 5 files changed, 36 insertions(+), 113 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index d30349b395..8fed094b07 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -63,9 +63,9 @@ void Test::zipAndDeleteTestResultsFolder() { index = 1; } -bool Test::compareImageLists(QStringList expectedImages, QStringList resultImages, QString testDirectory, bool interactiveMode, QProgressBar* progressBar) { +bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) { progressBar->setMinimum(0); - progressBar->setMaximum(expectedImages.length() - 1); + progressBar->setMaximum(expectedImagesFilenames.length() - 1); progressBar->setValue(0); progressBar->setVisible(true); @@ -74,10 +74,10 @@ bool Test::compareImageLists(QStringList expectedImages, QStringList resultImage const double THRESHOLD { 0.999 }; bool success{ true }; bool keepOn{ true }; - for (int i = 0; keepOn && i < expectedImages.length(); ++i) { + for (int i = 0; keepOn && i < expectedImagesFilenames.length(); ++i) { // First check that images are the same size - QImage resultImage(resultImages[i]); - QImage expectedImage(expectedImages[i]); + QImage resultImage(resultImagesFilenames[i]); + QImage expectedImage(expectedImagesFilenames[i]); if (resultImage.width() != expectedImage.width() || resultImage.height() != expectedImage.height()) { messageBox.critical(0, "Internal error", "Images are not the same size"); exit(-1); @@ -94,14 +94,14 @@ bool Test::compareImageLists(QStringList expectedImages, QStringList resultImage if (similarityIndex < THRESHOLD) { TestFailure testFailure = TestFailure{ (float)similarityIndex, - expectedImages[i].left(expectedImages[i].lastIndexOf("/") + 1), // path to the test (including trailing /) - QFileInfo(expectedImages[i].toStdString().c_str()).fileName(), // filename of expected image - QFileInfo(resultImages[i].toStdString().c_str()).fileName() // filename of result image + expectedImagesFilenames[i].left(expectedImagesFilenames[i].lastIndexOf("/") + 1), // path to the test (including trailing /) + QFileInfo(expectedImagesFilenames[i].toStdString().c_str()).fileName(), // filename of expected image + QFileInfo(resultImagesFilenames[i].toStdString().c_str()).fileName() // filename of result image }; mismatchWindow.setTestFailure(testFailure); - if (!interactiveMode) { + if (!isInteractiveMode) { appendTestResultsToFile(testResultsFolderPath, testFailure, mismatchWindow.getComparisonImage()); success = false; } else { @@ -181,9 +181,9 @@ void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure te comparisonImage.save(failureFolderPath + "/" + "Difference Image.jpg"); } -void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { +void Test::startTestsEvaluation() { // Get list of JPEG images in folder, sorted by name - QString pathToTestResultsDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); + pathToTestResultsDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); if (pathToTestResultsDirectory == "") { return; } @@ -199,8 +199,6 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { QStringList sortedTestResultsFilenames = createListOfAllJPEGimagesInDirectory(pathToTestResultsDirectory); QStringList expectedImagesURLs; - QStringList expectedImagesFilenames; - QStringList resultImages; const QString URLPrefix("https://raw.githubusercontent.com"); const QString githubUser("NissimHadar"); @@ -210,7 +208,7 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { foreach(QString currentFilename, sortedTestResultsFilenames) { QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename; if (isInSnapshotFilenameFormat(currentFilename)) { - resultImages << fullCurrentFilename; + resultImagesFilenames << fullCurrentFilename; QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); @@ -226,15 +224,10 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { } autoTester->downloadImages(expectedImagesURLs, pathToTestResultsDirectory, expectedImagesFilenames); +} - // Wait for do - - ////if (success) { - //// messageBox.information(0, "Success", "All images are as expected"); - ////} else { - //// messageBox.information(0, "Failure", "One or more images are not as expected"); - ////} - +void Test::finishTestsEvaluation(bool interactiveMode, QProgressBar* progressBar) { + bool success = compareImageLists(interactiveMode, progressBar); zipAndDeleteTestResultsFolder(); } @@ -253,70 +246,6 @@ bool Test::isAValidDirectory(QString pathname) { return true; } -// Two criteria are used to decide if a folder contains valid test results. -// 1) a 'test'js' file exists in the folder -// 2) the folder has the same number of actual and expected images -void Test::evaluateTestsRecursively(bool interactiveMode, QProgressBar* progressBar) { - // Select folder to start recursing from - QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder that will contain the top level test script", ".", QFileDialog::ShowDirsOnly); - if (topLevelDirectory == "") { - return; - } - - // Leave if test results folder could not be created - if (!createTestResultsFolderPathIfNeeded(topLevelDirectory)) { - return; - } - - bool success{ true }; - QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); - while (it.hasNext()) { - QString directory = it.next(); - - if (!isAValidDirectory(directory)) { - continue; - } - - const QString testPathname{ directory + "/" + TEST_FILENAME }; - QFileInfo fileInfo(testPathname); - if (!fileInfo.exists()) { - // Folder does not contain 'test.js' - continue; - } - - QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(directory); - - // Separate images into two lists. The first is the expected images, the second is the test results - // Images that are in the wrong format are ignored. - QStringList expectedImages; - QStringList resultImages; - foreach(QString currentFilename, sortedImageFilenames) { - QString fullCurrentFilename = directory + "/" + currentFilename; - if (isInExpectedImageFilenameFormat(currentFilename)) { - expectedImages << fullCurrentFilename; - } else if (isInSnapshotFilenameFormat(currentFilename)) { - resultImages << fullCurrentFilename; - } - } - - if (expectedImages.length() != resultImages.length()) { - // Number of images doesn't match - continue; - } - - // Set success to false if any test has failed - success &= compareImageLists(expectedImages, resultImages, directory, interactiveMode, progressBar); - } - - if (success) { - messageBox.information(0, "Success", "All images are as expected"); - } else { - messageBox.information(0, "Failure", "One or more images are not as expected"); - } - - zipAndDeleteTestResultsFolder(); -} - void Test::importTest(QTextStream& textStream, const QString& testPathname) { textStream << "Script.include(\"" << "file:///" << testPathname + "?raw=true\");" << endl; } diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 026dbf25f6..bb7831da5e 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -23,14 +23,15 @@ class Test { public: Test(); - void evaluateTests(bool interactiveMode, QProgressBar* progressBar); - void evaluateTestsRecursively(bool interactiveMode, QProgressBar* progressBar); + void startTestsEvaluation(); + void finishTestsEvaluation(bool interactiveMode, QProgressBar* progressBar); + void createRecursiveScript(); void createRecursiveScriptsRecursively(); void createTest(); void deleteOldSnapshots(); - bool compareImageLists(QStringList expectedImages, QStringList resultImages, QString testDirectory, bool interactiveMode, QProgressBar* progressBar); + bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar); QStringList createListOfAllJPEGimagesInDirectory(QString pathToImageDirectory); @@ -71,6 +72,10 @@ private: const int NUM_DIGITS { 5 }; const QString EXPECTED_IMAGE_PREFIX { "ExpectedImage_" }; const QString EXPECTED_IMAGE_TYPE { ".jpg" }; + + QString pathToTestResultsDirectory; + QStringList expectedImagesFilenames; + QStringList resultImagesFilenames; }; #endif // hifi_test_h \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 5fd726ad72..52499cd448 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -21,14 +21,7 @@ AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { } void AutoTester::on_evaluateTestsButton_clicked() { - ////QUrl imageUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png"); - ////downloader = new Downloader(imageUrl, this); - ////connect(downloader, SIGNAL (downloaded()), this, SLOT (saveImage())); - test->evaluateTests(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); -} - -void AutoTester::on_evaluateTestsRecursivelyButton_clicked() { - test->evaluateTestsRecursively(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); + test->startTestsEvaluation(); } void AutoTester::on_createRecursiveScriptButton_clicked() { @@ -68,6 +61,11 @@ void AutoTester::downloadImages(const QStringList& URLs, const QString& director _numberOfImagesDownloaded = 0; _index = 0; + ui.progressBar->setMinimum(0); + ui.progressBar->setMaximum(_numberOfImagesToDownload - 1); + ui.progressBar->setValue(0); + ui.progressBar->setVisible(true); + for (int i = 0; i < _numberOfImagesToDownload; ++i) { QUrl imageURL(URLs[i]); downloadImage(imageURL); @@ -80,8 +78,13 @@ void AutoTester::saveImage(int index) { QPixmap image; image.loadFromData(downloaders[index]->downloadedData()); - - image.save(_directoryName + "/" + _filenames[index]); + image.save(_directoryName + "/" + _filenames[index], 0, 100); ++_numberOfImagesDownloaded; + + if (_numberOfImagesDownloaded == _numberOfImagesToDownload) { + test->finishTestsEvaluation(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); + } else { + ui.progressBar->setValue(_numberOfImagesDownloaded); + } } diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index d5bab6d8a4..acf34c60a3 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -27,7 +27,6 @@ public: private slots: void on_evaluateTestsButton_clicked(); - void on_evaluateTestsRecursivelyButton_clicked(); void on_createRecursiveScriptButton_clicked(); void on_createRecursiveScriptsRecursivelyButton_clicked(); void on_createTestButton_clicked(); diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index 0d142ec43e..70060940d1 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -66,19 +66,6 @@ Create Recursive Script - - - - 20 - 130 - 220 - 40 - - - - Evaluate Tests Recursively - - From 0a2610a9e0b8335e89f6c725e117d24dacb2707e Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 3 Mar 2018 09:58:30 -0800 Subject: [PATCH 28/97] Evaluation seems to work. --- tools/auto-tester/src/ImageComparer.cpp | 6 ++-- tools/auto-tester/src/Test.cpp | 47 ++++++++++++++----------- tools/auto-tester/src/Test.h | 7 ++-- tools/auto-tester/src/ui/AutoTester.cpp | 7 ++-- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/tools/auto-tester/src/ImageComparer.cpp b/tools/auto-tester/src/ImageComparer.cpp index 94b95a5ab6..99f7d22c5f 100644 --- a/tools/auto-tester/src/ImageComparer.cpp +++ b/tools/auto-tester/src/ImageComparer.cpp @@ -17,13 +17,13 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) const { // Make sure the image is 8 bits per colour QImage::Format format = expectedImage.format(); - if (format != QImage::Format::Format_RGB32) { + if (format != QImage::Format::Format_ARGB32) { throw -1; } const int L = 255; // (2^number of bits per pixel) - 1 - const double K1{ 0.01 }; - const double K2{ 0.03 }; + const double K1 { 0.01 }; + const double K2 { 0.03 }; const double c1 = pow((K1 * L), 2); const double c2 = pow((K2 * L), 2); diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 8fed094b07..48fa530384 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -20,7 +20,7 @@ extern AutoTester* autoTester; Test::Test() { - QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + EXPECTED_IMAGE_TYPE); + QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + IMAGE_FORMAT); expectedImageFilenameFormat = QRegularExpression(regex); @@ -65,7 +65,7 @@ void Test::zipAndDeleteTestResultsFolder() { bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) { progressBar->setMinimum(0); - progressBar->setMaximum(expectedImagesFilenames.length() - 1); + progressBar->setMaximum(expectedImagesFullFilenames.length() - 1); progressBar->setValue(0); progressBar->setVisible(true); @@ -74,10 +74,11 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) const double THRESHOLD { 0.999 }; bool success{ true }; bool keepOn{ true }; - for (int i = 0; keepOn && i < expectedImagesFilenames.length(); ++i) { + for (int i = 0; keepOn && i < expectedImagesFullFilenames.length(); ++i) { // First check that images are the same size - QImage resultImage(resultImagesFilenames[i]); - QImage expectedImage(expectedImagesFilenames[i]); + QImage resultImage(resultImagesFullFilenames[i]); + QImage expectedImage(expectedImagesFullFilenames[i]); + if (resultImage.width() != expectedImage.width() || resultImage.height() != expectedImage.height()) { messageBox.critical(0, "Internal error", "Images are not the same size"); exit(-1); @@ -94,9 +95,9 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) if (similarityIndex < THRESHOLD) { TestFailure testFailure = TestFailure{ (float)similarityIndex, - expectedImagesFilenames[i].left(expectedImagesFilenames[i].lastIndexOf("/") + 1), // path to the test (including trailing /) - QFileInfo(expectedImagesFilenames[i].toStdString().c_str()).fileName(), // filename of expected image - QFileInfo(resultImagesFilenames[i].toStdString().c_str()).fileName() // filename of result image + expectedImagesFullFilenames[i].left(expectedImagesFullFilenames[i].lastIndexOf("/") + 1), // path to the test (including trailing /) + QFileInfo(expectedImagesFullFilenames[i].toStdString().c_str()).fileName(), // filename of expected image + QFileInfo(resultImagesFullFilenames[i].toStdString().c_str()).fileName() // filename of result image }; mismatchWindow.setTestFailure(testFailure); @@ -197,7 +198,7 @@ void Test::startTestsEvaluation() { // The expected images are represented as a URL to enabel download from GitHub // Images that are in the wrong format are ignored. - QStringList sortedTestResultsFilenames = createListOfAllJPEGimagesInDirectory(pathToTestResultsDirectory); + QStringList sortedTestResultsFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(pathToTestResultsDirectory); QStringList expectedImagesURLs; const QString URLPrefix("https://raw.githubusercontent.com"); @@ -205,18 +206,23 @@ void Test::startTestsEvaluation() { const QString testsRepo("hifi_tests"); const QString branch("addRecursionToAutotester"); + resultImagesFullFilenames.clear(); + expectedImagesFilenames.clear(); + expectedImagesFullFilenames.clear(); + foreach(QString currentFilename, sortedTestResultsFilenames) { QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename; if (isInSnapshotFilenameFormat(currentFilename)) { - resultImagesFilenames << fullCurrentFilename; + resultImagesFullFilenames << fullCurrentFilename; QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); // extract the digits at the end of the filename (exluding the file extension) QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); - QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + EXPECTED_IMAGE_TYPE; + QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + IMAGE_FORMAT; expectedImagesFilenames << expectedImageFilename; + expectedImagesFullFilenames << pathToTestResultsDirectory + "/" + expectedImageFilename; QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + expectedImagePartialSourceDirectory + "/" + expectedImageFilename); expectedImagesURLs << imageURLString; @@ -332,9 +338,10 @@ void Test::createTest() { return; } - QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(imageSourceDirectory); + QStringList sortedImageFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(imageSourceDirectory); - int i = 1; + int i = 1; + const int maxImages = pow(10, NUM_DIGITS); foreach (QString currentFilename, sortedImageFilenames) { QString fullCurrentFilename = imageSourceDirectory + "/" + currentFilename; if (isInExpectedImageFilenameFormat(currentFilename)) { @@ -343,12 +350,12 @@ void Test::createTest() { exit(-1); } } else if (isInSnapshotFilenameFormat(currentFilename)) { - const int maxImages = pow(10, NUM_DIGITS); + if (i >= maxImages) { messageBox.critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported"); exit(-1); } - QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".jpg"; + QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + IMAGE_FORMAT; QString imageDestinationDirectory = getExpectedImageDestinationDirectory(currentFilename); QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; @@ -383,7 +390,7 @@ void Test::deleteOldSnapshots() { continue; } - QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(directory); + QStringList sortedImageFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(directory); // Delete any file that is a snapshot (NOT the Expected Images) QStringList expectedImages; @@ -400,10 +407,10 @@ void Test::deleteOldSnapshots() { } } -QStringList Test::createListOfAllJPEGimagesInDirectory(QString pathToImageDirectory) { +QStringList Test::createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToImageDirectory) { imageDirectory = QDir(pathToImageDirectory); QStringList nameFilters; - nameFilters << "*.jpg"; + nameFilters << "*" + IMAGE_FORMAT; return imageDirectory.entryList(nameFilters, QDir::Files, QDir::Name); } @@ -422,9 +429,9 @@ bool Test::isInSnapshotFilenameFormat(QString filename) { bool last5CharactersAreDigits; filenameParts[0].right(5).toInt(&last5CharactersAreDigits, 10); - bool extensionIsJPG = filenameParts[1] == "jpg"; + bool extensionIsIMAGE_FORMAT = filenameParts[1] == IMAGE_FORMAT.right(3); // without the period - return (filnameHasNoPeriods && contains_tests && last5CharactersAreDigits && extensionIsJPG); + return (filnameHasNoPeriods && contains_tests && last5CharactersAreDigits && extensionIsIMAGE_FORMAT); } // For a file named "D_GitHub_hifi-tests_tests_content_entity_zone_create_0.jpg", the test directory is diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index bb7831da5e..56d924b82a 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -33,7 +33,7 @@ public: bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar); - QStringList createListOfAllJPEGimagesInDirectory(QString pathToImageDirectory); + QStringList createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToImageDirectory); bool isInSnapshotFilenameFormat(QString filename); bool isInExpectedImageFilenameFormat(QString filename); @@ -71,11 +71,12 @@ private: // Expected images are in the format ExpectedImage_dddd.jpg (d == decimal digit) const int NUM_DIGITS { 5 }; const QString EXPECTED_IMAGE_PREFIX { "ExpectedImage_" }; - const QString EXPECTED_IMAGE_TYPE { ".jpg" }; + const QString IMAGE_FORMAT { ".png" }; QString pathToTestResultsDirectory; QStringList expectedImagesFilenames; - QStringList resultImagesFilenames; + QStringList expectedImagesFullFilenames; + QStringList resultImagesFullFilenames; }; #endif // hifi_test_h \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 52499cd448..ade6b0514e 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -75,8 +75,11 @@ void AutoTester::downloadImages(const QStringList& URLs, const QString& director } void AutoTester::saveImage(int index) { - QPixmap image; - image.loadFromData(downloaders[index]->downloadedData()); + QPixmap pixmap; + pixmap.loadFromData(downloaders[index]->downloadedData()); + + QImage image = pixmap.toImage(); + image = image.convertToFormat(QImage::Format_ARGB32); image.save(_directoryName + "/" + _filenames[index], 0, 100); From b32ad2f69c7120cfcd76d5464bd6591141160aca Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 3 Mar 2018 18:22:51 -0800 Subject: [PATCH 29/97] createTests fixed. --- tools/auto-tester/src/Test.cpp | 13 ++----------- tools/auto-tester/src/Test.h | 1 - 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 48fa530384..dbaa3a05a5 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -344,13 +344,7 @@ void Test::createTest() { const int maxImages = pow(10, NUM_DIGITS); foreach (QString currentFilename, sortedImageFilenames) { QString fullCurrentFilename = imageSourceDirectory + "/" + currentFilename; - if (isInExpectedImageFilenameFormat(currentFilename)) { - if (!QFile::remove(fullCurrentFilename)) { - messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); - exit(-1); - } - } else if (isInSnapshotFilenameFormat(currentFilename)) { - + if (isInSnapshotFilenameFormat(currentFilename)) { if (i >= maxImages) { messageBox.critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported"); exit(-1); @@ -360,6 +354,7 @@ void Test::createTest() { QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; try { + QFile::remove(fullNewFileName); QFile::copy(fullCurrentFilename, fullNewFileName); } catch (...) { messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); @@ -471,7 +466,3 @@ QString Test::getExpectedImagePartialSourceDirectory(QString filename) { return result; } - -bool Test::isInExpectedImageFilenameFormat(QString filename) { - return (expectedImageFilenameFormat.match(filename).hasMatch()); -} \ No newline at end of file diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 56d924b82a..29e1b135ed 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -36,7 +36,6 @@ public: QStringList createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToImageDirectory); bool isInSnapshotFilenameFormat(QString filename); - bool isInExpectedImageFilenameFormat(QString filename); void importTest(QTextStream& textStream, const QString& testPathname); From 913ad569c0585769e53bc2d1e926a0afef47c572 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sun, 4 Mar 2018 17:36:20 -0800 Subject: [PATCH 30/97] Added completion message. --- tools/auto-tester/src/Test.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index dbaa3a05a5..7b6293dcbc 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -234,6 +234,13 @@ void Test::startTestsEvaluation() { void Test::finishTestsEvaluation(bool interactiveMode, QProgressBar* progressBar) { bool success = compareImageLists(interactiveMode, progressBar); + + if (success) { + messageBox.information(0, "Success", "All images are as expected"); + } else { + messageBox.information(0, "Failure", "One or more images are not as expected"); + } + zipAndDeleteTestResultsFolder(); } From 5a79f272f3e9ef29ed87977c586b2d7c34edc852 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sun, 4 Mar 2018 20:56:57 -0800 Subject: [PATCH 31/97] Allow multiple evaluations. --- tools/auto-tester/src/Test.cpp | 18 ++++++++++++------ tools/auto-tester/src/ui/AutoTester.cpp | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 7b6293dcbc..fbd30e7307 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -216,16 +216,22 @@ void Test::startTestsEvaluation() { resultImagesFullFilenames << fullCurrentFilename; QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); - - // extract the digits at the end of the filename (exluding the file extension) + + // Images are stored on GitHub as ExpectedImage_ddddd.png + // Extract the digits at the end of the filename (exluding the file extension) QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); - QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + IMAGE_FORMAT; + QString expectedImageStoredFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + IMAGE_FORMAT; + + QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + + expectedImagePartialSourceDirectory + "/" + expectedImageStoredFilename); + + expectedImagesURLs << imageURLString; + + // The image retrieved from Github needs a unique name + QString expectedImageFilename = currentFilename.replace("/", "_").replace(".", "_EI."); expectedImagesFilenames << expectedImageFilename; expectedImagesFullFilenames << pathToTestResultsDirectory + "/" + expectedImageFilename; - - QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + expectedImagePartialSourceDirectory + "/" + expectedImageFilename); - expectedImagesURLs << imageURLString; } } diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index ade6b0514e..5ac7be3dd8 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -81,7 +81,8 @@ void AutoTester::saveImage(int index) { QImage image = pixmap.toImage(); image = image.convertToFormat(QImage::Format_ARGB32); - image.save(_directoryName + "/" + _filenames[index], 0, 100); + QString fullPathname = _directoryName + "/" + _filenames[index]; + image.save(fullPathname, 0, 100); ++_numberOfImagesDownloaded; From 654770af512032cad26c91a8eff4cd1b0cdcc736 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 5 Mar 2018 09:39:26 -0800 Subject: [PATCH 32/97] fix controller dispatacher error --- scripts/system/controllers/controllerDispatcher.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 18b194dd3a..4f041d3067 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -43,6 +43,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.totalVariance = 0; this.highVarianceCount = 0; this.veryhighVarianceCount = 0; + this.orderedPluginNames = []; this.tabletID = null; this.blacklist = []; this.pointerManager = new PointerManager(); From 1997cd27bd463127a088148a013bd1e3efa70f0b Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 5 Mar 2018 11:26:37 -0800 Subject: [PATCH 33/97] correctly use default values --- scripts/system/html/js/entityProperties.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 2b29fbf041..86bbe7086b 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -321,22 +321,19 @@ function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults) { } var keys = Object.keys(updateKeyPair); keys.forEach(function (key) { - delete parsedData[groupName][key]; if (updateKeyPair[key] !== null && updateKeyPair[key] !== "null") { if (updateKeyPair[key] instanceof Element) { if (updateKeyPair[key].type === "checkbox") { - if (updateKeyPair[key].checked !== defaults[key]) { - parsedData[groupName][key] = updateKeyPair[key].checked; - } + parsedData[groupName][key] = updateKeyPair[key].checked; } else { var val = isNaN(updateKeyPair[key].value) ? updateKeyPair[key].value : parseInt(updateKeyPair[key].value); - if (val !== defaults[key]) { - parsedData[groupName][key] = val; - } + parsedData[groupName][key] = val; } } else { parsedData[groupName][key] = updateKeyPair[key]; } + } else if (defaults[key] !== null && defaults[key] !== "null") { + parsedData[groupName][key] = defaults[key]; } }); if (Object.keys(parsedData[groupName]).length === 0) { From d7725f1d73e99870fffae195399556151e224777 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sun, 4 Mar 2018 00:18:59 +0100 Subject: [PATCH 34/97] make the grabbable checkbox again, respect default true setting --- scripts/system/html/js/entityProperties.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 2b29fbf041..7e87586b4f 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1281,7 +1281,7 @@ function loaded() { if (elCloneable.checked) { elGrabbable.checked = false; } - userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, properties.dynamic); + userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, true); }); elCloneableDynamic.addEventListener('change', function(event) { userDataChanger("grabbableKey", "cloneDynamic", event.target, elUserData, -1); From 84815fadaeb6bf2476074466cc0d0da28dfb549d Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 5 Mar 2018 17:45:51 -0800 Subject: [PATCH 35/97] Use JPG->PNG trick to keep file sizes down. --- tools/auto-tester/src/Test.cpp | 79 +++++++++++-------------- tools/auto-tester/src/Test.h | 7 ++- tools/auto-tester/src/ui/AutoTester.cpp | 4 -- tools/auto-tester/src/ui/AutoTester.h | 1 - tools/auto-tester/src/ui/AutoTester.ui | 21 ++----- 5 files changed, 43 insertions(+), 69 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index fbd30e7307..53687fdeda 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -20,7 +22,7 @@ extern AutoTester* autoTester; Test::Test() { - QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + IMAGE_FORMAT); + QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + ".png"); expectedImageFilenameFormat = QRegularExpression(regex); @@ -194,11 +196,23 @@ void Test::startTestsEvaluation() { return; } + // Before any processing - all images are converted to PNGs, as this is the format stored on GitHub + QStringList sortedSnapshotFilenames = createListOfAll_imagesInDirectory("jpg", pathToTestResultsDirectory); + foreach(QString filename, sortedSnapshotFilenames) { + QStringList stringParts = filename.split("."); + copyJPGtoPNG( + pathToTestResultsDirectory + "/" + stringParts[0] + ".jpg", + pathToTestResultsDirectory + "/" + stringParts[0] + ".png" + ); + + QFile::remove(pathToTestResultsDirectory + "/" + stringParts[0] + ".jpg"); + } + // Create two lists. The first is the test results, the second is the expected images - // The expected images are represented as a URL to enabel download from GitHub + // The expected images are represented as a URL to enable download from GitHub // Images that are in the wrong format are ignored. - QStringList sortedTestResultsFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(pathToTestResultsDirectory); + QStringList sortedTestResultsFilenames = createListOfAll_imagesInDirectory("png", pathToTestResultsDirectory); QStringList expectedImagesURLs; const QString URLPrefix("https://raw.githubusercontent.com"); @@ -212,7 +226,7 @@ void Test::startTestsEvaluation() { foreach(QString currentFilename, sortedTestResultsFilenames) { QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename; - if (isInSnapshotFilenameFormat(currentFilename)) { + if (isInSnapshotFilenameFormat("png", currentFilename)) { resultImagesFullFilenames << fullCurrentFilename; QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); @@ -220,7 +234,7 @@ void Test::startTestsEvaluation() { // Images are stored on GitHub as ExpectedImage_ddddd.png // Extract the digits at the end of the filename (exluding the file extension) QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); - QString expectedImageStoredFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + IMAGE_FORMAT; + QString expectedImageStoredFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + ".png"; QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + expectedImagePartialSourceDirectory + "/" + expectedImageStoredFilename); @@ -351,24 +365,23 @@ void Test::createTest() { return; } - QStringList sortedImageFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(imageSourceDirectory); + QStringList sortedImageFilenames = createListOfAll_imagesInDirectory("jpg", imageSourceDirectory); int i = 1; const int maxImages = pow(10, NUM_DIGITS); foreach (QString currentFilename, sortedImageFilenames) { QString fullCurrentFilename = imageSourceDirectory + "/" + currentFilename; - if (isInSnapshotFilenameFormat(currentFilename)) { + if (isInSnapshotFilenameFormat("jpg", currentFilename)) { if (i >= maxImages) { messageBox.critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported"); exit(-1); } - QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + IMAGE_FORMAT; + QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".png"; QString imageDestinationDirectory = getExpectedImageDestinationDirectory(currentFilename); QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; try { - QFile::remove(fullNewFileName); - QFile::copy(fullCurrentFilename, fullNewFileName); + copyJPGtoPNG(fullCurrentFilename, fullNewFileName); } catch (...) { messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); exit(-1); @@ -380,45 +393,23 @@ void Test::createTest() { messageBox.information(0, "Success", "Test images have been created"); } -void Test::deleteOldSnapshots() { - // Select folder to start recursing from - QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select root folder for snapshot deletion", ".", QFileDialog::ShowDirsOnly); - if (topLevelDirectory == "") { - return; - } +void Test::copyJPGtoPNG(QString sourceJPGFullFilename, QString destinationPNGFullFilename) { + QFile::remove(destinationPNGFullFilename); - // Recurse over folders - QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); - while (it.hasNext()) { - QString directory = it.next(); + QImageReader reader; + reader.setFileName(sourceJPGFullFilename); - // Only process directories - QDir dir(directory); - if (!isAValidDirectory(directory)) { - continue; - } + QImage image = reader.read(); - QStringList sortedImageFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(directory); - - // Delete any file that is a snapshot (NOT the Expected Images) - QStringList expectedImages; - QStringList resultImages; - foreach(QString currentFilename, sortedImageFilenames) { - QString fullCurrentFilename = directory + "/" + currentFilename; - if (isInSnapshotFilenameFormat(currentFilename)) { - if (!QFile::remove(fullCurrentFilename)) { - messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nSnapshot deletion aborted"); - exit(-1); - } - } - } - } + QImageWriter writer; + writer.setFileName(destinationPNGFullFilename); + writer.write(image); } -QStringList Test::createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToImageDirectory) { +QStringList Test::createListOfAll_imagesInDirectory(QString imageFormat, QString pathToImageDirectory) { imageDirectory = QDir(pathToImageDirectory); QStringList nameFilters; - nameFilters << "*" + IMAGE_FORMAT; + nameFilters << "*." + imageFormat; return imageDirectory.entryList(nameFilters, QDir::Files, QDir::Name); } @@ -428,7 +419,7 @@ QStringList Test::createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToI // Filename (i.e. without extension) contains _tests_ (this is based on all test scripts being within the tests folder // Last 5 characters in filename are digits // Extension is jpg -bool Test::isInSnapshotFilenameFormat(QString filename) { +bool Test::isInSnapshotFilenameFormat(QString imageFormat, QString filename) { QStringList filenameParts = filename.split("."); bool filnameHasNoPeriods = (filenameParts.size() == 2); @@ -437,7 +428,7 @@ bool Test::isInSnapshotFilenameFormat(QString filename) { bool last5CharactersAreDigits; filenameParts[0].right(5).toInt(&last5CharactersAreDigits, 10); - bool extensionIsIMAGE_FORMAT = filenameParts[1] == IMAGE_FORMAT.right(3); // without the period + bool extensionIsIMAGE_FORMAT = (filenameParts[1] == imageFormat); return (filnameHasNoPeriods && contains_tests && last5CharactersAreDigits && extensionIsIMAGE_FORMAT); } diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 29e1b135ed..b849ab577f 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -33,9 +33,9 @@ public: bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar); - QStringList createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToImageDirectory); + QStringList createListOfAll_imagesInDirectory(QString imageFormat, QString pathToImageDirectory); - bool isInSnapshotFilenameFormat(QString filename); + bool isInSnapshotFilenameFormat(QString imageFormat, QString filename); void importTest(QTextStream& textStream, const QString& testPathname); @@ -49,6 +49,8 @@ public: QString getExpectedImageDestinationDirectory(QString filename); QString getExpectedImagePartialSourceDirectory(QString filename); + void copyJPGtoPNG(QString sourceJPGFullFilename, QString destinationPNGFullFilename); + private: const QString TEST_FILENAME { "test.js" }; const QString TEST_RESULTS_FOLDER { "TestResults" }; @@ -70,7 +72,6 @@ private: // Expected images are in the format ExpectedImage_dddd.jpg (d == decimal digit) const int NUM_DIGITS { 5 }; const QString EXPECTED_IMAGE_PREFIX { "ExpectedImage_" }; - const QString IMAGE_FORMAT { ".png" }; QString pathToTestResultsDirectory; QStringList expectedImagesFilenames; diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 5ac7be3dd8..a5e13331dd 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -36,10 +36,6 @@ void AutoTester::on_createTestButton_clicked() { test->createTest(); } -void AutoTester::on_deleteOldSnapshotsButton_clicked() { - test->deleteOldSnapshots(); -} - void AutoTester::on_closeButton_clicked() { exit(0); } diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index acf34c60a3..938e7ca2d2 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -30,7 +30,6 @@ private slots: void on_createRecursiveScriptButton_clicked(); void on_createRecursiveScriptsRecursivelyButton_clicked(); void on_createTestButton_clicked(); - void on_deleteOldSnapshotsButton_clicked(); void on_closeButton_clicked(); void saveImage(int index); diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index 70060940d1..55c3897e58 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -30,8 +30,8 @@ - 360 - 210 + 20 + 30 220 40 @@ -44,7 +44,7 @@ 20 - 75 + 135 220 40 @@ -70,7 +70,7 @@ 23 - 40 + 100 131 20 @@ -95,19 +95,6 @@ 24 - - - - 360 - 270 - 220 - 40 - - - - Delete Old Snapshots - - From 15c1f5ba307ad36562456c252e3d2a1fb27e4720 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 27 Feb 2018 16:44:45 -0800 Subject: [PATCH 36/97] fixed log spam undefined error --- scripts/system/libraries/entitySelectionTool.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 8a07ff0d20..a419e9d49c 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1322,8 +1322,9 @@ SelectionDisplay = (function() { isActiveTool(handleScaleRTFCube) || isActiveTool(handleStretchXSphere) || isActiveTool(handleStretchYSphere) || isActiveTool(handleStretchZSphere)); - var showOutlineForZone = (SelectionManager.selections.length === 1 && - SelectionManager.savedProperties[SelectionManager.selections[0]].type === "Zone"); + var showOutlineForZone = (SelectionManager.selections.length === 1 && + typeof SelectionManager.savedProperties[SelectionManager.selections[0]] !== "undefined" && + SelectionManager.savedProperties[SelectionManager.selections[0]].type === "Zone"); that.setHandleScaleEdgeVisible(showOutlineForZone || (!isActiveTool(handleRotatePitchRing) && !isActiveTool(handleRotateYawRing) && !isActiveTool(handleRotateRollRing))); From 53e1a0cae5fa41ba691e65caace1058867f2da91 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Thu, 1 Mar 2018 01:53:02 +0300 Subject: [PATCH 37/97] forward 'maybeEnableHmdPreview' if control is not visible --- interface/resources/qml/hifi/commerce/wallet/Wallet.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index ae42b8e3e1..e2f4385965 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -222,6 +222,8 @@ Rectangle { } else { sendToScript(msg); } + } else if (msg.method === 'maybeEnableHmdPreview') { + sendToScript(msg); } } } From b74be92fd8965ae297ad442ede65c4cd933b5fb8 Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 6 Mar 2018 11:29:43 -0800 Subject: [PATCH 38/97] redo scale handles to fix scaling into avatar collision causing chaos --- .../system/libraries/entitySelectionTool.js | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 8a07ff0d20..3c794f14fb 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -458,12 +458,12 @@ SelectionDisplay = (function() { borderSize: 1.4 }; var handleScaleLBNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, -y, -z) - var handleScaleRBNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, -y, z) - var handleScaleLBFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, -y, -z) + var handleScaleRBNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, -y, -z) + var handleScaleLBFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, -y, z) var handleScaleRBFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, -y, z) var handleScaleLTNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, y, -z) - var handleScaleRTNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, y, z) - var handleScaleLTFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, y, -z) + var handleScaleRTNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, y, -z) + var handleScaleLTFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, y, z) var handleScaleRTFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, y, z) var handlePropertiesScaleEdge = { @@ -1021,7 +1021,6 @@ SelectionDisplay = (function() { return; } - if (SelectionManager.hasSelection()) { var position = SelectionManager.worldPosition; var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation; @@ -1147,14 +1146,14 @@ SelectionDisplay = (function() { rotation: scaleCubeRotation, dimensions: scaleCubeDimensions }); - var scaleRBNCubePosition = { x:-scaleCubeOffsetX, y:-scaleCubeOffsetY, z:scaleCubeOffsetZ }; + var scaleRBNCubePosition = { x:scaleCubeOffsetX, y:-scaleCubeOffsetY, z:-scaleCubeOffsetZ }; scaleRBNCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleRBNCubePosition)); Overlays.editOverlay(handleScaleRBNCube, { position: scaleRBNCubePosition, rotation: scaleCubeRotation, dimensions: scaleCubeDimensions }); - var scaleLBFCubePosition = { x:scaleCubeOffsetX, y:-scaleCubeOffsetY, z:-scaleCubeOffsetZ }; + var scaleLBFCubePosition = { x:-scaleCubeOffsetX, y:-scaleCubeOffsetY, z:scaleCubeOffsetZ }; scaleLBFCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleLBFCubePosition)); Overlays.editOverlay(handleScaleLBFCube, { position: scaleLBFCubePosition, @@ -1175,14 +1174,14 @@ SelectionDisplay = (function() { rotation: scaleCubeRotation, dimensions: scaleCubeDimensions }); - var scaleRTNCubePosition = { x:-scaleCubeOffsetX, y:scaleCubeOffsetY, z:scaleCubeOffsetZ }; + var scaleRTNCubePosition = { x:scaleCubeOffsetX, y:scaleCubeOffsetY, z:-scaleCubeOffsetZ }; scaleRTNCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleRTNCubePosition)); Overlays.editOverlay(handleScaleRTNCube, { position: scaleRTNCubePosition, rotation: scaleCubeRotation, dimensions: scaleCubeDimensions }); - var scaleLTFCubePosition = { x:scaleCubeOffsetX, y:scaleCubeOffsetY, z:-scaleCubeOffsetZ }; + var scaleLTFCubePosition = { x:-scaleCubeOffsetX, y:scaleCubeOffsetY, z:scaleCubeOffsetZ }; scaleLTFCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleLTFCubePosition)); Overlays.editOverlay(handleScaleLTFCube, { position: scaleLTFCubePosition, @@ -1236,9 +1235,11 @@ SelectionDisplay = (function() { }); // UPDATE STRETCH HIGHLIGHT PANELS - var scaleLTFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleLTFCubePosition); var scaleRBFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRBFCubePosition); - var stretchPanelXDimensions = Vec3.subtract(scaleLTFCubePositionRotated, scaleRBFCubePositionRotated); + var scaleRTFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRTFCubePosition); + var scaleLTNCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleLTNCubePosition); + var scaleRTNCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRTNCubePosition); + var stretchPanelXDimensions = Vec3.subtract(scaleRTNCubePositionRotated, scaleRBFCubePositionRotated); var tempY = Math.abs(stretchPanelXDimensions.y); stretchPanelXDimensions.x = STRETCH_PANEL_WIDTH; stretchPanelXDimensions.y = Math.abs(stretchPanelXDimensions.z); @@ -1249,8 +1250,6 @@ SelectionDisplay = (function() { rotation: rotationZ, dimensions: stretchPanelXDimensions }); - var scaleLTNCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleLTNCubePosition); - var scaleRTFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRTFCubePosition); var stretchPanelYDimensions = Vec3.subtract(scaleLTNCubePositionRotated, scaleRTFCubePositionRotated); var tempX = Math.abs(stretchPanelYDimensions.x); stretchPanelYDimensions.x = Math.abs(stretchPanelYDimensions.z); @@ -1262,9 +1261,7 @@ SelectionDisplay = (function() { rotation: rotationY, dimensions: stretchPanelYDimensions }); - var scaleRTFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRTFCubePosition); - var scaleRBNCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRBNCubePosition); - var stretchPanelZDimensions = Vec3.subtract(scaleRTFCubePositionRotated, scaleRBNCubePositionRotated); + var stretchPanelZDimensions = Vec3.subtract(scaleLTNCubePositionRotated, scaleRBFCubePositionRotated); var tempX = Math.abs(stretchPanelZDimensions.x); stretchPanelZDimensions.x = Math.abs(stretchPanelZDimensions.y); stretchPanelZDimensions.y = tempX; @@ -1957,7 +1954,11 @@ SelectionDisplay = (function() { }; var onMove = function(event) { - var proportional = (spaceMode === SPACE_WORLD) || event.isShifted || directionEnum === STRETCH_DIRECTION.ALL; + if (event.x === undefined || event.y === undefined) { + return; + } + + var proportional = (spaceMode === SPACE_WORLD) || directionEnum === STRETCH_DIRECTION.ALL; var position, dimensions, rotation; if (spaceMode === SPACE_LOCAL) { @@ -1998,12 +1999,6 @@ SelectionDisplay = (function() { vector = grid.snapToSpacing(vector); var changeInDimensions = Vec3.multiply(NEGATE_VECTOR, vec3Mult(localSigns, vector)); - if (directionEnum === STRETCH_DIRECTION.ALL) { - var toCameraDistance = getDistanceToCamera(position); - var dimensionsMultiple = toCameraDistance * STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE; - changeInDimensions = Vec3.multiply(changeInDimensions, dimensionsMultiple); - } - var newDimensions; if (proportional) { var absoluteX = Math.abs(changeInDimensions.x); @@ -2085,31 +2080,38 @@ SelectionDisplay = (function() { function addHandleScaleTool(overlay, mode, directionEnum) { var directionVector, offset, selectedHandle; if (directionEnum === SCALE_DIRECTION.LBN) { - directionVector = { x:1, y:1, z:1 }; + directionVector = { x:1, y:0, z:1 }; + offset = { x:-1, y:-1, z:-1 }; selectedHandle = handleScaleLBNCube; } else if (directionEnum === SCALE_DIRECTION.RBN) { - directionVector = { x:1, y:1, z:-1 }; + directionVector = { x:-1, y:0, z:1 }; + offset = { x:1, y:-1, z:-1 }; selectedHandle = handleScaleRBNCube; } else if (directionEnum === SCALE_DIRECTION.LBF) { - directionVector = { x:-1, y:1, z:1 }; + directionVector = { x:1, y:0, z:-1 }; + offset = { x:-1, y:-1, z:1 }; selectedHandle = handleScaleLBFCube; } else if (directionEnum === SCALE_DIRECTION.RBF) { - directionVector = { x:-1, y:1, z:-1 }; + directionVector = { x:-1, y:0, z:-1 }; + offset = { x:1, y:-1, z:1 }; selectedHandle = handleScaleRBFCube; } else if (directionEnum === SCALE_DIRECTION.LTN) { - directionVector = { x:1, y:-1, z:1 }; + directionVector = { x:1, y:0, z:1 }; + offset = { x:-1, y:1, z:-1 }; selectedHandle = handleScaleLTNCube; } else if (directionEnum === SCALE_DIRECTION.RTN) { - directionVector = { x:1, y:-1, z:-1 }; + directionVector = { x:-1, y:0, z:1 }; + offset = { x:1, y:1, z:-1 }; selectedHandle = handleScaleRTNCube; } else if (directionEnum === SCALE_DIRECTION.LTF) { - directionVector = { x:-1, y:-1, z:1 }; + directionVector = { x:1, y:0, z:-1 }; + offset = { x:-1, y:1, z:1 }; selectedHandle = handleScaleLTFCube; } else if (directionEnum === SCALE_DIRECTION.RTF) { - directionVector = { x:-1, y:-1, z:-1 }; + directionVector = { x:-1, y:0, z:-1 }; + offset = { x:1, y:1, z:1 }; selectedHandle = handleScaleRTFCube; } - offset = Vec3.multiply(directionVector, NEGATE_VECTOR); var tool = makeStretchTool(mode, STRETCH_DIRECTION.ALL, directionVector, directionVector, offset, null, selectedHandle); return addHandleTool(overlay, tool); From a23884d0e03407841616b4d0bfc6109cc961bcac Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 2 Mar 2018 17:33:28 -0800 Subject: [PATCH 39/97] Prevent crash during long backup web requests --- domain-server/src/DomainServer.cpp | 54 ++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d2ef1a4156..178345a144 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1937,6 +1937,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; + QPointer connectionPtr { connection }; + auto nodeList = DependencyManager::get(); auto getSetting = [this](QString keyPath, QVariant value) -> bool { @@ -2120,30 +2122,38 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url return true; } else if (url.path() == URI_API_BACKUPS) { auto deferred = makePromise("getAllBackupsAndStatus"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonDocument docJSON(QJsonObject::fromVariantMap(result)); - connection->respond(HTTPConnection::StatusCode200, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); + connectionPtr->respond(HTTPConnection::StatusCode200, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); _contentManager->getAllBackupsAndStatus(deferred); return true; } else if (url.path().startsWith(URI_API_BACKUPS_ID)) { auto id = url.path().mid(QString(URI_API_BACKUPS_ID).length()); auto deferred = makePromise("consolidateBackup"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonObject rootJSON; auto success = result["success"].toBool(); if (success) { auto path = result["backupFilePath"].toString(); auto file { std::unique_ptr(new QFile(path)) }; if (file->open(QIODevice::ReadOnly)) { - connection->respond(HTTPConnection::StatusCode200, std::move(file)); + connectionPtr->respond(HTTPConnection::StatusCode200, std::move(file)); } else { qCritical(domain_server) << "Unable to load consolidated backup at:" << path << result; - connection->respond(HTTPConnection::StatusCode500, "Error opening backup"); + connectionPtr->respond(HTTPConnection::StatusCode500, "Error opening backup"); } } else { - connection->respond(HTTPConnection::StatusCode400); + connectionPtr->respond(HTTPConnection::StatusCode400); } }); _contentManager->consolidateBackup(deferred, id); @@ -2264,12 +2274,16 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } else if (uploadedFilename.endsWith(".zip", Qt::CaseInsensitive)) { auto deferred = makePromise("recoverFromUploadedBackup"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonObject rootJSON; auto success = result["success"].toBool(); rootJSON["success"] = success; QJsonDocument docJSON(rootJSON); - connection->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), + connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); @@ -2297,12 +2311,16 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } auto deferred = makePromise("createManualBackup"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonObject rootJSON; auto success = result["success"].toBool(); rootJSON["success"] = success; QJsonDocument docJSON(rootJSON); - connection->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), + connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); _contentManager->createManualBackup(deferred, it.value()); @@ -2322,12 +2340,16 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } else if (url.path().startsWith(URI_API_BACKUPS_RECOVER)) { auto id = url.path().mid(QString(URI_API_BACKUPS_RECOVER).length()); auto deferred = makePromise("recoverFromBackup"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonObject rootJSON; auto success = result["success"].toBool(); rootJSON["success"] = success; QJsonDocument docJSON(rootJSON); - connection->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), + connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); _contentManager->recoverFromBackup(deferred, id); @@ -2423,12 +2445,16 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url if (url.path().startsWith(URI_API_BACKUPS_ID)) { auto id = url.path().mid(QString(URI_API_BACKUPS_ID).length()); auto deferred = makePromise("deleteBackup"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonObject rootJSON; auto success = result["success"].toBool(); rootJSON["success"] = success; QJsonDocument docJSON(rootJSON); - connection->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), + connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); _contentManager->deleteBackup(deferred, id); From 48aa862c16799a054d5c8c3bd1ddb026990006e4 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Mar 2018 13:52:42 -0800 Subject: [PATCH 40/97] Show Connection instructions in Send Money when 0 connections --- .../commerce/wallet/sendMoney/SendMoney.qml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml index 07c85a7f6a..5d03296823 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml @@ -398,6 +398,7 @@ Item { // Item { id: filterBarContainer; + visible: !connectionInstructions.visible; // Size height: 40; // Anchors @@ -495,6 +496,78 @@ Item { } } } + + // "Make a Connection" instructions + Rectangle { + id: connectionInstructions; + visible: connectionsModel.count === 0 && !connectionsLoading.visible; + anchors.fill: parent; + color: "white"; + + RalewayRegular { + id: makeAConnectionText; + // Properties + text: "Make a Connection"; + // Anchors + anchors.top: parent.top; + anchors.topMargin: 20; + anchors.left: parent.left; + anchors.right: parent.right; + // Text Size + size: 24; + // Text Positioning + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter; + // Style + color: hifi.colors.darkGray; + } + + Image { + id: connectionImage; + source: "qrc:/icons/connection.svg"; + width: 150; + height: 150; + mipmap: true; + // Anchors + anchors.top: makeAConnectionText.bottom; + anchors.topMargin: 15; + anchors.horizontalCenter: parent.horizontalCenter; + } + + FontLoader { id: ralewayRegular; source: "qrc:/fonts/Raleway-Regular.ttf"; } + Text { + id: connectionHelpText; + // Anchors + anchors.top: connectionImage.bottom; + anchors.topMargin: 15; + anchors.left: parent.left + anchors.leftMargin: 40; + anchors.right: parent.right + anchors.rightMargin: 40; + // Text alignment + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHLeft + // Style + font.pixelSize: 18; + font.family: ralewayRegular.name + color: hifi.colors.darkGray + wrapMode: Text.Wrap + textFormat: Text.StyledText; + property string instructions: + "When you meet someone you want to remember later, you can connect with a handshake:

" + property string hmdMountedInstructions: + "1. Put your hand out onto their hand and squeeze your controller's grip button on its side.
" + + "2. Once the other person puts their hand onto yours, you'll see your connection form.
" + + "3. After about 3 seconds, you're connected!" + property string hmdNotMountedInstructions: + "1. Press and hold the 'x' key to extend your arm.
" + + "2. Once the other person puts their hand onto yours, you'll see your connection form.
" + + "3. After about 3 seconds, you're connected!"; + // Text + text: + HMD.mounted ? instructions + hmdMountedInstructions : instructions + hmdNotMountedInstructions + } + } } } } From a83b54e10dd63f312d143b6b9ac1b850410f7900 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 6 Mar 2018 13:52:41 -0800 Subject: [PATCH 41/97] fix for getSetting QVariant ref in DomainServer --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d2ef1a4156..cf99ca4344 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1939,7 +1939,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url auto nodeList = DependencyManager::get(); - auto getSetting = [this](QString keyPath, QVariant value) -> bool { + auto getSetting = [this](QString keyPath, QVariant& value) -> bool { value = _settingsManager.valueForKeyPath(keyPath); if (!value.isValid()) { From 47e8e26255d267f450d7143f0c35ea2d8eece588 Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 6 Mar 2018 14:04:15 -0800 Subject: [PATCH 42/97] CR indent fixes --- .../system/libraries/entitySelectionTool.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 3c794f14fb..a4acbbf67c 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1954,10 +1954,10 @@ SelectionDisplay = (function() { }; var onMove = function(event) { - if (event.x === undefined || event.y === undefined) { - return; - } - + if (event.x === undefined || event.y === undefined) { + return; + } + var proportional = (spaceMode === SPACE_WORLD) || directionEnum === STRETCH_DIRECTION.ALL; var position, dimensions, rotation; @@ -2081,35 +2081,35 @@ SelectionDisplay = (function() { var directionVector, offset, selectedHandle; if (directionEnum === SCALE_DIRECTION.LBN) { directionVector = { x:1, y:0, z:1 }; - offset = { x:-1, y:-1, z:-1 }; + offset = { x:-1, y:-1, z:-1 }; selectedHandle = handleScaleLBNCube; } else if (directionEnum === SCALE_DIRECTION.RBN) { directionVector = { x:-1, y:0, z:1 }; - offset = { x:1, y:-1, z:-1 }; + offset = { x:1, y:-1, z:-1 }; selectedHandle = handleScaleRBNCube; } else if (directionEnum === SCALE_DIRECTION.LBF) { directionVector = { x:1, y:0, z:-1 }; - offset = { x:-1, y:-1, z:1 }; + offset = { x:-1, y:-1, z:1 }; selectedHandle = handleScaleLBFCube; } else if (directionEnum === SCALE_DIRECTION.RBF) { directionVector = { x:-1, y:0, z:-1 }; - offset = { x:1, y:-1, z:1 }; + offset = { x:1, y:-1, z:1 }; selectedHandle = handleScaleRBFCube; } else if (directionEnum === SCALE_DIRECTION.LTN) { directionVector = { x:1, y:0, z:1 }; - offset = { x:-1, y:1, z:-1 }; + offset = { x:-1, y:1, z:-1 }; selectedHandle = handleScaleLTNCube; } else if (directionEnum === SCALE_DIRECTION.RTN) { directionVector = { x:-1, y:0, z:1 }; - offset = { x:1, y:1, z:-1 }; + offset = { x:1, y:1, z:-1 }; selectedHandle = handleScaleRTNCube; } else if (directionEnum === SCALE_DIRECTION.LTF) { directionVector = { x:1, y:0, z:-1 }; - offset = { x:-1, y:1, z:1 }; + offset = { x:-1, y:1, z:1 }; selectedHandle = handleScaleLTFCube; } else if (directionEnum === SCALE_DIRECTION.RTF) { directionVector = { x:-1, y:0, z:-1 }; - offset = { x:1, y:1, z:1 }; + offset = { x:1, y:1, z:1 }; selectedHandle = handleScaleRTFCube; } var tool = makeStretchTool(mode, STRETCH_DIRECTION.ALL, directionVector, From 97d283cc5f3d18628a69e55334c8e91e5a3d65b5 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 6 Mar 2018 16:17:27 -0800 Subject: [PATCH 43/97] use correct api call for audio and correct function call to set stereo input mode --- interface/resources/qml/hifi/audio/Audio.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 156332579a..684a732286 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -131,7 +131,7 @@ Rectangle { text: qsTr("use stereo for stereo devices"); checked: false; onClicked: { - var success = Audio.setIsStereoInput(checked); + var success = AudioScriptingInterface.setStereoInput(checked); if (!success) { checked = !checked; } @@ -219,7 +219,7 @@ Rectangle { onPressed: { if (!checked) { stereoMic.checked = false; - Audio.setIsStereoInput(false); // the next selected audio device might not support stereo + AudioScriptingInterface.setStereoInput(false); // the next selected audio device might not support stereo AudioScriptingInterface.setInputDevice(info, bar.currentIndex === 1); } } From 05e9aa52c90fc07786aed06a2579da8634cdce9e Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 6 Mar 2018 16:22:54 -0800 Subject: [PATCH 44/97] Moved can-cast-shadow checkbox to behaviour section. --- scripts/system/html/entityProperties.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index d6710238fb..7389442649 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -61,10 +61,6 @@ -
- - -
@@ -317,6 +313,10 @@
+
+ + +
From 17c12fde9c66ca0fd723b478eee7aa4b93fab588 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 6 Mar 2018 16:32:04 -0800 Subject: [PATCH 45/97] Fix for HandshakeRequest logic --- libraries/networking/src/udt/Connection.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 77ed589e0b..b34c05106f 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -578,6 +578,7 @@ void Connection::processControl(ControlPacketPointer controlPacket) { #ifdef UDT_CONNECTION_DEBUG qCDebug(networking) << "Got handshake request, stopping SendQueue"; #endif + _hasReceivedHandshakeACK = false; stopSendQueue(); } break; From 4b3d63eea4952c46749593fdb49d1e79699172d2 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 6 Mar 2018 16:37:05 -0800 Subject: [PATCH 46/97] Added math.h to includes (MacOS build error). --- tools/auto-tester/src/Test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 53687fdeda..2b3d121638 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -21,6 +21,8 @@ #include "ui/AutoTester.h" extern AutoTester* autoTester; +#include + Test::Test() { QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + ".png"); From 251e4a312736cba17c7e4a51e0f38cd7029dc561 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 6 Mar 2018 16:35:49 -0800 Subject: [PATCH 47/97] Fixed blocks importer textures being interpreted as image entities --- interface/src/Application.cpp | 18 +++++++++--------- interface/src/Application.h | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index af159263ed..189b4c02bc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6607,17 +6607,17 @@ void Application::addAssetToWorld(QString path, QString zipFile, bool isZip, boo addAssetToWorldInfo(filename, "Adding " + mapping.mid(1) + " to the Asset Server."); - addAssetToWorldWithNewMapping(path, mapping, 0); + addAssetToWorldWithNewMapping(path, mapping, 0, isBlocks); } -void Application::addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy) { +void Application::addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy, bool isBlocks) { auto request = DependencyManager::get()->createGetMappingRequest(mapping); QObject::connect(request, &GetMappingRequest::finished, this, [=](GetMappingRequest* request) mutable { const int MAX_COPY_COUNT = 100; // Limit number of duplicate assets; recursion guard. auto result = request->getError(); if (result == GetMappingRequest::NotFound) { - addAssetToWorldUpload(filePath, mapping); + addAssetToWorldUpload(filePath, mapping, isBlocks); } else if (result != GetMappingRequest::NoError) { QString errorInfo = "Could not map asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); @@ -6629,7 +6629,7 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin } copy++; mapping = mapping.insert(mapping.lastIndexOf("."), "-" + QString::number(copy)); - addAssetToWorldWithNewMapping(filePath, mapping, copy); + addAssetToWorldWithNewMapping(filePath, mapping, copy, isBlocks); } else { QString errorInfo = "Too many copies of asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); @@ -6642,7 +6642,7 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin request->start(); } -void Application::addAssetToWorldUpload(QString filePath, QString mapping) { +void Application::addAssetToWorldUpload(QString filePath, QString mapping, bool isBlocks) { qInfo(interfaceapp) << "Uploading" << filePath << "to Asset Server as" << mapping; auto upload = DependencyManager::get()->createUpload(filePath); QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { @@ -6651,7 +6651,7 @@ void Application::addAssetToWorldUpload(QString filePath, QString mapping) { qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { - addAssetToWorldSetMapping(filePath, mapping, hash); + addAssetToWorldSetMapping(filePath, mapping, hash, isBlocks); } // Remove temporary directory created by Clara.io market place download. @@ -6668,7 +6668,7 @@ void Application::addAssetToWorldUpload(QString filePath, QString mapping) { upload->start(); } -void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash) { +void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash, bool isBlocks) { auto request = DependencyManager::get()->createSetMappingRequest(mapping, hash); connect(request, &SetMappingRequest::finished, this, [=](SetMappingRequest* request) mutable { if (request->getError() != SetMappingRequest::NoError) { @@ -6677,8 +6677,8 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { // to prevent files that aren't models from being loaded into world automatically - if (filePath.endsWith(OBJ_EXTENSION) || filePath.endsWith(FBX_EXTENSION) || - filePath.endsWith(JPG_EXTENSION) || filePath.endsWith(PNG_EXTENSION)) { + if (filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION) || + filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION) && (!isBlocks)) { addAssetToWorldAddEntity(filePath, mapping); } else { qCDebug(interfaceapp) << "Zipped contents are not supported entity files"; diff --git a/interface/src/Application.h b/interface/src/Application.h index ad12a4dc67..8b8e76d584 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -322,9 +322,9 @@ public slots: void addAssetToWorldFromURLRequestFinished(); void addAssetToWorld(QString filePath, QString zipFile, bool isZip, bool isBlocks); void addAssetToWorldUnzipFailure(QString filePath); - void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy); - void addAssetToWorldUpload(QString filePath, QString mapping); - void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash); + void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy, bool isBlocks); + void addAssetToWorldUpload(QString filePath, QString mapping, bool isBlocks); + void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash, bool isBlocks); void addAssetToWorldAddEntity(QString filePath, QString mapping); void handleUnzip(QString sourceFile, QStringList destinationFile, bool autoAdd, bool isZip, bool isBlocks); From 866bec0b34da3dc8da1c7ffd741d08e86ed919be Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 7 Mar 2018 02:36:07 +0100 Subject: [PATCH 48/97] rule -> role --- interface/src/avatar/MyAvatar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fa5206e128..d48d059bed 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -346,7 +346,7 @@ public: * restoreRoleAnimation() is used to restore a specified animation role's default animation clip. If you have not specified an override animation * for the specified role, this function will have no effect. * @function MyAvatar.restoreRoleAnimation - * @param rule {string} The animation role clip to restore + * @param role {string} The animation role clip to restore */ Q_INVOKABLE void restoreRoleAnimation(const QString& role); From 923c81ae2863f7154270f85a08369b4dff4e6c7c Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Mar 2018 17:38:27 -0800 Subject: [PATCH 49/97] Swap order of the ZoneRendererJob with DrawLocalLights to fix the local lights --- libraries/render-utils/src/RenderDeferredTask.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index f262307944..50620bfcce 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -142,13 +142,12 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN(0); const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN(1); - + // Clear Light, Haze and Skybox Stages and render zones from the general metas bucket + const auto zones = task.addJob("ZoneRenderer", metas); + // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. task.addJob("DrawLight", lights); - // Filter zones from the general metas bucket - const auto zones = task.addJob("ZoneRenderer", metas); - // Light Clustering // Create the cluster grid of lights, cpu job for now const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).asVarying(); From c6e5f4c9c83774d323f7408f1d7b7a8f4e452765 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 6 Mar 2018 19:24:09 -0800 Subject: [PATCH 50/97] zip file drags don't auto add model textures --- interface/src/Application.cpp | 17 +++++++++-------- interface/src/Application.h | 8 ++++---- .../src/FileScriptingInterface.cpp | 13 +++++++++++++ .../script-engine/src/FileScriptingInterface.h | 1 + 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 189b4c02bc..9a04a9509e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6607,17 +6607,17 @@ void Application::addAssetToWorld(QString path, QString zipFile, bool isZip, boo addAssetToWorldInfo(filename, "Adding " + mapping.mid(1) + " to the Asset Server."); - addAssetToWorldWithNewMapping(path, mapping, 0, isBlocks); + addAssetToWorldWithNewMapping(path, mapping, 0, isZip, isBlocks); } -void Application::addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy, bool isBlocks) { +void Application::addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy, bool isZip, bool isBlocks) { auto request = DependencyManager::get()->createGetMappingRequest(mapping); QObject::connect(request, &GetMappingRequest::finished, this, [=](GetMappingRequest* request) mutable { const int MAX_COPY_COUNT = 100; // Limit number of duplicate assets; recursion guard. auto result = request->getError(); if (result == GetMappingRequest::NotFound) { - addAssetToWorldUpload(filePath, mapping, isBlocks); + addAssetToWorldUpload(filePath, mapping, isZip, isBlocks); } else if (result != GetMappingRequest::NoError) { QString errorInfo = "Could not map asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); @@ -6629,7 +6629,7 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin } copy++; mapping = mapping.insert(mapping.lastIndexOf("."), "-" + QString::number(copy)); - addAssetToWorldWithNewMapping(filePath, mapping, copy, isBlocks); + addAssetToWorldWithNewMapping(filePath, mapping, copy, isZip, isBlocks); } else { QString errorInfo = "Too many copies of asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); @@ -6642,7 +6642,7 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin request->start(); } -void Application::addAssetToWorldUpload(QString filePath, QString mapping, bool isBlocks) { +void Application::addAssetToWorldUpload(QString filePath, QString mapping, bool isZip, bool isBlocks) { qInfo(interfaceapp) << "Uploading" << filePath << "to Asset Server as" << mapping; auto upload = DependencyManager::get()->createUpload(filePath); QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { @@ -6651,7 +6651,7 @@ void Application::addAssetToWorldUpload(QString filePath, QString mapping, bool qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { - addAssetToWorldSetMapping(filePath, mapping, hash, isBlocks); + addAssetToWorldSetMapping(filePath, mapping, hash, isZip, isBlocks); } // Remove temporary directory created by Clara.io market place download. @@ -6668,7 +6668,7 @@ void Application::addAssetToWorldUpload(QString filePath, QString mapping, bool upload->start(); } -void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash, bool isBlocks) { +void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash, bool isZip, bool isBlocks) { auto request = DependencyManager::get()->createSetMappingRequest(mapping, hash); connect(request, &SetMappingRequest::finished, this, [=](SetMappingRequest* request) mutable { if (request->getError() != SetMappingRequest::NoError) { @@ -6678,7 +6678,8 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q } else { // to prevent files that aren't models from being loaded into world automatically if (filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION) || - filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION) && (!isBlocks)) { + filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION) && + (!isBlocks) && (!isZip)) { addAssetToWorldAddEntity(filePath, mapping); } else { qCDebug(interfaceapp) << "Zipped contents are not supported entity files"; diff --git a/interface/src/Application.h b/interface/src/Application.h index 8b8e76d584..e4d784f2d5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -320,11 +320,11 @@ public slots: // FIXME: Move addAssetToWorld* methods to own class? void addAssetToWorldFromURL(QString url); void addAssetToWorldFromURLRequestFinished(); - void addAssetToWorld(QString filePath, QString zipFile, bool isZip, bool isBlocks); + void addAssetToWorld(QString filePath, QString zipFile, bool isZip = false, bool isBlocks = false); void addAssetToWorldUnzipFailure(QString filePath); - void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy, bool isBlocks); - void addAssetToWorldUpload(QString filePath, QString mapping, bool isBlocks); - void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash, bool isBlocks); + void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy, bool isZip = false, bool isBlocks = false); + void addAssetToWorldUpload(QString filePath, QString mapping, bool isZip = false, bool isBlocks = false); + void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash, bool isZip = false, bool isBlocks = false); void addAssetToWorldAddEntity(QString filePath, QString mapping); void handleUnzip(QString sourceFile, QStringList destinationFile, bool autoAdd, bool isZip, bool isBlocks); diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index 1472e53045..3bf044fd8b 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -68,6 +68,10 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool if (path.contains("vr.google.com/downloads")) { isZip = true; } + if (!hasModel(fileList)) { + isZip = false; + } + emit unzipResult(path, fileList, autoAdd, isZip, isBlocks); } @@ -107,6 +111,15 @@ bool FileScriptingInterface::isTempDir(QString tempDir) { return (testContainer == tempContainer); } +bool FileScriptingInterface::hasModel(QStringList fileList) { + for (int i = 0; i < fileList.size(); i++) { + if (fileList.at(i).toLower().contains(".fbx") || fileList.at(i).toLower().contains(".obj")) { + return true; + } + } + return false; +} + QString FileScriptingInterface::getTempDir() { QTemporaryDir dir; dir.setAutoRemove(false); diff --git a/libraries/script-engine/src/FileScriptingInterface.h b/libraries/script-engine/src/FileScriptingInterface.h index e4c27dbf7f..5cbe417130 100644 --- a/libraries/script-engine/src/FileScriptingInterface.h +++ b/libraries/script-engine/src/FileScriptingInterface.h @@ -32,6 +32,7 @@ signals: private: bool isTempDir(QString tempDir); + bool hasModel(QStringList fileList); QStringList unzipFile(QString path, QString tempDir); void recursiveFileScan(QFileInfo file, QString* dirName); void downloadZip(QString path, const QString link); From 13767beece24de41649b9d408961009b296562ed Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 7 Mar 2018 08:19:36 -0800 Subject: [PATCH 51/97] Caps change --- interface/resources/qml/hifi/audio/Audio.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 684a732286..b598e26954 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -128,7 +128,7 @@ Rectangle { AudioControls.CheckBox { id: stereoMic spacing: muteMic.spacing; - text: qsTr("use stereo for stereo devices"); + text: qsTr("Use stereo for stereo devices"); checked: false; onClicked: { var success = AudioScriptingInterface.setStereoInput(checked); From 2d448d7208ae90a8bdea3ba45d30865b78f80864 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 7 Mar 2018 10:02:35 -0800 Subject: [PATCH 52/97] tablet scale and position changes --- interface/src/Application.cpp | 2 +- scripts/system/libraries/WebTablet.js | 5 +++-- scripts/system/libraries/utils.js | 4 ++-- scripts/system/tablet-ui/tabletUI.js | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 35b7de7284..36c661f8be 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -891,7 +891,7 @@ Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); Setting::Handle sessionRunTime{ "sessionRunTime", 0 }; -const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 100.0f; +const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 70.0f; const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f; const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true; const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false; diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index a34191b951..511bb6989e 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -46,8 +46,9 @@ function calcSpawnInfo(hand, landscape) { var headPos = (HMD.active && Camera.mode === "first person") ? HMD.position : Camera.position; var headRot = (HMD.active && Camera.mode === "first person") ? HMD.orientation : Camera.orientation; - - var forward = Quat.getForward(Quat.cancelOutRollAndPitch(headRot)); + var dominantHandRotation = MyAvatar.getDominantHand() === "right" ? -20 : 20; + var offsetRotation = Quat.fromPitchYawRollDegrees(0, dominantHandRotation, 0); + var forward = Vec3.multiplyQbyV(offsetRotation, Quat.getForward(Quat.cancelOutRollAndPitch(headRot))); var FORWARD_OFFSET = 0.5 * MyAvatar.sensorToWorldScale; finalPosition = Vec3.sum(headPos, Vec3.multiply(FORWARD_OFFSET, forward)); var orientation = Quat.lookAt({x: 0, y: 0, z: 0}, forward, Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.UNIT_Y)); diff --git a/scripts/system/libraries/utils.js b/scripts/system/libraries/utils.js index 442a9f6d24..6afde85c29 100644 --- a/scripts/system/libraries/utils.js +++ b/scripts/system/libraries/utils.js @@ -356,7 +356,7 @@ getTabletWidthFromSettings = function () { var DEFAULT_TABLET_WIDTH = 0.4375; var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var toolbarMode = tablet.toolbarMode; - var DEFAULT_TABLET_SCALE = 100; + var DEFAULT_TABLET_SCALE = 70; var tabletScalePercentage = DEFAULT_TABLET_SCALE; if (!toolbarMode) { if (HMD.active) { @@ -441,4 +441,4 @@ getMainTabletIDs = function () { tabletIDs.push(HMD.homeButtonID); } return tabletIDs; -}; \ No newline at end of file +}; diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index 100d0e82ee..ee3dab7308 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -19,11 +19,11 @@ var tabletRezzed = false; var activeHand = null; var DEFAULT_WIDTH = 0.4375; - var DEFAULT_TABLET_SCALE = 100; + var DEFAULT_TABLET_SCALE = 70; var preMakeTime = Date.now(); var validCheckTime = Date.now(); var debugTablet = false; - var tabletScalePercentage = 100.0; + var tabletScalePercentage = 70.0; UIWebTablet = null; var MSECS_PER_SEC = 1000.0; var MUTE_MICROPHONE_MENU_ITEM = "Mute Microphone"; From 28589094c2b6f4b7b569ed40a3efd152f2b5cc46 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 7 Mar 2018 10:18:40 -0800 Subject: [PATCH 53/97] hopefully fixed mac/ubuntu builds --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9a04a9509e..7a9ce6f649 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6677,8 +6677,8 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { // to prevent files that aren't models from being loaded into world automatically - if (filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION) || - filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION) && + if ((filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION) || + filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION)) && (!isBlocks) && (!isZip)) { addAssetToWorldAddEntity(filePath, mapping); } else { From da414b94fdd88344cb0e8f06c72dbfc575f6a18f Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 7 Mar 2018 10:47:37 -0800 Subject: [PATCH 54/97] WIP - adding the creation of recursive scripts. --- tools/auto-tester/src/Test.cpp | 45 +++++++++++++++++++++++++--------- tools/auto-tester/src/Test.h | 4 +++ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 2b3d121638..f514696ad3 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -84,7 +84,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) QImage expectedImage(expectedImagesFullFilenames[i]); if (resultImage.width() != expectedImage.width() || resultImage.height() != expectedImage.height()) { - messageBox.critical(0, "Internal error", "Images are not the same size"); + messageBox.critical(0, "Internal error #1", "Images are not the same size"); exit(-1); } @@ -92,7 +92,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) try { similarityIndex = imageComparer.compareImages(resultImage, expectedImage); } catch (...) { - messageBox.critical(0, "Internal error", "Image not in expected format"); + messageBox.critical(0, "Internal error #2", "Image not in expected format"); exit(-1); } @@ -139,20 +139,20 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage) { if (!QDir().exists(testResultsFolderPath)) { - messageBox.critical(0, "Internal error", "Folder " + testResultsFolderPath + " not found"); + messageBox.critical(0, "Internal error #3", "Folder " + testResultsFolderPath + " not found"); exit(-1); } QString failureFolderPath { testResultsFolderPath + "/" + "Failure_" + QString::number(index) }; if (!QDir().mkdir(failureFolderPath)) { - messageBox.critical(0, "Internal error", "Failed to create folder " + failureFolderPath); + messageBox.critical(0, "Internal error #4", "Failed to create folder " + failureFolderPath); exit(-1); } ++index; QFile descriptionFile(failureFolderPath + "/" + TEST_RESULTS_FILENAME); if (!descriptionFile.open(QIODevice::ReadWrite)) { - messageBox.critical(0, "Internal error", "Failed to create file " + TEST_RESULTS_FILENAME); + messageBox.critical(0, "Internal error #5", "Failed to create file " + TEST_RESULTS_FILENAME); exit(-1); } @@ -172,14 +172,14 @@ void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure te sourceFile = testFailure._pathname + testFailure._expectedImageFilename; destinationFile = failureFolderPath + "/" + "Expected Image.jpg"; if (!QFile::copy(sourceFile, destinationFile)) { - messageBox.critical(0, "Internal error", "Failed to copy " + sourceFile + " to " + destinationFile); + messageBox.critical(0, "Internal error #6", "Failed to copy " + sourceFile + " to " + destinationFile); exit(-1); } sourceFile = testFailure._pathname + testFailure._actualImageFilename; destinationFile = failureFolderPath + "/" + "Actual Image.jpg"; if (!QFile::copy(sourceFile, destinationFile)) { - messageBox.critical(0, "Internal error", "Failed to copy " + sourceFile + " to " + destinationFile); + messageBox.critical(0, "Internal error #7", "Failed to copy " + sourceFile + " to " + destinationFile); exit(-1); } @@ -282,7 +282,24 @@ bool Test::isAValidDirectory(QString pathname) { } void Test::importTest(QTextStream& textStream, const QString& testPathname) { - textStream << "Script.include(\"" << "file:///" << testPathname + "?raw=true\");" << endl; + // `testPathname` includes the full path to the test. We need the portion below (and including) `tests` + QStringList filenameParts = testPathname.split('/'); + int i{ 0 }; + while (i < filenameParts.length() && filenameParts[i] != "tests") { + ++i; + } + + if (i == filenameParts.length()) { + messageBox.critical(0, "Internal error #10", "Bad testPathname"); + exit(-1); + } + + QString filename; + for (int j = i; j < filenameParts.length(); ++j) { + filename += "/" + filenameParts[j]; + } + + textStream << "Script.include(\"" << "https://raw.githubusercontent.com/" << user << "/hifi_tests/" << branch << filename + "\");" << endl; } // Creates a single script in a user-selected folder. @@ -298,7 +315,7 @@ void Test::createRecursiveScript() { QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { messageBox.critical(0, - "Internal Error", + "Internal Error #8", "Failed to create \"" + recursiveTestsFilename + "\" in directory \"" + topLevelDirectory + "\"" ); @@ -308,7 +325,7 @@ void Test::createRecursiveScript() { QTextStream textStream(&allTestsFilename); textStream << "// This is an automatically generated file, created by auto-tester" << endl << endl; - textStream << "var autoTester = Script.require(\"https://github.com/highfidelity/hifi_tests/blob/master/tests/utils/autoTester.js?raw=true\");" << endl; + textStream << "var autoTester = Script.require(\"https://raw.githubusercontent.com/" + user + "/hifi_tests/" + branch + "/tests/utils/autoTester.js\");" << endl; textStream << "autoTester.enableRecursive();" << endl << endl; QVector testPathnames; @@ -459,11 +476,17 @@ QString Test::getExpectedImagePartialSourceDirectory(QString filename) { QString filenameWithoutExtension = filename.split(".")[0]; QStringList filenameParts = filenameWithoutExtension.split("_"); + // Note that the topmost "tests" folder is assumed to be the root int i { 0 }; - while (filenameParts[i] != "tests") { + while (i < filenameParts.length() && filenameParts[i] != "tests") { ++i; } + if (i == filenameParts.length()) { + messageBox.critical(0, "Internal error #9", "Bad filename"); + exit(-1); + } + QString result = filenameParts[i]; for (int j = i + 1; j < filenameParts.length() - 1; ++j) { diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index b849ab577f..2a26e042b9 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -77,6 +77,10 @@ private: QStringList expectedImagesFilenames; QStringList expectedImagesFullFilenames; QStringList resultImagesFullFilenames; + + // Used for accessing GitHub + const QString user{ "NissimHadar" }; + const QString branch{ "addRecursionToAutotester" }; }; #endif // hifi_test_h \ No newline at end of file From 9bd7f31ff32b7a68bcc333e71217604194c5034f Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 7 Mar 2018 11:30:30 -0800 Subject: [PATCH 55/97] Now search for `tests` folder bottom-up. --- tools/auto-tester/src/Test.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index f514696ad3..8267435fad 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -476,13 +476,14 @@ QString Test::getExpectedImagePartialSourceDirectory(QString filename) { QString filenameWithoutExtension = filename.split(".")[0]; QStringList filenameParts = filenameWithoutExtension.split("_"); - // Note that the topmost "tests" folder is assumed to be the root - int i { 0 }; - while (i < filenameParts.length() && filenameParts[i] != "tests") { - ++i; + // Note that the bottom-most "tests" folder is assumed to be the root + // This is required because the tests folder is named hifi_tests + int i { filenameParts.length() - 1 }; + while (i >= 0 && filenameParts[i] != "tests") { + --i; } - if (i == filenameParts.length()) { + if (i < 0) { messageBox.critical(0, "Internal error #9", "Bad filename"); exit(-1); } From 9ae2da7e4b3a3b9f2560b39602d955874a5bf934 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 7 Mar 2018 13:18:36 -0800 Subject: [PATCH 56/97] fixed logic for texture files/non-models --- interface/src/Application.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7a9ce6f649..7fff296323 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6676,10 +6676,10 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { - // to prevent files that aren't models from being loaded into world automatically - if ((filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION) || - filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION)) && - (!isBlocks) && (!isZip)) { + // to prevent files that aren't models or texture files from being loaded into world automatically + if (filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION) || + (filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION) && + ((!isBlocks) && (!isZip)))) { addAssetToWorldAddEntity(filePath, mapping); } else { qCDebug(interfaceapp) << "Zipped contents are not supported entity files"; From b47b512ab9a767039b629e26daa75b2d2528b025 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 7 Mar 2018 13:25:40 -0800 Subject: [PATCH 57/97] Completed recursive creation of recursive scripts. --- tools/auto-tester/src/Test.cpp | 58 ++++++++++++++++++++++++++++++---- tools/auto-tester/src/Test.h | 2 ++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 8267435fad..1078ce1bc4 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -311,6 +311,52 @@ void Test::createRecursiveScript() { return; } + createRecursiveScript(topLevelDirectory, true); +} + +// This method creates a `testRecursive.js` script in every sub-folder. +void Test::createRecursiveScriptsRecursively() { + // Select folder to start recursing from + QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the root folder for the recursive scripts", ".", QFileDialog::ShowDirsOnly); + if (topLevelDirectory == "") { + return; + } + + createRecursiveScript(topLevelDirectory, false); + + QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + while (it.hasNext()) { + QString directory = it.next(); + + // Only process directories + QDir dir(); + if (!isAValidDirectory(directory)) { + continue; + } + + // Only process directories that have sub-directories + bool hasNoSubDirectories{ true }; + QDirIterator it2(directory.toStdString().c_str(), QDirIterator::Subdirectories); + while (it2.hasNext()) { + QString directory2 = it2.next(); + + // Only process directories + QDir dir(); + if (isAValidDirectory(directory2)) { + hasNoSubDirectories = false; + break; + } + } + + if (!hasNoSubDirectories) { + createRecursiveScript(directory, false); + } + } + + messageBox.information(0, "Success", "Scripts have been created"); +} + +void Test::createRecursiveScript(QString topLevelDirectory, bool interactiveMode) { const QString recursiveTestsFilename("testRecursive.js"); QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { @@ -350,7 +396,7 @@ void Test::createRecursiveScript() { continue; } - const QString testPathname{ directory + "/" + TEST_FILENAME }; + const QString testPathname { directory + "/" + TEST_FILENAME }; QFileInfo fileInfo(testPathname); if (fileInfo.exists()) { // Current folder contains a test @@ -360,7 +406,7 @@ void Test::createRecursiveScript() { } } - if (testPathnames.length() <= 0) { + if (interactiveMode && testPathnames.length() <= 0) { messageBox.information(0, "Failure", "No \"" + TEST_FILENAME + "\" files found"); allTestsFilename.close(); return; @@ -370,10 +416,10 @@ void Test::createRecursiveScript() { textStream << "autoTester.runRecursive();" << endl; allTestsFilename.close(); - messageBox.information(0, "Success", "Script has been created"); -} - -void Test::createRecursiveScriptsRecursively() { + + if (interactiveMode) { + messageBox.information(0, "Success", "Script has been created"); + } } void Test::createTest() { diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 2a26e042b9..411f27eae6 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -28,6 +28,8 @@ public: void createRecursiveScript(); void createRecursiveScriptsRecursively(); + void createRecursiveScript(QString topLevelDirectory, bool interactiveMode); + void createTest(); void deleteOldSnapshots(); From 0aacdcd5580f4d63530023d694d2c9a8ec5c72a0 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 7 Mar 2018 13:33:39 -0800 Subject: [PATCH 58/97] docs --- .../graphics-scripting/src/graphics-scripting/Forward.h | 6 ++++++ .../src/graphics-scripting/ScriptableModel.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/libraries/graphics-scripting/src/graphics-scripting/Forward.h b/libraries/graphics-scripting/src/graphics-scripting/Forward.h index 3d710b41b4..ed8e96a12f 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/Forward.h +++ b/libraries/graphics-scripting/src/graphics-scripting/Forward.h @@ -65,6 +65,12 @@ namespace scriptable { QString lightmapMap; QString scatteringMap; }; + + /**jsdoc + * @typedef {object} Graphics.MaterialLayer + * @property {Material} material - This layer's material. + * @property {number} priority - The priority of this layer. If multiple materials are applied to a mesh part, only the highest priority layer is used. + */ class ScriptableMaterialLayer { public: ScriptableMaterialLayer() {} diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h index a1278132ca..ac0b7b9623 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h @@ -21,6 +21,8 @@ namespace scriptable { * @property {Uuid} objectID - UUID of corresponding inworld object (if model is associated) * @property {number} numMeshes - The number of submeshes contained in the model. * @property {Graphics.Mesh[]} meshes - Array of submesh references. + * @property {Object.} materialLayers - Map of materials layer lists. You can look up a material layer list by mesh part number or by material name. + * @property {string[]} materialNames - Array of all the material names used by the mesh parts of this model, in order (e.g. materialNames[0] is the name of the first mesh part's material). */ class ScriptableModel : public ScriptableModelBase { From 2987c90f965ff2f92eb7d847097d4c716be85731 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 7 Mar 2018 13:48:35 -0800 Subject: [PATCH 59/97] fixed syntax for ubuntu --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7fff296323..429348c593 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6677,8 +6677,8 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { // to prevent files that aren't models or texture files from being loaded into world automatically - if (filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION) || - (filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION) && + if ((filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION)) || + ((filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION)) && ((!isBlocks) && (!isZip)))) { addAssetToWorldAddEntity(filePath, mapping); } else { From a0eb7e0712373cdd87901e85f283ee56db9ad23c Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 7 Mar 2018 15:01:12 -0800 Subject: [PATCH 60/97] Don't default unknown Marketplace item types to 'Entity' --- interface/resources/qml/hifi/commerce/checkout/Checkout.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 372fb3c774..96ffa390bf 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -147,8 +147,7 @@ Rectangle { } else if (root.itemHref.indexOf('.json') > -1) { root.itemType = "entity"; // "wearable" type handled later } else { - console.log("WARNING - Item type is UNKNOWN!"); - root.itemType = "entity"; + root.itemType = "unknown"; } } From 16e39f363725fa05619a91929307a7ea26992e24 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 7 Mar 2018 15:01:12 -0800 Subject: [PATCH 61/97] Don't default unknown Marketplace item types to 'Entity' --- interface/resources/qml/hifi/commerce/checkout/Checkout.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 372fb3c774..96ffa390bf 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -147,8 +147,7 @@ Rectangle { } else if (root.itemHref.indexOf('.json') > -1) { root.itemType = "entity"; // "wearable" type handled later } else { - console.log("WARNING - Item type is UNKNOWN!"); - root.itemType = "entity"; + root.itemType = "unknown"; } } From a4854839a4c3148e91d1a103f2b5b634f581fe14 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 7 Mar 2018 17:45:10 -0800 Subject: [PATCH 62/97] Enable user selection of destination folder when creating a test. --- tools/auto-tester/src/Test.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 1078ce1bc4..c14c6b9437 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -430,6 +430,11 @@ void Test::createTest() { return; } + QString imageDestinationDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder to save the test images", ".", QFileDialog::ShowDirsOnly); + if (imageDestinationDirectory == "") { + return; + } + QStringList sortedImageFilenames = createListOfAll_imagesInDirectory("jpg", imageSourceDirectory); int i = 1; @@ -442,7 +447,6 @@ void Test::createTest() { exit(-1); } QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".png"; - QString imageDestinationDirectory = getExpectedImageDestinationDirectory(currentFilename); QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; try { From 9681f0eb779278c7170ccbb6647cef940cbdff56 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 7 Mar 2018 18:20:26 -0800 Subject: [PATCH 63/97] restore old scale math, disable avatar collisions while scaling --- .../system/libraries/entitySelectionTool.js | 64 +++++++++++++------ 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 54254f6548..53769650e2 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -272,17 +272,19 @@ SelectionDisplay = (function() { var STRETCH_SPHERE_OFFSET = 0.06; var STRETCH_SPHERE_CAMERA_DISTANCE_MULTIPLE = 0.01; var STRETCH_MINIMUM_DIMENSION = 0.001; - var STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE = 2; + var STRETCH_ALL_MINIMUM_DIMENSION = 0.01; + var STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE = 6; var STRETCH_PANEL_WIDTH = 0.01; var SCALE_CUBE_OFFSET = 0.5; var SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE = 0.015; - var SCALE_MINIMUM_DIMENSION = 0.02; var CLONER_OFFSET = { x:0.9, y:-0.9, z:0.9 }; var CTRL_KEY_CODE = 16777249; + var AVATAR_COLLISIONS_OPTION = "Enable Avatar Collisions"; + var TRANSLATE_DIRECTION = { X : 0, Y : 1, @@ -336,6 +338,8 @@ SelectionDisplay = (function() { var ctrlPressed = false; + var handleStretchCollisionOverride = false; + var handlePropertiesTranslateArrowCones = { shape: "Cone", solid: true, @@ -597,6 +601,11 @@ SelectionDisplay = (function() { var activeTool = null; var handleTools = {}; + that.shutdown = function() { + that.restoreAvatarCollisionsFromStretch(); + } + Script.scriptEnding.connect(that.shutdown); + // We get mouseMoveEvents from the handControllers, via handControllerPointer. // But we dont' get mousePressEvents. that.triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); @@ -1740,6 +1749,13 @@ SelectionDisplay = (function() { }; }; + that.restoreAvatarCollisionsFromStretch = function() { + if (handleStretchCollisionOverride) { + Menu.setIsOptionChecked(AVATAR_COLLISIONS_OPTION, true); + handleStretchCollisionOverride = false; + } + } + // TOOL DEFINITION: HANDLE STRETCH TOOL function makeStretchTool(stretchMode, directionEnum, directionVec, pivot, offset, stretchPanel, scaleHandle) { var directionFor3DStretch = directionVec; @@ -1942,6 +1958,10 @@ SelectionDisplay = (function() { if (scaleHandle != null) { Overlays.editOverlay(scaleHandle, { color: COLOR_SCALE_CUBE_SELECTED }); } + if (Menu.isOptionChecked(AVATAR_COLLISIONS_OPTION)) { + Menu.setIsOptionChecked(AVATAR_COLLISIONS_OPTION, false); + handleStretchCollisionOverride = true; + } }; var onEnd = function(event, reason) { @@ -1951,6 +1971,7 @@ SelectionDisplay = (function() { if (scaleHandle != null) { Overlays.editOverlay(scaleHandle, { color: COLOR_SCALE_CUBE }); } + that.restoreAvatarCollisionsFromStretch(); pushCommandForSelections(); }; @@ -2000,6 +2021,12 @@ SelectionDisplay = (function() { vector = grid.snapToSpacing(vector); var changeInDimensions = Vec3.multiply(NEGATE_VECTOR, vec3Mult(localSigns, vector)); + if (directionEnum === STRETCH_DIRECTION.ALL) { + var toCameraDistance = getDistanceToCamera(position); + var dimensionsMultiple = toCameraDistance * STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE; + changeInDimensions = Vec3.multiply(changeInDimensions, dimensionsMultiple); + } + var newDimensions; if (proportional) { var absoluteX = Math.abs(changeInDimensions.x); @@ -2022,9 +2049,11 @@ SelectionDisplay = (function() { newDimensions = Vec3.sum(initialDimensions, changeInDimensions); } - newDimensions.x = Math.max(newDimensions.x, STRETCH_MINIMUM_DIMENSION); - newDimensions.y = Math.max(newDimensions.y, STRETCH_MINIMUM_DIMENSION); - newDimensions.z = Math.max(newDimensions.z, STRETCH_MINIMUM_DIMENSION); + var minimumDimension = directionEnum === STRETCH_DIRECTION.ALL ? STRETCH_ALL_MINIMUM_DIMENSION : + STRETCH_MINIMUM_DIMENSION; + newDimensions.x = Math.max(newDimensions.x, minimumDimension); + newDimensions.y = Math.max(newDimensions.y, minimumDimension); + newDimensions.z = Math.max(newDimensions.z, minimumDimension); var changeInPosition = Vec3.multiplyQbyV(rotation, vec3Mult(localDeltaPivot, changeInDimensions)); if (directionEnum === STRETCH_DIRECTION.ALL) { @@ -2081,38 +2110,31 @@ SelectionDisplay = (function() { function addHandleScaleTool(overlay, mode, directionEnum) { var directionVector, offset, selectedHandle; if (directionEnum === SCALE_DIRECTION.LBN) { - directionVector = { x:1, y:0, z:1 }; - offset = { x:-1, y:-1, z:-1 }; + directionVector = { x:1, y:1, z:1 }; selectedHandle = handleScaleLBNCube; } else if (directionEnum === SCALE_DIRECTION.RBN) { - directionVector = { x:-1, y:0, z:1 }; - offset = { x:1, y:-1, z:-1 }; + directionVector = { x:-1, y:1, z:1 }; selectedHandle = handleScaleRBNCube; } else if (directionEnum === SCALE_DIRECTION.LBF) { - directionVector = { x:1, y:0, z:-1 }; - offset = { x:-1, y:-1, z:1 }; + directionVector = { x:1, y:1, z:-1 }; selectedHandle = handleScaleLBFCube; } else if (directionEnum === SCALE_DIRECTION.RBF) { - directionVector = { x:-1, y:0, z:-1 }; - offset = { x:1, y:-1, z:1 }; + directionVector = { x:-1, y:1, z:-1 }; selectedHandle = handleScaleRBFCube; } else if (directionEnum === SCALE_DIRECTION.LTN) { - directionVector = { x:1, y:0, z:1 }; - offset = { x:-1, y:1, z:-1 }; + directionVector = { x:1, y:-1, z:1 }; selectedHandle = handleScaleLTNCube; } else if (directionEnum === SCALE_DIRECTION.RTN) { - directionVector = { x:-1, y:0, z:1 }; - offset = { x:1, y:1, z:-1 }; + directionVector = { x:-1, y:-1, z:1 }; selectedHandle = handleScaleRTNCube; } else if (directionEnum === SCALE_DIRECTION.LTF) { - directionVector = { x:1, y:0, z:-1 }; - offset = { x:-1, y:1, z:1 }; + directionVector = { x:1, y:-1, z:-1 }; selectedHandle = handleScaleLTFCube; } else if (directionEnum === SCALE_DIRECTION.RTF) { - directionVector = { x:-1, y:0, z:-1 }; - offset = { x:1, y:1, z:1 }; + directionVector = { x:-1, y:-1, z:-1 }; selectedHandle = handleScaleRTFCube; } + offset = Vec3.multiply(directionVector, NEGATE_VECTOR); var tool = makeStretchTool(mode, STRETCH_DIRECTION.ALL, directionVector, directionVector, offset, null, selectedHandle); return addHandleTool(overlay, tool); From 554c37d14b5c1b25669eff2c9e9568d0e554b39f Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 7 Mar 2018 19:34:08 -0800 Subject: [PATCH 64/97] removed undefined event checks in scaling --- scripts/system/libraries/entitySelectionTool.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 53769650e2..fced5fc4e9 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1976,10 +1976,6 @@ SelectionDisplay = (function() { }; var onMove = function(event) { - if (event.x === undefined || event.y === undefined) { - return; - } - var proportional = (spaceMode === SPACE_WORLD) || directionEnum === STRETCH_DIRECTION.ALL; var position, dimensions, rotation; From d0cc64f63d07104ee40737e83a86424d86f6f8c0 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Mar 2018 11:19:49 -0800 Subject: [PATCH 65/97] Fix font loading for MacOS via different font loading method --- interface/resources/qml/CurrentAPI.qml | 2 -- interface/resources/qml/controls-uit/CheckBoxQQC2.qml | 4 ++-- interface/resources/qml/controls-uit/Keyboard.qml | 9 +++------ interface/resources/qml/controls-uit/SpinBox.qml | 3 +-- interface/resources/qml/controls-uit/TextEdit.qml | 6 +++--- interface/resources/qml/controls-uit/TextField.qml | 4 +--- interface/resources/qml/controls/FontAwesome.qml | 3 +-- interface/resources/qml/dialogs/FileDialog.qml | 5 +---- interface/resources/qml/dialogs/TabletFileDialog.qml | 5 +---- .../qml/dialogs/assetDialog/AssetDialogContent.qml | 5 +---- interface/resources/qml/hifi/AssetServer.qml | 3 +-- interface/resources/qml/hifi/ComboDialog.qml | 2 -- interface/resources/qml/hifi/DesktopLetterboxMessage.qml | 7 +++---- interface/resources/qml/hifi/LetterboxMessage.qml | 7 +++---- interface/resources/qml/hifi/NameCard.qml | 3 +-- interface/resources/qml/hifi/Pal.qml | 3 +-- .../hifi/commerce/common/EmulatedMarketplaceHeader.qml | 3 +-- .../qml/hifi/commerce/wallet/sendMoney/SendMoney.qml | 5 ++--- .../resources/qml/hifi/dialogs/TabletAssetServer.qml | 3 +-- .../qml/hifi/tablet/tabletWindows/TabletFileDialog.qml | 5 +---- .../resources/qml/styles-uit/AnonymousProRegular.qml | 3 +-- interface/resources/qml/styles-uit/FiraSansRegular.qml | 3 +-- interface/resources/qml/styles-uit/FiraSansSemiBold.qml | 3 +-- interface/resources/qml/styles-uit/HiFiGlyphs.qml | 3 +-- interface/resources/qml/styles-uit/RalewayBold.qml | 5 ++--- interface/resources/qml/styles-uit/RalewayLight.qml | 3 +-- interface/resources/qml/styles-uit/RalewayRegular.qml | 3 +-- interface/resources/qml/styles-uit/RalewaySemiBold.qml | 4 ++-- interface/src/Application.cpp | 9 +++++++++ 29 files changed, 47 insertions(+), 76 deletions(-) diff --git a/interface/resources/qml/CurrentAPI.qml b/interface/resources/qml/CurrentAPI.qml index d9255e51eb..96bfb5c36b 100644 --- a/interface/resources/qml/CurrentAPI.qml +++ b/interface/resources/qml/CurrentAPI.qml @@ -33,8 +33,6 @@ Item { width: parent.width height: parent.height } - - FontLoader { id: ralewayRegular; source: "qrc:/fonts/Raleway-Regular.ttf"; } Timer { id: updateList diff --git a/interface/resources/qml/controls-uit/CheckBoxQQC2.qml b/interface/resources/qml/controls-uit/CheckBoxQQC2.qml index 040cd8e505..8a9686ff5e 100644 --- a/interface/resources/qml/controls-uit/CheckBoxQQC2.qml +++ b/interface/resources/qml/controls-uit/CheckBoxQQC2.qml @@ -109,9 +109,9 @@ CheckBox { contentItem: Text { id: root - FontLoader { id: ralewaySemiBold; source: "qrc:/fonts/Raleway-SemiBold.ttf"; } font.pixelSize: hifi.fontSizes.inputLabel - font.family: ralewaySemiBold.name + font.family: "Raleway" + font.weight: Font.DemiBold text: checkBox.text color: checkBox.color x: 2 diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml index 0c86754734..ea76d44aaa 100644 --- a/interface/resources/qml/controls-uit/Keyboard.qml +++ b/interface/resources/qml/controls-uit/Keyboard.qml @@ -125,8 +125,7 @@ Rectangle { TextInput { id: mirrorText visible: showMirrorText - FontLoader { id: font; source: "qrc:/fonts/FiraSans-Regular.ttf"; } - font.family: font.name + font.family: "Fira Sans" font.pixelSize: 20 verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter @@ -165,8 +164,6 @@ Rectangle { anchors.bottom: parent.bottom anchors.bottomMargin: 0 - FontLoader { id: hiFiGlyphs; source: "qrc:/fonts/hifi-glyphs.ttf"; } - Column { id: columnAlpha width: keyboardWidth @@ -250,7 +247,7 @@ Rectangle { Key { width: 43; glyph: ","; } Key { width: 43; glyph: "."; } Key { - fontFamily: hiFiGlyphs.name; + fontFamily: "hifi-glyphs"; fontPixelSize: 48; letterAnchors.topMargin: -4; verticalAlignment: Text.AlignVCenter; @@ -343,7 +340,7 @@ Rectangle { Key { width: 43; glyph: ","; } Key { width: 43; glyph: "."; } Key { - fontFamily: hiFiGlyphs.name; + fontFamily: "hifi-glyphs"; fontPixelSize: 48; letterAnchors.topMargin: -4; verticalAlignment: Text.AlignVCenter; diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml index f2a7e0efe8..30f6682d5a 100644 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -25,8 +25,7 @@ SpinBox { property color colorLabelInside: hifi.colors.white property real controlHeight: height + (spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0) - FontLoader { id: firaSansSemiBold; source: "qrc:/fonts/FiraSans-SemiBold.ttf"; } - font.family: firaSansSemiBold.name + font.family: "Fira Sans SemiBold" font.pixelSize: hifi.fontSizes.textFieldInput height: hifi.fontSizes.textFieldInput + 13 // Match height of TextField control. diff --git a/interface/resources/qml/controls-uit/TextEdit.qml b/interface/resources/qml/controls-uit/TextEdit.qml index 34eff7586a..0fe03150f4 100644 --- a/interface/resources/qml/controls-uit/TextEdit.qml +++ b/interface/resources/qml/controls-uit/TextEdit.qml @@ -16,9 +16,9 @@ import "../styles-uit" TextEdit { property real size: 32 - - FontLoader { id: ralewaySemiBold; source: "qrc:/fonts/Raleway-SemiBold.ttf"; } - font.family: ralewaySemiBold.name + + font.family: "Raleway" + font.weight: Font.DemiBold font.pointSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index ee646b2575..782ab454b5 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -34,9 +34,7 @@ TextField { placeholderText: textField.placeholderText - FontLoader { id: firaSansRegular; source: "qrc:/fonts/FiraSans-Regular.ttf"; } - FontLoader { id: hifiGlyphs; source: "qrc:/fonts/hifi-glyphs.ttf"; } - font.family: firaSansRegular.name + font.family: "Fira Sans" font.pixelSize: hifi.fontSizes.textFieldInput height: implicitHeight + 3 // Make surrounding box higher so that highlight is vertically centered. property alias textFieldLabel: textFieldLabel diff --git a/interface/resources/qml/controls/FontAwesome.qml b/interface/resources/qml/controls/FontAwesome.qml index 7eda46e17e..2c897b6347 100644 --- a/interface/resources/qml/controls/FontAwesome.qml +++ b/interface/resources/qml/controls/FontAwesome.qml @@ -4,13 +4,12 @@ import QtQuick.Controls.Styles 1.3 Text { id: root - FontLoader { id: iconFont; source: "qrc:/fonts/fontawesome-webfont.ttf"; } property int size: 32 width: size height: size font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: iconFont.name + font.family: "FontAwesome" } diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index c078ace264..572e7a7918 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -532,9 +532,6 @@ ModalWindow { itemDelegate: Item { clip: true - FontLoader { id: firaSansSemiBold; source: "qrc:/fonts/FiraSans-SemiBold.ttf"; } - FontLoader { id: firaSansRegular; source: "qrc:/fonts/FiraSans-Regular.ttf"; } - FiraSansSemiBold { text: getText(); elide: styleData.elideMode @@ -548,7 +545,7 @@ ModalWindow { size: hifi.fontSizes.tableText color: hifi.colors.baseGrayHighlight font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir) - ? firaSansSemiBold.name : firaSansRegular.name + ? "Fira Sans SemiBold" : "Fira Sans" function getText() { if (styleData.row === -1) { diff --git a/interface/resources/qml/dialogs/TabletFileDialog.qml b/interface/resources/qml/dialogs/TabletFileDialog.qml index 776f47d19d..c635095ac6 100644 --- a/interface/resources/qml/dialogs/TabletFileDialog.qml +++ b/interface/resources/qml/dialogs/TabletFileDialog.qml @@ -496,9 +496,6 @@ TabletModalWindow { itemDelegate: Item { clip: true - //FontLoader { id: firaSansSemiBold; source: "qrc:/fonts/FiraSans-SemiBold.ttf"; } - //FontLoader { id: firaSansRegular; source: "qrc:/fonts/FiraSans-Regular.ttf"; } - FiraSansSemiBold { text: getText(); elide: styleData.elideMode @@ -512,7 +509,7 @@ TabletModalWindow { size: hifi.fontSizes.tableText color: hifi.colors.baseGrayHighlight //font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir) - //? firaSansSemiBold.name : firaSansRegular.name + //? "Fira Sans SemiBold" : "Fira Sans" function getText() { if (styleData.row === -1) { diff --git a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml index dabc66c502..84f4c694ff 100644 --- a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml +++ b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml @@ -345,9 +345,6 @@ Item { itemDelegate: Item { clip: true - FontLoader { id: firaSansSemiBold; source: "qrc:/fonts/FiraSans-SemiBold.ttf"; } - FontLoader { id: firaSansRegular; source: "qrc:/fonts/FiraSans-Regular.ttf"; } - FiraSansSemiBold { text: styleData.value elide: styleData.elideMode @@ -361,7 +358,7 @@ Item { size: hifi.fontSizes.tableText color: hifi.colors.baseGrayHighlight font.family: (styleData.row !== -1 && assetTableView.model.get(styleData.row).fileIsDir) - ? firaSansSemiBold.name : firaSansRegular.name + ? "Fira Sans SemiBold" : "Fira Sans" } } diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 19a559b66c..34be11d4df 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -660,8 +660,7 @@ Windows.ScrollingWindow { text: styleData.value - FontLoader { id: firaSansSemiBold; source: "qrc:/fonts/FiraSans-SemiBold.ttf"; } - font.family: firaSansSemiBold.name + font.family: "Fira Sans SemiBold" font.pixelSize: hifi.fontSizes.textFieldInput height: hifi.dimensions.tableRowHeight diff --git a/interface/resources/qml/hifi/ComboDialog.qml b/interface/resources/qml/hifi/ComboDialog.qml index 0b1a3b1a5c..06254bb7fb 100644 --- a/interface/resources/qml/hifi/ComboDialog.qml +++ b/interface/resources/qml/hifi/ComboDialog.qml @@ -25,8 +25,6 @@ Item { property int dialogHeight; property int comboOptionTextSize: 16; property int comboBodyTextSize: 16; - FontLoader { id: ralewayRegular; source: "qrc:/fonts/Raleway-Regular.ttf"; } - FontLoader { id: ralewaySemiBold; source: "qrc:/fonts/Raleway-SemiBold.ttf"; } visible: false; id: combo; anchors.fill: parent; diff --git a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml index 9230bbe962..ede8590bfb 100644 --- a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml +++ b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml @@ -24,8 +24,6 @@ Item { property real headerTextMargin: -5 property real headerGlyphMargin: -15 property bool isDesktop: false - FontLoader { id: ralewayRegular; source: "qrc:/fonts/Raleway-Regular.ttf"; } - FontLoader { id: ralewaySemiBold; source: "qrc:/fonts/Raleway-SemiBold.ttf"; } visible: false id: letterbox anchors.fill: parent @@ -78,7 +76,8 @@ Item { // Text Size font.pixelSize: headerTextPixelSize // Style - font.family: ralewaySemiBold.name + font.family: "Raleway" + font.weight: Font.DemiBold color: hifi.colors.darkGray horizontalAlignment: Text.AlignHLeft verticalAlignment: Text.AlignVCenter @@ -101,7 +100,7 @@ Item { horizontalAlignment: Text.AlignHLeft // Style font.pixelSize: popupTextPixelSize - font.family: ralewayRegular.name + font.family: "Raleway" color: hifi.colors.darkGray wrapMode: Text.WordWrap textFormat: Text.StyledText diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index dcd0d906db..0e9ce89ddb 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -23,8 +23,6 @@ Item { property real popupTextPixelSize: 16 property real headerTextMargin: -5 property real headerGlyphMargin: -15 - FontLoader { id: ralewayRegular; source: "qrc:/fonts/Raleway-Regular.ttf"; } - FontLoader { id: ralewaySemiBold; source: "qrc:/fonts/Raleway-SemiBold.ttf"; } visible: false id: letterbox anchors.fill: parent @@ -82,7 +80,8 @@ Item { // Text Size font.pixelSize: headerTextPixelSize // Style - font.family: ralewaySemiBold.name + font.family: "Raleway" + font.weight: Font.DemiBold color: hifi.colors.darkGray horizontalAlignment: Text.AlignHLeft verticalAlignment: Text.AlignVCenter @@ -127,7 +126,7 @@ Item { horizontalAlignment: Text.AlignHLeft // Style font.pixelSize: popupTextPixelSize - font.family: ralewayRegular.name + font.family: "Raleway" color: hifi.colors.darkGray wrapMode: Text.WordWrap textFormat: Text.StyledText diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 4c9c746488..c97a802f10 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -177,8 +177,7 @@ Item { anchors.right: parent.right anchors.rightMargin: editGlyph.width + editGlyph.anchors.rightMargin // Style - FontLoader { id: firaSansSemiBold; source: "qrc:/fonts/FiraSans-SemiBold.ttf"; } - font.family: firaSansSemiBold.name + font.family: "Fira Sans SemiBold" font.pixelSize: displayNameTextPixelSize selectionColor: hifi.colors.blueAccent selectedTextColor: "black" diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 699173aaeb..d779b4ba42 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -908,7 +908,6 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter; } - FontLoader { id: ralewayRegular; source: "qrc:/fonts/Raleway-Regular.ttf"; } Text { id: connectionHelpText; // Anchors @@ -923,7 +922,7 @@ Rectangle { horizontalAlignment: Text.AlignHLeft // Style font.pixelSize: 18; - font.family: ralewayRegular.name + font.family: "Raleway" color: hifi.colors.darkGray wrapMode: Text.WordWrap textFormat: Text.StyledText; diff --git a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml index 8eb03c1254..8a7e809b3d 100644 --- a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml +++ b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml @@ -141,10 +141,9 @@ Item { } } - FontLoader { id: ralewayRegular; source: "qrc:/fonts/Raleway-Regular.ttf"; } TextMetrics { id: textMetrics; - font.family: ralewayRegular.name + font.family: "Raleway" text: usernameText.text; } diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml index 07c85a7f6a..d0aa89923f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml @@ -924,14 +924,13 @@ Item { anchors.right: parent.right; anchors.rightMargin: 20; height: 95; - - FontLoader { id: firaSansSemiBold; source: "qrc:/fonts/FiraSans-SemiBold.ttf"; } + TextArea { id: optionalMessage; property int maximumLength: 72; property string previousText: text; placeholderText: "Optional Public Message (" + maximumLength + " character limit)"; - font.family: firaSansSemiBold.name; + font.family: "Fira Sans SemiBold"; font.pixelSize: 20; // Anchors anchors.fill: parent; diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index 0f70b44477..a85e5d4498 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -659,8 +659,7 @@ Rectangle { text: styleData.value - FontLoader { id: firaSansSemiBold; source: "qrc:/fonts/FiraSans-SemiBold.ttf"; } - font.family: firaSansSemiBold.name + font.family: "Fira Sans SemiBold" font.pixelSize: hifi.fontSizes.textFieldInput height: hifi.dimensions.tableRowHeight diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml index ead63537f0..08b0104fce 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml @@ -478,9 +478,6 @@ Rectangle { itemDelegate: Item { clip: true - //FontLoader { id: firaSansSemiBold; source: "qrc:/fonts/FiraSans-SemiBold.ttf"; } - //FontLoader { id: firaSansRegular; source: "qrc:/fonts/FiraSans-Regular.ttf"; } - FiraSansSemiBold { text: getText(); elide: styleData.elideMode @@ -494,7 +491,7 @@ Rectangle { size: hifi.fontSizes.tableText color: hifi.colors.baseGrayHighlight //font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir) - //? firaSansSemiBold.name : firaSansRegular.name + //? "Fira Sans SemiBold" : "Fira Sans" function getText() { if (styleData.row === -1) { diff --git a/interface/resources/qml/styles-uit/AnonymousProRegular.qml b/interface/resources/qml/styles-uit/AnonymousProRegular.qml index c832910ec2..d7e13423b6 100644 --- a/interface/resources/qml/styles-uit/AnonymousProRegular.qml +++ b/interface/resources/qml/styles-uit/AnonymousProRegular.qml @@ -14,10 +14,9 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: anonymousProRegular; source: "qrc:/fonts/AnonymousPro-Regular.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: anonymousProRegular.name + font.family: "Anonymous Pro" } diff --git a/interface/resources/qml/styles-uit/FiraSansRegular.qml b/interface/resources/qml/styles-uit/FiraSansRegular.qml index 6d73210120..1166fa5cba 100644 --- a/interface/resources/qml/styles-uit/FiraSansRegular.qml +++ b/interface/resources/qml/styles-uit/FiraSansRegular.qml @@ -14,10 +14,9 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: firaSansRegular; source: "qrc:/fonts/FiraSans-Regular.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: firaSansRegular.name + font.family: "Fira Sans" } diff --git a/interface/resources/qml/styles-uit/FiraSansSemiBold.qml b/interface/resources/qml/styles-uit/FiraSansSemiBold.qml index 2bfd319d49..2f095c57a6 100644 --- a/interface/resources/qml/styles-uit/FiraSansSemiBold.qml +++ b/interface/resources/qml/styles-uit/FiraSansSemiBold.qml @@ -14,10 +14,9 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: firaSansSemiBold; source: "qrc:/fonts/FiraSans-SemiBold.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: firaSansSemiBold.name + font.family: "Fira Sans SemiBold" } diff --git a/interface/resources/qml/styles-uit/HiFiGlyphs.qml b/interface/resources/qml/styles-uit/HiFiGlyphs.qml index baab41e166..07f0212f0c 100644 --- a/interface/resources/qml/styles-uit/HiFiGlyphs.qml +++ b/interface/resources/qml/styles-uit/HiFiGlyphs.qml @@ -12,12 +12,11 @@ import QtQuick 2.5 Text { id: root - FontLoader { id: hiFiGlyphs; source: "qrc:/fonts/hifi-glyphs.ttf"; } property int size: 32 font.pixelSize: size width: size height: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: hiFiGlyphs.name + font.family: "hifi-glyphs" } diff --git a/interface/resources/qml/styles-uit/RalewayBold.qml b/interface/resources/qml/styles-uit/RalewayBold.qml index 963d8d9ba4..5f42ecd90b 100644 --- a/interface/resources/qml/styles-uit/RalewayBold.qml +++ b/interface/resources/qml/styles-uit/RalewayBold.qml @@ -14,11 +14,10 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: ralewayBold; source: "qrc:/fonts/Raleway-Bold.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: ralewayBold.name - font.bold: true // Font seems to need this in order to display bold. + font.family: "Raleway" + font.bold: true } diff --git a/interface/resources/qml/styles-uit/RalewayLight.qml b/interface/resources/qml/styles-uit/RalewayLight.qml index 8957b70c82..e6b12fca9c 100644 --- a/interface/resources/qml/styles-uit/RalewayLight.qml +++ b/interface/resources/qml/styles-uit/RalewayLight.qml @@ -14,10 +14,9 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: ralewayLight; source: "qrc:/fonts/Raleway-Light.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: ralewayLight.name + font.family: "Raleway Light" } diff --git a/interface/resources/qml/styles-uit/RalewayRegular.qml b/interface/resources/qml/styles-uit/RalewayRegular.qml index fd2661928c..5c9b87dc8a 100644 --- a/interface/resources/qml/styles-uit/RalewayRegular.qml +++ b/interface/resources/qml/styles-uit/RalewayRegular.qml @@ -14,10 +14,9 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: ralewayRegular; source: "qrc:/fonts/Raleway-Regular.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: ralewayRegular.name + font.family: "Raleway" } diff --git a/interface/resources/qml/styles-uit/RalewaySemiBold.qml b/interface/resources/qml/styles-uit/RalewaySemiBold.qml index 7ec9ea3b34..0b25f900bc 100644 --- a/interface/resources/qml/styles-uit/RalewaySemiBold.qml +++ b/interface/resources/qml/styles-uit/RalewaySemiBold.qml @@ -14,10 +14,10 @@ import QtQuick.Controls.Styles 1.4 Text { id: root - FontLoader { id: ralewaySemiBold; source: "qrc:/fonts/Raleway-SemiBold.ttf"; } property real size: 32 font.pixelSize: size verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft - font.family: ralewaySemiBold.name + font.family: "Raleway" + font.weight: Font.DemiBold } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 719fbf4ae8..fb17138fbb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -981,6 +981,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qInstallMessageHandler(messageHandler); QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf"); + QFontDatabase::addApplicationFont(":/fonts/fontawesome-webfont.ttf"); + QFontDatabase::addApplicationFont(":/fonts/hifi-glyphs.ttf"); + QFontDatabase::addApplicationFont(":/fonts/AnonymousPro-Regular.ttf"); + QFontDatabase::addApplicationFont(":/fonts/FiraSans-Regular.ttf"); + QFontDatabase::addApplicationFont(":/fonts/FiraSans-SemiBold.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Raleway-Light.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Raleway-Regular.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Raleway-Bold.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Raleway-SemiBold.ttf"); _window->setWindowTitle("High Fidelity Interface"); Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us From d1b87b31167019342a0388849e1c85686a5d3ad4 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Mar 2018 12:14:42 -0800 Subject: [PATCH 66/97] Added missing avatar shadows. --- interface/src/avatar/MyAvatar.cpp | 12 ++++++------ interface/src/avatar/MyAvatar.h | 2 -- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b6fa3fde96..a5e24b8707 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1115,6 +1115,7 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) { void MyAvatar::setEnableMeshVisible(bool isEnabled) { _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); + _skeletonModel->setCanCastShadow(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); } void MyAvatar::setEnableInverseKinematics(bool isEnabled) { @@ -1467,6 +1468,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { int skeletonModelChangeCount = _skeletonModelChangeCount; Avatar::setSkeletonModelURL(skeletonModelURL); _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); + _skeletonModel->setCanCastShadow(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); _headBoneSet.clear(); _cauterizationNeedsUpdate = true; @@ -1848,12 +1850,6 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved); } -void MyAvatar::setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visible) { - if (model->isActive() && model->isRenderable()) { - model->setVisibleInScene(visible, scene, render::ItemKey::TAG_BITS_NONE, true); - } -} - void MyAvatar::initHeadBones() { int neckJointIndex = -1; if (_skeletonModel->isLoaded()) { @@ -2043,8 +2039,12 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { _attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) { + _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); + + _attachmentModels[i]->setCanCastShadow(shouldDrawHead, qApp->getMain3DScene(), + render::ItemKey::TAG_BITS_NONE, true); } } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fa5206e128..2615f8fa0f 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -681,8 +681,6 @@ private: // These are made private for MyAvatar so that you will use the "use" methods instead virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; - void setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visiblity); - virtual void updatePalms() override {} void lateUpdatePalms(); From a703b5a3b54dd658be2d15bf18ffe6e66165448e Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Mar 2018 12:15:26 -0800 Subject: [PATCH 67/97] Added check to correct crashing when selecting ambient occlusion from menu. --- libraries/render-utils/src/DeferredLightingEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 665e767c7c..78bc3ba195 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -492,7 +492,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, deferredFramebuffer->getPrimaryDepthTexture()); // FIXME: Different render modes should have different tasks - if (args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && deferredLightingEffect->isAmbientOcclusionEnabled()) { + if (args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && deferredLightingEffect->isAmbientOcclusionEnabled() && ambientOcclusionFramebuffer) { batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, ambientOcclusionFramebuffer->getOcclusionTexture()); } else { // need to assign the white texture if ao is off From 22f18dbf56598b3644cddd9739e8e54c59856217 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Mar 2018 13:12:13 -0800 Subject: [PATCH 68/97] Don't hit certain Commerce backend endpoints when wallet isn't yet auth'd --- interface/src/commerce/Ledger.cpp | 41 ++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 712c505e8a..858af9b13d 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -80,9 +80,13 @@ void Ledger::signedSend(const QString& propertyName, const QByteArray& text, con void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail, QJsonObject& requestParams) { auto wallet = DependencyManager::get(); - requestParams["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); - - send(endpoint, success, fail, QNetworkAccessManager::PostOperation, AccountManagerAuth::Required, requestParams); + QStringList cachedPublicKeys = wallet->listPublicKeys(); + if (!cachedPublicKeys.isEmpty()) { + requestParams["public_keys"] = QJsonArray::fromStringList(cachedPublicKeys); + send(endpoint, success, fail, QNetworkAccessManager::PostOperation, AccountManagerAuth::Required, requestParams); + } else { + qDebug(commerce) << "User attempted to call keysQuery, but cachedPublicKeys was empty!"; + } } void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail) { @@ -296,14 +300,18 @@ void Ledger::updateLocation(const QString& asset_id, const QString location, con emit walletScriptingInterface->walletNotSetup(); qDebug(commerce) << "User attempted to update the location of a certificate, but their wallet wasn't ready. Status:" << walletStatus; } else { - QStringList keys = wallet->listPublicKeys(); - QString key = keys[0]; - QJsonObject transaction; - transaction["certificate_id"] = asset_id; - transaction["place_name"] = location; - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - signedSend("transaction", transactionString, key, "location", "updateLocationSuccess", "updateLocationFailure", controlledFailure); + QStringList cachedPublicKeys = wallet->listPublicKeys(); + if (!cachedPublicKeys.isEmpty()) { + QString key = cachedPublicKeys[0]; + QJsonObject transaction; + transaction["certificate_id"] = asset_id; + transaction["place_name"] = location; + QJsonDocument transactionDoc{ transaction }; + auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); + signedSend("transaction", transactionString, key, "location", "updateLocationSuccess", "updateLocationFailure", controlledFailure); + } else { + qDebug(commerce) << "User attempted to update the location of a certificate, but cachedPublicKeys was empty!"; + } } } @@ -359,7 +367,12 @@ void Ledger::alreadyOwned(const QString& marketplaceId) { auto wallet = DependencyManager::get(); QString endpoint = "already_owned"; QJsonObject request; - request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); - request["marketplace_item_id"] = marketplaceId; - send(endpoint, "alreadyOwnedSuccess", "alreadyOwnedFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request); + QStringList cachedPublicKeys = wallet->listPublicKeys(); + if (!cachedPublicKeys.isEmpty()) { + request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); + request["marketplace_item_id"] = marketplaceId; + send(endpoint, "alreadyOwnedSuccess", "alreadyOwnedFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request); + } else { + qDebug(commerce) << "User attempted to use the alreadyOwned endpoint, but cachedPublicKeys was empty!"; + } } From b273d78729d7f6922a8e87d85ccdb262fc66cbcd Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Mar 2018 13:12:13 -0800 Subject: [PATCH 69/97] Don't hit certain Commerce backend endpoints when wallet isn't yet auth'd --- interface/src/commerce/Ledger.cpp | 41 ++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 712c505e8a..858af9b13d 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -80,9 +80,13 @@ void Ledger::signedSend(const QString& propertyName, const QByteArray& text, con void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail, QJsonObject& requestParams) { auto wallet = DependencyManager::get(); - requestParams["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); - - send(endpoint, success, fail, QNetworkAccessManager::PostOperation, AccountManagerAuth::Required, requestParams); + QStringList cachedPublicKeys = wallet->listPublicKeys(); + if (!cachedPublicKeys.isEmpty()) { + requestParams["public_keys"] = QJsonArray::fromStringList(cachedPublicKeys); + send(endpoint, success, fail, QNetworkAccessManager::PostOperation, AccountManagerAuth::Required, requestParams); + } else { + qDebug(commerce) << "User attempted to call keysQuery, but cachedPublicKeys was empty!"; + } } void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail) { @@ -296,14 +300,18 @@ void Ledger::updateLocation(const QString& asset_id, const QString location, con emit walletScriptingInterface->walletNotSetup(); qDebug(commerce) << "User attempted to update the location of a certificate, but their wallet wasn't ready. Status:" << walletStatus; } else { - QStringList keys = wallet->listPublicKeys(); - QString key = keys[0]; - QJsonObject transaction; - transaction["certificate_id"] = asset_id; - transaction["place_name"] = location; - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - signedSend("transaction", transactionString, key, "location", "updateLocationSuccess", "updateLocationFailure", controlledFailure); + QStringList cachedPublicKeys = wallet->listPublicKeys(); + if (!cachedPublicKeys.isEmpty()) { + QString key = cachedPublicKeys[0]; + QJsonObject transaction; + transaction["certificate_id"] = asset_id; + transaction["place_name"] = location; + QJsonDocument transactionDoc{ transaction }; + auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); + signedSend("transaction", transactionString, key, "location", "updateLocationSuccess", "updateLocationFailure", controlledFailure); + } else { + qDebug(commerce) << "User attempted to update the location of a certificate, but cachedPublicKeys was empty!"; + } } } @@ -359,7 +367,12 @@ void Ledger::alreadyOwned(const QString& marketplaceId) { auto wallet = DependencyManager::get(); QString endpoint = "already_owned"; QJsonObject request; - request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); - request["marketplace_item_id"] = marketplaceId; - send(endpoint, "alreadyOwnedSuccess", "alreadyOwnedFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request); + QStringList cachedPublicKeys = wallet->listPublicKeys(); + if (!cachedPublicKeys.isEmpty()) { + request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); + request["marketplace_item_id"] = marketplaceId; + send(endpoint, "alreadyOwnedSuccess", "alreadyOwnedFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request); + } else { + qDebug(commerce) << "User attempted to use the alreadyOwned endpoint, but cachedPublicKeys was empty!"; + } } From 409f5293bfe7214c3bdb71e79daa3cbe480a85cd Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Mar 2018 13:51:34 -0800 Subject: [PATCH 70/97] Try this --- interface/src/Application.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fb17138fbb..cd99a91073 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -981,15 +981,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qInstallMessageHandler(messageHandler); QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf"); - QFontDatabase::addApplicationFont(":/fonts/fontawesome-webfont.ttf"); - QFontDatabase::addApplicationFont(":/fonts/hifi-glyphs.ttf"); - QFontDatabase::addApplicationFont(":/fonts/AnonymousPro-Regular.ttf"); - QFontDatabase::addApplicationFont(":/fonts/FiraSans-Regular.ttf"); - QFontDatabase::addApplicationFont(":/fonts/FiraSans-SemiBold.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Raleway-Light.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Raleway-Regular.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Raleway-Bold.ttf"); - QFontDatabase::addApplicationFont(":/fonts/Raleway-SemiBold.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/fontawesome-webfont.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/hifi-glyphs.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/AnonymousPro-Regular.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/FiraSans-Regular.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/FiraSans-SemiBold.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-Light.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-Regular.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-Bold.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-SemiBold.ttf"); _window->setWindowTitle("High Fidelity Interface"); Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us From 9d805283d14bc31d61d19abf11fd41ee1d283015 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 8 Mar 2018 14:24:44 -0800 Subject: [PATCH 71/97] clear wallet when picking a new one --- .../qml/hifi/commerce/wallet/Wallet.qml | 3 ++- interface/src/commerce/QmlCommerce.cpp | 5 ++++ interface/src/commerce/QmlCommerce.h | 1 + interface/src/commerce/Wallet.cpp | 24 +++++++++++-------- interface/src/commerce/Wallet.h | 3 ++- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index fa065bc4de..b8b34dc395 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -174,11 +174,12 @@ Rectangle { WalletChoice { id: walletChoice; proceedFunction: function (isReset) { - console.log(isReset ? "Reset wallet." : "Trying again with new wallet."); + console.log("WalletChoice", isReset ? "Reset wallet." : "Trying again with new wallet."); Commerce.setSoftReset(); if (isReset) { walletResetSetup(); } else { + Commerce.clearWallet(); var msg = { referrer: walletChoice.referrer } followReferrer(msg); } diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 557193c074..53ec59049f 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -138,6 +138,11 @@ void QmlCommerce::setSoftReset() { wallet->setSoftReset(); } +void QmlCommerce::clearWallet() { + auto wallet = DependencyManager::get(); + wallet->clear(); +} + void QmlCommerce::setPassphrase(const QString& passphrase) { auto wallet = DependencyManager::get(); wallet->setPassphrase(passphrase); diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index 6a4eaa2be2..b4af4393e3 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -67,6 +67,7 @@ protected: Q_INVOKABLE void setPassphrase(const QString& passphrase); Q_INVOKABLE void changePassphrase(const QString& oldPassphrase, const QString& newPassphrase); Q_INVOKABLE void setSoftReset(); + Q_INVOKABLE void clearWallet(); Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false); Q_INVOKABLE void balance(); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index fad82115d6..060f8de09b 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -343,19 +343,23 @@ Wallet::Wallet() { auto accountManager = DependencyManager::get(); connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() { getWalletStatus(); - _publicKeys.clear(); - - if (_securityImage) { - delete _securityImage; - } - _securityImage = nullptr; - - // tell the provider we got nothing - updateImageProvider(); - _passphrase->clear(); + clear(); }); } +void Wallet::clear() { + _publicKeys.clear(); + + if (_securityImage) { + delete _securityImage; + } + _securityImage = nullptr; + + // tell the provider we got nothing + updateImageProvider(); + _passphrase->clear(); +} + Wallet::~Wallet() { if (_securityImage) { delete _securityImage; diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index d771f404e5..8a7d6b8c07 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -49,8 +49,9 @@ public: bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); } bool walletIsAuthenticatedWithPassphrase(); bool changePassphrase(const QString& newPassphrase); - void setSoftReset() { _isOverridingServer = true; } + void setSoftReset() { _isOverridingServer = true; } bool wasSoftReset() { bool was = _isOverridingServer; _isOverridingServer = false; return was; } + void clear(); void getWalletStatus(); enum WalletStatus { From 47b08d722880ba24c94b8fd730c049d221499f13 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 8 Mar 2018 15:38:00 -0800 Subject: [PATCH 72/97] Update Hifi icon --- android/app/src/main/AndroidManifest.xml | 4 ++-- .../app/src/main/res/drawable/ic_launcher.xml | 17 +++++++++++++++++ android/app/src/main/res/drawable/icon.png | Bin 9914 -> 0 bytes .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 5195 -> 0 bytes .../main/res/mipmap-hdpi/ic_launcher_round.png | Bin 5023 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 4333 -> 0 bytes .../main/res/mipmap-mdpi/ic_launcher_round.png | Bin 4369 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 5931 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 5635 -> 0 bytes .../src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 7424 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 6905 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 9114 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 8380 -> 0 bytes 13 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 android/app/src/main/res/drawable/ic_launcher.xml delete mode 100644 android/app/src/main/res/drawable/icon.png delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5e93bdffa3..b3a8c87649 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -19,9 +19,9 @@ android:allowBackup="true" android:screenOrientation="unspecified" android:theme="@style/NoSystemUI" - android:icon="@mipmap/ic_launcher" + android:icon="@drawable/ic_launcher" android:launchMode="singleTop" - android:roundIcon="@mipmap/ic_launcher_round"> + android:roundIcon="@drawable/ic_launcher"> diff --git a/android/app/src/main/res/drawable/ic_launcher.xml b/android/app/src/main/res/drawable/ic_launcher.xml new file mode 100644 index 0000000000..03b1edc4e9 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/icon.png b/android/app/src/main/res/drawable/icon.png deleted file mode 100644 index 70aaf9b4ed60a80081821907d53086beb249eb3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9914 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 P0B~TR#op}QjIjR)wK5d} diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index d376d7af8852da4934eed5fb8b3fa718a6977d33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5195 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 FV1h;$)&2kg diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index 81a137957d489151137f4ec48490fed96ddf0373..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5023 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

FpAv>ypK&zL`d0&`aN|8w zg&BM-aN6V<;pwx&q4TQIN0n!uPRC=Ub~O;&_$jfkK1o>Hey#;x7QxW^tkV(Sf2$~k zvXWzzZQm#((M$ExvU3CDCKVW?E76KdkdbIQ5T^U#bhYEOG?Uu?8_C~)>~vb1zjfoW z&xK*G5N6;HzdI-f<#!w9qHMcFrL2i4H5MonQY%8rkXLUcaNSm*5h=F`!~98TdedOU bmA?l7BAQ7ybVso%00000NkvXXu0mjfd0HQi diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index d032c300142532c9cd1d2679277d365c20f4e964..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4369 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 N002ovPDHLkV1nK$3jhEB diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index 3cccf1037b45e43400c9648cdc9cc129d8df2e86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5635 zcmV+e7X0anP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000XvNkl&NI67{OY)wO(HaR0M$TIGrFrYYs=m;v5 z#bK01rBXp;M=6^W5DUdoWEmAiQ9*R5;Ed3FU(&rz(lkw*v?Tq{ha?V^w022u()8Zn z@A<-qa^Cm3IrrYPyyq7HejyV)*0C(Z^EXAcr*&l6`^#MwIHEc-m( zAkJnJXJd#n4RNL*&aMj8xI$ULmBd*;;_PwaY%6j0Epb*voYfI$XeAEftduy*C(iPS zvuB7iHE|Xp3-C=0aW&;w-AO3m8J2ebb2&-xLFJ_Hbtu(8JTGB23sxob~A}0{RhW--l81&wo%4 z4|M^Ph%;*#CjWfqg`$9Np5Xy>5w?52V?si}FNw2_T`2ip4iabA1Y5wR#92-kOum;d zh_l#W3HVhPPrjG0h_hZ&3+SrdPD|ZUcPRzDE+_pW-XqQ~kwU;kIoZv!G|&S25@)q? zqFdyFKnb{vIQv0P@XuoQOo#eiz;Zdct>$CTi;CX_=p+w9uktU_OPJ^{0hbbIC!|ik zn3mvINS7$J082|eMbev5@*$t3ed!& zeCDI@_f?&<8iG1fY611c*?^7+cvb4YQ`E$wJY$^S1z0vMgP@KI#0^XMe_?;il z|2l3-K!oQbLKfg(T*O&wYXm$Q%yE=3769UGb!!Cdk_7~ee9u&FvjVR4Y;2GP1a9%~ zbu9_FHP}PBVJ-l~*?lbucuW=$a5lCiV7n|J;G7`NF83wia>>X2yQY9r;!NR7K%W3_ zkdp8$pQk;Q@#W! zh_f)Y-77%cZ#2ND?pc`@aPgy{~IYpdZ)!dBO6j?yP$tBLZH76h` z=mL^sP%&$Q|Mv%MTMHp6G86=iYiUlnSCA?g{+~1jibiW;Ua|KSXVO zu#?|NoZa+u3$ymopRR?N5(hyY6$GLo4D5w7H(%;k3i@3QAvroIF^QU=wnhn_J$Ee% zm@TFypnUe@Ft2(=I##|6)8fCwm^CY~ygu9gtB^3Z$^}zFdL@XfHn(PJqC!kds4IJR zG>i+UqjKT2fMQ%Y4V4R~!kC$Xx}%>V&{zGLQ!p)=gUb0+0v?-}@>vtSyEI3%c6s_i zQJa9`@wcPoiQ)cd;s}&HJ`_b`If_PUQ9k2Q)E)U4jr9&VO_i`8{~Y%3zVa`}KZny) z0k~Xn9fPJmwZByonSwVANyZT26# z-+?uE11wus!nQ9LuIj3b?oh|c<1l7s!1TsH{E9I%1CEo&FZ%ynwKcFE$b)6eN?3C@ zxZCK*n5*A?8;0Sxg3=S0w`GGy1aVd&YGNS_>V<*lDm3)n>OjaNjfD8 z?@L1Q_}fuDZb-W*dPIl92L_{PR4UBN=AywMTo}K_ga$f|219|g&}ld;%Pwfkx#F`h zFQ1R1QK{}WkI}a~?&9&cqwv8LZ<&Ps?b#)HvzQv^Dx3Zn*beN1ZGYRS`EWa|d7EKB z{smk%D;gbkpEqFb!4FaK;$&35@|>hpyz~^TJ2&`jQ=`KUS4}nS#}31qw;45i-feUI zwgY)EE}983wGW81KeuT6)n3e!f>E_?GSHSheSwpLeYYdKskQ|MoM|7y!y#=lsE5hY+T1=?k zwibo=sUajqLQIKk%h&In9WBaA;F$ytr6^-EBdy%<&5 zOHlji2NyNgn)i--JZH_q&dth~VaZvI#`E6T8Xa}0c|XS;|GLGnY+Q=!t!v!5d1nO* z?@a=wE1aGkM}8>Sq*sk1&QSL3!zj-fhw>TYVcoT<*#|2CI8Gcz?V*oQ`}zLP&1ZXI zKXw>!xqQZXuDk?QZ!JRE)X^xPH38)_AH&%@ZUE_3^Zi}2Y_~8d0woiNqxSGVG@fgK ze0iS{W>|AKz%Z<@y9?5*PI)%G_*Foxm=ae}Hf^k&abLfL5(5k)`aw)rGN-xv0yD%2kO=)yaq&IYHs z63!}Pcww%DtET#bSk24lc_#W*LR-t&!w==_uMxHJM`*}(sQvWApBiQRl zPFP`FGy~N;)?JW%F*ydLR~ecXW0LX!hgeY?|0U^_sM(v_HTwK>4KQZS^1f~wTJy#e z=p#&eiRp?@#gsT$a#n@++m6MI@{DorK3}go-JUx?P>1;Zj&#Z$LQ)he=01(aI$PK! zzd`&FMPoSxbu@^xuZgqXp>~W_H{xumkQ9m1Nh48z=2X}u-}bNFFx=hOTX}bjr>sxN z9_03rsEIY69dbRaxf?otmt%Zw21HFPL~TNSYd^9m1dcLPQJP}Epou~0GY_G@;D^q4 z*YC}BkN+n}gY>F=&$7)r8mUX zK2Fccc|E8TA7`s1UE(?+De|0QL_e5Uzlw%JAtV!DF=rx3r-Y!10qIrmHCK4MvkCB$ zET$>m7m^}z_Rbq&%$yF#iKD@Nr+3(4+rJBC&yR7>XD3I4bjmM@vtfbG2ZDH{xsK8k za|Csiopef+P8tcz=H)&YO$Fq^T5Chyk&j_oGRHlFsfmT?zT@{2XZL!m8ium~FSn3h zIZsT9J1MB6Af_o$GI1nKOJ9WTKpqY#fiZJBN+t}2Vb~wt z{kl2|LUMGYsEt2EoNXfa*}&a{6?Z5JX!_>#2jc90(kVBJX^L;f!M#fab(B+3N4eMK z4DJmvB@SY0pYw=w|J&eL2+1)JlA<6aM?*~QQ$gv8`J`9vAkM}UXSW11>77A9Q?BrA zpXJ2a6QozoCcP??^vV^aS7wvWgI<|UdgUt8tFlP1n&T3)1^6dT$x!5ieAQK$q dBm|lN4FHon#${yAnn3^n002ovPDHLkV1m~Fh0Fi| diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index e97062e0ee222ba85204e3e6b2758c622eddd6d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7424 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 diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index f01203c738e29c6371cd4185ab10c9a817ea33d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9114 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 Tu8OV$002TsQ?W|kJmh}>;TD+- From 77901e5089b38ae91b810d23d0b4c80f1c8c89dc Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Mar 2018 20:11:35 -0800 Subject: [PATCH 73/97] Corrected MacOS warnings. --- tools/auto-tester/src/Test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index c14c6b9437..9bced3d1fc 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -329,7 +329,7 @@ void Test::createRecursiveScriptsRecursively() { QString directory = it.next(); // Only process directories - QDir dir(); + QDir dir; if (!isAValidDirectory(directory)) { continue; } @@ -341,7 +341,7 @@ void Test::createRecursiveScriptsRecursively() { QString directory2 = it2.next(); // Only process directories - QDir dir(); + QDir dir; if (isAValidDirectory(directory2)) { hasNoSubDirectories = false; break; From 81de668c1edec983420d4b1f9a6cfb5e677486ef Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 23 Feb 2018 11:20:45 -0800 Subject: [PATCH 74/97] faster per-entity raypick culling --- libraries/entities/src/EntityTreeElement.cpp | 33 +++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 9e32bc3346..1ebb07c3a2 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -643,25 +643,25 @@ EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& ori int entityNumber = 0; EntityItemID entityID; forEachEntity([&](EntityItemPointer entity) { - if ( (visibleOnly && !entity->isVisible()) || (collidableOnly && (entity->getCollisionless() || entity->getShapeType() == SHAPE_TYPE_NONE)) - || (entityIdsToInclude.size() > 0 && !entityIdsToInclude.contains(entity->getID())) - || (entityIDsToDiscard.size() > 0 && entityIDsToDiscard.contains(entity->getID())) ) { - return; - } - + // use simple line-sphere for broadphase check + // (this is faster and more likely to cull results than the filter check below so we do it first) bool success; AABox entityBox = entity->getAABox(success); if (!success) { return; } + glm::vec3 sphereCenter = entityBox.calcCenter() - origin; + float r2 = 0.25f * glm::length2(entityBox.getScale()); + float d = glm::dot(sphereCenter, direction); + if (glm::length2(sphereCenter) > r2 && (glm::abs(d) > 0.0f && glm::distance2(d * direction, sphereCenter) > r2)) { + return; + } - float localDistance; - BoxFace localFace; - glm::vec3 localSurfaceNormal; - QVariantMap localExtraInfo; - - // if the ray doesn't intersect with our cube, we can stop searching! - if (!entityBox.findRayIntersection(origin, direction, localDistance, localFace, localSurfaceNormal)) { + // check RayPick filter settings + if ((visibleOnly && !entity->isVisible()) + || (collidableOnly && (entity->getCollisionless() || entity->getShapeType() == SHAPE_TYPE_NONE)) + || (entityIdsToInclude.size() > 0 && !entityIdsToInclude.contains(entity->getID())) + || (entityIDsToDiscard.size() > 0 && entityIDsToDiscard.contains(entity->getID())) ) { return; } @@ -682,14 +682,17 @@ EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& ori // we can use the AABox's ray intersection by mapping our origin and direction into the entity frame // and testing intersection there. + float localDistance; + BoxFace localFace; + glm::vec3 localSurfaceNormal; if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace, localSurfaceNormal)) { if (entityFrameBox.contains(entityFrameOrigin) || localDistance < distance) { // now ask the entity if we actually intersect if (entity->supportsDetailedRayIntersection()) { + QVariantMap localExtraInfo; if (entity->findDetailedRayIntersection(origin, direction, keepSearching, element, localDistance, - localFace, localSurfaceNormal, localExtraInfo, precisionPicking)) { - + localFace, localSurfaceNormal, localExtraInfo, precisionPicking)) { if (localDistance < distance) { distance = localDistance; face = localFace; From 79b9fec900f5587b1de2c2686cad4e0649e054f9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 23 Feb 2018 16:08:31 -0800 Subject: [PATCH 75/97] add rayHitsSphere() util method --- libraries/shared/src/GeometryUtil.cpp | 8 ++++++++ libraries/shared/src/GeometryUtil.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index 0742a5625b..65adc28e07 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -40,6 +40,14 @@ glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec } } +bool rayHitsSphere(const glm::vec3& rayStart, const glm::vec3& rayDirection, + const glm::vec3& sphereCenter, float sphereRadiusSquared) { + glm::vec3 center = sphereCenter - rayStart; + float distance = glm::dot(center, rayDirection); + return (glm::length2(center) < sphereRadiusSquared + || (glm::abs(distance) > 0.0f && glm::distance2(distance * rayDirection, center) < sphereRadiusSquared)); +} + // Computes the penetration between a point and a sphere (centered at the origin) // if point is inside sphere: returns true and stores the result in 'penetration' // (the vector that would move the point outside the sphere) diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index 4832616fbd..bc09b71fc6 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -19,6 +19,9 @@ class Plane; glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end); +bool rayHitsSphere(const glm::vec3& rayStart, const glm::vec3& rayDirection, + const glm::vec3& sphereCenter, float sphereRadiusSquared); + /// Computes the penetration between a point and a sphere (centered at the origin) /// \param point the point location relative to sphere center (origin) /// \param defaultDirection the direction of the pentration when the point is near the origin From 6ab85d5800266635a51f23f01f829045e10ed600 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 23 Feb 2018 16:09:03 -0800 Subject: [PATCH 76/97] cleanup and a few small optimizations --- libraries/entities/src/EntityTreeElement.cpp | 40 +++++++++----------- libraries/entities/src/EntityTreeElement.h | 2 +- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 1ebb07c3a2..e6bcdc9487 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -598,13 +598,13 @@ EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, con EntityItemID result; float distanceToElementCube = std::numeric_limits::max(); - float distanceToElementDetails = distance; BoxFace localFace; glm::vec3 localSurfaceNormal; - QVariantMap localExtraInfo; - // if the ray doesn't intersect with our cube, we can stop searching! - if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace, localSurfaceNormal)) { + // if the ray doesn't intersect with our cube OR the distance to element is less than current best distance + // we can stop searching! + if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace, localSurfaceNormal) + || (!_cube.contains(origin) && distanceToElementCube > distance)) { keepSearching = false; // no point in continuing to search return result; // we did not intersect } @@ -616,20 +616,17 @@ EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, con // if the distance to the element cube is not less than the current best distance, then it's not possible // for any details inside the cube to be closer so we don't need to consider them. - if (_cube.contains(origin) || distanceToElementCube < distance) { - - EntityItemID entityID = findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, - face, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, visibleOnly, collidableOnly, - localExtraInfo, precisionPicking, distanceToElementCube); - if (!entityID.isNull()) { - if (distanceToElementDetails < distance) { - distance = distanceToElementDetails; - face = localFace; - surfaceNormal = localSurfaceNormal; - extraInfo = localExtraInfo; - result = entityID; - } - } + QVariantMap localExtraInfo; + float distanceToElementDetails = distance; + EntityItemID entityID = findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, + face, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, visibleOnly, collidableOnly, + localExtraInfo, precisionPicking); + if (!entityID.isNull() && distanceToElementDetails < distance) { + distance = distanceToElementDetails; + face = localFace; + surfaceNormal = localSurfaceNormal; + extraInfo = localExtraInfo; + result = entityID; } return result; } @@ -637,7 +634,7 @@ EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, con EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, const QVector& entityIDsToDiscard, - bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking, float distanceToElementCube) { + bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking) { // only called if we do intersect our bounding cube, but find if we actually intersect with entities... int entityNumber = 0; @@ -650,10 +647,7 @@ EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& ori if (!success) { return; } - glm::vec3 sphereCenter = entityBox.calcCenter() - origin; - float r2 = 0.25f * glm::length2(entityBox.getScale()); - float d = glm::dot(sphereCenter, direction); - if (glm::length2(sphereCenter) > r2 && (glm::abs(d) > 0.0f && glm::distance2(d * direction, sphereCenter) > r2)) { + if (!rayHitsSphere(origin, direction, entityBox.calcCenter(), 0.25f * glm::length2(entityBox.getScale()))) { return; } diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 2313bde0c4..80707fcb14 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -155,7 +155,7 @@ public: bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly, - QVariantMap& extraInfo, bool precisionPicking, float distanceToElementCube); + QVariantMap& extraInfo, bool precisionPicking); virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const override; From 2750f3ee71d350e7a9451dce9dfc9a1075dbfb5b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 23 Feb 2018 16:38:42 -0800 Subject: [PATCH 77/97] remove unused cruft and avoid useless work --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 2 +- .../entities-renderer/src/RenderableModelEntityItem.h | 2 +- .../entities-renderer/src/RenderablePolyVoxEntityItem.cpp | 2 +- .../entities-renderer/src/RenderablePolyVoxEntityItem.h | 2 +- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/EntityTreeElement.cpp | 8 +++----- libraries/entities/src/EntityTreeElement.h | 2 +- libraries/entities/src/LightEntityItem.cpp | 2 +- libraries/entities/src/LightEntityItem.h | 2 +- libraries/entities/src/LineEntityItem.h | 2 +- libraries/entities/src/PolyLineEntityItem.h | 2 +- libraries/entities/src/PolyVoxEntityItem.h | 2 +- libraries/entities/src/ShapeEntityItem.cpp | 2 +- libraries/entities/src/ShapeEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.h | 2 +- libraries/entities/src/WebEntityItem.cpp | 2 +- libraries/entities/src/WebEntityItem.h | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 2 +- libraries/entities/src/ZoneEntityItem.h | 2 +- 20 files changed, 22 insertions(+), 24 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index eb42e9af22..c4fa71a488 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -286,7 +286,7 @@ bool RenderableModelEntityItem::supportsDetailedRayIntersection() const { } bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const { auto model = getModel(); if (!model) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 5d7d84b7bc..68bc70c8a9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -68,7 +68,7 @@ public: virtual bool supportsDetailedRayIntersection() const override; virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 2b1de8d11b..0211daff1e 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -565,7 +565,7 @@ public: #endif bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 0a00d1cb73..70c87dca6f 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -53,7 +53,7 @@ public: virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d08c5514e9..0303964e18 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -159,7 +159,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return false; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const { return true; } diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index e6bcdc9487..2c51ff13f1 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -594,8 +594,6 @@ EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, con const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking) { - keepSearching = true; // assume that we will continue searching after this. - EntityItemID result; float distanceToElementCube = std::numeric_limits::max(); BoxFace localFace; @@ -618,7 +616,7 @@ EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, con // for any details inside the cube to be closer so we don't need to consider them. QVariantMap localExtraInfo; float distanceToElementDetails = distance; - EntityItemID entityID = findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, + EntityItemID entityID = findDetailedRayIntersection(origin, direction, element, distanceToElementDetails, face, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, visibleOnly, collidableOnly, localExtraInfo, precisionPicking); if (!entityID.isNull() && distanceToElementDetails < distance) { @@ -631,7 +629,7 @@ EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, con return result; } -EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, +EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, const QVector& entityIDsToDiscard, bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking) { @@ -685,7 +683,7 @@ EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& ori // now ask the entity if we actually intersect if (entity->supportsDetailedRayIntersection()) { QVariantMap localExtraInfo; - if (entity->findDetailedRayIntersection(origin, direction, keepSearching, element, localDistance, + if (entity->findDetailedRayIntersection(origin, direction, element, localDistance, localFace, localSurfaceNormal, localExtraInfo, precisionPicking)) { if (localDistance < distance) { distance = localDistance; diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 80707fcb14..b219d64d9d 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -152,7 +152,7 @@ public: const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking = false); virtual EntityItemID findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking); diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 85edefa413..3f7fc5f799 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -298,7 +298,7 @@ void LightEntityItem::resetLightPropertiesChanged() { } bool LightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const { diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index 3be1d48aa5..4d0bde3718 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -86,7 +86,7 @@ public: virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override; diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index 9f16807084..375453e0e9 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -61,7 +61,7 @@ class LineEntityItem : public EntityItem { // never have a ray intersection pick a LineEntityItem. virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override { return false; } diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 8af2b26216..2dc8befe97 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -94,7 +94,7 @@ class PolyLineEntityItem : public EntityItem { // never have a ray intersection pick a PolyLineEntityItem. virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override { return false; } diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 47d2a4b4e1..90982fe448 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -45,7 +45,7 @@ class PolyVoxEntityItem : public EntityItem { // never have a ray intersection pick a PolyVoxEntityItem. virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override { return false; } diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 2425208a87..db3d6798be 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -228,7 +228,7 @@ bool ShapeEntityItem::supportsDetailedRayIntersection() const { } bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const { // determine the ray in the frame of the entity transformed from a unit sphere diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 7ad1b3c1c2..46d696f979 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -92,7 +92,7 @@ public: bool supportsDetailedRayIntersection() const override; bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 7b1089e6ed..7030a95562 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -129,7 +129,7 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits } bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const { glm::vec3 dimensions = getScaledDimensions(); diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 3ab743ecfd..06b377ee14 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -48,7 +48,7 @@ public: virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override; diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 91e7bca063..548bca3225 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -106,7 +106,7 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst } bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const { glm::vec3 dimensions = getScaledDimensions(); diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 7d8f37cd83..dab7cd5e22 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -47,7 +47,7 @@ public: virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override; diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 6083e5b8de..4ae020f966 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -296,7 +296,7 @@ void ZoneEntityItem::setCompoundShapeURL(const QString& url) { } bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const { diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 95b6248fde..2c6b01fc69 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -105,7 +105,7 @@ public: virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override; From 7a19f48b9c36579fa68eb2fb833470e2503016a6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 1 Mar 2018 16:15:26 -0800 Subject: [PATCH 78/97] move rayHitsSphere logic to AABox method --- libraries/entities/src/EntityTreeElement.cpp | 2 +- libraries/shared/src/AABox.cpp | 9 +++++++++ libraries/shared/src/AABox.h | 1 + libraries/shared/src/GeometryUtil.cpp | 8 -------- libraries/shared/src/GeometryUtil.h | 3 --- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 2c51ff13f1..654d4b4ecc 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -645,7 +645,7 @@ EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& ori if (!success) { return; } - if (!rayHitsSphere(origin, direction, entityBox.calcCenter(), 0.25f * glm::length2(entityBox.getScale()))) { + if (!entityBox.rayHitsBoundingSphere(origin, direction)) { return; } diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index cea0a83d52..cbf3c1b785 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -287,6 +287,15 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct return false; } +bool AABox::rayHitsBoundingSphere(const glm::vec3& origin, const glm::vec3& direction) const { + glm::vec3 localCenter = calcCenter() - origin; + float distance = glm::dot(localCenter, direction); + const float ONE_OVER_TWO_SQUARED = 0.25f; + float radiusSquared = ONE_OVER_TWO_SQUARED * glm::length2(_scale); + return (glm::length2(localCenter) < radiusSquared + || (glm::abs(distance) > 0.0f && glm::distance2(distance * direction, localCenter) < radiusSquared)); +} + bool AABox::touchesSphere(const glm::vec3& center, float radius) const { // Avro's algorithm from this paper: http://www.mrtc.mdh.se/projects/3Dgraphics/paperF.pdf glm::vec3 e = glm::max(_corner - center, Vectors::ZERO) + glm::max(center - _corner - _scale, Vectors::ZERO); diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index 24485eaad6..2d5ca242d6 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -71,6 +71,7 @@ public: bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const; bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) const; + bool rayHitsBoundingSphere(const glm::vec3& origin, const glm::vec3& direction) const; bool touchesSphere(const glm::vec3& center, float radius) const; // fast but may generate false positives bool touchesAAEllipsoid(const glm::vec3& center, const glm::vec3& radials) const; bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index 65adc28e07..0742a5625b 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -40,14 +40,6 @@ glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec } } -bool rayHitsSphere(const glm::vec3& rayStart, const glm::vec3& rayDirection, - const glm::vec3& sphereCenter, float sphereRadiusSquared) { - glm::vec3 center = sphereCenter - rayStart; - float distance = glm::dot(center, rayDirection); - return (glm::length2(center) < sphereRadiusSquared - || (glm::abs(distance) > 0.0f && glm::distance2(distance * rayDirection, center) < sphereRadiusSquared)); -} - // Computes the penetration between a point and a sphere (centered at the origin) // if point is inside sphere: returns true and stores the result in 'penetration' // (the vector that would move the point outside the sphere) diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index bc09b71fc6..4832616fbd 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -19,9 +19,6 @@ class Plane; glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end); -bool rayHitsSphere(const glm::vec3& rayStart, const glm::vec3& rayDirection, - const glm::vec3& sphereCenter, float sphereRadiusSquared); - /// Computes the penetration between a point and a sphere (centered at the origin) /// \param point the point location relative to sphere center (origin) /// \param defaultDirection the direction of the pentration when the point is near the origin From 9fbe7ec194da243c0cc48eb46e61905bb946a56d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 1 Mar 2018 22:48:55 -0800 Subject: [PATCH 79/97] time-box Picks and solve in round-robin sequence --- .../src/raypick/PickScriptingInterface.cpp | 10 +- .../src/raypick/PickScriptingInterface.h | 10 +- libraries/entities/src/EntityItem.cpp | 2 +- libraries/pointers/src/PickCacheOptimizer.h | 125 ++++++++++-------- libraries/pointers/src/PickManager.cpp | 9 +- libraries/pointers/src/PickManager.h | 11 +- 6 files changed, 107 insertions(+), 60 deletions(-) diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 43e0c059f0..1bf6dd2f8e 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -174,4 +174,12 @@ void PickScriptingInterface::registerMetaTypes(QScriptEngine* engine) { engine->globalObject().setProperty("PickType", pickTypes); qScriptRegisterMetaType(engine, pickTypesToScriptValue, pickTypesFromScriptValue); -} \ No newline at end of file +} + +unsigned int PickScriptingInterface::getPerFrameTimeBudget() const { + return DependencyManager::get()->getPerFrameTimeBudget(); +} + +void PickScriptingInterface::setPerFrameTimeBudget(unsigned int numUsecs) { + DependencyManager::get()->setPerFrameTimeBudget(numUsecs); +} diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index 98427e34ca..288d3008bb 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -185,6 +185,14 @@ public: */ Q_INVOKABLE bool isMouse(unsigned int uid); + Q_PROPERTY(unsigned int perFrameTimeBudget READ getPerFrameTimeBudget WRITE setPerFrameTimeBudget) + /**jsdoc + * The max number of usec to spend per frame updating Pick results. + * @typedef {number} Picks.perFrameTimeBudget + */ + unsigned int getPerFrameTimeBudget() const; + void setPerFrameTimeBudget(unsigned int numUsecs); + public slots: static constexpr unsigned int PICK_NOTHING() { return 0; } static constexpr unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); } @@ -202,4 +210,4 @@ public slots: static constexpr unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } }; -#endif // hifi_PickScriptingInterface_h \ No newline at end of file +#endif // hifi_PickScriptingInterface_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f77d8a59c3..c01ebe8ca4 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2984,4 +2984,4 @@ std::unordered_map EntityItem::getMaterial toReturn = _materials; } return toReturn; -} \ No newline at end of file +} diff --git a/libraries/pointers/src/PickCacheOptimizer.h b/libraries/pointers/src/PickCacheOptimizer.h index 10c9d6cf84..e930f8c663 100644 --- a/libraries/pointers/src/PickCacheOptimizer.h +++ b/libraries/pointers/src/PickCacheOptimizer.h @@ -37,7 +37,7 @@ template class PickCacheOptimizer { public: - void update(std::unordered_map>& picks, bool shouldPickHUD); + void update(std::unordered_map>& picks, uint32_t& nextToUpdate, uint64_t expiry, bool shouldPickHUD); protected: typedef std::unordered_map> PickCache; @@ -67,66 +67,85 @@ void PickCacheOptimizer::cacheResult(const bool intersects, const PickResultP } template -void PickCacheOptimizer::update(std::unordered_map>& picks, bool shouldPickHUD) { +void PickCacheOptimizer::update(std::unordered_map>& picks, + uint32_t& nextToUpdate, uint64_t expiry, bool shouldPickHUD) { PickCache results; - for (const auto& pickPair : picks) { - std::shared_ptr> pick = std::static_pointer_cast>(pickPair.second); - + const uint32_t INVALID_PICK_ID = 0; + std::unordered_map>::iterator itr = picks.begin(); + if (nextToUpdate != INVALID_PICK_ID) { + itr = picks.find(nextToUpdate); + if (itr == picks.end()) { + itr = picks.begin(); + } + } + uint32_t numUpdates = 0; + while(numUpdates < picks.size()) { + std::shared_ptr> pick = std::static_pointer_cast>(itr->second); T mathematicalPick = pick->getMathematicalPick(); PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap()); if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f || !mathematicalPick) { pick->setPickResult(res); - continue; - } - - if (pick->getFilter().doesPickEntities()) { - PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { - PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick); - if (entityRes) { - cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick); - } - } - } - - if (pick->getFilter().doesPickOverlays()) { - PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) { - PickResultPointer overlayRes = pick->getOverlayIntersection(mathematicalPick); - if (overlayRes) { - cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick); - } - } - } - - if (pick->getFilter().doesPickAvatars()) { - PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) { - PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick); - if (avatarRes) { - cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick); - } - } - } - - // Can't intersect with HUD in desktop mode - if (pick->getFilter().doesPickHUD() && shouldPickHUD) { - PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector(), QVector() }; - if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) { - PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick); - if (hudRes) { - cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick); - } - } - } - - if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res->checkOrFilterAgainstMaxDistance(pick->getMaxDistance()))) { - pick->setPickResult(res); } else { - pick->setPickResult(pick->getDefaultResult(mathematicalPick.toVariantMap())); + if (pick->getFilter().doesPickEntities()) { + PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { + PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick); + if (entityRes) { + cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick); + } + } + } + + if (pick->getFilter().doesPickOverlays()) { + PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) { + PickResultPointer overlayRes = pick->getOverlayIntersection(mathematicalPick); + if (overlayRes) { + cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick); + } + } + } + + if (pick->getFilter().doesPickAvatars()) { + PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) { + PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick); + if (avatarRes) { + cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick); + } + } + } + + // Can't intersect with HUD in desktop mode + if (pick->getFilter().doesPickHUD() && shouldPickHUD) { + PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector(), QVector() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) { + PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick); + if (hudRes) { + cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick); + } + } + } + + if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res->checkOrFilterAgainstMaxDistance(pick->getMaxDistance()))) { + pick->setPickResult(res); + } else { + pick->setPickResult(pick->getDefaultResult(mathematicalPick.toVariantMap())); + } + } + + ++itr; + if (itr == picks.end()) { + itr = picks.begin(); + } + nextToUpdate = itr->first; + ++numUpdates; + uint64_t now = usecTimestampNow(); + if (usecTimestampNow() > expiry) { + break; } } } -#endif // hifi_PickCacheOptimizer_h \ No newline at end of file +#endif // hifi_PickCacheOptimizer_h diff --git a/libraries/pointers/src/PickManager.cpp b/libraries/pointers/src/PickManager.cpp index 92fec014da..b73b54cdb6 100644 --- a/libraries/pointers/src/PickManager.cpp +++ b/libraries/pointers/src/PickManager.cpp @@ -89,14 +89,17 @@ void PickManager::setIncludeItems(unsigned int uid, const QVector& includ } void PickManager::update() { + uint64_t expiry = usecTimestampNow() + _perFrameTimeBudget; std::unordered_map>> cachedPicks; withReadLock([&] { cachedPicks = _picks; }); bool shouldPickHUD = _shouldPickHUDOperator(); - _rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], shouldPickHUD); - _stylusPickCacheOptimizer.update(cachedPicks[PickQuery::Stylus], false); + // we pass the same expiry to both updates + // even when the rayPicks consume all the budget at least one stylus will be updated + _rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], _nextPickToUpdate[PickQuery::Ray], expiry, shouldPickHUD); + _stylusPickCacheOptimizer.update(cachedPicks[PickQuery::Stylus], _nextPickToUpdate[PickQuery::Stylus], expiry, false); } bool PickManager::isLeftHand(unsigned int uid) { @@ -121,4 +124,4 @@ bool PickManager::isMouse(unsigned int uid) { return pick->isMouse(); } return false; -} \ No newline at end of file +} diff --git a/libraries/pointers/src/PickManager.h b/libraries/pointers/src/PickManager.h index 5b069879a8..3b466be2bc 100644 --- a/libraries/pointers/src/PickManager.h +++ b/libraries/pointers/src/PickManager.h @@ -14,6 +14,8 @@ #include "Pick.h" #include "PickCacheOptimizer.h" +#include + class PickManager : public Dependency, protected ReadWriteLockable { SINGLETON_DEPENDENCY @@ -48,17 +50,24 @@ public: static const unsigned int INVALID_PICK_ID { 0 }; + unsigned int getPerFrameTimeBudget() const { return _perFrameTimeBudget; } + void setPerFrameTimeBudget(unsigned int numUsecs) { _perFrameTimeBudget = numUsecs; } + protected: std::function _shouldPickHUDOperator; std::function _calculatePos2DFromHUDOperator; std::shared_ptr findPick(unsigned int uid) const; std::unordered_map>> _picks; + unsigned int _nextPickToUpdate[PickQuery::NUM_PICK_TYPES] { 0, 0 }; std::unordered_map _typeMap; unsigned int _nextPickID { INVALID_PICK_ID + 1 }; PickCacheOptimizer _rayPickCacheOptimizer; PickCacheOptimizer _stylusPickCacheOptimizer; + + static const unsigned int DEFAULT_PER_FRAME_TIME_BUDGET = 2 * USECS_PER_MSEC; + unsigned int _perFrameTimeBudget { DEFAULT_PER_FRAME_TIME_BUDGET }; }; -#endif // hifi_PickManager_h \ No newline at end of file +#endif // hifi_PickManager_h From 7a39bd5c816edc4ce77c378e8d112df35056dd64 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 2 Mar 2018 09:29:42 -0800 Subject: [PATCH 80/97] remove tab whitespace --- libraries/shared/src/AABox.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index 2d5ca242d6..cf79cf9d04 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -71,7 +71,7 @@ public: bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const; bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) const; - bool rayHitsBoundingSphere(const glm::vec3& origin, const glm::vec3& direction) const; + bool rayHitsBoundingSphere(const glm::vec3& origin, const glm::vec3& direction) const; bool touchesSphere(const glm::vec3& center, float radius) const; // fast but may generate false positives bool touchesAAEllipsoid(const glm::vec3& center, const glm::vec3& radials) const; bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; From 24635b045110975c9d21f495a65097c920637bc7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 2 Mar 2018 14:51:18 -0800 Subject: [PATCH 81/97] remove unused debug cruft variable --- libraries/pointers/src/PickCacheOptimizer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/pointers/src/PickCacheOptimizer.h b/libraries/pointers/src/PickCacheOptimizer.h index e930f8c663..dd1fa6cecb 100644 --- a/libraries/pointers/src/PickCacheOptimizer.h +++ b/libraries/pointers/src/PickCacheOptimizer.h @@ -141,7 +141,6 @@ void PickCacheOptimizer::update(std::unordered_mapfirst; ++numUpdates; - uint64_t now = usecTimestampNow(); if (usecTimestampNow() > expiry) { break; } From f83c6000df8f90d35dad902e0a77b0f9f56a886c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 6 Mar 2018 11:06:49 -0800 Subject: [PATCH 82/97] use 'auto' for very long type --- libraries/pointers/src/PickCacheOptimizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/pointers/src/PickCacheOptimizer.h b/libraries/pointers/src/PickCacheOptimizer.h index dd1fa6cecb..95ffa104ee 100644 --- a/libraries/pointers/src/PickCacheOptimizer.h +++ b/libraries/pointers/src/PickCacheOptimizer.h @@ -71,7 +71,7 @@ void PickCacheOptimizer::update(std::unordered_map>::iterator itr = picks.begin(); + auto iter = picks.begin(); if (nextToUpdate != INVALID_PICK_ID) { itr = picks.find(nextToUpdate); if (itr == picks.end()) { From 9eecd3cb80b0c3361ad3649f4415981465f47c0f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 6 Mar 2018 11:07:10 -0800 Subject: [PATCH 83/97] update styluses first: they are cheap --- libraries/pointers/src/PickManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/pointers/src/PickManager.cpp b/libraries/pointers/src/PickManager.cpp index b73b54cdb6..ba8fa814f0 100644 --- a/libraries/pointers/src/PickManager.cpp +++ b/libraries/pointers/src/PickManager.cpp @@ -96,10 +96,10 @@ void PickManager::update() { }); bool shouldPickHUD = _shouldPickHUDOperator(); - // we pass the same expiry to both updates - // even when the rayPicks consume all the budget at least one stylus will be updated - _rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], _nextPickToUpdate[PickQuery::Ray], expiry, shouldPickHUD); + // we pass the same expiry to both updates, but the stylus updates are relatively cheap + // and the rayPicks updae will ALWAYS update at least one ray even when there is no budget _stylusPickCacheOptimizer.update(cachedPicks[PickQuery::Stylus], _nextPickToUpdate[PickQuery::Stylus], expiry, false); + _rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], _nextPickToUpdate[PickQuery::Ray], expiry, shouldPickHUD); } bool PickManager::isLeftHand(unsigned int uid) { From 3f1944eb8af38ff5493ededd69c2521cc1a259d1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 7 Mar 2018 10:06:32 -0800 Subject: [PATCH 84/97] fix variable name typo --- libraries/pointers/src/PickCacheOptimizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/pointers/src/PickCacheOptimizer.h b/libraries/pointers/src/PickCacheOptimizer.h index 95ffa104ee..49a039935c 100644 --- a/libraries/pointers/src/PickCacheOptimizer.h +++ b/libraries/pointers/src/PickCacheOptimizer.h @@ -71,7 +71,7 @@ void PickCacheOptimizer::update(std::unordered_map Date: Thu, 8 Mar 2018 10:11:26 -0800 Subject: [PATCH 85/97] more readable code --- libraries/entities/src/EntityTreeElement.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 654d4b4ecc..1ae55bc333 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -601,8 +601,8 @@ EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, con // if the ray doesn't intersect with our cube OR the distance to element is less than current best distance // we can stop searching! - if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace, localSurfaceNormal) - || (!_cube.contains(origin) && distanceToElementCube > distance)) { + bool hit = _cube.findRayIntersection(origin, direction, distanceToElementCube, localFace, localSurfaceNormal); + if (!hit || (!_cube.contains(origin) && distanceToElementCube > distance)) { keepSearching = false; // no point in continuing to search return result; // we did not intersect } From c49d0557fca907d00cdef01b46ee5608448bbb28 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 9 Mar 2018 09:29:37 -0800 Subject: [PATCH 86/97] fixing check box issues --- interface/resources/qml/hifi/audio/Audio.qml | 2 +- libraries/audio-client/src/AudioClient.h | 1 + libraries/audio/src/AbstractAudioInterface.h | 6 ++++-- libraries/script-engine/src/AudioScriptingInterface.cpp | 8 ++++++++ libraries/script-engine/src/AudioScriptingInterface.h | 1 + 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index b598e26954..6e0131c86f 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -129,7 +129,7 @@ Rectangle { id: stereoMic spacing: muteMic.spacing; text: qsTr("Use stereo for stereo devices"); - checked: false; + checked: AudioScriptingInterface.isStereoEnabled(); onClicked: { var success = AudioScriptingInterface.setStereoInput(checked); if (!success) { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 053202f583..1ec58c8507 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -193,6 +193,7 @@ public slots: bool isMuted() { return _muted; } virtual bool setIsStereoInput(bool stereo) override; + virtual bool isStereoEnabled() override { return _isStereoInput; } void setNoiseReduction(bool isNoiseGateEnabled); bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; } diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index ba1e733f13..20ab1a80ec 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -28,7 +28,7 @@ class AbstractAudioInterface : public QObject { Q_OBJECT public: AbstractAudioInterface(QObject* parent = 0) : QObject(parent) {}; - + static void emitAudioPacket(const void* audioData, size_t bytes, quint16& sequenceNumber, bool isStereo, const Transform& transform, glm::vec3 avatarBoundingBoxCorner, glm::vec3 avatarBoundingBoxScale, PacketType packetType, QString codecName = QString("")); @@ -40,8 +40,10 @@ public: public slots: virtual bool shouldLoopbackInjectors() { return false; } - + virtual bool setIsStereoInput(bool stereo) = 0; + + virtual bool isStereoEnabled() = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index dd8d284c12..9bf275ddbf 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -67,3 +67,11 @@ bool AudioScriptingInterface::setStereoInput(bool stereo) { } return stereoInputChanged; } + +bool AudioScriptingInterface::isStereoEnabled() { + bool stereoEnabled = false; + if (_localAudioInterface) { + stereoEnabled = _localAudioInterface->isStereoEnabled(); + } + return stereoEnabled; +} diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index d46430ccce..08357536b7 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -36,6 +36,7 @@ protected: Q_INVOKABLE ScriptAudioInjector* playSystemSound(SharedSoundPointer sound, const QVector3D& position); Q_INVOKABLE bool setStereoInput(bool stereo); + Q_INVOKABLE bool isStereoEnabled(); signals: void mutedByMixer(); /// the client has been muted by the mixer From 3a39fca26819d64b0ac82232fb163d3f01436cb4 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 9 Mar 2018 10:09:51 -0800 Subject: [PATCH 87/97] made requested changes --- interface/resources/qml/hifi/audio/Audio.qml | 4 ++-- libraries/audio-client/src/AudioClient.h | 2 +- libraries/audio/src/AbstractAudioInterface.h | 2 +- libraries/script-engine/src/AudioScriptingInterface.cpp | 4 ++-- libraries/script-engine/src/AudioScriptingInterface.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 6e0131c86f..776bebf374 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -128,8 +128,8 @@ Rectangle { AudioControls.CheckBox { id: stereoMic spacing: muteMic.spacing; - text: qsTr("Use stereo for stereo devices"); - checked: AudioScriptingInterface.isStereoEnabled(); + text: qsTr("Use stereo for input device"); + checked: AudioScriptingInterface.isStereoInput(); onClicked: { var success = AudioScriptingInterface.setStereoInput(checked); if (!success) { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 1ec58c8507..3bfbdb49ce 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -193,7 +193,7 @@ public slots: bool isMuted() { return _muted; } virtual bool setIsStereoInput(bool stereo) override; - virtual bool isStereoEnabled() override { return _isStereoInput; } + virtual bool isStereoInput() override { return _isStereoInput; } void setNoiseReduction(bool isNoiseGateEnabled); bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; } diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 20ab1a80ec..30cbceeb0e 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -43,7 +43,7 @@ public slots: virtual bool setIsStereoInput(bool stereo) = 0; - virtual bool isStereoEnabled() = 0; + virtual bool isStereoInput() = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index 9bf275ddbf..f248c20d41 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -68,10 +68,10 @@ bool AudioScriptingInterface::setStereoInput(bool stereo) { return stereoInputChanged; } -bool AudioScriptingInterface::isStereoEnabled() { +bool AudioScriptingInterface::isStereoInput() { bool stereoEnabled = false; if (_localAudioInterface) { - stereoEnabled = _localAudioInterface->isStereoEnabled(); + stereoEnabled = _localAudioInterface->isStereoInput(); } return stereoEnabled; } diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 08357536b7..be2b4ebc8c 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -36,7 +36,7 @@ protected: Q_INVOKABLE ScriptAudioInjector* playSystemSound(SharedSoundPointer sound, const QVector3D& position); Q_INVOKABLE bool setStereoInput(bool stereo); - Q_INVOKABLE bool isStereoEnabled(); + Q_INVOKABLE bool isStereoInput(); signals: void mutedByMixer(); /// the client has been muted by the mixer From e21c4988fb8035209c3e2ad034a870ac5fa68628 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 9 Mar 2018 10:11:25 -0800 Subject: [PATCH 88/97] stereo checkbox text change --- interface/resources/qml/hifi/audio/Audio.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 776bebf374..ba50b7f238 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -128,7 +128,7 @@ Rectangle { AudioControls.CheckBox { id: stereoMic spacing: muteMic.spacing; - text: qsTr("Use stereo for input device"); + text: qsTr("Enable stereo input"); checked: AudioScriptingInterface.isStereoInput(); onClicked: { var success = AudioScriptingInterface.setStereoInput(checked); From 317d9a8dbc40d1c28d441c35b758db39037645a5 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 9 Mar 2018 11:45:39 -0800 Subject: [PATCH 89/97] Correct can cast shadow flag being visible on entities that can't cast shadows. --- scripts/system/html/entityProperties.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 7389442649..82a450bedd 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -313,7 +313,7 @@

-
+
From 10447bf10e6c4a370b842a2d11039a376af1f25f Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 9 Mar 2018 13:04:04 -0800 Subject: [PATCH 90/97] Fix the fact that all avatars should cast shadows, not just MyAvatar. since this is always a SkeletonMOdel class let s just turn it on by default there --- interface/src/avatar/MyAvatar.cpp | 6 ++---- .../avatars-renderer/src/avatars-renderer/SkeletonModel.cpp | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a5e24b8707..9620a2dcec 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1115,7 +1115,6 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) { void MyAvatar::setEnableMeshVisible(bool isEnabled) { _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); - _skeletonModel->setCanCastShadow(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); } void MyAvatar::setEnableInverseKinematics(bool isEnabled) { @@ -1468,7 +1467,6 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { int skeletonModelChangeCount = _skeletonModelChangeCount; Avatar::setSkeletonModelURL(skeletonModelURL); _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); - _skeletonModel->setCanCastShadow(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); _headBoneSet.clear(); _cauterizationNeedsUpdate = true; @@ -2043,8 +2041,8 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); - _attachmentModels[i]->setCanCastShadow(shouldDrawHead, qApp->getMain3DScene(), - render::ItemKey::TAG_BITS_NONE, true); + _attachmentModels[i]->setCanCastShadow(shouldDrawHead, qApp->getMain3DScene(), + render::ItemKey::TAG_BITS_NONE, true); } } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp index b2a494230b..b25df633c0 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp @@ -33,6 +33,10 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : { // SkeletonModels, and by extention Avatars, use Dual Quaternion skinning. _useDualQuaternionSkinning = true; + + // Avatars all cast shadow + _canCastShadow = true; + assert(_owningAvatar); } From fec30b83637683fd75b2e20d1e210cc8554c02e9 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 9 Mar 2018 15:04:14 -0800 Subject: [PATCH 91/97] Fixing the menu for Shadow and AO to do the correct path to engine config --- interface/src/Menu.cpp | 45 +++++++++++++++++++------- interface/src/Menu.h | 2 +- interface/src/ui/PreferencesDialog.cpp | 28 ---------------- 3 files changed, 34 insertions(+), 41 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ca6f7a31d1..733fd785d4 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -45,6 +45,9 @@ #include "LocationBookmarks.h" #include "DeferredLightingEffect.h" +#include "AmbientOcclusionEffect.h" +#include "RenderShadowTask.h" + #if defined(Q_OS_MAC) || defined(Q_OS_WIN) #include "SpeechRecognizer.h" #endif @@ -361,18 +364,6 @@ Menu::Menu() { // Developer menu ---------------------------------- MenuWrapper* developerMenu = addMenu("Developer", "Developer"); - // Developer > Graphics - MenuWrapper* graphicsOptionsMenu = developerMenu->addMenu("Render"); - action = addCheckableActionToQMenuAndActionHash(graphicsOptionsMenu, MenuOption::Shadows, 0, true); - connect(action, &QAction::triggered, [action] { - DependencyManager::get()->setShadowMapEnabled(action->isChecked()); - }); - - action = addCheckableActionToQMenuAndActionHash(graphicsOptionsMenu, MenuOption::AmbientOcclusion, 0, false); - connect(action, &QAction::triggered, [action] { - DependencyManager::get()->setAmbientOcclusionEnabled(action->isChecked()); - }); - // Developer > UI >>> MenuWrapper* uiOptionsMenu = developerMenu->addMenu("UI"); action = addCheckableActionToQMenuAndActionHash(uiOptionsMenu, MenuOption::DesktopTabletToToolbar, 0, @@ -389,6 +380,36 @@ Menu::Menu() { // Developer > Render >>> MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render"); + action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, true); + connect(action, &QAction::triggered, [action] { + auto renderConfig = qApp->getRenderEngine()->getConfiguration(); + if (renderConfig) { + auto mainViewShadowTaskConfig = renderConfig->getConfig("RenderMainView.RenderShadowTask"); + if (mainViewShadowTaskConfig) { + if (action->isChecked()) { + mainViewShadowTaskConfig->setPreset("Enabled"); + } else { + mainViewShadowTaskConfig->setPreset("None"); + } + } + } + }); + + action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion, 0, false); + connect(action, &QAction::triggered, [action] { + auto renderConfig = qApp->getRenderEngine()->getConfiguration(); + if (renderConfig) { + auto mainViewAmbientOcclusionConfig = renderConfig->getConfig("RenderMainView.AmbientOcclusion"); + if (mainViewAmbientOcclusionConfig) { + if (action->isChecked()) { + mainViewAmbientOcclusionConfig->setPreset("Enabled"); + } else { + mainViewAmbientOcclusionConfig->setPreset("None"); + } + } + } + }); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DefaultSkybox, 0, true); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 1d37b74ffe..cf9eed1a27 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -205,7 +205,7 @@ namespace MenuOption { const QString DesktopTabletToToolbar = "Desktop Tablet Becomes Toolbar"; const QString HMDTabletToToolbar = "HMD Tablet Becomes Toolbar"; const QString Shadows = "Shadows"; - const QString AmbientOcclusion = "AmbientOcclusion"; + const QString AmbientOcclusion = "Ambient Occlusion"; } #endif // hifi_Menu_h diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 48b56c7ced..4c233b986c 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -24,10 +24,6 @@ #include "SnapshotAnimated.h" #include "UserActivityLogger.h" -#include "AmbientOcclusionEffect.h" -#include "AntialiasingEffect.h" -#include "RenderShadowTask.h" - void setupPreferences() { auto preferences = DependencyManager::get(); auto nodeList = DependencyManager::get(); @@ -295,30 +291,6 @@ void setupPreferences() { } #endif - - { - static const QString RENDER("Graphics"); - auto renderConfig = qApp->getRenderEngine()->getConfiguration(); - if (renderConfig) { - auto mainViewAmbientOcclusionConfig = renderConfig->getConfig("RenderMainView.AmbientOcclusion"); - if (mainViewAmbientOcclusionConfig) { - auto getter = [mainViewAmbientOcclusionConfig]()->QString { return mainViewAmbientOcclusionConfig->getPreset(); }; - auto setter = [mainViewAmbientOcclusionConfig](QString preset) { mainViewAmbientOcclusionConfig->setPreset(preset); }; - auto preference = new ComboBoxPreference(RENDER, "Ambient occlusion", getter, setter); - preference->setItems(mainViewAmbientOcclusionConfig->getPresetList()); - preferences->addPreference(preference); - } - - auto mainViewShadowConfig = renderConfig->getConfig("RenderMainView.RenderShadowTask"); - if (mainViewShadowConfig) { - auto getter = [mainViewShadowConfig]()->QString { return mainViewShadowConfig->getPreset(); }; - auto setter = [mainViewShadowConfig](QString preset) { mainViewShadowConfig->setPreset(preset); }; - auto preference = new ComboBoxPreference(RENDER, "Shadows", getter, setter); - preference->setItems(mainViewShadowConfig->getPresetList()); - preferences->addPreference(preference); - } - } - } { static const QString NETWORKING("Networking"); From 9b9b62d0e4e2c1211ab27b50ec8dceb721352187 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 9 Mar 2018 15:20:51 -0800 Subject: [PATCH 92/97] Transition to hover if falling and height above ground is greater than the threshold. --- libraries/physics/src/CharacterController.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index d39930ab76..9b6e9fe7a0 100755 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -756,6 +756,9 @@ void CharacterController::updateState() { SET_STATE(State::Hover, "double jump button"); } else if ((jumpButtonHeld || vertTargetSpeedIsNonZero) && (now - _jumpButtonDownStartTime) > JUMP_TO_HOVER_PERIOD) { SET_STATE(State::Hover, "jump button held"); + } else if (_floorDistance > _scaleFactor * DEFAULT_AVATAR_FALL_HEIGHT) { + // Transition to hover if we are above the fall threshold + SET_STATE(State::Hover, "above fall threshold"); } } break; From 4b27cd73ffa9f8e9589f4cffb26720750f1e3478 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 9 Mar 2018 13:36:43 -0800 Subject: [PATCH 93/97] LogHandler class stores regexps rather than always recreating General efficiency tweaks; move to C++11. --- libraries/shared/src/LogHandler.cpp | 64 +++++++++++------------------ libraries/shared/src/LogHandler.h | 22 ++++++---- 2 files changed, 40 insertions(+), 46 deletions(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index cb3c0d07b2..ee063bbd31 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -92,12 +91,13 @@ void LogHandler::setShouldDisplayMilliseconds(bool shouldDisplayMilliseconds) { void LogHandler::flushRepeatedMessages() { QMutexLocker lock(&_mutex); - QHash::iterator message = _repeatMessageCountHash.begin(); - while (message != _repeatMessageCountHash.end()) { + for(auto& message: _repeatedMessages) { - if (message.value() > 0) { + if (message->messageCount > 1) { QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"") - .arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key())); + .arg(message->messageCount - 1) + .arg(message->regexp.pattern()) + .arg(message->lastMessage); QMessageLogContext emptyContext; lock.unlock(); @@ -105,8 +105,7 @@ void LogHandler::flushRepeatedMessages() { lock.relock(); } - _lastRepeatedMessage.remove(message.key()); - message = _repeatMessageCountHash.erase(message); + message->messageCount = 0; } } @@ -118,44 +117,25 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont if (type == LogDebug) { // for debug messages, check if this matches any of our regexes for repeated log messages - foreach(const QString& regexString, getInstance()._repeatedMessageRegexes) { - QRegExp repeatRegex(regexString); - if (repeatRegex.indexIn(message) != -1) { - - if (!_repeatMessageCountHash.contains(regexString)) { - // we have a match but didn't have this yet - output the first one - _repeatMessageCountHash[regexString] = 0; - - // break the foreach so we output the first match - break; - } else { - // we have a match - add 1 to the count of repeats for this message and set this as the last repeated message - _repeatMessageCountHash[regexString] += 1; - _lastRepeatedMessage[regexString] = message; - - // return out, we're not printing this one - return QString(); - } + for(auto& repeatRegex: _repeatedMessages) { + if (repeatRegex->regexp.indexIn(message) != -1) { + // If we've printed the first one then return out. + if (repeatRegex->messageCount++ == 0) break; + repeatRegex->lastMessage = message; + return QString(); } } } + if (type == LogDebug) { // see if this message is one we should only print once - foreach(const QString& regexString, getInstance()._onlyOnceMessageRegexes) { - QRegExp onlyOnceRegex(regexString); - if (onlyOnceRegex.indexIn(message) != -1) { - if (!_onlyOnceMessageCountHash.contains(message)) { - // we have a match and haven't yet printed this message. - _onlyOnceMessageCountHash[message] = 1; - // break the foreach so we output the first match - break; - } else { - // We've already printed this message, don't print it again. - return QString(); + for(auto& onceOnly : _onetimeMessages) { + if (onceOnly->regexp.indexIn(message) != -1) { + if (onceOnly->messageCount++ == 0) break; // we have a match and haven't yet printed this message. + else return QString(); // We've already printed this message, don't print it again. } } } - } // log prefix is in the following format // [TIMESTAMP] [DEBUG] [PID] [TID] [TARGET] logged string @@ -217,10 +197,16 @@ const QString& LogHandler::addRepeatedMessageRegex(const QString& regexString) { QMetaObject::invokeMethod(this, "setupRepeatedMessageFlusher"); QMutexLocker lock(&_mutex); - return *_repeatedMessageRegexes.insert(regexString); + std::unique_ptr<_RepeatedMessage> repeatRecord(new _RepeatedMessage()); + repeatRecord->regexp = QRegExp(regexString); + _repeatedMessages.insert(std::move(repeatRecord)); + return regexString; } const QString& LogHandler::addOnlyOnceMessageRegex(const QString& regexString) { QMutexLocker lock(&_mutex); - return *_onlyOnceMessageRegexes.insert(regexString); + std::unique_ptr<_OnceOnlyMessage> onetimeMessage(new _OnceOnlyMessage()); + onetimeMessage->regexp = QRegExp(regexString); + _onetimeMessages.insert(std::move(onetimeMessage)); + return regexString; } diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index ea961a8d4c..bbf6d62f03 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -13,11 +13,12 @@ #ifndef hifi_LogHandler_h #define hifi_LogHandler_h -#include #include -#include #include +#include #include +#include +#include const int VERBOSE_LOG_INTERVAL_SECONDS = 5; @@ -66,12 +67,19 @@ private: bool _shouldOutputProcessID { false }; bool _shouldOutputThreadID { false }; bool _shouldDisplayMilliseconds { false }; - QSet _repeatedMessageRegexes; - QHash _repeatMessageCountHash; - QHash _lastRepeatedMessage; - QSet _onlyOnceMessageRegexes; - QHash _onlyOnceMessageCountHash; + struct _RepeatedMessage { + QRegExp regexp; + int messageCount { 0 }; + QString lastMessage; + }; + std::set> _repeatedMessages; + + struct _OnceOnlyMessage { + QRegExp regexp; + int messageCount { 0 }; + }; + std::set> _onetimeMessages; static QMutex _mutex; }; From d4cf22fbaf03b145e321bb73b174d100ff1a6204 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 9 Mar 2018 15:11:05 -0800 Subject: [PATCH 94/97] LogHandler class stores regexps - code tweaks Code standard changes from review. --- libraries/shared/src/LogHandler.cpp | 20 ++++++++++++++------ libraries/shared/src/LogHandler.h | 18 +++++++++--------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index ee063bbd31..88110da95b 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -117,10 +117,12 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont if (type == LogDebug) { // for debug messages, check if this matches any of our regexes for repeated log messages - for(auto& repeatRegex: _repeatedMessages) { + for(auto& repeatRegex : _repeatedMessages) { if (repeatRegex->regexp.indexIn(message) != -1) { // If we've printed the first one then return out. - if (repeatRegex->messageCount++ == 0) break; + if (repeatRegex->messageCount++ == 0) { + break; + } repeatRegex->lastMessage = message; return QString(); } @@ -131,11 +133,17 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont // see if this message is one we should only print once for(auto& onceOnly : _onetimeMessages) { if (onceOnly->regexp.indexIn(message) != -1) { - if (onceOnly->messageCount++ == 0) break; // we have a match and haven't yet printed this message. - else return QString(); // We've already printed this message, don't print it again. + if (onceOnly->messageCount++ == 0) { + // we have a match and haven't yet printed this message. + break; + } + else { + // We've already printed this message, don't print it again. + return QString(); } } } + } // log prefix is in the following format // [TIMESTAMP] [DEBUG] [PID] [TID] [TARGET] logged string @@ -197,7 +205,7 @@ const QString& LogHandler::addRepeatedMessageRegex(const QString& regexString) { QMetaObject::invokeMethod(this, "setupRepeatedMessageFlusher"); QMutexLocker lock(&_mutex); - std::unique_ptr<_RepeatedMessage> repeatRecord(new _RepeatedMessage()); + std::unique_ptr repeatRecord(new RepeatedMessage()); repeatRecord->regexp = QRegExp(regexString); _repeatedMessages.insert(std::move(repeatRecord)); return regexString; @@ -205,7 +213,7 @@ const QString& LogHandler::addRepeatedMessageRegex(const QString& regexString) { const QString& LogHandler::addOnlyOnceMessageRegex(const QString& regexString) { QMutexLocker lock(&_mutex); - std::unique_ptr<_OnceOnlyMessage> onetimeMessage(new _OnceOnlyMessage()); + std::unique_ptr onetimeMessage(new OnceOnlyMessage()); onetimeMessage->regexp = QRegExp(regexString); _onetimeMessages.insert(std::move(onetimeMessage)); return regexString; diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index bbf6d62f03..fbf7bddaab 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -68,18 +68,18 @@ private: bool _shouldOutputThreadID { false }; bool _shouldDisplayMilliseconds { false }; - struct _RepeatedMessage { - QRegExp regexp; - int messageCount { 0 }; - QString lastMessage; + struct RepeatedMessage { + QRegExp regexp; + int messageCount { 0 }; + QString lastMessage; }; - std::set> _repeatedMessages; + std::set> _repeatedMessages; - struct _OnceOnlyMessage { - QRegExp regexp; - int messageCount { 0 }; + struct OnceOnlyMessage { + QRegExp regexp; + int messageCount { 0 }; }; - std::set> _onetimeMessages; + std::set> _onetimeMessages; static QMutex _mutex; }; From c78df4d96724589e690351b26db3d70fa75132e7 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 9 Mar 2018 15:41:56 -0800 Subject: [PATCH 95/97] Setting the correct Job config for ssao check box and fixing typo --- 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 733fd785d4..fa0e8087f0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -399,7 +399,7 @@ Menu::Menu() { connect(action, &QAction::triggered, [action] { auto renderConfig = qApp->getRenderEngine()->getConfiguration(); if (renderConfig) { - auto mainViewAmbientOcclusionConfig = renderConfig->getConfig("RenderMainView.AmbientOcclusion"); + auto mainViewAmbientOcclusionConfig = renderConfig->getConfig("RenderMainView.AmbientOcclusion"); if (mainViewAmbientOcclusionConfig) { if (action->isChecked()) { mainViewAmbientOcclusionConfig->setPreset("Enabled"); From cc166dbece16be8b9d92311a0e6c3c53045b984c Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 9 Mar 2018 15:44:56 -0800 Subject: [PATCH 96/97] LogHandler regexps - use vector of values --- libraries/shared/src/LogHandler.cpp | 39 ++++++++++++++--------------- libraries/shared/src/LogHandler.h | 6 ++--- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 88110da95b..49927a325b 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -93,11 +93,11 @@ void LogHandler::flushRepeatedMessages() { QMutexLocker lock(&_mutex); for(auto& message: _repeatedMessages) { - if (message->messageCount > 1) { + if (message.messageCount > 1) { QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"") - .arg(message->messageCount - 1) - .arg(message->regexp.pattern()) - .arg(message->lastMessage); + .arg(message.messageCount - 1) + .arg(message.regexp.pattern()) + .arg(message.lastMessage); QMessageLogContext emptyContext; lock.unlock(); @@ -105,7 +105,7 @@ void LogHandler::flushRepeatedMessages() { lock.relock(); } - message->messageCount = 0; + message.messageCount = 0; } } @@ -117,13 +117,13 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont if (type == LogDebug) { // for debug messages, check if this matches any of our regexes for repeated log messages - for(auto& repeatRegex : _repeatedMessages) { - if (repeatRegex->regexp.indexIn(message) != -1) { + for (auto& repeatRegex : _repeatedMessages) { + if (repeatRegex.regexp.indexIn(message) != -1) { // If we've printed the first one then return out. - if (repeatRegex->messageCount++ == 0) { + if (repeatRegex.messageCount++ == 0) { break; } - repeatRegex->lastMessage = message; + repeatRegex.lastMessage = message; return QString(); } } @@ -131,13 +131,12 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont if (type == LogDebug) { // see if this message is one we should only print once - for(auto& onceOnly : _onetimeMessages) { - if (onceOnly->regexp.indexIn(message) != -1) { - if (onceOnly->messageCount++ == 0) { + for (auto& onceOnly : _onetimeMessages) { + if (onceOnly.regexp.indexIn(message) != -1) { + if (onceOnly.messageCount++ == 0) { // we have a match and haven't yet printed this message. break; - } - else { + } else { // We've already printed this message, don't print it again. return QString(); } @@ -205,16 +204,16 @@ const QString& LogHandler::addRepeatedMessageRegex(const QString& regexString) { QMetaObject::invokeMethod(this, "setupRepeatedMessageFlusher"); QMutexLocker lock(&_mutex); - std::unique_ptr repeatRecord(new RepeatedMessage()); - repeatRecord->regexp = QRegExp(regexString); - _repeatedMessages.insert(std::move(repeatRecord)); + RepeatedMessage repeatRecord; + repeatRecord.regexp = QRegExp(regexString); + _repeatedMessages.push_back(repeatRecord); return regexString; } const QString& LogHandler::addOnlyOnceMessageRegex(const QString& regexString) { QMutexLocker lock(&_mutex); - std::unique_ptr onetimeMessage(new OnceOnlyMessage()); - onetimeMessage->regexp = QRegExp(regexString); - _onetimeMessages.insert(std::move(onetimeMessage)); + OnceOnlyMessage onetimeMessage; + onetimeMessage.regexp = QRegExp(regexString); + _onetimeMessages.push_back(onetimeMessage); return regexString; } diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index fbf7bddaab..2e64f16c1e 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include const int VERBOSE_LOG_INTERVAL_SECONDS = 5; @@ -73,13 +73,13 @@ private: int messageCount { 0 }; QString lastMessage; }; - std::set> _repeatedMessages; + std::vector _repeatedMessages; struct OnceOnlyMessage { QRegExp regexp; int messageCount { 0 }; }; - std::set> _onetimeMessages; + std::vector _onetimeMessages; static QMutex _mutex; }; From 84cc4c18a40c7025da738137da87ee4bc91628bc Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 9 Mar 2018 18:13:26 -0800 Subject: [PATCH 97/97] Added date/time to testResultsFolder. --- tools/auto-tester/src/Test.cpp | 22 +++++++--------------- tools/auto-tester/src/Test.h | 7 ++++--- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 9bced3d1fc..347cfd90dc 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -31,21 +31,13 @@ Test::Test() { mismatchWindow.setModal(true); } -bool Test::createTestResultsFolderPathIfNeeded(QString directory) { - // The test results folder is located in the root of the tests (i.e. for recursive test evaluation) - if (testResultsFolderPath == "") { - testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER; - QDir testResultsFolder(testResultsFolderPath); +bool Test::createTestResultsFolderPath(QString directory) { + QDateTime now = QDateTime::currentDateTime(); + testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER + "--" + now.toString(DATETIME_FORMAT); + QDir testResultsFolder(testResultsFolderPath); - if (testResultsFolder.exists()) { - testResultsFolder.removeRecursively(); - } - - // Create a new test results folder - return QDir().mkdir(testResultsFolderPath); - } else { - return true; - } + // Create a new test results folder + return QDir().mkdir(testResultsFolderPath); } void Test::zipAndDeleteTestResultsFolder() { @@ -194,7 +186,7 @@ void Test::startTestsEvaluation() { } // Quit if test results folder could not be created - if (!createTestResultsFolderPathIfNeeded(pathToTestResultsDirectory)) { + if (!createTestResultsFolderPath(pathToTestResultsDirectory)) { return; } diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 411f27eae6..cd5075002a 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -43,7 +43,7 @@ public: void appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage); - bool createTestResultsFolderPathIfNeeded(QString directory); + bool createTestResultsFolderPath(QString directory); void zipAndDeleteTestResultsFolder(); bool isAValidDirectory(QString pathname); @@ -81,8 +81,9 @@ private: QStringList resultImagesFullFilenames; // Used for accessing GitHub - const QString user{ "NissimHadar" }; - const QString branch{ "addRecursionToAutotester" }; + const QString user { "NissimHadar" }; + const QString branch { "addRecursionToAutotester" }; + const QString DATETIME_FORMAT { "yyyy-MM-dd_hh-mm-ss" }; }; #endif // hifi_test_h \ No newline at end of file