diff --git a/cmake/externals/quazip/CMakeLists.txt b/cmake/externals/quazip/CMakeLists.txt index f2690e0a7d..7bf6f05d9f 100644 --- a/cmake/externals/quazip/CMakeLists.txt +++ b/cmake/externals/quazip/CMakeLists.txt @@ -41,6 +41,9 @@ if (APPLE) elseif (WIN32) set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/quazip5.lib CACHE FILEPATH "Location of QuaZip release library") set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/quazip5d.lib CACHE FILEPATH "Location of QuaZip release library") +elseif (CMAKE_SYSTEM_NAME MATCHES "Linux") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip5.so CACHE FILEPATH "Location of QuaZip release library") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5d.so CACHE FILEPATH "Location of QuaZip release library") else () set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip5.so CACHE FILEPATH "Location of QuaZip release library") set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5.so CACHE FILEPATH "Location of QuaZip release library") diff --git a/interface/resources/qml/controls/FlickableWebViewCore.qml b/interface/resources/qml/controls/FlickableWebViewCore.qml index 8e7db44b7d..943f15e1de 100644 --- a/interface/resources/qml/controls/FlickableWebViewCore.qml +++ b/interface/resources/qml/controls/FlickableWebViewCore.qml @@ -21,6 +21,7 @@ Item { signal newViewRequestedCallback(var request) signal loadingChangedCallback(var loadRequest) + width: parent.width property bool interactive: false @@ -29,6 +30,10 @@ Item { id: hifi } + function stop() { + webViewCore.stop(); + } + function unfocus() { webViewCore.runJavaScript("if (document.activeElement) document.activeElement.blur();", function(result) { console.log('unfocus completed: ', result); diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 931c64e1ef..71bf69fdc8 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -21,6 +21,10 @@ Item { property bool passwordField: false property alias flickable: webroot.interactive + function stop() { + webroot.stop(); + } + // FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface // or provide HMDinfo object to QML in RenderableWebEntityItem and do the following. /* diff --git a/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml b/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml index b1b6de4644..aadd7c88ae 100644 --- a/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml @@ -254,7 +254,7 @@ ModalWindow { text: root.warning; wrapMode: Text.WordWrap; font.italic: true; - maximumLineCount: 2; + maximumLineCount: 3; } HiFiGlyphs { diff --git a/interface/resources/qml/dialogs/CustomQueryDialog.qml b/interface/resources/qml/dialogs/CustomQueryDialog.qml index 008ed5b860..0c86b93c4b 100644 --- a/interface/resources/qml/dialogs/CustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/CustomQueryDialog.qml @@ -254,7 +254,7 @@ ModalWindow { text: root.warning; wrapMode: Text.WordWrap; font.italic: true; - maximumLineCount: 2; + maximumLineCount: 3; } HiFiGlyphs { diff --git a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml index 623388e9b3..81a2c5c1e0 100644 --- a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml @@ -282,7 +282,7 @@ TabletModalWindow { text: root.warning; wrapMode: Text.WordWrap; font.italic: true; - maximumLineCount: 2; + maximumLineCount: 3; } HiFiGlyphs { diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 08e3e7a552..6b48f8d51d 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -124,6 +124,14 @@ Rectangle { root.numUpdatesAvailable = result.data.updates.length; } } + + onAppInstalled: { + root.installedApps = Commerce.getInstalledApps(); + } + + onAppUninstalled: { + root.installedApps = Commerce.getInstalledApps(); + } } Timer { @@ -249,6 +257,145 @@ Rectangle { Commerce.getWalletStatus(); } } + + Item { + id: installedAppsContainer; + z: 998; + visible: false; + anchors.top: titleBarContainer.bottom; + anchors.topMargin: -titleBarContainer.additionalDropdownHeight; + anchors.left: parent.left; + anchors.bottom: parent.bottom; + width: parent.width; + + RalewayRegular { + id: installedAppsHeader; + anchors.top: parent.top; + anchors.topMargin: 10; + anchors.left: parent.left; + anchors.leftMargin: 12; + height: 80; + width: paintedWidth; + text: "All Installed Marketplace Apps"; + color: hifi.colors.black; + size: 22; + } + + ListView { + id: installedAppsList; + clip: true; + model: installedAppsModel; + snapMode: ListView.SnapToItem; + // Anchors + anchors.top: installedAppsHeader.bottom; + anchors.left: parent.left; + anchors.bottom: sideloadAppButton.top; + width: parent.width; + delegate: Item { + width: parent.width; + height: 40; + + RalewayRegular { + text: model.appUrl; + // Text size + size: 16; + // Anchors + anchors.left: parent.left; + anchors.leftMargin: 12; + height: parent.height; + anchors.right: sideloadAppOpenButton.left; + anchors.rightMargin: 8; + elide: Text.ElideRight; + // Style + color: hifi.colors.black; + // Alignment + verticalAlignment: Text.AlignVCenter; + + MouseArea { + anchors.fill: parent; + onClicked: { + Window.copyToClipboard((model.appUrl).slice(0, -9)); + } + } + } + + HifiControlsUit.Button { + id: sideloadAppOpenButton; + text: "OPEN"; + color: hifi.buttons.blue; + colorScheme: hifi.colorSchemes.dark; + anchors.top: parent.top; + anchors.topMargin: 2; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 2; + anchors.right: uninstallGlyph.left; + anchors.rightMargin: 8; + width: 80; + onClicked: { + Commerce.openApp(model.appUrl); + } + } + + HiFiGlyphs { + id: uninstallGlyph; + text: hifi.glyphs.close; + color: hifi.colors.black; + size: 22; + anchors.top: parent.top; + anchors.right: parent.right; + anchors.rightMargin: 6; + width: 35; + height: parent.height; + horizontalAlignment: Text.AlignHCenter; + MouseArea { + anchors.fill: parent; + hoverEnabled: true; + onEntered: { + parent.text = hifi.glyphs.closeInverted; + } + onExited: { + parent.text = hifi.glyphs.close; + } + onClicked: { + Commerce.uninstallApp(model.appUrl); + } + } + } + } + } + HifiControlsUit.Button { + id: sideloadAppButton; + color: hifi.buttons.blue; + colorScheme: hifi.colorSchemes.dark; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 8; + anchors.left: parent.left; + anchors.leftMargin: 8; + anchors.right: closeAppListButton.left; + anchors.rightMargin: 8; + height: 40; + text: "SIDELOAD APP FROM LOCAL DISK"; + onClicked: { + Window.browseChanged.connect(onFileOpenChanged); + Window.browseAsync("Locate your app's .app.json file", "", "*.app.json"); + } + } + HifiControlsUit.Button { + id: closeAppListButton; + color: hifi.buttons.white; + colorScheme: hifi.colorSchemes.dark; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 8; + anchors.right: parent.right; + anchors.rightMargin: 8; + width: 100; + height: 40; + text: "BACK"; + onClicked: { + installedAppsContainer.visible = false; + } + } + } HifiWallet.NeedsLogIn { id: needsLogIn; @@ -317,7 +464,7 @@ Rectangle { // Item { id: purchasesContentsContainer; - visible: root.activeView === "purchasesMain"; + visible: root.activeView === "purchasesMain" && !installedAppsList.visible; // Anchors anchors.left: parent.left; anchors.right: parent.right; @@ -959,6 +1106,39 @@ Rectangle { } } + Keys.onPressed: { + if ((event.key == Qt.Key_F) && (event.modifiers & Qt.ControlModifier)) { + installedAppsContainer.visible = !installedAppsContainer.visible; + console.log("User changed visibility of installedAppsContainer to " + installedAppsContainer.visible); + } + } + function onFileOpenChanged(filename) { + // disconnect the event, otherwise the requests will stack up + try { // Not all calls to onFileOpenChanged() connect an event. + Window.browseChanged.disconnect(onFileOpenChanged); + } catch (e) { + console.log('Purchases.qml ignoring', e); + } + if (filename) { + Commerce.installApp(filename); + } + } + ListModel { + id: installedAppsModel; + } + onInstalledAppsChanged: { + installedAppsModel.clear(); + var installedAppsArray = root.installedApps.split(","); + var installedAppsObject = []; + // "- 1" because the last app string ends with "," + for (var i = 0; i < installedAppsArray.length - 1; i++) { + installedAppsObject[i] = { + "appUrl": installedAppsArray[i] + } + } + installedAppsModel.append(installedAppsObject); + } + // // Function Name: fromScript() // diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c38caca090..cd4562da54 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -145,6 +145,16 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "AudioClient.h" #include "audio/AudioScope.h" #include "avatar/AvatarManager.h" @@ -1060,6 +1070,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (steamClient) { qCDebug(interfaceapp) << "[VERSION] SteamVR buildID:" << steamClient->getSteamVRBuildID(); } + setCrashAnnotation("steam", property(hifi::properties::STEAM).toBool() ? "1" : "0"); + qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); qCDebug(interfaceapp) << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION; qCDebug(interfaceapp) << "[VERSION] VERSION:" << BuildInfo::VERSION; @@ -1145,6 +1157,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo const DomainHandler& domainHandler = nodeList->getDomainHandler(); connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl))); + connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){ + setCrashAnnotation("domain", domainURL.toString().toStdString()); + }); connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain())); connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); @@ -1190,6 +1205,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto dialogsManager = DependencyManager::get(); connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog); connect(accountManager.data(), &AccountManager::usernameChanged, this, &Application::updateWindowTitle); + connect(accountManager.data(), &AccountManager::usernameChanged, [](QString username){ + setCrashAnnotation("username", username.toStdString()); + }); // set the account manager's root URL and trigger a login request if we don't have the access token accountManager->setIsAgent(true); @@ -1207,6 +1225,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount); connect(this, &Application::activeDisplayPluginChanged, this, [](){ qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode()); + auto displayPlugin = qApp->getActiveDisplayPlugin(); + setCrashAnnotation("display_plugin", displayPlugin->getName().toStdString()); + setCrashAnnotation("hmd", displayPlugin->isHmd() ? "1" : "0"); }); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode); @@ -1214,6 +1235,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(myAvatar.get(), &MyAvatar::positionGoneTo, DependencyManager::get().data(), &AddressManager::storeCurrentAddress); + connect(myAvatar.get(), &MyAvatar::skeletonModelURLChanged, [](){ + QUrl avatarURL = qApp->getMyAvatar()->getSkeletonModelURL(); + setCrashAnnotation("avatar", avatarURL.toString().toStdString()); + }); + + // Inititalize sample before registering _sampleSound = DependencyManager::get()->getSound(PathUtils::resourcesUrl("sounds/sample.wav")); @@ -1306,6 +1333,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Needs to happen AFTER the render engine initialization to access its configuration initializeUi(); + updateVerboseLogging(); + init(); qCDebug(interfaceapp, "init() complete."); @@ -1376,6 +1405,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo userActivityLogger.disable(false); } + QString machineFingerPrint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); + if (userActivityLogger.isEnabled()) { // sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value. // The value will be 0 if the user blew away settings this session, which is both a feature and a bug. @@ -1425,11 +1456,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo properties["first_run"] = firstRun.get(); // add the user's machine ID to the launch event - properties["machine_fingerprint"] = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); + properties["machine_fingerprint"] = machineFingerPrint; userActivityLogger.logAction("launch", properties); } + setCrashAnnotation("machine_fingerprint", machineFingerPrint.toStdString()); + _entityEditSender.setMyAvatar(myAvatar.get()); // The entity octree will have to know about MyAvatar for the parentJointName import @@ -2174,6 +2207,46 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID()); } +void Application::updateVerboseLogging() { + bool enable = Menu::getInstance()->isOptionChecked(MenuOption::VerboseLogging); + + const_cast(&animation())->setEnabled(QtDebugMsg, enable); + const_cast(&animation())->setEnabled(QtInfoMsg, enable); + + const_cast(&avatars())->setEnabled(QtDebugMsg, enable); + const_cast(&avatars())->setEnabled(QtInfoMsg, enable); + + const_cast(&scriptengine())->setEnabled(QtDebugMsg, enable); + const_cast(&scriptengine())->setEnabled(QtInfoMsg, enable); + + const_cast(&modelformat())->setEnabled(QtDebugMsg, enable); + const_cast(&modelformat())->setEnabled(QtInfoMsg, enable); + + const_cast(&controllers())->setEnabled(QtDebugMsg, enable); + const_cast(&controllers())->setEnabled(QtInfoMsg, enable); + + const_cast(&resourceLog())->setEnabled(QtDebugMsg, enable); + const_cast(&resourceLog())->setEnabled(QtInfoMsg, enable); + + const_cast(&networking())->setEnabled(QtDebugMsg, enable); + const_cast(&networking())->setEnabled(QtInfoMsg, enable); + + const_cast(&asset_client())->setEnabled(QtDebugMsg, enable); + const_cast(&asset_client())->setEnabled(QtInfoMsg, enable); + + const_cast(&messages_client())->setEnabled(QtDebugMsg, enable); + const_cast(&messages_client())->setEnabled(QtInfoMsg, enable); + + const_cast(&storagelogging())->setEnabled(QtDebugMsg, enable); + const_cast(&storagelogging())->setEnabled(QtInfoMsg, enable); + + const_cast(&uiLogging())->setEnabled(QtDebugMsg, enable); + const_cast(&uiLogging())->setEnabled(QtInfoMsg, enable); + + const_cast(&glLogging())->setEnabled(QtDebugMsg, enable); + const_cast(&glLogging())->setEnabled(QtInfoMsg, enable); +} + void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) { DomainHandler::ConnectionRefusedReason reasonCode = static_cast(reasonCodeInt); @@ -3042,7 +3115,6 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { PROFILE_RANGE(render, __FUNCTION__); bool sandboxIsRunning = SandboxUtils::readStatus(reply->readAll()); - qDebug() << "HandleSandboxStatus" << sandboxIsRunning; enum HandControllerType { Vive, diff --git a/interface/src/Application.h b/interface/src/Application.h index 74b0e5a110..6d611bc8e2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -399,6 +399,8 @@ public slots: Q_INVOKABLE bool askBeforeSetAvatarUrl(const QString& avatarUrl) { return askToSetAvatarUrl(avatarUrl); } + void updateVerboseLogging(); + private slots: void onDesktopRootItemCreated(QQuickItem* qmlContext); void onDesktopRootContextCreated(QQmlContext* qmlContext); diff --git a/interface/src/ConnectionMonitor.cpp b/interface/src/ConnectionMonitor.cpp index fcb1908994..8deddbda82 100644 --- a/interface/src/ConnectionMonitor.cpp +++ b/interface/src/ConnectionMonitor.cpp @@ -43,12 +43,10 @@ void ConnectionMonitor::init() { } void ConnectionMonitor::startTimer() { - qDebug() << "ConnectionMonitor: Starting timer"; _timer.start(DISPLAY_AFTER_DISCONNECTED_FOR_X_MS); } void ConnectionMonitor::stopTimer() { - qDebug() << "ConnectionMonitor: Stopping timer"; _timer.stop(); DependencyManager::get()->setDomainConnectionFailureVisibility(false); } diff --git a/interface/src/Crashpad.cpp b/interface/src/Crashpad.cpp index ae2f341337..e39cd42d81 100644 --- a/interface/src/Crashpad.cpp +++ b/interface/src/Crashpad.cpp @@ -15,6 +15,8 @@ #if HAS_CRASHPAD +#include + #include #include @@ -23,8 +25,8 @@ #include #include #include -// #include -// #include +#include +#include using namespace crashpad; @@ -35,7 +37,8 @@ static std::wstring gIPCPipe; extern QString qAppFileName(); -// crashpad::AnnotationList* crashpadAnnotations { nullptr }; +std::mutex annotationMutex; +crashpad::SimpleStringDictionary* crashpadAnnotations { nullptr }; #include @@ -102,12 +105,14 @@ bool startCrashHandler() { } void setCrashAnnotation(std::string name, std::string value) { - // if (!crashpadAnnotations) { - // crashpadAnnotations = new crashpad::AnnotationList(); // don't free this, let it leak - // crashpad::CrashpadInfo* crashpad_info = crashpad::GetCrashpadInfo(); - // crashpad_info->set_simple_annotations(crashpadAnnotations); - // } - // crashpadAnnotations->SetKeyValue(name, value); + std::lock_guard guard(annotationMutex); + if (!crashpadAnnotations) { + crashpadAnnotations = new crashpad::SimpleStringDictionary(); // don't free this, let it leak + crashpad::CrashpadInfo* crashpad_info = crashpad::CrashpadInfo::GetCrashpadInfo(); + crashpad_info->set_simple_annotations(crashpadAnnotations); + } + std::replace(value.begin(), value.end(), ',', ';'); + crashpadAnnotations->SetKeyValue(name, value); } #else diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 33cfc481d7..b3c059de7f 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -20,6 +20,7 @@ #include #include +#include "Crashpad.h" #include "DiscoverabilityManager.h" #include "Menu.h" @@ -127,10 +128,12 @@ void DiscoverabilityManager::updateLocation() { QNetworkAccessManager::PutOperation, callbackParameters); } - // Update Steam + // Update Steam and crash logger + QUrl currentAddress = addressManager->currentFacingPublicAddress(); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { - steamClient->updateLocation(domainHandler.getHostname(), addressManager->currentFacingPublicAddress()); + steamClient->updateLocation(domainHandler.getHostname(), currentAddress); } + setCrashAnnotation("address", currentAddress.toString().toStdString()); } void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply) { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index e8737d92ae..96d92e91e9 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -9,11 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/**jsdoc - * The LOD class manages your Level of Detail functions within interface - * @namespace LODManager - */ - #ifndef hifi_LODManager_h #define hifi_LODManager_h @@ -39,10 +34,32 @@ const float ADJUST_LOD_MIN_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE * 0.04f; class AABox; +/**jsdoc + * The LOD class manages your Level of Detail functions within Interface. + * @namespace LODManager + * @property {number} presentTime Read-only. + * @property {number} engineRunTime Read-only. + * @property {number} gpuTime Read-only. + * @property {number} avgRenderTime Read-only. + * @property {number} fps Read-only. + * @property {number} lodLevel Read-only. + * @property {number} lodDecreaseFPS Read-only. + * @property {number} lodIncreaseFPS Read-only. + */ + class LODManager : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY + Q_PROPERTY(float presentTime READ getPresentTime) + Q_PROPERTY(float engineRunTime READ getEngineRunTime) + Q_PROPERTY(float gpuTime READ getGPUTime) + Q_PROPERTY(float avgRenderTime READ getAverageRenderTime) + Q_PROPERTY(float fps READ getMaxTheoreticalFPS) + Q_PROPERTY(float lodLevel READ getLODLevel) + Q_PROPERTY(float lodDecreaseFPS READ getLODDecreaseFPS) + Q_PROPERTY(float lodIncreaseFPS READ getLODIncreaseFPS) + public: /**jsdoc @@ -138,28 +155,6 @@ public: */ Q_INVOKABLE float getLODIncreaseFPS() const; - /**jsdoc - * @namespace LODManager - * @property {number} presentTime Read-only. - * @property {number} engineRunTime Read-only. - * @property {number} gpuTime Read-only. - * @property {number} avgRenderTime Read-only. - * @property {number} fps Read-only. - * @property {number} lodLevel Read-only. - * @property {number} lodDecreaseFPS Read-only. - * @property {number} lodIncreaseFPS Read-only. - */ - - Q_PROPERTY(float presentTime READ getPresentTime) - Q_PROPERTY(float engineRunTime READ getEngineRunTime) - Q_PROPERTY(float gpuTime READ getGPUTime) - Q_PROPERTY(float avgRenderTime READ getAverageRenderTime) - Q_PROPERTY(float fps READ getMaxTheoreticalFPS) - Q_PROPERTY(float lodLevel READ getLODLevel) - - Q_PROPERTY(float lodDecreaseFPS READ getLODDecreaseFPS) - Q_PROPERTY(float lodIncreaseFPS READ getLODIncreaseFPS) - float getPresentTime() const { return _presentTime; } float getEngineRunTime() const { return _engineRunTime; } float getGPUTime() const { return _gpuTime; } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4384635147..50ff65ad1a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -810,6 +810,9 @@ Menu::Menu() { scriptEngines->loadScript(defaultScriptsLoc.toString()); }); + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::VerboseLogging, 0, false, + qApp, SLOT(updateVerboseLogging())); + #if 0 /// -------------- REMOVED FOR NOW -------------- addDisabledActionAndSeparator(navigateMenu, "History"); QAction* backAction = addActionToQMenuAndActionHash(navigateMenu, MenuOption::Back, 0, addressManager.data(), SLOT(goBack())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index bba70a6a89..c8c8ee42df 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -142,6 +142,7 @@ namespace MenuOption { const QString Pair = "Pair"; const QString PhysicsShowHulls = "Draw Collision Shapes"; const QString PhysicsShowOwned = "Highlight Simulation Ownership"; + const QString VerboseLogging = "Verbose Logging"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString Preferences = "General..."; const QString Quit = "Quit"; diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 3e0e4adf18..35e6ca1c92 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -615,9 +615,15 @@ void Wallet::updateImageProvider() { securityImageProvider->setSecurityImage(_securityImage); // inform tablet security image provider - QQmlEngine* tabletEngine = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")->getTabletSurface()->getSurfaceContext()->engine(); - securityImageProvider = reinterpret_cast(tabletEngine->imageProvider(SecurityImageProvider::PROVIDER_NAME)); - securityImageProvider->setSecurityImage(_securityImage); + TabletProxy* tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); + if (tablet) { + OffscreenQmlSurface* tabletSurface = tablet->getTabletSurface(); + if (tabletSurface) { + QQmlEngine* tabletEngine = tabletSurface->getSurfaceContext()->engine(); + securityImageProvider = reinterpret_cast(tabletEngine->imageProvider(SecurityImageProvider::PROVIDER_NAME)); + securityImageProvider->setSecurityImage(_securityImage); + } + } } void Wallet::chooseSecurityImage(const QString& filename) { diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index ee615cde20..a3c80bf1b6 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -108,11 +108,9 @@ AudioDeviceList::~AudioDeviceList() { // store the selected device foreach(std::shared_ptr adevice, _devices) { if (adevice->selectedDesktop) { - qDebug() << "Saving Desktop for" << _mode << "name" << adevice->info.deviceName(); settingDesktop.set(adevice->info.deviceName()); } if (adevice->selectedHMD) { - qDebug() << "Saving HMD for" << _mode << "name" << adevice->info.deviceName(); settingHMD.set(adevice->info.deviceName()); } } @@ -311,7 +309,6 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { } } - qDebug() << "adding audio device:" << device.display << device.selectedDesktop << device.selectedHMD << _mode; newDevices.push_back(newDevice(device)); } diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index f19caa8478..4fceda3b04 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -28,7 +28,7 @@ class ScriptEngine; /**jsdoc * The Controller API provides facilities to interact with computer and controller hardware. * - *
Functions:
+ *
Functions
* *

Properties

*
    @@ -143,6 +143,61 @@ class ScriptEngine; *
  • {@link Controller.stopInputPlayback|stopInputPlayback}
  • *
* + *
Entity Methods:
+ * + *

The default scripts implement hand controller actions that use {@link Entities.callEntityMethod} to call entity script + * methods, if present in the entity being interacted with.

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Method NameDescriptionExample
startFarTrigger
continueFarTrigger
stopFarTrigger
These methods are called when a user is more than 0.3m away from the entity, the entity is triggerable, and the + * user starts, continues, or stops squeezing the trigger.A light switch that can be toggled on and off from a distance.
startNearTrigger
continueNearTrigger
stopNearTrigger
These methods are called when a user is less than 0.3m away from the entity, the entity is triggerable, and the + * user starts, continues, or stops squeezing the trigger.A doorbell that can be rung when a user is near.
startDistanceGrab
continueDistanceGrab
These methods are called when a user is more than 0.3m away from the entity, the entity is either cloneable, or + * grabbable and not locked, and the user starts or continues to squeeze the trigger.A comet that emits icy particle trails when a user is dragging it through the sky.
startNearGrab
continueNearGrab
These methods are called when a user is less than 0.3m away from the entity, the entity is either cloneable, or + * grabbable and not locked, and the user starts or continues to squeeze the trigger.A ball that glows when it's being held close.
releaseGrabThis method is called when a user releases the trigger when having been either distance or near grabbing an + * entity.Turn off the ball glow or comet trail with the user finishes grabbing it.
startEquip
continueEquip
releaseEquip
These methods are called when a user starts, continues, or stops equipping an entity.A glass that stays in the user's hand after the trigger is clicked.
+ *

All the entity methods are called with the following two arguments:

+ *
    + *
  • The entity ID.
  • + *
  • A string, "hand,userID" — where "hand" is "left" or "right", and "userID" + * is the user's {@link MyAvatar|MyAvatar.sessionUUID}.
  • + *
+ * * @namespace Controller * * @property {Controller.Actions} Actions - Predefined actions on Interface and the user's avatar. These can be used as end diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 310a4cc1cd..d01e7d6671 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -80,7 +80,6 @@ void DialogsManager::showFeed() { } void DialogsManager::setDomainConnectionFailureVisibility(bool visible) { - qDebug() << "DialogsManager::setDomainConnectionFailureVisibility: visible" << visible; auto tabletScriptingInterface = DependencyManager::get(); auto tablet = dynamic_cast(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index 79004a72a6..9777e9c6af 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -588,6 +588,7 @@ void AnimExpression::evalUnaryMinus(const AnimVariantMap& map, std::stack #include #include diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h index 86a43c0c13..3c3858e2ba 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h @@ -39,7 +39,9 @@ class UserInputMapper; * methods. *
  • Use {@link Controller.parseMapping} or {@link Controller.loadMapping} to load a {@link Controller.MappingJSON}.
  • * - *

    Enable the mapping using {@link MappingObject#enable|enable} or {@link Controller.enableMapping} for it to take effect. + * + *

    Enable the mapping using {@link MappingObject#enable|enable} or {@link Controller.enableMapping} for it to take + * effect.

    * *

    Mappings and their routes are applied according to the following rules:

    *
      @@ -49,7 +51,7 @@ class UserInputMapper; * output that already has a route the new route is ignored. *
    • New mappings override previous mappings: each output is processed using the route in the most recently enabled * mapping that contains that output.
    • - *

      + *
    * * @class MappingObject */ diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h index 0336638068..d33f3e3383 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -29,7 +29,8 @@ class ScriptingInterface; *

    A route in a {@link MappingObject} used by the {@link Controller} API.

    * *

    Create a route using {@link MappingObject} methods and apply this object's methods to process it, terminating with - * {@link RouteObject#to} to apply it to a Standard control, action, or script function.

    + * {@link RouteObject#to} to apply it to a Standard control, action, or script function. Note: Loops are not + * permitted.

    * *

    Some methods apply to routes with number data, some apply routes with {@link Pose} data, and some apply to both route * types.

    diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index f333e805ce..693e3d0cf4 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -308,12 +308,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { item->setProperty(URL_PROPERTY, _lastSourceUrl); }); } else if (_contentType == ContentType::QmlContent) { - _webSurface->load(_lastSourceUrl, [this](QQmlContext* context, QObject* item) { - if (item && item->objectName() == "tabletRoot") { - auto tabletScriptingInterface = DependencyManager::get(); - tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data()); - } - }); + _webSurface->load(_lastSourceUrl); } _fadeStartTime = usecTimestampNow(); _webSurface->resume(); @@ -323,32 +318,21 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { void WebEntityRenderer::destroyWebSurface() { QSharedPointer webSurface; + ContentType contentType{ ContentType::NoContent }; withWriteLock([&] { webSurface.swap(_webSurface); + std::swap(contentType, _contentType); }); if (webSurface) { --_currentWebCount; QQuickItem* rootItem = webSurface->getRootItem(); - // Explicitly set the web URL to an empty string, in an effort to get a - // faster shutdown of any chromium processes interacting with audio - if (rootItem && _contentType == ContentType::HtmlContent) { - rootItem->setProperty(URL_PROPERTY, ""); - } - - if (rootItem && rootItem->objectName() == "tabletRoot") { - auto tabletScriptingInterface = DependencyManager::get(); - tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", nullptr); - } // Fix for crash in QtWebEngineCore when rapidly switching domains // Call stop on the QWebEngineView before destroying OffscreenQMLSurface. - if (rootItem) { - QObject* obj = rootItem->findChild("webEngineView"); - if (obj) { - // stop loading - QMetaObject::invokeMethod(obj, "stop"); - } + if (rootItem && contentType == ContentType::HtmlContent) { + // stop loading + QMetaObject::invokeMethod(rootItem, "stop"); } webSurface->pause(); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index d4a8b11453..5e76d18515 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -390,17 +390,18 @@ public slots: /**jsdoc * Find all entities of a particular name that intersect a sphere defined by a center point and radius. * @function Entities.findEntitiesByName - * @param {Entities.EntityType} entityName - The name of the entity to search for. + * @param {string} entityName - The name of the entity to search for. * @param {Vec3} center - The point about which to search. * @param {number} radius - The radius within which to search. - * @param {boolean} caseSensitiveSearch - Choose whether to to return case sensitive results back. - * @returns {Uuid[]} An array of entity IDs of the specified type that intersect the search sphere. The array is empty if - * no entities could be found. - * @example Get back a list of entities + * @param {boolean} [caseSensitive=false] - If true then the search is case-sensitive. + * @returns {Uuid[]} An array of entity IDs that have the specified name and intersect the search sphere. The array is empty + * if no entities could be found. + * @example Report the number of entities with the name, "Light-Target". * var entityIDs = Entities.findEntitiesByName("Light-Target", MyAvatar.position, 10, false); - * print("Number of Entities with the name Light-Target " + entityIDs.length); + * print("Number of entities with the name "Light-Target": " + entityIDs.length); */ - Q_INVOKABLE QVector findEntitiesByName(const QString entityName, const glm::vec3& center, float radius, bool caseSensitiveSearch = false ) const; + Q_INVOKABLE QVector findEntitiesByName(const QString entityName, const glm::vec3& center, float radius, + bool caseSensitiveSearch = false ) const; /**jsdoc * Find the first entity intersected by a {@link PickRay}. Light and Zone entities are not diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 1e59646795..86422ef70c 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -996,14 +996,12 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS QByteArray filename = subobject.properties.at(0).toByteArray(); QByteArray filepath = filename.replace('\\', '/'); filename = fileOnUrl(filepath, url); - qDebug() << "Filename" << filepath << filename; _textureFilepaths.insert(getID(object.properties), filepath); _textureFilenames.insert(getID(object.properties), filename); } else if (subobject.name == "TextureName" && subobject.properties.length() >= TEXTURE_NAME_MIN_SIZE) { // trim the name from the timestamp QString name = QString(subobject.properties.at(0).toByteArray()); name = name.left(name.indexOf('[')); - qDebug() << "Filename" << name; _textureNames.insert(getID(object.properties), name); } else if (subobject.name == "Texture_Alpha_Source" && subobject.properties.length() >= TEXTURE_ALPHA_SOURCE_MIN_SIZE) { tex.assign(tex.alphaSource, subobject.properties.at(0).value()); diff --git a/libraries/networking/src/EntityScriptClient.cpp b/libraries/networking/src/EntityScriptClient.cpp index 75ae7369fb..1eab5bf2d7 100644 --- a/libraries/networking/src/EntityScriptClient.cpp +++ b/libraries/networking/src/EntityScriptClient.cpp @@ -192,8 +192,6 @@ void EntityScriptClient::handleNodeClientConnectionReset(SharedNodePointer node) return; } - //qCDebug(entity_script_client) << "EntityScriptClient detected client connection reset handshake with Asset Server - failing any pending requests"; - forceFailureOfPendingRequests(node); } diff --git a/libraries/networking/src/NetworkLogging.h b/libraries/networking/src/NetworkLogging.h index 518c600efe..30116ff405 100644 --- a/libraries/networking/src/NetworkLogging.h +++ b/libraries/networking/src/NetworkLogging.h @@ -17,7 +17,6 @@ Q_DECLARE_LOGGING_CATEGORY(resourceLog) Q_DECLARE_LOGGING_CATEGORY(networking) Q_DECLARE_LOGGING_CATEGORY(asset_client) -Q_DECLARE_LOGGING_CATEGORY(entity_script_client) Q_DECLARE_LOGGING_CATEGORY(messages_client) #endif // hifi_NetworkLogging_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 35db43e5e7..2efd32f2e8 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -795,9 +795,10 @@ QString getMarketplaceID(const QString& urlString) { } bool Octree::readFromURL(const QString& urlString) { - QString marketplaceID = getMarketplaceID(urlString); + QString trimmedUrl = urlString.trimmed(); + QString marketplaceID = getMarketplaceID(trimmedUrl); auto request = - std::unique_ptr(DependencyManager::get()->createResourceRequest(this, urlString)); + std::unique_ptr(DependencyManager::get()->createResourceRequest(this, trimmedUrl)); if (!request) { return false; diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index ab7c2ec252..3ea3616b15 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -153,6 +153,8 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { // remove the objects (aka MotionStates) from physics _physicsEngine->removeSetOfObjects(_physicalObjects); + clearOwnershipData(); + // delete the MotionStates for (auto stateItr : _physicalObjects) { EntityMotionState* motionState = static_cast(&(*stateItr)); @@ -165,7 +167,6 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { _physicalObjects.clear(); // clear all other lists specific to this derived class - clearOwnershipData(); _entitiesToRemoveFromPhysics.clear(); _entitiesToAddToPhysics.clear(); _incomingChanges.clear(); diff --git a/libraries/qml/src/qml/impl/SharedObject.cpp b/libraries/qml/src/qml/impl/SharedObject.cpp index 9253c41b39..2fde057ca8 100644 --- a/libraries/qml/src/qml/impl/SharedObject.cpp +++ b/libraries/qml/src/qml/impl/SharedObject.cpp @@ -90,19 +90,23 @@ SharedObject::~SharedObject() { _renderControl = nullptr; } + if (_rootItem) { + delete _rootItem; + _rootItem = nullptr; + } + if (_quickWindow) { _quickWindow->destroy(); delete _quickWindow; _quickWindow = nullptr; } - // _rootItem is parented to the quickWindow, so needs no explicit destruction - //if (_rootItem) { - // delete _rootItem; - // _rootItem = nullptr; - //} - - releaseEngine(_qmlContext->engine()); + if (_qmlContext) { + auto engine = _qmlContext->engine(); + delete _qmlContext; + _qmlContext = nullptr; + releaseEngine(engine); + } } void SharedObject::create(OffscreenSurface* surface) { @@ -210,9 +214,9 @@ QQmlEngine* SharedObject::acquireEngine(OffscreenSurface* surface) { if (!globalEngine) { Q_ASSERT(0 == globalEngineRefCount); globalEngine = new QQmlEngine(); - surface->initializeQmlEngine(result); - ++globalEngineRefCount; + surface->initializeEngine(result); } + ++globalEngineRefCount; result = globalEngine; #else result = new QQmlEngine(); diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 90424b04b2..7086b65f4c 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -16,6 +16,7 @@ #include "AbstractViewStateInterface.h" #include "RenderUtilsLogging.h" #include "DebugDraw.h" +#include "StencilMaskPass.h" #include "animdebugdraw_vert.h" #include "animdebugdraw_frag.h" @@ -70,7 +71,7 @@ public: typedef render::Payload AnimDebugDrawPayload; namespace render { - template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::opaqueShape() : ItemKey::Builder::opaqueShape().withInvisible()).withTagBits(ItemKey::TAG_BITS_ALL); } + template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::transparentShape() : ItemKey::Builder::transparentShape().withInvisible()).withTagBits(ItemKey::TAG_BITS_ALL); } template <> const Item::Bound payloadGetBound(const AnimDebugDrawData::Pointer& data) { return data->_bound; } template <> void payloadRender(const AnimDebugDrawData::Pointer& data, RenderArgs* args) { data->render(args); @@ -104,6 +105,7 @@ AnimDebugDraw::AnimDebugDraw() : state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + PrepareStencil::testMaskDrawShape(*state.get()); auto vertShader = animdebugdraw_vert::getShader(); auto fragShader = animdebugdraw_frag::getShader(); auto program = gpu::Shader::createProgram(vertShader, fragShader); diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index e620fc2d61..dd4bda2e37 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -198,7 +198,7 @@ Antialiasing::~Antialiasing() { _antialiasingTextures[1].reset(); } -const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { +const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline(const render::RenderContextPointer& renderContext) { if (!_antialiasingPipeline) { @@ -207,17 +207,6 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("taaParamsBuffer"), AntialiasingPass_ParamsSlot)); - - slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), AntialiasingPass_FrameTransformSlot)); - - slotBindings.insert(gpu::Shader::Binding(std::string("historyMap"), AntialiasingPass_HistoryMapSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("sourceMap"), AntialiasingPass_SourceMapSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("velocityMap"), AntialiasingPass_VelocityMapSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), AntialiasingPass_DepthMapSlot)); - - - gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -225,6 +214,21 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { // Good to go add the brand new pipeline _antialiasingPipeline = gpu::Pipeline::create(program, state); + + gpu::doInBatch("SurfaceGeometryPass::CurvaturePipeline", renderContext->args->_context, [program](gpu::Batch& batch) { + batch.runLambda([program]() { + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("taaParamsBuffer"), AntialiasingPass_ParamsSlot)); + + slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), AntialiasingPass_FrameTransformSlot)); + + slotBindings.insert(gpu::Shader::Binding(std::string("historyMap"), AntialiasingPass_HistoryMapSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("sourceMap"), AntialiasingPass_SourceMapSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("velocityMap"), AntialiasingPass_VelocityMapSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), AntialiasingPass_DepthMapSlot)); + gpu::Shader::makeProgram(*program, slotBindings); + }); + }); } return _antialiasingPipeline; @@ -347,7 +351,7 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const batch.setViewportTransform(args->_viewport); // TAA step - getAntialiasingPipeline(); + getAntialiasingPipeline(renderContext); batch.setResourceFramebufferSwapChainTexture(AntialiasingPass_HistoryMapSlot, _antialiasingBuffers, 0); batch.setResourceTexture(AntialiasingPass_SourceMapSlot, sourceBuffer->getRenderBuffer(0)); batch.setResourceTexture(AntialiasingPass_VelocityMapSlot, velocityBuffer->getVelocityTexture()); @@ -358,7 +362,7 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const batch.setUniformBuffer(AntialiasingPass_FrameTransformSlot, deferredFrameTransform->getFrameTransformBuffer()); batch.setFramebufferSwapChain(_antialiasingBuffers, 1); - batch.setPipeline(getAntialiasingPipeline()); + batch.setPipeline(getAntialiasingPipeline(renderContext)); batch.draw(gpu::TRIANGLE_STRIP, 4); // Blend step diff --git a/libraries/render-utils/src/AntialiasingEffect.h b/libraries/render-utils/src/AntialiasingEffect.h index a89666f58b..9f62fd76c1 100644 --- a/libraries/render-utils/src/AntialiasingEffect.h +++ b/libraries/render-utils/src/AntialiasingEffect.h @@ -174,7 +174,7 @@ public: void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); - const gpu::PipelinePointer& getAntialiasingPipeline(); + const gpu::PipelinePointer& getAntialiasingPipeline(const render::RenderContextPointer& renderContext); const gpu::PipelinePointer& getBlendPipeline(); const gpu::PipelinePointer& getDebugBlendPipeline(); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index d3bf3ab198..51046f10b3 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -168,7 +168,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con outputs.edit4() = halfNormalTexture; auto linearDepthPipeline = getLinearDepthPipeline(renderContext); - auto downsamplePipeline = getDownsamplePipeline(); + auto downsamplePipeline = getDownsamplePipeline(renderContext); auto depthViewport = args->_viewport; auto halfViewport = depthViewport >> 1; @@ -241,19 +241,12 @@ const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline(const render } -const gpu::PipelinePointer& LinearDepthPass::getDownsamplePipeline() { +const gpu::PipelinePointer& LinearDepthPass::getDownsamplePipeline(const render::RenderContextPointer& renderContext) { if (!_downsamplePipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto ps = surfaceGeometry_downsampleDepthNormal_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DepthLinearPass_FrameTransformSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("linearDepthMap"), DepthLinearPass_DepthMapSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), DepthLinearPass_NormalMapSlot)); - gpu::Shader::makeProgram(*program, slotBindings); - - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); PrepareStencil::testShape(*state); @@ -261,6 +254,16 @@ const gpu::PipelinePointer& LinearDepthPass::getDownsamplePipeline() { // Good to go add the brand new pipeline _downsamplePipeline = gpu::Pipeline::create(program, state); + + gpu::doInBatch("LinearDepthPass::run", renderContext->args->_context, [program](gpu::Batch& batch) { + batch.runLambda([program]() { + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", DepthLinearPass_FrameTransformSlot)); + slotBindings.insert(gpu::Shader::Binding("linearDepthMap", DepthLinearPass_DepthMapSlot)); + slotBindings.insert(gpu::Shader::Binding("normalMap", DepthLinearPass_NormalMapSlot)); + gpu::Shader::makeProgram(*program, slotBindings); + }); + }); } return _downsamplePipeline; diff --git a/libraries/render-utils/src/SurfaceGeometryPass.h b/libraries/render-utils/src/SurfaceGeometryPass.h index 501cf3fa87..367f599f67 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.h +++ b/libraries/render-utils/src/SurfaceGeometryPass.h @@ -84,7 +84,7 @@ private: const gpu::PipelinePointer& getLinearDepthPipeline(const render::RenderContextPointer& renderContext); gpu::PipelinePointer _linearDepthPipeline; - const gpu::PipelinePointer& getDownsamplePipeline(); + const gpu::PipelinePointer& getDownsamplePipeline(const render::RenderContextPointer& renderContext); gpu::PipelinePointer _downsamplePipeline; gpu::RangeTimerPointer _gpuTimer; diff --git a/libraries/render-utils/src/VelocityBufferPass.cpp b/libraries/render-utils/src/VelocityBufferPass.cpp index 78471d48af..3f7da4cdcd 100644 --- a/libraries/render-utils/src/VelocityBufferPass.cpp +++ b/libraries/render-utils/src/VelocityBufferPass.cpp @@ -113,7 +113,7 @@ void VelocityBufferPass::run(const render::RenderContextPointer& renderContext, outputs.edit1() = velocityFBO; outputs.edit2() = velocityTexture; - auto cameraMotionPipeline = getCameraMotionPipeline(); + auto cameraMotionPipeline = getCameraMotionPipeline(renderContext); auto fullViewport = args->_viewport; @@ -143,18 +143,12 @@ void VelocityBufferPass::run(const render::RenderContextPointer& renderContext, } -const gpu::PipelinePointer& VelocityBufferPass::getCameraMotionPipeline() { +const gpu::PipelinePointer& VelocityBufferPass::getCameraMotionPipeline(const render::RenderContextPointer& renderContext) { if (!_cameraMotionPipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto ps = velocityBuffer_cameraMotion_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), VelocityBufferPass_FrameTransformSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), VelocityBufferPass_DepthMapSlot)); - gpu::Shader::makeProgram(*program, slotBindings); - - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); // Stencil test the curvature pass for objects pixels only, not the background @@ -164,6 +158,16 @@ const gpu::PipelinePointer& VelocityBufferPass::getCameraMotionPipeline() { // Good to go add the brand new pipeline _cameraMotionPipeline = gpu::Pipeline::create(program, state); + + gpu::doInBatch("VelocityBufferPass::CameraMotionPipeline", renderContext->args->_context, + [program](gpu::Batch& batch) { + batch.runLambda([program]() { + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), VelocityBufferPass_FrameTransformSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), VelocityBufferPass_DepthMapSlot)); + gpu::Shader::makeProgram(*program, slotBindings); + }); + }); } return _cameraMotionPipeline; diff --git a/libraries/render-utils/src/VelocityBufferPass.h b/libraries/render-utils/src/VelocityBufferPass.h index fb2b729368..50b994f6db 100644 --- a/libraries/render-utils/src/VelocityBufferPass.h +++ b/libraries/render-utils/src/VelocityBufferPass.h @@ -79,7 +79,7 @@ private: VelocityFramebufferPointer _velocityFramebuffer; - const gpu::PipelinePointer& getCameraMotionPipeline(); + const gpu::PipelinePointer& getCameraMotionPipeline(const render::RenderContextPointer& renderContext); gpu::PipelinePointer _cameraMotionPipeline; gpu::RangeTimerPointer _gpuTimer; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index c79ffffec7..f0a13cc62b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -2161,6 +2161,32 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& }, forceRedownload); } +/**jsdoc + * Triggered when the script starts for a user. + *

    Note: Can only be connected to via this.preload = function (...) { ... } in the entity script.

    + *
    Available in:Client Entity ScriptsServer Entity Scripts
    + * @function Entities.preload + * @param {Uuid} entityID - The ID of the entity that the script is running in. + * @returns {Signal} + * @example Get the ID of the entity that a client entity script is running in. + * var entityScript = (function () { + * this.entityID = Uuid.NULL; + * + * this.preload = function (entityID) { + * this.entityID = entityID; + * print("Entity ID: " + this.entityID); + * }; + * ); + * + * var entityID = Entities.addEntity({ + * type: "Box", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 0.5, y: 0.5, z: 0.5 }, + * color: { red: 255, green: 0, blue: 0 }, + * script: "(" + entityScript + ")", // Could host the script on a Web server instead. + * lifetime: 300 // Delete after 5 minutes. + * }); + */ // since all of these operations can be asynch we will always do the actual work in the response handler // for the download void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success , const QString& status) { @@ -2345,6 +2371,13 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co processDeferredEntityLoads(entityScript, entityID); } +/**jsdoc + * Triggered when the script terminates for a user. + *

    Note: Can only be connected to via this.unoad = function () { ... } in the entity script.

    + *
    Available in:Client Entity ScriptsServer Entity Scripts
    + * @function Entities.unload + * @returns {Signal} + */ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 871705d74b..a788cd9f0e 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -273,9 +273,9 @@ QVariantList ScriptEngines::getRunning() { } else { displayURLString = displayURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded)); } - resultNode.insert("url", displayURLString); // The path contains the exact path/URL of the script, which also is used in the stopScript function. - resultNode.insert("path", normalizeScriptURL(runningScript).toString()); + resultNode.insert("path", displayURLString); + resultNode.insert("url", normalizeScriptURL(runningScript).toString()); resultNode.insert("local", runningScriptURL.isLocalFile()); result.append(resultNode); } @@ -538,7 +538,6 @@ int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) { int ii=0; for (auto initializer : _scriptInitializers) { ii++; - qDebug() << "initializer" << ii; initializer(scriptEngine); } return ii; diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index b1ceab4149..c7ad4a790d 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -213,7 +213,7 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio int byteForSection = (BITS_IN_OCTAL * section / BITS_IN_BYTE); unsigned char* byteAt = octalCode + 1 + byteForSection; char bitInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE; - char shiftBy = BITS_IN_BYTE - bitInByte - BITS_IN_OCTAL; + int8_t shiftBy = BITS_IN_BYTE - bitInByte - BITS_IN_OCTAL; const unsigned char UNSHIFTED_MASK = 0x07; unsigned char shiftedMask; unsigned char shiftedValue; diff --git a/libraries/shared/src/Trace.h b/libraries/shared/src/Trace.h index 93e2c6c4c2..1e1326968f 100644 --- a/libraries/shared/src/Trace.h +++ b/libraries/shared/src/Trace.h @@ -102,6 +102,9 @@ private: }; inline void traceEvent(const QLoggingCategory& category, const QString& name, EventType type, const QString& id = "", const QVariantMap& args = {}, const QVariantMap& extra = {}) { + if (!DependencyManager::isSet()) { + return; + } const auto& tracer = DependencyManager::get(); if (tracer) { tracer->traceEvent(category, name, type, id, args, extra); diff --git a/libraries/shared/src/shared/MiniPromises.cpp b/libraries/shared/src/shared/MiniPromises.cpp index bb78852c29..21a3f44d50 100644 --- a/libraries/shared/src/shared/MiniPromises.cpp +++ b/libraries/shared/src/shared/MiniPromises.cpp @@ -22,6 +22,5 @@ namespace { } void MiniPromise::registerMetaTypes(QObject* engine) { auto scriptEngine = qobject_cast(engine); - qDebug() << "----------------------- MiniPromise::registerMetaTypes ------------" << scriptEngine; qScriptRegisterMetaType(scriptEngine, promiseToScriptValue, promiseFromScriptValue); } diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp index 8fe1454242..b983213e4a 100644 --- a/libraries/shared/src/shared/Storage.cpp +++ b/libraries/shared/src/shared/Storage.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include "StorageLogging.h" Q_LOGGING_CATEGORY(storagelogging, "hifi.core.storage") @@ -102,4 +102,4 @@ FileStorage::~FileStorage() { if (_file.isOpen()) { _file.close(); } -} \ No newline at end of file +} diff --git a/libraries/shared/src/shared/StorageLogging.h b/libraries/shared/src/shared/StorageLogging.h new file mode 100644 index 0000000000..33d89411bd --- /dev/null +++ b/libraries/shared/src/shared/StorageLogging.h @@ -0,0 +1,18 @@ +// +// StorageLogging.h +// +// Created by Seth Alves on 2018-4-20 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_StorageLogging_h +#define hifi_StorageLogging_h + +#include + +Q_DECLARE_LOGGING_CATEGORY(storagelogging) + +#endif // hifi_StorageLogging_h diff --git a/libraries/ui/src/ui/Logging.h b/libraries/ui/src/ui/Logging.h index 6d31b0e86a..dd14268dba 100644 --- a/libraries/ui/src/ui/Logging.h +++ b/libraries/ui/src/ui/Logging.h @@ -6,8 +6,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_Controllers_Logging_h -#define hifi_Controllers_Logging_h +#ifndef hifi_UI_Logging_h +#define hifi_UI_Logging_h #include diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 43b573a169..48e778c063 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -102,7 +102,7 @@ class AudioHandler : public QObject, QRunnable { public: AudioHandler(OffscreenQmlSurface* surface, const QString& deviceName, QObject* parent = nullptr); - virtual ~AudioHandler() { qDebug() << "Audio Handler Destroyed"; } + virtual ~AudioHandler() { } void run() override; @@ -115,6 +115,7 @@ private: class UrlHandler : public QObject { Q_OBJECT public: + UrlHandler(QObject* parent = nullptr) : QObject(parent) {} Q_INVOKABLE bool canHandleUrl(const QString& url) { static auto handler = dynamic_cast(qApp); return handler && handler->canAcceptURL(url); @@ -223,6 +224,17 @@ void AudioHandler::run() { qDebug() << "QML Audio changed to " << _newTargetDevice; } +OffscreenQmlSurface::~OffscreenQmlSurface() { + clearFocusItem(); +} + +void OffscreenQmlSurface::clearFocusItem() { + if (_currentFocusItem) { + disconnect(_currentFocusItem, &QObject::destroyed, this, &OffscreenQmlSurface::focusDestroyed); + } + _currentFocusItem = nullptr; +} + void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) { Parent::initializeEngine(engine); new QQmlFileSelector(engine); @@ -246,7 +258,7 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) { auto rootContext = engine->rootContext(); rootContext->setContextProperty("GL", ::getGLContextData()); - rootContext->setContextProperty("urlHandler", new UrlHandler()); + rootContext->setContextProperty("urlHandler", new UrlHandler(rootContext)); rootContext->setContextProperty("resourceDirectoryUrl", QUrl::fromLocalFile(PathUtils::resourcesPath())); rootContext->setContextProperty("ApplicationInterface", qApp); auto javaScriptToInject = getEventBridgeJavascript(); @@ -545,17 +557,15 @@ bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QT } void OffscreenQmlSurface::focusDestroyed(QObject* obj) { - if (_currentFocusItem) { - disconnect(_currentFocusItem, &QObject::destroyed, this, &OffscreenQmlSurface::focusDestroyed); - } - _currentFocusItem = nullptr; + clearFocusItem(); } void OffscreenQmlSurface::onFocusObjectChanged(QObject* object) { + clearFocusItem(); + QQuickItem* item = static_cast(object); if (!item) { setFocusText(false); - _currentFocusItem = nullptr; return; } @@ -563,10 +573,6 @@ void OffscreenQmlSurface::onFocusObjectChanged(QObject* object) { qApp->sendEvent(object, &query); setFocusText(query.value(Qt::ImEnabled).toBool()); - if (_currentFocusItem) { - disconnect(_currentFocusItem, &QObject::destroyed, this, 0); - } - // Raise and lower keyboard for QML text fields. // HTML text fields are handled in emitWebEvent() methods - testing READ_ONLY_PROPERTY prevents action for HTML files. const char* READ_ONLY_PROPERTY = "readOnly"; diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 9fa86f12a3..b95a8f117d 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -22,7 +22,8 @@ class OffscreenQmlSurface : public hifi::qml::OffscreenSurface { Q_OBJECT Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged) public: - + ~OffscreenQmlSurface(); + static void addWhitelistContextHandler(const std::initializer_list& urls, const QmlContextCallback& callback); static void addWhitelistContextHandler(const QUrl& url, const QmlContextCallback& callback) { addWhitelistContextHandler({ { url } }, callback); }; @@ -58,6 +59,7 @@ public slots: void sendToQml(const QVariant& message); protected: + void clearFocusItem(); void setFocusText(bool newFocusText); void initializeEngine(QQmlEngine* engine) override; void onRootContextCreated(QQmlContext* qmlContext) override; diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 6d2b1f129b..c99c8d401a 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -1291,6 +1291,7 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", MENU_EASE_ON_FOCUS); Menu.removeMenuItem("Edit", MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE); Menu.removeMenuItem("Edit", MENU_SHOW_ZONES_IN_EDIT_MODE); + Menu.removeMenuItem("Edit", MENU_CREATE_ENTITIES_GRABBABLE); } Script.scriptEnding.connect(function () { diff --git a/scripts/system/particle_explorer/particleExplorer.js b/scripts/system/particle_explorer/particleExplorer.js index 3598f30ee0..099c4be9e3 100644 --- a/scripts/system/particle_explorer/particleExplorer.js +++ b/scripts/system/particle_explorer/particleExplorer.js @@ -321,7 +321,8 @@ { id: "alpha", name: "Alpha", - type: "SliderFloat" + type: "SliderFloat", + max: 1.0 }, { type: "Row" @@ -329,7 +330,8 @@ { id: "alphaSpread", name: "Alpha Spread", - type: "SliderFloat" + type: "SliderFloat", + max: 1.0 }, { type: "Row" @@ -337,7 +339,8 @@ { id: "alphaStart", name: "Alpha Start", - type: "SliderFloat" + type: "SliderFloat", + max: 1.0 }, { type: "Row" @@ -345,7 +348,8 @@ { id: "alphaFinish", name: "Alpha Finish", - type: "SliderFloat" + type: "SliderFloat", + max: 1.0 }, { type: "Row" diff --git a/tests/controllers/CMakeLists.txt b/tests/controllers/CMakeLists.txt index b5e866ccce..ce1c150ed4 100644 --- a/tests/controllers/CMakeLists.txt +++ b/tests/controllers/CMakeLists.txt @@ -23,5 +23,9 @@ if (WIN32) add_dependency_external_projects(wasapi) endif() +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + target_link_libraries(${TARGET_NAME} atomic) +endif() + package_libraries_for_deployment() -endif() \ No newline at end of file +endif() diff --git a/tests/qml/qml/controls/WebEntityView.qml b/tests/qml/qml/controls/WebEntityView.qml new file mode 100644 index 0000000000..5bd29ef457 --- /dev/null +++ b/tests/qml/qml/controls/WebEntityView.qml @@ -0,0 +1,47 @@ +// +// WebEntityView.qml +// +// Created by Kunal Gosar on 16 March 2017 +// Copyright 2017 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 +// + +import QtQuick 2.5 +import QtWebEngine 1.5 +import Hifi 1.0 + +/* +TestItem { + Rectangle { + anchors.fill: parent + anchors.margins: 10 + color: "blue" + property string url: "" + ColorAnimation on color { + loops: Animation.Infinite; from: "blue"; to: "yellow"; duration: 1000 + } + } +} +*/ + +WebEngineView { + id: webViewCore + objectName: "webEngineView" + width: parent !== null ? parent.width : undefined + height: parent !== null ? parent.height : undefined + + onFeaturePermissionRequested: { + grantFeaturePermission(securityOrigin, feature, true); + } + + //disable popup + onContextMenuRequested: { + request.accepted = true; + } + + onNewViewRequested: { + newViewRequestedCallback(request) + } +} diff --git a/tests/qml/src/main.cpp b/tests/qml/src/main.cpp index 022f7290f4..349ac55d88 100644 --- a/tests/qml/src/main.cpp +++ b/tests/qml/src/main.cpp @@ -28,52 +28,87 @@ #include #include #include - +#include #include #include +#include + #include -#include #include #include #include #include #include #include +#include +#include +namespace gl { +extern void initModuleGl(); +} -class OffscreenQmlSurface : public hifi::qml::OffscreenSurface { +class QTestItem : public QQuickItem { + Q_OBJECT +public: + QTestItem(QQuickItem* parent = nullptr) : QQuickItem(parent) { qDebug() << __FUNCTION__; } + ~QTestItem() { qDebug() << __FUNCTION__; } +}; + +QUrl getTestResource(const QString& relativePath) { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; + qDebug() << "Resources Path: " << dir; + } + return QUrl::fromLocalFile(dir + relativePath); +} + +#define DIVISIONS_X 5 +#define DIVISIONS_Y 5 + +using QmlPtr = QSharedPointer; +using TextureAndFence = hifi::qml::OffscreenSurface::TextureAndFence; + +struct QmlInfo { + QmlPtr surface; + GLuint texture{ 0 }; + uint64_t lifetime{ 0 }; }; class TestWindow : public QWindow { - public: TestWindow(); - private: - using TextureAndFence = hifi::qml::OffscreenSurface::TextureAndFence; QOpenGLContext _glContext; OffscreenGLCanvas _sharedContext; - OffscreenQmlSurface _offscreenQml; + std::array, DIVISIONS_X> _surfaces; + QOpenGLFunctions_4_5_Core _glf; - uint32_t _currentTexture{ 0 }; - GLsync _readFence{ 0 }; std::function _discardLamdba; QSize _size; + size_t _surfaceCount{ 0 }; GLuint _fbo{ 0 }; const QSize _qmlSize{ 640, 480 }; bool _aboutToQuit{ false }; + uint64_t _createStopTime; void initGl(); + void updateSurfaces(); + void buildSurface(QmlInfo& qmlInfo, bool allowVideo); + void destroySurface(QmlInfo& qmlInfo); void resizeWindow(const QSize& size); void draw(); void resizeEvent(QResizeEvent* ev) override; }; TestWindow::TestWindow() { - setSurfaceType(QSurface::OpenGLSurface); + Setting::init(); + setSurfaceType(QSurface::OpenGLSurface); QSurfaceFormat format; format.setDepthBufferSize(24); format.setStencilBufferSize(8); @@ -83,13 +118,16 @@ TestWindow::TestWindow() { QSurfaceFormat::setDefaultFormat(format); setFormat(format); + qmlRegisterType("Hifi", 1, 0, "TestItem"); + show(); + _createStopTime = usecTimestampNow() + (3000u * USECS_PER_SECOND); resize(QSize(800, 600)); auto timer = new QTimer(this); timer->setTimerType(Qt::PreciseTimer); - timer->setInterval(5); + timer->setInterval(30); connect(timer, &QTimer::timeout, [&] { draw(); }); timer->start(); @@ -97,7 +135,6 @@ TestWindow::TestWindow() { timer->stop(); _aboutToQuit = true; }); - } void TestWindow::initGl() { @@ -105,6 +142,7 @@ void TestWindow::initGl() { if (!_glContext.create() || !_glContext.makeCurrent(this)) { qFatal("Unable to intialize Window GL context"); } + gl::initModuleGl(); _glf.initializeOpenGLFunctions(); _glf.glCreateFramebuffers(1, &_fbo); @@ -113,15 +151,97 @@ void TestWindow::initGl() { qFatal("Unable to intialize Shared GL context"); } hifi::qml::OffscreenSurface::setSharedContext(_sharedContext.getContext()); - _discardLamdba = _offscreenQml.getDiscardLambda(); - _offscreenQml.resize({ 640, 480 }); - _offscreenQml.load(QUrl::fromLocalFile("C:/Users/bdavi/Git/hifi/tests/qml/qml/main.qml")); + _discardLamdba = hifi::qml::OffscreenSurface::getDiscardLambda(); } void TestWindow::resizeWindow(const QSize& size) { _size = size; } +static const int DEFAULT_MAX_FPS = 10; +static const QString CONTROL_URL{ "/qml/controls/WebEntityView.qml" }; +static const char* URL_PROPERTY{ "url" }; + +QString getSourceUrl(bool video) { + static const std::vector SOURCE_URLS{ + "https://www.reddit.com/wiki/random", + "https://en.wikipedia.org/wiki/Wikipedia:Random", + "https://slashdot.org/", + }; + + static const std::vector VIDEO_SOURCE_URLS{ + "https://www.youtube.com/watch?v=gDXwhHm4GhM", + "https://www.youtube.com/watch?v=Ch_hoYPPeGc", + }; + + const auto& sourceUrls = video ? VIDEO_SOURCE_URLS : SOURCE_URLS; + auto index = rand() % sourceUrls.size(); + return sourceUrls[index]; +} + +void TestWindow::buildSurface(QmlInfo& qmlInfo, bool video) { + ++_surfaceCount; + auto lifetimeSecs = (uint32_t)(5.0f + (randFloat() * 10.0f)); + auto lifetimeUsecs = (USECS_PER_SECOND * lifetimeSecs); + qmlInfo.lifetime = lifetimeUsecs + usecTimestampNow(); + qmlInfo.texture = 0; + qmlInfo.surface.reset(new hifi::qml::OffscreenSurface()); + qmlInfo.surface->load(getTestResource(CONTROL_URL), [video](QQmlContext* context, QQuickItem* item) { + item->setProperty(URL_PROPERTY, getSourceUrl(video)); + }); + qmlInfo.surface->setMaxFps(DEFAULT_MAX_FPS); + qmlInfo.surface->resize(_qmlSize); + qmlInfo.surface->resume(); +} + +void TestWindow::destroySurface(QmlInfo& qmlInfo) { + auto& surface = qmlInfo.surface; + auto webView = surface->getRootItem(); + if (webView) { + // stop loading + QMetaObject::invokeMethod(webView, "stop"); + webView->setProperty(URL_PROPERTY, "about:blank"); + } + surface->pause(); + surface.reset(); +} + +void TestWindow::updateSurfaces() { + auto now = usecTimestampNow(); + // Fetch any new textures + for (size_t x = 0; x < DIVISIONS_X; ++x) { + for (size_t y = 0; y < DIVISIONS_Y; ++y) { + auto& qmlInfo = _surfaces[x][y]; + if (!qmlInfo.surface) { + if (now < _createStopTime && randFloat() > 0.99f) { + buildSurface(qmlInfo, x == 0 && y == 0); + } else { + continue; + } + } + + if (now > qmlInfo.lifetime) { + destroySurface(qmlInfo); + continue; + } + + auto& surface = qmlInfo.surface; + auto& currentTexture = qmlInfo.texture; + + TextureAndFence newTextureAndFence; + if (surface->fetchTexture(newTextureAndFence)) { + if (currentTexture != 0) { + auto readFence = _glf.glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + _discardLamdba(currentTexture, readFence); + } + currentTexture = newTextureAndFence.first; + _glf.glWaitSync((GLsync)newTextureAndFence.second, 0, GL_TIMEOUT_IGNORED); + } + } + } +} + void TestWindow::draw() { if (_aboutToQuit) { return; @@ -140,38 +260,30 @@ void TestWindow::draw() { return; } + updateSurfaces(); + + auto size = this->geometry().size(); + auto incrementX = size.width() / DIVISIONS_X; + auto incrementY = size.height() / DIVISIONS_Y; + _glf.glViewport(0, 0, size.width(), size.height()); _glf.glClearColor(1, 0, 0, 1); _glf.glClear(GL_COLOR_BUFFER_BIT); - - TextureAndFence newTextureAndFence; - if (_offscreenQml.fetchTexture(newTextureAndFence)) { - if (_currentTexture) { - _discardLamdba(_currentTexture, _readFence); - _readFence = 0; + for (uint32_t x = 0; x < DIVISIONS_X; ++x) { + for (uint32_t y = 0; y < DIVISIONS_Y; ++y) { + auto& qmlInfo = _surfaces[x][y]; + if (!qmlInfo.surface || !qmlInfo.texture) { + continue; + } + _glf.glNamedFramebufferTexture(_fbo, GL_COLOR_ATTACHMENT0, qmlInfo.texture, 0); + _glf.glBlitNamedFramebuffer(_fbo, 0, + // src coordinates + 0, 0, _qmlSize.width() - 1, _qmlSize.height() - 1, + // dst coordinates + incrementX * x, incrementY * y, incrementX * (x + 1), incrementY * (y + 1), + // blit mask and filter + GL_COLOR_BUFFER_BIT, GL_NEAREST); } - - _currentTexture = newTextureAndFence.first; - _glf.glWaitSync((GLsync)newTextureAndFence.second, 0, GL_TIMEOUT_IGNORED); - _glf.glNamedFramebufferTexture(_fbo, GL_COLOR_ATTACHMENT0, _currentTexture, 0); } - - auto diff = _size - _qmlSize; - diff /= 2; - auto qmlExtent = diff + _qmlSize; - - if (_currentTexture) { - _glf.glBlitNamedFramebuffer(_fbo, 0, - 0, 0, _qmlSize.width() - 1, _qmlSize.height() - 1, - diff.width(), diff.height(), qmlExtent.width() - 1, qmlExtent.height() - 2, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - - if (_readFence) { - _glf.glDeleteSync(_readFence); - } - _readFence = _glf.glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - _glf.glFlush(); - _glContext.swapBuffers(this); } @@ -180,11 +292,9 @@ void TestWindow::resizeEvent(QResizeEvent* ev) { } int main(int argc, char** argv) { - setupHifiApplication("QML Test"); - QGuiApplication app(argc, argv); TestWindow window; - app.exec(); - return 0; + return app.exec(); } +#include "main.moc" diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index fd4d8d88dd..d688474379 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -27,6 +27,10 @@ if (WIN32) add_dependency_external_projects(wasapi) endif() +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + target_link_libraries(${TARGET_NAME} atomic) +endif() + package_libraries_for_deployment() diff --git a/tools/jsdoc/plugins/hifi.js b/tools/jsdoc/plugins/hifi.js index 7c643d398c..5092e8b809 100644 --- a/tools/jsdoc/plugins/hifi.js +++ b/tools/jsdoc/plugins/hifi.js @@ -94,20 +94,20 @@ exports.handlers = { if (e.doclet.hifiInterface) { rows.push("Interface Scripts"); } - if (e.doclet.hifiAssignmentClient) { - rows.push("Assignment Client Scripts"); - } if (e.doclet.hifiClientEntity) { rows.push("Client Entity Scripts"); } if (e.doclet.hifiServerEntity) { rows.push("Server Entity Scripts"); } + if (e.doclet.hifiAssignmentClient) { + rows.push("Assignment Client Scripts"); + } // Append an Available In: table at the end of the namespace description. if (rows.length > 0) { - var table = "

    Available In:" + rows.join("") + "
    "; - e.doclet.description = e.doclet.description + table; + var table = "

    Available in:" + rows.join("") + "
    "; + e.doclet.description = (e.doclet.description ? e.doclet.description : "") + table; } } } @@ -124,7 +124,7 @@ exports.defineTags = function (dictionary) { }); // @hifi-assignment-client - dictionary.defineTag("hifi-assigment-client", { + dictionary.defineTag("hifi-assignment-client", { onTagged: function (doclet, tag) { doclet.hifiAssignmentClient = true; }