diff --git a/CMakeLists.txt b/CMakeLists.txt index 25fd4731e6..ff9fbe9244 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# If we're running under the gradle build, HIFI_ANDROID will be set here, but +# If we're running under the gradle build, HIFI_ANDROID will be set here, but # ANDROID will not be set until after the `project` statement. This is the *ONLY* # place you need to use `HIFI_ANDROID` instead of `ANDROID` if (WIN32 AND NOT HIFI_ANDROID) @@ -61,8 +61,6 @@ else() endif() option(DISABLE_KTX_CACHE "Disable KTX Cache" OFF) - - set(PLATFORM_QT_GL OpenGL) if (USE_GLES) @@ -132,8 +130,8 @@ set_packaging_parameters() # FIXME hack to work on the proper Android toolchain if (ANDROID) - add_subdirectory(android/app) - return() + add_subdirectory(android/app) + return() endif() # add subdirectories for all targets @@ -148,16 +146,14 @@ if (BUILD_SERVER) endif() if (BUILD_CLIENT) - add_subdirectory(interface) - set_target_properties(interface PROPERTIES FOLDER "Apps") - if (ANDROID) - add_subdirectory(gvr-interface) - set_target_properties(gvr-interface PROPERTIES FOLDER "Apps") - endif() + add_subdirectory(interface) + set_target_properties(interface PROPERTIES FOLDER "Apps") + + option(USE_SIXENSE "Build Interface with sixense library/plugin" OFF) endif() if (BUILD_CLIENT OR BUILD_SERVER) - add_subdirectory(plugins) + add_subdirectory(plugins) endif() # BUILD_TOOLS option will be handled inside the tools's CMakeLists.txt because 'scribe' tool is required for build anyway diff --git a/INSTALL.md b/INSTALL.md index 79d7e96977..e07d28a43d 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -17,6 +17,8 @@ To produce an executable installer on Windows, the following are required: - [Nullsoft Scriptable Install System](http://nsis.sourceforge.net/Download) - 3.0b3 - [UAC Plug-in for Nullsoft](http://nsis.sourceforge.net/UAC_plug-in) - 0.2.4c - [nsProcess Plug-in for Nullsoft](http://nsis.sourceforge.net/NsProcess_plugin) - 1.6 +- [Inetc Plug-in for Nullsoft](http://nsis.sourceforge.net/Inetc_plug-in) - 1.0 +- [NSISpcre Plug-in for Nullsoft](http://nsis.sourceforge.net/NSISpcre_plug-in) - 1.0 Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System. diff --git a/cmake/externals/quazip/CMakeLists.txt b/cmake/externals/quazip/CMakeLists.txt index 0d66b365a2..f2690e0a7d 100644 --- a/cmake/externals/quazip/CMakeLists.txt +++ b/cmake/externals/quazip/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_policy(SET CMP0046 OLD) include(ExternalProject) -set(QUAZIP_CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_PREFIX_PATH=${QT_CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_NAME_DIR:PATH=/lib -DZLIB_ROOT=${ZLIB_ROOT} -DCMAKE_POSITION_INDEPENDENT_CODE=ON) +set(QUAZIP_CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_PREFIX_PATH=${QT_CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_NAME_DIR:PATH=/lib -DZLIB_ROOT=${ZLIB_ROOT} -DCMAKE_POSITION_INDEPENDENT_CODE=ON) if (APPLE) else () diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 702636dd01..032f83e8be 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -46,9 +46,18 @@ macro(GENERATE_INSTALLERS) set(UNINSTALLER_HEADER_IMAGE "") fix_path_for_nsis(${_UNINSTALLER_HEADER_BAD_PATH} UNINSTALLER_HEADER_IMAGE) - # grab the latest VC redist (2017) and add it to the installer, our NSIS template - # will call it during the install - install(CODE "file(DOWNLOAD https://go.microsoft.com/fwlink/?LinkId=746572 \"\${CMAKE_INSTALL_PREFIX}/vcredist_x64.exe\")") + # we use external libraries that still need the 120 (VS2013) redistributables + # so we include them as well until those external libraries are updated + # to use the redistributables that match what we build our applications for + set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS + "C:/Windows/System32/msvcp120.dll" + "C:/Windows/System32/msvcr120.dll" + ) + + set(CMAKE_INSTALL_UCRT_LIBRARIES TRUE) + set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ${INTERFACE_INSTALL_DIR}) + set(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT ${CLIENT_COMPONENT}) + include(InstallRequiredSystemLibraries) elseif (APPLE) # produce a drag and drop DMG on OS X set(CPACK_GENERATOR "DragNDrop") diff --git a/cmake/macros/PackageLibrariesForDeployment.cmake b/cmake/macros/PackageLibrariesForDeployment.cmake index d324776572..29f4617a6f 100644 --- a/cmake/macros/PackageLibrariesForDeployment.cmake +++ b/cmake/macros/PackageLibrariesForDeployment.cmake @@ -39,7 +39,9 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$,$,$>:--release> \"$\"" + COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND}\ + ${EXTRA_DEPLOY_OPTIONS} $<$,$,$>:--release>\ + --no-compiler-runtime --no-opengl-sw --no-angle -no-system-d3d-compiler \"$\"" ) set(QTAUDIO_PATH "$/audio") diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index e26f81edd9..a962504e72 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -149,6 +149,8 @@ macro(SET_PACKAGING_PARAMETERS) set(CLIENT_LAUNCH_NOW_REG_KEY "ClientLaunchAfterInstall") set(SERVER_LAUNCH_NOW_REG_KEY "ServerLaunchAfterInstall") set(CUSTOM_INSTALL_REG_KEY "CustomInstall") + set(CLIENT_ID_REG_KEY "ClientGUID") + set(GA_TRACKING_ID $ENV{GA_TRACKING_ID}) endif () # setup component categories for installer diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index b91d78f628..1a0fa2fac7 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -41,6 +41,8 @@ set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_REG_KEY@") set(SERVER_LAUNCH_NOW_REG_KEY "@SERVER_LAUNCH_NOW_REG_KEY@") set(CLIENT_LAUNCH_NOW_REG_KEY "@CLIENT_LAUNCH_NOW_REG_KEY@") set(CUSTOM_INSTALL_REG_KEY "@CUSTOM_INSTALL_REG_KEY@") +set(GA_TRACKING_ID "@GA_TRACKING_ID@") +set(CLIENT_ID_REG_KEY "@CLIENT_ID_REG_KEY@") set(INSTALLER_HEADER_IMAGE "@INSTALLER_HEADER_IMAGE@") set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@") set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index c1bfebe2c4..f174727f95 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -319,6 +319,78 @@ Function DownloadFile FunctionEnd !endif + +!include NSISpcre.nsh +!insertmacro REMatches + +Var CampaignName + +!macro GetCampaignName RetVar + Call GetCampaignName + Pop ${RetVar} +!macroend + +Function GetCampaignName + Push $0 ; Stash $0 + + ; Parse filename out of the path + ${RECaptureMatches} $0 "([^\\]*\\)*(.*)\.exe" $EXEPATH 0 + ${If} $0 == 2 + Pop $0 ; Discard Path + Pop $0 ; Recover filename + ; Parse campaign out of the filename + ${RECaptureMatches} $0 "HighFidelity-([^-]*-)Beta-.*" $0 0 + ${If} $0 == 1 + Pop $0 ; Recover campaign name + StrCpy $0 $0 -1 0 ; Remove trailing - and copy to _RetVar + ${Else} + StrCpy $0 "" + ${EndIf} + ${Else} + StrCpy $0 "" + ${EndIf} + + Exch $0 ; Restore $0 and push result +FunctionEnd + +!macro CreateGUID RetVar + System::Call 'ole32::CoCreateGuid(g .s)' + Pop ${RetVar} + ; Strip opening and closing braces + StrCpy ${RetVar} ${RetVar} -1 1 +!macroend + +Var GAClientID + +!macro InitGAClientID + ; Generate a new GUID on every run for now + !insertmacro CreateGUID $GAClientID +!macroend + +!macro GoogleAnalytics Category Action Label Value + ${If} "@GA_TRACKING_ID@" != "" + Push $0 + Push $1 + + StrCpy $0 "https://google-analytics.com/collect?v=1&tid=@GA_TRACKING_ID@" + StrCpy $0 "$0&cid=$GAClientID&t=event&ec=${Category}&ea=${Action}" + + ${If} "${Label}" != "" + StrCpy $0 "$0&el=${Label}" + ${EndIf} + ${If} "${Value}" != "" + StrCpy $0 "$0&ev=${Value}" + ${EndIf} + + GetTempFileName $1 + inetc::get /SILENT $0 $1 /END + Delete $1 + + Pop $1 + Pop $0 + ${EndIf} +!macroend + ;-------------------------------- ; Installation types @@ -342,28 +414,32 @@ SectionEnd ;-------------------------------- ;Pages + !define MUI_CUSTOMFUNCTION_ABORT OnUserAbort + + !define MUI_PAGE_CUSTOMFUNCTION_PRE PageWelcomePre !insertmacro MUI_PAGE_WELCOME + !define MUI_PAGE_CUSTOMFUNCTION_PRE PageLicensePre !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" Page custom InstallTypesPage ReadInstallTypes - !define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction + !define MUI_PAGE_CUSTOMFUNCTION_PRE PageDirectoryPre !insertmacro MUI_PAGE_DIRECTORY ;Start Menu Folder Page Configuration !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" - - !define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction + !define MUI_PAGE_CUSTOMFUNCTION_PRE PageStartMenuPre !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER - !define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction + !define MUI_PAGE_CUSTOMFUNCTION_PRE PageComponentsPre @CPACK_NSIS_PAGE_COMPONENTS@ Page custom PostInstallOptionsPage ReadPostInstallOptions + !define MUI_PAGE_CUSTOMFUNCTION_PRE PageInstallFilesPre !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_UNPAGE_CONFIRM @@ -452,8 +528,40 @@ Var CopyFromProductionCheckbox Var ExpressInstallRadioButton Var CustomInstallRadioButton Var InstallTypeDialog -Var Express Var CustomInstallTemporaryState +Var Express + +!macro MaybeSkipPage + ; Check if Express is set, if so, abort the post install options page + ${If} $Express == "1" + Abort + ${EndIf} +!macroend + +Function OnUserAbort + !insertmacro GoogleAnalytics "Installer" "Abort" "User Abort" "" +FunctionEnd +Function PageWelcomePre + !insertmacro GoogleAnalytics "Installer" "Welcome" "" "" +FunctionEnd +Function PageLicensePre + !insertmacro GoogleAnalytics "Installer" "License" "" "" +FunctionEnd +Function PageDirectoryPre + !insertmacro MaybeSkipPage + !insertmacro GoogleAnalytics "Installer" "Directory" "" "" +FunctionEnd +Function PageStartMenuPre + !insertmacro MaybeSkipPage + !insertmacro GoogleAnalytics "Installer" "StartMenu" "" "" +FunctionEnd +Function PageComponentsPre + !insertmacro MaybeSkipPage + !insertmacro GoogleAnalytics "Installer" "Components" "" "" +FunctionEnd +Function PageInstallFilesPre + !insertmacro GoogleAnalytics "Installer" "Install" "" "" +FunctionEnd !macro SetInstallOption Checkbox OptionName Default ; reads the value for the given install option to the registry @@ -472,6 +580,8 @@ Var CustomInstallTemporaryState !macroend Function InstallTypesPage + !insertmacro GoogleAnalytics "Installer" "Install Types" "" "" + !insertmacro MUI_HEADER_TEXT "Choose Installation Type" "Express or Custom Install" nsDialogs::Create 1018 @@ -523,14 +633,10 @@ Function ChangeCustomLabel Pop $R1 FunctionEnd -Function AbortFunction - ; Check if Express is set, if so, abort the post install options page - StrCmp $Express "1" 0 end - Abort - end: -FunctionEnd - Function PostInstallOptionsPage + !insertmacro MaybeSkipPage + !insertmacro GoogleAnalytics "Installer" "Post Install Options" "" "" + !insertmacro MUI_HEADER_TEXT "Setup Options" "" nsDialogs::Create 1018 @@ -540,11 +646,6 @@ Function PostInstallOptionsPage Abort ${EndIf} - ; Check if Express is set, if so, abort the post install options page - StrCmp $Express "1" 0 end - Abort - end: - StrCpy $CurrentOffset 0 StrCpy $OffsetUnits u @@ -837,9 +938,6 @@ Section "-Core installation" Delete "$INSTDIR\ui_resources_200_percent.pak" Delete "$INSTDIR\vccorlib120.dll" Delete "$INSTDIR\version" - Delete "$INSTDIR\msvcr140.dll" - Delete "$INSTDIR\msvcp140.dll" - Delete "$INSTDIR\vcruntime140.dll" Delete "$INSTDIR\xinput1_3.dll" ; Delete old desktop shortcuts before they were renamed during Sandbox rename @@ -858,11 +956,8 @@ Section "-Core installation" ; Rename the incorrectly cased Raleway font Rename "$INSTDIR\resources\qml\styles-uit\RalewaySemibold.qml" "$INSTDIR\resources\qml\styles-uit\RalewaySemiBold.qml" - ExecWait "$INSTDIR\vcredist_x64.exe /install /q /norestart" - ; Remove the Old Interface directory and vcredist_x64.exe (from installs prior to Server Console) RMDir /r "$INSTDIR\Interface" - Delete "$INSTDIR\vcredist_x64.exe" ;Use the entire tree produced by the INSTALL target. Keep the ;list of directories here in sync with the RMDir commands below. @@ -965,6 +1060,7 @@ Section "-Core installation" ; Handle whichever post install options were set Call HandlePostInstallOptions + !insertmacro GoogleAnalytics "Installer" "Done" "" "" SectionEnd !include nsProcess.nsh @@ -979,7 +1075,7 @@ SectionEnd ${If} $R0 == 0 ; the process is running, ask the user to close it - + ${If} "${displayName}" == "@CONSOLE_DISPLAY_NAME@" MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION \ "${displayName} cannot be ${action} while ${displayName} is running.$\r$\nPlease close it in the system tray and click Retry to continue." \ @@ -992,6 +1088,8 @@ SectionEnd /SD IDCANCEL IDRETRY Prompt_${UniqueID} IDCANCEL 0 ${EndIf} + !insertmacro GoogleAnalytics "Installer" "Abort" "${displayName} Running" "" + ; If the user decided to cancel, stop the current installer/uninstaller Abort @@ -1219,6 +1317,11 @@ Function .onInit Quit !endif + !insertmacro InitGAClientID + !insertmacro GetCampaignName $CampaignName + + !insertmacro GoogleAnalytics "Installer" "Start" "$CampaignName" "" + ; make sure none of the installed applications are still running !insertmacro CheckForRunningApplications "installed" "Installer" ${nsProcess::Unload} diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index ce672be604..a11fe74c58 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -727,7 +728,7 @@ void DomainServer::setupNodeListAndAssignments() { packetReceiver.registerListener(PacketType::OctreeDataPersist, this, "processOctreeDataPersistMessage"); packetReceiver.registerListener(PacketType::OctreeFileReplacement, this, "handleOctreeFileReplacementRequest"); - packetReceiver.registerListener(PacketType::OctreeFileReplacementFromUrl, this, "handleOctreeFileReplacementFromURLRequest"); + packetReceiver.registerListener(PacketType::DomainContentReplacementFromUrl, this, "handleDomainContentReplacementFromURLRequest"); // set a custom packetVersionMatch as the verify packet operator for the udt::Socket nodeList->setPacketFilterOperator(&DomainServer::isPacketVerified); @@ -736,7 +737,6 @@ void DomainServer::setupNodeListAndAssignments() { auto assetClient = DependencyManager::set(); assetClient->moveToThread(&_assetClientThread); _assetClientThread.start(); - // add whatever static assignments that have been parsed to the queue addStaticAssignmentsToQueue(); } @@ -2136,7 +2136,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } else if (url.path().startsWith(URI_API_BACKUPS_ID)) { auto id = url.path().mid(QString(URI_API_BACKUPS_ID).length()); auto deferred = makePromise("consolidateBackup"); - deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE, id](QString error, QVariantMap result) { if (!connectionPtr) { return; } @@ -2147,7 +2147,14 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url auto path = result["backupFilePath"].toString(); auto file { std::unique_ptr(new QFile(path)) }; if (file->open(QIODevice::ReadOnly)) { - connectionPtr->respond(HTTPConnection::StatusCode200, std::move(file)); + constexpr const char* CONTENT_TYPE_ZIP = "application/zip"; + + auto downloadedFilename = id; + downloadedFilename.replace(QRegularExpression(".zip$"), ".content.zip"); + auto contentDisposition = "attachment; filename=\"" + downloadedFilename + "\""; + connectionPtr->respond(HTTPConnection::StatusCode200, std::move(file), CONTENT_TYPE_ZIP, { + { "Content-Disposition", contentDisposition.toUtf8() } + }); } else { qCritical(domain_server) << "Unable to load consolidated backup at:" << path << result; connectionPtr->respond(HTTPConnection::StatusCode500, "Error opening backup"); @@ -3429,13 +3436,10 @@ void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile) { } } -void DomainServer::handleOctreeFileReplacementFromURLRequest(QSharedPointer message) { +void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer message) { qInfo() << "Received request to replace content from a url"; auto node = DependencyManager::get()->findNodeWithAddr(message->getSenderSockAddr()); - if (node) { - qDebug() << "Found node: " << node->getCanReplaceContent(); - } - if (node->getCanReplaceContent()) { + if (node && node->getCanReplaceContent()) { // Convert message data into our URL QString url(message->getMessage()); QUrl modelsURL = QUrl(url, QUrl::StrictMode); @@ -3448,7 +3452,12 @@ void DomainServer::handleOctreeFileReplacementFromURLRequest(QSharedPointererror(); if (networkError == QNetworkReply::NoError) { - handleOctreeFileReplacement(reply->readAll()); + if (modelsURL.fileName().endsWith(".json.gz")) { + handleOctreeFileReplacement(reply->readAll()); + } else if (modelsURL.fileName().endsWith(".zip")) { + auto deferred = makePromise("recoverFromUploadedBackup"); + _contentManager->recoverFromUploadedBackup(deferred, reply->readAll()); + } } else { qDebug() << "Error downloading JSON from specified file: " << modelsURL; } @@ -3456,12 +3465,9 @@ void DomainServer::handleOctreeFileReplacementFromURLRequest(QSharedPointer message) { auto node = DependencyManager::get()->nodeWithUUID(message->getSourceID()); if (node->getCanReplaceContent()) { handleOctreeFileReplacement(message->readAll()); } -} +} \ No newline at end of file diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 6e9fe28c0a..b118008d3d 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -91,7 +91,7 @@ private slots: void processICEServerHeartbeatDenialPacket(QSharedPointer message); void processICEServerHeartbeatACK(QSharedPointer message); - void handleOctreeFileReplacementFromURLRequest(QSharedPointer message); + void handleDomainContentReplacementFromURLRequest(QSharedPointer message); void handleOctreeFileReplacementRequest(QSharedPointer message); void handleOctreeFileReplacement(QByteArray octreeFile); diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index bc60d23166..17237b998c 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -191,7 +191,11 @@ add_dependencies(${TARGET_NAME} resources) if (WIN32) # These are external plugins, but we need to do the 'add dependency' here so that their # binary directories get added to the fixup path - add_dependency_external_projects(sixense) + + if (USE_SIXENSE) + add_dependency_external_projects(sixense) + endif () + add_dependency_external_projects(sdl2) add_dependency_external_projects(OpenVR) add_dependency_external_projects(neuron) @@ -327,13 +331,13 @@ if (APPLE) else() # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy_if_different - "${RESOURCES_RCC}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different + "${RESOURCES_RCC}" "$" # FIXME, the edit script code loads HTML from the scripts folder # which in turn relies on CSS that refers to the fonts. In theory - # we should be able to modify the CSS to reference the QRC path to - # the ttf files, but doing so generates a CORS policy violation, + # we should be able to modify the CSS to reference the QRC path to + # the ttf files, but doing so generates a CORS policy violation, # so we have to retain a copy of the fonts outside of the resources binary COMMAND "${CMAKE_COMMAND}" -E copy_directory "${PROJECT_SOURCE_DIR}/resources/fonts" @@ -388,3 +392,6 @@ endif() add_dependency_external_projects(GifCreator) find_package(GifCreator REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GIFCREATOR_INCLUDE_DIRS}) + +# tell CMake to exclude ui_console.h for policy CMP0071 +set_property(SOURCE ui_console.h PROPERTY SKIP_AUTOMOC ON) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 63cf0526dd..15cca18aa4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -351,6 +351,7 @@ static const QString OBJ_EXTENSION = ".obj"; static const QString AVA_JSON_EXTENSION = ".ava.json"; static const QString WEB_VIEW_TAG = "noDownload=true"; static const QString ZIP_EXTENSION = ".zip"; +static const QString CONTENT_ZIP_EXTENSION = ".content.zip"; static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f; @@ -378,7 +379,7 @@ static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system"; static const QString DOMAIN_SPAWNING_POINT = "/0, -10, 0"; -const QHash Application::_acceptedExtensions { +const std::vector> Application::_acceptedExtensions { { SVO_EXTENSION, &Application::importSVOFromURL }, { SVO_JSON_EXTENSION, &Application::importSVOFromURL }, { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }, @@ -386,6 +387,7 @@ const QHash Application::_acceptedExtensi { JS_EXTENSION, &Application::askToLoadScript }, { FST_EXTENSION, &Application::askToSetAvatarUrl }, { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, + { CONTENT_ZIP_EXTENSION, &Application::askToReplaceDomainContent }, { ZIP_EXTENSION, &Application::importFromZIP }, { JPG_EXTENSION, &Application::importImage }, { PNG_EXTENSION, &Application::importImage } @@ -2709,6 +2711,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor()); + surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); surfaceContext->setContextProperty("Selection", DependencyManager::get().data()); surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get().data()); surfaceContext->setContextProperty("Wallet", DependencyManager::get().data()); @@ -6185,11 +6188,9 @@ bool Application::canAcceptURL(const QString& urlString) const { } else if (urlString.startsWith(HIFI_URL_SCHEME)) { return true; } - QHashIterator i(_acceptedExtensions); QString lowerPath = url.path().toLower(); - while (i.hasNext()) { - i.next(); - if (lowerPath.endsWith(i.key(), Qt::CaseInsensitive)) { + for (auto& pair : _acceptedExtensions) { + if (lowerPath.endsWith(pair.first, Qt::CaseInsensitive)) { return true; } } @@ -6206,12 +6207,10 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) { } QUrl url(urlString); - QHashIterator i(_acceptedExtensions); QString lowerPath = url.path().toLower(); - while (i.hasNext()) { - i.next(); - if (lowerPath.endsWith(i.key(), Qt::CaseInsensitive)) { - AcceptURLMethod method = i.value(); + for (auto& pair : _acceptedExtensions) { + if (lowerPath.endsWith(pair.first, Qt::CaseInsensitive)) { + AcceptURLMethod method = pair.second; return (this->*method)(urlString); } } @@ -6398,13 +6397,11 @@ void Application::replaceDomainContent(const QString& url) { QByteArray urlData(url.toUtf8()); auto limitedNodeList = DependencyManager::get(); const auto& domainHandler = limitedNodeList->getDomainHandler(); - limitedNodeList->eachMatchingNode([](const SharedNodePointer& node) { - return node->getType() == NodeType::EntityServer && node->getActiveSocket(); - }, [&urlData, limitedNodeList, &domainHandler](const SharedNodePointer& octreeNode) { - auto octreeFilePacket = NLPacket::create(PacketType::OctreeFileReplacementFromUrl, urlData.size(), true); - octreeFilePacket->write(urlData); - limitedNodeList->sendPacket(std::move(octreeFilePacket), domainHandler.getSockAddr()); - }); + + auto octreeFilePacket = NLPacket::create(PacketType::DomainContentReplacementFromUrl, urlData.size(), true); + octreeFilePacket->write(urlData); + limitedNodeList->sendPacket(std::move(octreeFilePacket), domainHandler.getSockAddr()); + auto addressManager = DependencyManager::get(); addressManager->handleLookupString(DOMAIN_SPAWNING_POINT); QString newHomeAddress = addressManager->getHost() + DOMAIN_SPAWNING_POINT; diff --git a/interface/src/Application.h b/interface/src/Application.h index 35ecb91504..e46b354698 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -605,7 +605,7 @@ private: GLCanvas* _glWidget{ nullptr }; typedef bool (Application::* AcceptURLMethod)(const QString &); - static const QHash _acceptedExtensions; + static const std::vector> _acceptedExtensions; glm::uvec2 _renderResolution; diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 57d1cc0acf..10050c94d0 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -63,6 +63,19 @@ static const float OPAQUE_ALPHA_THRESHOLD = 0.99f; const QString Web3DOverlay::TYPE = "web3d"; const QString Web3DOverlay::QML = "Web3DOverlay.qml"; + +static auto qmlSurfaceDeleter = [](OffscreenQmlSurface* surface) { + AbstractViewStateInterface::instance()->postLambdaEvent([surface] { + if (AbstractViewStateInterface::instance()->isAboutToQuit()) { + // WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown + // if the application has already stopped its event loop, delete must be explicit + delete surface; + } else { + surface->deleteLater(); + } + }); +}; + Web3DOverlay::Web3DOverlay() { _touchDevice.setCapabilities(QTouchDevice::Position); _touchDevice.setType(QTouchDevice::TouchScreen); @@ -75,7 +88,8 @@ Web3DOverlay::Web3DOverlay() { connect(this, &Web3DOverlay::resizeWebSurface, this, &Web3DOverlay::onResizeWebSurface); //need to be intialized before Tablet 1st open - _webSurface = DependencyManager::get()->acquire(_url); + _webSurface = DependencyManager::get()->acquire(QML); + _cachedWebSurface = true; _webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED _webSurface->getSurfaceContext()->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED @@ -114,6 +128,7 @@ void Web3DOverlay::destroyWebSurface() { if (!_webSurface) { return; } + QQuickItem* rootItem = _webSurface->getRootItem(); if (rootItem && rootItem->objectName() == "tabletRoot") { @@ -135,10 +150,15 @@ void Web3DOverlay::destroyWebSurface() { QObject::disconnect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent); QObject::disconnect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived); - auto offscreenCache = DependencyManager::get(); - // FIXME prevents crash on shutdown, but we shoudln't have to do this check - if (offscreenCache) { - offscreenCache->release(QML, _webSurface); + + // If the web surface was fetched out of the cache, release it back into the cache + if (_cachedWebSurface) { + auto offscreenCache = DependencyManager::get(); + // FIXME prevents crash on shutdown, but we shoudln't have to do this check + if (offscreenCache) { + offscreenCache->release(QML, _webSurface); + } + _cachedWebSurface = false; } _webSurface.reset(); } @@ -147,6 +167,8 @@ void Web3DOverlay::buildWebSurface() { if (_webSurface) { return; } + // FIXME the context save here is most likely unecessary since the QML surfaces now render + // off the main thread, and all GL context work is done off the main thread (I *think*) gl::withSavedContext([&] { // FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces // and the current rendering load) @@ -156,10 +178,13 @@ void Web3DOverlay::buildWebSurface() { if (isWebContent()) { _webSurface = DependencyManager::get()->acquire(QML); + _cachedWebSurface = true; _webSurface->getRootItem()->setProperty("url", _url); _webSurface->getRootItem()->setProperty("scriptURL", _scriptURL); } else { - _webSurface = DependencyManager::get()->acquire(_url); + _webSurface = QSharedPointer(new OffscreenQmlSurface(), qmlSurfaceDeleter); + _webSurface->load(_url); + _cachedWebSurface = false; setupQmlSurface(); } _webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition())); diff --git a/interface/src/ui/overlays/Web3DOverlay.h b/interface/src/ui/overlays/Web3DOverlay.h index 4098e98488..d888424cbc 100644 --- a/interface/src/ui/overlays/Web3DOverlay.h +++ b/interface/src/ui/overlays/Web3DOverlay.h @@ -88,6 +88,7 @@ private: InputMode _inputMode { Touch }; QSharedPointer _webSurface; + bool _cachedWebSurface{ false }; gpu::TexturePointer _texture; QString _url; QString _scriptURL; diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 52b9364e98..bd00ded12d 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -239,7 +239,7 @@ void WebEntityRenderer::doRender(RenderArgs* args) { } bool WebEntityRenderer::hasWebSurface() { - return (bool)_webSurface; + return (bool)_webSurface && _webSurface->getRootItem(); } bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { @@ -303,7 +303,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { _fadeStartTime = usecTimestampNow(); _webSurface->resume(); - return true; + return _webSurface->getRootItem(); } void WebEntityRenderer::destroyWebSurface() { diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 44ef34a3a4..137d6ef396 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -157,7 +157,7 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u } if (usingUserData) { - _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getUserData().toUtf8())); + _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getUserData().toUtf8()), materialURLString); // Since our material changed, the current name might not be valid anymore, so we need to update setCurrentMaterialName(_currentMaterialName); diff --git a/libraries/model-networking/src/model-networking/MaterialCache.cpp b/libraries/model-networking/src/model-networking/MaterialCache.cpp index cf3e255e0c..f0cbfc914a 100644 --- a/libraries/model-networking/src/model-networking/MaterialCache.cpp +++ b/libraries/model-networking/src/model-networking/MaterialCache.cpp @@ -20,7 +20,7 @@ void NetworkMaterialResource::downloadFinished(const QByteArray& data) { parsedMaterials.reset(); if (_url.toString().contains(".json")) { - parsedMaterials = parseJSONMaterials(QJsonDocument::fromJson(data)); + parsedMaterials = parseJSONMaterials(QJsonDocument::fromJson(data), _url); } // TODO: parse other material types @@ -75,7 +75,7 @@ bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3& * @property {number} materialVersion=1 - The version of the material. Currently not used. * @property {Material|Material[]} materials - The details of the material or materials. */ -NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMaterials(const QJsonDocument& materialJSON) { +NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMaterials(const QJsonDocument& materialJSON, const QUrl& baseUrl) { ParsedMaterials toReturn; if (!materialJSON.isNull() && materialJSON.isObject()) { QJsonObject materialJSONObject = materialJSON.object(); @@ -91,13 +91,13 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater QJsonArray materials = materialsValue.toArray(); for (auto material : materials) { if (!material.isNull() && material.isObject()) { - auto parsedMaterial = parseJSONMaterial(material.toObject()); + auto parsedMaterial = parseJSONMaterial(material.toObject(), baseUrl); toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second; toReturn.names.push_back(parsedMaterial.first); } } } else if (materialsValue.isObject()) { - auto parsedMaterial = parseJSONMaterial(materialsValue.toObject()); + auto parsedMaterial = parseJSONMaterial(materialsValue.toObject(), baseUrl); toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second; toReturn.names.push_back(parsedMaterial.first); } @@ -138,7 +138,7 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater * @property {string} lightMap - URL of light map texture image. Currently not used. */ // Note: See MaterialEntityItem.h for default values used in practice. -std::pair> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON) { +std::pair> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl) { std::string name = ""; std::shared_ptr material = std::make_shared(); for (auto& key : materialJSON.keys()) { @@ -199,57 +199,58 @@ std::pair> NetworkMaterialResource } else if (key == "albedoMap") { auto value = materialJSON.value(key); if (value.isString()) { + QString urlString = value.toString(); bool useAlphaChannel = false; auto opacityMap = materialJSON.find("opacityMap"); - if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == value.toString()) { + if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == urlString) { useAlphaChannel = true; } - material->setAlbedoMap(value.toString(), useAlphaChannel); + material->setAlbedoMap(baseUrl.resolved(urlString), useAlphaChannel); } } else if (key == "roughnessMap") { auto value = materialJSON.value(key); if (value.isString()) { - material->setRoughnessMap(value.toString(), false); + material->setRoughnessMap(baseUrl.resolved(value.toString()), false); } } else if (key == "glossMap") { auto value = materialJSON.value(key); if (value.isString()) { - material->setRoughnessMap(value.toString(), true); + material->setRoughnessMap(baseUrl.resolved(value.toString()), true); } } else if (key == "metallicMap") { auto value = materialJSON.value(key); if (value.isString()) { - material->setMetallicMap(value.toString(), false); + material->setMetallicMap(baseUrl.resolved(value.toString()), false); } } else if (key == "specularMap") { auto value = materialJSON.value(key); if (value.isString()) { - material->setMetallicMap(value.toString(), true); + material->setMetallicMap(baseUrl.resolved(value.toString()), true); } } else if (key == "normalMap") { auto value = materialJSON.value(key); if (value.isString()) { - material->setNormalMap(value.toString(), false); + material->setNormalMap(baseUrl.resolved(value.toString()), false); } } else if (key == "bumpMap") { auto value = materialJSON.value(key); if (value.isString()) { - material->setNormalMap(value.toString(), true); + material->setNormalMap(baseUrl.resolved(value.toString()), true); } } else if (key == "occlusionMap") { auto value = materialJSON.value(key); if (value.isString()) { - material->setOcclusionMap(value.toString()); + material->setOcclusionMap(baseUrl.resolved(value.toString())); } } else if (key == "scatteringMap") { auto value = materialJSON.value(key); if (value.isString()) { - material->setScatteringMap(value.toString()); + material->setScatteringMap(baseUrl.resolved(value.toString())); } } else if (key == "lightMap") { auto value = materialJSON.value(key); if (value.isString()) { - material->setLightmapMap(value.toString()); + material->setLightmapMap(baseUrl.resolved(value.toString())); } } } diff --git a/libraries/model-networking/src/model-networking/MaterialCache.h b/libraries/model-networking/src/model-networking/MaterialCache.h index 468a12c677..074cd6c98d 100644 --- a/libraries/model-networking/src/model-networking/MaterialCache.h +++ b/libraries/model-networking/src/model-networking/MaterialCache.h @@ -37,8 +37,8 @@ public: ParsedMaterials parsedMaterials; - static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON); - static std::pair> parseJSONMaterial(const QJsonObject& materialJSON); + static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON, const QUrl& baseUrl); + static std::pair> parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl); private: static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index b253ac4af3..f17cdbb7e8 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -556,58 +556,58 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, im return nullptr; } -void NetworkMaterial::setAlbedoMap(const QString& url, bool useAlphaChannel) { - auto map = fetchTextureMap(QUrl(url), image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); +void NetworkMaterial::setAlbedoMap(const QUrl& url, bool useAlphaChannel) { + auto map = fetchTextureMap(url, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); if (map) { map->setUseAlphaChannel(useAlphaChannel); setTextureMap(MapChannel::ALBEDO_MAP, map); } } -void NetworkMaterial::setNormalMap(const QString& url, bool isBumpmap) { - auto map = fetchTextureMap(QUrl(url), isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP); +void NetworkMaterial::setNormalMap(const QUrl& url, bool isBumpmap) { + auto map = fetchTextureMap(url, isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP); if (map) { setTextureMap(MapChannel::NORMAL_MAP, map); } } -void NetworkMaterial::setRoughnessMap(const QString& url, bool isGloss) { - auto map = fetchTextureMap(QUrl(url), isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); +void NetworkMaterial::setRoughnessMap(const QUrl& url, bool isGloss) { + auto map = fetchTextureMap(url, isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); if (map) { setTextureMap(MapChannel::ROUGHNESS_MAP, map); } } -void NetworkMaterial::setMetallicMap(const QString& url, bool isSpecular) { - auto map = fetchTextureMap(QUrl(url), isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); +void NetworkMaterial::setMetallicMap(const QUrl& url, bool isSpecular) { + auto map = fetchTextureMap(url, isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); if (map) { setTextureMap(MapChannel::METALLIC_MAP, map); } } -void NetworkMaterial::setOcclusionMap(const QString& url) { - auto map = fetchTextureMap(QUrl(url), image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); +void NetworkMaterial::setOcclusionMap(const QUrl& url) { + auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); if (map) { setTextureMap(MapChannel::OCCLUSION_MAP, map); } } -void NetworkMaterial::setEmissiveMap(const QString& url) { - auto map = fetchTextureMap(QUrl(url), image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); +void NetworkMaterial::setEmissiveMap(const QUrl& url) { + auto map = fetchTextureMap(url, image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); if (map) { setTextureMap(MapChannel::EMISSIVE_MAP, map); } } -void NetworkMaterial::setScatteringMap(const QString& url) { - auto map = fetchTextureMap(QUrl(url), image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); +void NetworkMaterial::setScatteringMap(const QUrl& url) { + auto map = fetchTextureMap(url, image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); if (map) { setTextureMap(MapChannel::SCATTERING_MAP, map); } } -void NetworkMaterial::setLightmapMap(const QString& url) { - auto map = fetchTextureMap(QUrl(url), image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); +void NetworkMaterial::setLightmapMap(const QUrl& url) { + auto map = fetchTextureMap(url, image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); if (map) { //map->setTextureTransform(_lightmapTransform); //map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index bbb00d72eb..4dfa8b17ea 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -164,14 +164,14 @@ public: NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl); NetworkMaterial(const NetworkMaterial& material); - void setAlbedoMap(const QString& url, bool useAlphaChannel); - void setNormalMap(const QString& url, bool isBumpmap); - void setRoughnessMap(const QString& url, bool isGloss); - void setMetallicMap(const QString& url, bool isSpecular); - void setOcclusionMap(const QString& url); - void setEmissiveMap(const QString& url); - void setScatteringMap(const QString& url); - void setLightmapMap(const QString& url); + void setAlbedoMap(const QUrl& url, bool useAlphaChannel); + void setNormalMap(const QUrl& url, bool isBumpmap); + void setRoughnessMap(const QUrl& url, bool isGloss); + void setMetallicMap(const QUrl& url, bool isSpecular); + void setOcclusionMap(const QUrl& url); + void setEmissiveMap(const QUrl& url); + void setScatteringMap(const QUrl& url); + void setLightmapMap(const QUrl& url); protected: friend class Geometry; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 98a9087d37..09fd31a41e 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -121,7 +121,7 @@ public: ReplicatedAvatarIdentity, ReplicatedKillAvatar, ReplicatedBulkAvatarData, - OctreeFileReplacementFromUrl, + DomainContentReplacementFromUrl, ChallengeOwnership, EntityScriptCallMethod, ChallengeOwnershipRequest, @@ -171,7 +171,7 @@ public: << PacketTypeEnum::Value::DomainServerPathResponse << PacketTypeEnum::Value::DomainServerAddedNode << PacketTypeEnum::Value::DomainServerConnectionToken << PacketTypeEnum::Value::DomainSettingsRequest << PacketTypeEnum::Value::OctreeDataFileRequest << PacketTypeEnum::Value::OctreeDataFileReply - << PacketTypeEnum::Value::OctreeDataPersist << PacketTypeEnum::Value::OctreeFileReplacementFromUrl + << PacketTypeEnum::Value::OctreeDataPersist << PacketTypeEnum::Value::DomainContentReplacementFromUrl << PacketTypeEnum::Value::DomainSettings << PacketTypeEnum::Value::ICEServerPeerInformation << PacketTypeEnum::Value::ICEServerQuery << PacketTypeEnum::Value::ICEServerHeartbeat << PacketTypeEnum::Value::ICEServerHeartbeatACK << PacketTypeEnum::Value::ICEPing diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 7fece45b2f..319b6ad415 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -8,6 +8,9 @@ include_hifi_library_headers(audio) include_hifi_library_headers(networking) include_hifi_library_headers(octree) +# tell CMake to exclude qrc_fonts.cpp for policy CMP0071 +set_property(SOURCE qrc_fonts.cpp PROPERTY SKIP_AUTOMOC ON) + if (NOT ANDROID) target_nsight() endif () diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index ecfb4847e4..5c64d4b584 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -47,6 +47,8 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr } } +const graphics::MaterialPointer MeshPartPayload::DEFAULT_MATERIAL = std::make_shared(); + MeshPartPayload::MeshPartPayload(const std::shared_ptr& mesh, int partIndex, graphics::MaterialPointer material) { updateMeshPart(mesh, partIndex); addMaterial(graphics::MaterialLayer(material, 0)); @@ -99,7 +101,7 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShad builder.withSubMetaCulled(); } - if (_drawMaterials.top().material) { + if (topMaterialExists()) { auto matKey = _drawMaterials.top().material->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); @@ -119,7 +121,7 @@ Item::Bound MeshPartPayload::getBound() const { ShapeKey MeshPartPayload::getShapeKey() const { graphics::MaterialKey drawMaterialKey; - if (_drawMaterials.top().material) { + if (topMaterialExists()) { drawMaterialKey = _drawMaterials.top().material->getKey(); } @@ -171,7 +173,7 @@ void MeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // apply material properties - RenderPipelines::bindMaterial(_drawMaterials.top().material, batch, args->_enableTexturing); + RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! @@ -356,7 +358,7 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCas builder.withDeformed(); } - if (_drawMaterials.top().material) { + if (topMaterialExists()) { auto matKey = _drawMaterials.top().material->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); @@ -387,7 +389,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe } graphics::MaterialKey drawMaterialKey; - if (_drawMaterials.top().material) { + if (topMaterialExists()) { drawMaterialKey = _drawMaterials.top().material->getKey(); } @@ -469,7 +471,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // apply material properties - RenderPipelines::bindMaterial(_drawMaterials.top().material, batch, args->_enableTexturing); + RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 087550345d..08ad7a8311 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -65,15 +65,18 @@ public: graphics::Mesh::Part _drawPart; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } - size_t getMaterialTextureSize() { return _drawMaterials.top().material ? _drawMaterials.top().material->getTextureSize() : 0; } - int getMaterialTextureCount() { return _drawMaterials.top().material ? _drawMaterials.top().material->getTextureCount() : 0; } - bool hasTextureInfo() const { return _drawMaterials.top().material ? _drawMaterials.top().material->hasTextureInfo() : false; } + size_t getMaterialTextureSize() { return topMaterialExists() ? _drawMaterials.top().material->getTextureSize() : 0; } + int getMaterialTextureCount() { return topMaterialExists() ? _drawMaterials.top().material->getTextureCount() : 0; } + bool hasTextureInfo() const { return topMaterialExists() ? _drawMaterials.top().material->hasTextureInfo() : false; } void addMaterial(graphics::MaterialLayer material); void removeMaterial(graphics::MaterialPointer material); protected: + static const graphics::MaterialPointer DEFAULT_MATERIAL; render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() }; + + bool topMaterialExists() const { return !_drawMaterials.empty() && _drawMaterials.top().material; } }; namespace render { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 2617ef12ad..70f873734a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1604,7 +1604,8 @@ void Model::createVisibleRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); - _modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName()); + auto material = getGeometry()->getShapeMaterial(shapeID); + _modelMeshMaterialNames.push_back(material ? material->getName() : ""); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; } diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 06cf929368..4a0f52e272 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -20,8 +20,12 @@ if (NOT SERVER_ONLY AND NOT ANDROID) add_subdirectory(${DIR}) set(DIR "oculusLegacy") add_subdirectory(${DIR}) - set(DIR "hifiSixense") - add_subdirectory(${DIR}) + + if (USE_SIXENSE) + set(DIR "hifiSixense") + add_subdirectory(${DIR}) + endif() + set(DIR "hifiSpacemouse") add_subdirectory(${DIR}) set(DIR "hifiNeuron") diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 638cadf574..893b7f48b1 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -19,7 +19,7 @@ if (WIN32 AND (NOT USE_GLES)) set(TARGET_NAME oculus) setup_hifi_plugin(Multimedia) link_hifi_libraries( - shared task gl gpu gpu-gl controllers ui qml + shared task gl gpu ${PLATFORM_GL_BACKEND} controllers ui qml plugins ui-plugins display-plugins input-plugins audio-client networking render-utils ${PLATFORM_GL_BACKEND} diff --git a/scripts/developer/tests/webOverlayTool.js b/scripts/developer/tests/webOverlayTool.js new file mode 100644 index 0000000000..1a3aa35205 --- /dev/null +++ b/scripts/developer/tests/webOverlayTool.js @@ -0,0 +1,102 @@ +// webSpawnTool.js +// +// Stress tests the rendering of web surfaces over time +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +SPAWNER = function (properties) { + properties = properties || {}; + var RADIUS = properties.radius || 5.0; // Spawn within this radius (square) + var SPAWN_COUNT = properties.count || 10000; // number of entities to spawn + var SPAWN_LIMIT = properties.spawnLimit || 1; + var SPAWN_INTERVAL = properties.spawnInterval || properties.interval || 2; + var SPAWN_LIFETIME = properties.lifetime || 10; // Entity timeout (when/if we crash, we need the entities to delete themselves) + + function randomPositionXZ(center, radius) { + return { + x: center.x + (Math.random() * radius * 2.0) - radius, + y: center.y, + z: center.z + (Math.random() * radius * 2.0) - radius + }; + } + + function makeObject(properties) { + + var overlay = Overlays.addOverlay("web3d", { + name: "Web", + url: "https://www.reddit.com/r/random", + localPosition: randomPositionXZ( { x: 0, y: 0, z: -1 }, 1), + localRotation: Quat.angleAxis(180, Vec3.Y_AXIS), + dimensions: {x: .8, y: .45, z: 0.1}, + color: { red: 255, green: 255, blue: 255 }, + alpha: 1.0, + showKeyboardFocusHighlight: false, + visible: true + }); + + var now = Date.now(); + + return { + destroy: function () { + Overlays.deleteOverlay(overlay) + }, + getAge: function () { + return (Date.now() - now) / 1000.0; + } + }; + } + + + var items = []; + var toCreate = 0; + var spawned = 0; + var spawnTimer = 0.0; + var keepAliveTimer = 0.0; + + function clear () { + } + + function create() { + toCreate = SPAWN_COUNT; + Script.update.connect(spawn); + } + + function spawn(dt) { + if (toCreate <= 0) { + Script.update.disconnect(spawn); + print("Finished spawning"); + } + else if ((spawnTimer -= dt) < 0.0){ + spawnTimer = SPAWN_INTERVAL; + + var n = Math.min(toCreate, SPAWN_LIMIT); + print("Spawning " + n + " items (" + (spawned += n) + ")"); + + toCreate -= n; + for (; n > 0; --n) { + items.push(makeObject()); + } + } + } + + function despawn() { + print("despawning"); + items.forEach(function (item) { + item.destroy(); + }); + item = []; + } + + function init () { + Script.update.disconnect(init); + Script.scriptEnding.connect(despawn); + clear(); + create(); + } + + Script.update.connect(init); +}; + +SPAWNER(); diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index ef7f35cf10..fd4d8d88dd 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -13,8 +13,8 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") # link in the shared libraries link_hifi_libraries( - shared task workload networking animation - ktx image octree gl gpu gpu-gl + shared task networking animation + ktx image octree gl gpu ${PLATFORM_GL_BACKEND} render render-utils graphics fbx model-networking graphics-scripting entities entities-renderer audio avatars script-engine