From b81f69d97a7aabaf2f6dc50e573dad7cb065fd45 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 23 Feb 2018 18:40:16 -0800 Subject: [PATCH 01/65] 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 2a1c22e7a5eb53548d0f901cfb3e9143e1c6c7ef Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Mar 2018 11:10:45 -0800 Subject: [PATCH 02/65] "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 03/65] [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 04/65] [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 b50044fb2b667a8a2d98ca7b3cee864870894c0a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 2 Mar 2018 13:15:27 +1300 Subject: [PATCH 05/65] 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 7107e1539ffa735b7fc90e7b09c694da0f4d3d70 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 2 Mar 2018 13:45:31 +1300 Subject: [PATCH 06/65] 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 5bb4023fb5d62869923a2a0f9a1b47383d05c3df Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Mar 2018 19:23:17 -0800 Subject: [PATCH 07/65] 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 08/65] 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 d29adcd000dd5dffc33849c9763008a1f62e78d1 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Mar 2018 16:08:14 -0800 Subject: [PATCH 09/65] 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 10/65] 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 11/65] 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 12/65] 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 13/65] 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 14/65] 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 15/65] 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 84815fadaeb6bf2476074466cc0d0da28dfb549d Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 5 Mar 2018 17:45:51 -0800 Subject: [PATCH 16/65] 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 b74be92fd8965ae297ad442ede65c4cd933b5fb8 Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 6 Mar 2018 11:29:43 -0800 Subject: [PATCH 17/65] 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 47e8e26255d267f450d7143f0c35ea2d8eece588 Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 6 Mar 2018 14:04:15 -0800 Subject: [PATCH 18/65] 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 19/65] 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 4b3d63eea4952c46749593fdb49d1e79699172d2 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 6 Mar 2018 16:37:05 -0800 Subject: [PATCH 20/65] 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 21/65] 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 c6e5f4c9c83774d323f7408f1d7b7a8f4e452765 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 6 Mar 2018 19:24:09 -0800 Subject: [PATCH 22/65] 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 23/65] 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 24/65] 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 25/65] 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 26/65] 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 27/65] 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 28/65] 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 29/65] 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 2987c90f965ff2f92eb7d847097d4c716be85731 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 7 Mar 2018 13:48:35 -0800 Subject: [PATCH 30/65] 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 31/65] 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 32/65] 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 33/65] 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 34/65] 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 35/65] 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 36/65] 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 22f18dbf56598b3644cddd9739e8e54c59856217 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Mar 2018 13:12:13 -0800 Subject: [PATCH 37/65] 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 38/65] 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 39/65] 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 40/65] 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 41/65] 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 zcmV+b9slBqP)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} z000szNkli7HV-Sz#hFijJMqP+;yG$|W*Vpn?4y@CF~5MTf>80ZU>0^I>W5NPKA z27wSz2h;!+KpC(b*ahqb_IH&)4qmw(XMw-RKESEK2w=GNc#tKF$nx(pEvd?ZuYgU! z2J3O9x&q|~0ZWz(fib`^pl6O>Q#J43L*=-`aiqmt_F#;alYrd?Dgxe6!*tsY^WVsJpGeE{&w5@pTefe`p3i39 zvnkM1z;!A|w&yzFNxKO&6S!ODCa;G0GwmYKCCD9fiu~eK1$ z&&{SleSm+>r)#m9OyD@?Si0RXBd4z;vi?I7d+^S-yu(-83SDF*( z9ORJ!3I&!6=VT(#O)6%J!}xhy1u6zEQ}I$9#$_}yAJ~*Y7a-5mQYg|n7I~;ms{&oF zVx?$?%Ucu32aHp3QZ&Oj%aLXU`U$N}T`RgYgDgjy6=I$|BLq?hohaJM*-Z&FT*XDvMus0QkOrKh;-Y9H zr=;A`(%QAbDlUpPGC0*=P6;%CcHCI6=(6;%oH-!SAXK#tMcWaUGY14x&6lD*&DbGL zm_m^Whcsb*RXh|K(l=e8o+=)S4C$FJPjPf z?LrBpPy#8GKnf+0qALp&RH0C0NHATXkcx*QLqh2S)v0(WGNdkDplTHlMTS(T3sj-v zp~#Smbb)rOcqlStce+4jDjtdqDN7fqoIE*?NMQ?1%b7!(uv!%tMH{I-ya}sO&6py? z=Bp-MAOqN@;-Y9H+bm}eSqs~w;-Y9H2V6-P=nEAWMH~5|DS@`8+O>i~)6{FoJ~fsr zz@cZRRsox7q84zz%3}l@iEZ7O)0bfc8w*XM&6X=i2n4XEPy`Zg4~g&okBU35&bi3K z?I|RI)};UCaDi3V84 zra5fYtQob{gg<`I3cL6dhn?U&c;$AQ`>4K%5OHt9zsF{5D|z5C)C za9oSejeNd_=*Ev_pChMDKm_kk&OJgP&*>xZoPO|B(fH1sAx` zU`eVQ^J0@9=Vq=z8t^$V!i>it$3tN=nZ%5RarEj(;Nr_EzTy_#Lr(@#7-bzzT_^t4 zChFgqPk8NejD~u&q9SlOa(h7%A~lD#0T_w3fZCQTkO9mGM#vw~+3!M%VaDT_@hHx| z0|-pGj^c^e~gu|JmrtQE7bpGM; zv~~poSqFF<&<7zfV^P`f=)BJ*u0bbIJYh0{3D?% zQWJJ?GzNEK8iC~Aa$G}B%(6g2iW7~1Y2rEc$9RTiaOR7{f$;kg4p;v5hfEXGosj*U z7H|z5ifiD|1AW2p+ILC*um{ak1Ws4>n>Hax?k!KPKr~toH2?Hgu0R0)g%H!T+k^=) z4JnQgcupTd$yHPFjky#@4^{88r8%!e`L{H_{W6V9UL{$v8{sWNINezlDXj^c2h3>h zd2MOJ0FDFxLAJ`^ndX7H5ATR`DY@cieCPkH5ckb=DEj^i8ka64xMU%T-QOWRUWCh? z&0i5j9xk`@Xaxe81I#|!Pmd7|qq#kJM~Z!JwU&?Ed>Z)mc=M{oWUnNnt6XEe> zOQbo#11&uv6M^~wUs``=E>0wb<_l2t({YqsJr(bnqg3Xz-MTf_5nT2L4T~0#DEn46 zL+#&(R0#~T{>+L%0Cxk=9B7H65xK(LN^|At)&t+@ODMi-DxOo$RGIE*k%A3`R=h>S zq6Ngi-DY)$TOMEtr%NvG9%Lpkx3%AusX%VvGcbpv8~Fd}@+OxPOg$;LR2T-rTZHd| z33ArB36kG`M{wn0xdx=p3d(fW0}P$OxXW=4JTebPI7DdWViM&$5l*L+#O-cUro`^= z2)(yBwQ+0{a1Ib}i$Ix7D8zw#LA-A!6B>qrJGFo*tzJgsJ1-IYa=o>M z1gzouS!7TnA=4%-MXhD&ax)$ko-;?$ZOU|&n0&$E#6NZtmy!wgwtJVG}f{IH+Q1fR;dixoT@p$B)WMWT9F^* zMBz=DjJmQZkk#=rZx&vEGQMLQRgc_-8IP(g*_68Za|kYb9W77-kOXd~g|)8E5C~v7 zn6ov1G2u_&r|NeP*!wPyE=uEDf2H>Mr_g){&K8_4b9Z!PYqI7U;2AAYLU8G8)XaTY zWz0qdS1h9X>4)W9kDQ--hO}iVI|u|Y3wTZQ7gN9RS!)0EsLGrT2(4a9_2aWa6REpB zUbAwQ6|%WE(g3C+L^sV}JihLQ{{)AV9{+OajsU%8KUI&;!U%^D4mDeym64Thp!xjt z`qh&-N_!t7&;Cd50^LY$PhAd7rI`)#xfTc@0$hU-OSK~3=(^{g#0ZDzIrBFMo*=wF z{9`A{-HmGfD@z8Ma{GqYcd*%dZxL0G%}$qREpUyMqpZ=MrHr;v3cQ7BjxoYPivRgW zdd_~#b_EX#w!^$=0o70co4l_}#(WKMC0VXOH+bdt4m)tJ2AGHt%Qats#ziku`Oxhc z4RtEJ9X(Y4%kQar;#cy%cISa+Ya$&~zOW-ZAwl3ugjlE*mk|D7DHZqKK%#u7%5n!_ zM8Z`4`@Pi8pM&P{rtbDwXkB?a>_EYe?!`ucDXAfTZ0jZ}?!Jb|y45PF^&3H=BdnQ;}iPHD)!xVHPMZq z$QfoK^i;g*g!`d8suSHDmjchB>&F<;F#fTV=sEKd9KHK06Egi&CgRjDm`mMDe~{aU z<%X~dU>fjlXS{}v>_j)mGT=NMj+`99VJ><@U1~)g;CH~o zK&&%gPJ6esW|K>Rr!mcwj8G8gfFbmlI*Y)BYn3dA5&ipT)IR$kL^pjRZ)bKm0lu;N zIyt$7+d&|Zla9XyrkjblFcWc#MvkHTv{`u17^y~Bd&;PL=??^#zX|aeqR5vTn9M_N z1k2g+6m}6P#aLuHnX}DE2;uhNzvwbbrcB3u{3%_pwc1}n!{QfceEVhe>K|ltC5Pu< zAj_?+%Jplsn?N9MUYr3ufMN7AB4M;ZG5(7tQgX#DxPNp;;a_no_YzE1-}qrqT7@$9 zS$&;(9K{a8LKi4SKj1##HVmWKh=kDm0g6UlNb$t$@t$>lYJsp|h<*JJg3Defw0a48 zWd*|PO)W(<0RIjA-jc{R*jbTWT0wOEMqhf3t^Bf+|G_wV9)qK2ZyY5( zq3v6cmdEQ#WBVd@5EJSKNfCgSq&k!Tnr*nnPJg`*kDiq0Y#1h(hD@x} zDFyRNfpEJK2>E@d3)9dc9+!1N6A8?C3^N+Wh{qtAJXmB)XmZoK(}~a=>DzUyk=5PS z03RT$z6T2-*o7$2;q(DcwWJzuJsyOd{T5&yOlO+bA$7)~WsFmgQ!)r4n<1ec`aSE} z$XVfX;49?O*c+_Jm4z7G_EzV}Cn~M4)oI`B4fK~IJ23#kV1(!^pcEY40YA-GqzwWg yYlvL~R9O9(-B#1I7uZi1Lge~PQAK|9{{sM)@n9j_&YM^O0000PpQ}WSXmiN|0^c~J2n;(O{vFE^o3v! zZ<8f2HaI`x%iztrf4=if%jNdSeci0=PWc(CW)!ajpD0yLSWgr|RHDH2crCcUr*C~z z5E@9p?hZV{ud!$Gyki3aR{_$}e5@UKZ2-t;k`N#0(8}z1$`JlQx~K5f5`+i=b$BI+ zYvLm)0H|NALLmTE0U=Q7oCZJ+70u*I^?fC_f` zex-dLC_=h+HVgnc36zi5g3s=J&?J>;^o!Vf5*vZNcH9Tn*RMD3w?@m{p#ZS%6)=9! zFH}Q^kitc{-sf=~ft{=gbKYM@IsPDp)&V)Y3npjo|FBWcjc=Tv-`d=q)96vKupKn{ zbPwyY=`gu-xek!Ny*yuQ!>|WFw+d7RU#)cw|9M%!Fq#MndA+n9r+V8!_;AZO$=aj- zy3v%EVndG%9;=iQefGS7HBupwry` zz+3{rX|r4B6gNIL!YO!t)cfIB?oKs_13);cC&B^1T8UlIaIi+MA0Ggeasqj)<>~)) z((rfSGIZiBbrRmbdJ&?)-qWSaU?!ES+j#vM6@ufd~pcR?P%a zwP*TY44IA87*Az9uq47QRhkl{egV&eZo^tspCt$W(36=Ws#9z%7NZMM$s-)I_j;BQ zN0pN~=21&06a6B0XROSLbRkYwvHxkuZyG$|9+#(reccM*#rYvgc0=D;%ZbYR=&Fs& zv6~~$?MA-U`gNO!8``FHN=Q)QXuI*hL;MK*S)}A$nb0tVzY1wVX|l zuX|`-KYtc(s>aVYLl#Fa^vFL#u}6%ZEK>0~S7SVu`uA^!6J!%A6YuodcKJ&(Mbzln zk_Hy+oqym-B=a-#{R-VgZFX-8Z_;nFoLUf|UPIyEt_(2T`h#yZXty41iEQCIq(7H8 z%FobWF3vT4EE;F7P?1}&U!@mbOfK?1Lt-SDN?o&{A}?i<&WYOT@=eumucpV#DNNdF zVHOT9PZFD6AoDQlo#C>?nt~kq*B?dTB#;xQo)x0=}$J9P?m!=nF+& zHa>H(bS_OzOEoQ1E7L1e-EVzSd02!hY*lVHy9p$b@7Lh6a?<2J;5XMFd4u zS~8O7m4c-FWrh(d|P+^GJF!cGrV*CTXe2UWQtou#E!d2 zgr<@16@|M=GYa)Dp6DrBbwd>kY*TF0)FE9o4tI3pJN8D=;-Ox2jR8Kvi(eG*>hiJuYh0PSP&Rnt^p!pVSZ3mo(5;Z_VK@ zR@S@Lf3k(WriL~2R(2mHwI+RP`V?~~gGU@bPg2Hc&KTfX>p>xDEV+__Mjpw1>iv_t zD+DtgeKa~Jyird+#MAQzWso_k3ZsTKdIq0GL`7-_4GE^n3TD#xE&poW)bKioTdn&| zoTD;pGP@3o7psn59KAUTU&zy26ZRbI{-wC4w>2(Dn4R*}d9^%1M^PsbR=2|@ zWG9qhQZZZIP~cs9X?sj9dm-zQy&=0HEw=J}#mr_{tfS#q!;nt5Tb51es^Vw12m1%V zhjE|?!2yC{M+V9VT43E=`F&(*kCl^Lbh!92e<&ZF(+wAER`;`HkvzJld) zCmo%DenS$f8}NH(49|AkHmW;-h$}Qa)FezU);+?MZv0uAsQ37iqUWm8U!_!~l}y+( z9f>Ld4N+d%Qo*;<3t~+oO>%vLj%LHtrYKW&7fl8ULEg$2?_AneZx7GHF(?e-hCg+> z&@U@@-&}OppU@(z57E?uYoRWKU#1i;+F?PXNg~nfuN6aZ& z@-k_ks_|<1B_1TSi2Abk3K#HiHHL7N#J9X8ez}|}nMIZHf!X!BjAZMx;KYP@xI!t5 zR#H7|54P?2VW`|8^v8YgyQl^srWCvZ=bHF(95VredWFK@hUVO}ym&ug4knK6Bawp= zsbyJwBZtE^gNyNE$m8sXL$WTi^~CyuFijHyM$_%q^0yK{q~X4c1RIn%d|}48<y#auq*VsAa{6gG2U>Ry26fhfoc9Th2)05$?Jvz9TIrYynXT5@{tZLX%Th*u zsiat>PNV!h$GzmUMIY`q*#31XxwfRNr_p}Yal&zTdqp72f+V#xZ99$R9r64^E%B;x z?cw=_@}f}M2=`)haJ^zglj zCu9uu<7W8wRZ04vwB4hQy#v)q-J}|-< zh2AP;oMxzG8f4s9ytZi48I~QN*<10uRb6~SiWHGH^VK*r9C)*^8#I{&I~|QirJz0q z2wpF}TFk5W-?2llz9n@#ZhGXkKB4>&wIkIcg|2>;Jaf{sKr%6VYq>byI*Pir! z(xgs*GqO3OveDAH@yM^W&foEJmp)4jz5J)u_k`+UW;#nkX1Vpu&+W4J@_dzQIlzPK z4n5R7@6B~o(W290^9On;Kd-nPJ}qZ)zchEe^!aUvch1@PlIkUHXz=KL!g(C2B2L`b zxS=rOu>CA?SqTY@oX6enZIR-r{U~P^^?ly`P$e~$P{7sn{w#VteLOeqG%cy!^<%-^ zUdKLd)nZ>)A5+_akMJ|=KgKtQo!(2{jK}$_q&k})nLl$sI9-1~HyA6rNuo_kdH`dm zpWWIC3oHTvz-*_cuLS^p8~}g_27v1a06^>l!272Fu=ff8B+~(a+AYzhR|Nnbv8yY| z8~Q99p!~fIr(65`jqZ7e+Wy-nR(Ds;4aHI(PLiH;;I9CHhqvK~|vJ6^k+@U3q4ZIrw{vEyOb*$u@Do{*?9WOY5ZLyNv^Ng^-r*;b943 z|ElvlF6ZrGiS|`4m|TGWLjWhh$x{-jK_{<)#a=*;h^TQNZ-}Vj#<)2~2s3C4AwJ0OzNfj&wF$bk6dX7~AYf4Oj9nDXMbo<5X!Uk#zRw0Msv2(ZX zA*xfr#ZjmB-qXkL1az=^%&_3b?141ZUqXnx$#QmCnzG2F&+~WJamVO(eMagy82~!| zdRevb8`aRRJ{E{BKirrVb>N+H<$t606rfW_TBV|i(*maR1w^Nal=wy-EEqoHmInny6h2rq?W0v_aB^rc2VcB0j=YqwRAvEU zPPDcfY}dHI&Xntv3))Y0~+a~nV2dGF<5 z4v4IB_v!t>5m!#7G8l7&#Ar#spB<*Dedm?96TM0ZSW zgP$5Ru<$ndf!Fh`$lhgZ)T_F`pN_kbbgthT#*9B>C$p10(BtQ{%7dM%#sLq=lN;h3 zD-}A141;{Vhw-d6(4TRpd=MDpQq&I6X(8*>5DH8=sVlMCq!c+QmCP&+#O)as9X>Rg zD1AvCOXQU(LAEpQm@%7RygK4mm~CGOx?0q+ZJG+~Dt=h^&j$G|6l?w=W6nOWr2-g} zfKUNw|3@4rBKQm^h`<7|@XouiTn=!3>XB@Q^)2!R5k-!C&pZx9cMjVtuxa|@Hy?Ck zV9o)|4qZsGqmg@rFsA>MpA1$Lu3*B4s&YWdm~->*aJa)1m=7z#YLm5H<9DFnDwWLvqF`6t@0nhKSQI zlS3PO=8Yin;NK)o8py2+@R&4am;#F| z33if*NdvA$V$ujB$(XaL$Q-y8u{I636>$wXpt3jyTOUXu@j8nVn_08& zBbb}?YOh3vbTR|$C#T$4t3=y%Cwxf}np>PRKe7s|jck+)S9DGa; zquSw~Lz;hQwkh3j{djoAwsY5$9)efQyJ4T@w+bEH%WVjDwo{rKVDmMTtycdbG#QI~ zjXAmG2cpA$yB=9S@oykGXSAf3q1nbemcKsJ>3F|s=VM9Sgk8LR7_|R8AX&hdXd5p8 z;Vj2gZs5N{d=|o@`+TF-Y7P-q;g#&K|AXA!ZpB`FMsOyE*I175=F4?;`%~%^`m;4z z|5M{|(Z+Ef%p*&V?2h*blWWDB%PmfHoXehYQ)AyY4X~@sZKBM;Uw!V-XPT|!gZZuj!KI- zmP%WG9z*+|p_E_CEY)8+tsR~G>je(0xw*Dm9`4=m%)|uf_o*$z+PW~iPJI>r%D4v* zKj|td?4CfxrWu^W80N-Ay0oL6`+CGP=Kx%HlP*r7@#s)%K5}I~jgv!2D(XnPNo-C3 zd3Yz1A#h^XPWOBPw>CNBacRZ%p0DBkPSuprpH2KadPvYnGgwEIr^(-W{usHgJ7Jge z?b>ELncMV^blyK-4R!}>%H+lXtS2 zVBN1m94@QWz0UeGmLm7WE&SH;vTu^3x?Oy<`C^j$VASA)J2eJ0j*iZo8-H1_ zdLZ7JF)9vlRSaJi8K-ZTKabU_Mr+`d)KsBlzCYDP1iVDn>1wkM^XSp>kj?f7;LY|g z#n9_G<{d3Jj2UksTpH+I8cM7dXFlU;(ZxFFw-KLVE56c>nHYYOoP>`lS4N`88JG`$ zc)x5iIrJ9B=(gE&(vf_cs%p^w*)T&uU%I;RWrB8Ny7NO}q5Ps%D}0R*s^0U}d2Nj- zTtbvUWBY0H!y?1a*e66WB|h=ynUk>@L9W%Z3H(sHZ9eJBtUg(Dz-vFcyvpE)0i^u_ zi`Uv5|FY!u?k55HQh444>aZHE5h}rdM8=(_Ke_y_HYoGZM7AoTWDjewI&>A8ky0T)G+p@O~*FN4U^A-}<{6 zUC$4@iK*L^CJR32>|$tZldX?WI{Cx|!d(SPt$%eoWen*xzPU!pmsTlG_Et$AtbW{D za#f^4yOy=G5aMTNVB!34D-LQa?b?w`Vk66_I@=C*-nyR+pU6J!{2UDcnVbZ!;mE`k zVzAw_@A8hZkHo~HIu5bKXYMt_+clnKt`S=>P{U$wSd!UgfNXI=zTzKmo5?eIAl z6nV{A_To)(P`+Q96#VEoLHMr&Vy!0X?J4f5RvTuS!u*+!TMYaL0dwyQ{9=UKE~x)` zh&ga63^3r%Ca~^G$n=a1YS^MsyfglZP~_po^yod<=_&k!)qNV2Mvv zl_9S3g2_`($B?LvF4ZQSUrNZ{M=+D*NJZPPr;0yEvlFw3G)(hVWE7Igc0Zk2K5l!q z%g9U)e-Y%9XfzNJ?C{rA#7g>XWO~P-*L}M^qIC5xJekyEyZtI=t+uEV*Wp2ue0vlB zIK990uM+(OE*3MqkbfZ8zNho~dyyp@rej=P2=baw_k7Tt=gH=<4d}82ovUDxg1x2b z_yJWZ_0GF~2>&01h8T59jXqsd57n;s2g36WSH2xC7UIfY7DPQ}p?lb_cXVoq7B|+i zCfsKX=QkH>IyZKu0q4@?a+=hTio}-X8Jf>mB4dCrc2!zRIhcF*S+TEk)SsWJQ6U`J z9nW38W=sBV-Q%jAlf*}gM{%GvxMAYM1CQNXTEJPEbrUyjVO$@Me=q%m+Gi2ij{$+7+gz(nHm+_J- z4QQ8j@s_A>s9)Q*A+$xI3fta$NUliY`APXPR06(r@!~bQAM!G&o%(#H+G=DzURX5L z<*rY*cho!aQoz5MAnYF3Lz?3Lki<85U>q^!)&pO{B_yzBxDxfw`d4%7x~MYTkSf%B zmk+cKqqjAFZ}U7?JzA@K<#v1JRDj}rf)610Ou2oZw>_`tJ6|4q?Z)~A{^I3x-gmds z7Bcr0+dClm%u8hJ;V9*nJ5cQWxTPUdI4u#CgG*RLu6J>}QS9FiRBRQ5EtYLa>Vx|; zc3ypzB-q~kRjKM~i81TnoqnPME*_F)s}B{g@tsu|=1Hi2$r$=2MeM0T!QaTH zTknHgYO{(zdonuqwjEUKkM)pRQW17@pgwi90=oHPlk;ah8>$|s*Ia^T~{2svbFII+FLr%Rr-rhw^ zVAI1L+ur42?+EFANR!NG=<|sMWgO|xU~g{`&I@f=ls%2$p1!&kXsq-ME3;tcBsu(T+#*5mrsuIK_K-?e z@&VW0O5p3Xlwo3BPb!b!j9+Aq3;iksV1kuj8YqqC6}r2p^s<ZPM^>};qisto*c6SAM ngVi)j+Y?pd69IJ`od-GKa6*gk_M++EZvjwO)>f)icop=25FsOb 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 42/65] 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 43/65] 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 44/65] 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 45/65] 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 46/65] 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 47/65] 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 48/65] 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 49/65] 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 50/65] 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 51/65] 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 52/65] 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 53/65] 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 54/65] 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 55/65] 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 56/65] 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 57/65] 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 58/65] 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 59/65] 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 60/65] 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 4b27cd73ffa9f8e9589f4cffb26720750f1e3478 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 9 Mar 2018 13:36:43 -0800 Subject: [PATCH 61/65] 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 62/65] 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 63/65] 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 64/65] 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 65/65] 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