Merge branch 'master' of github.com:highfidelity/hifi into serverless-domains

This commit is contained in:
Seth Alves 2018-03-21 11:11:43 -07:00
commit 4033af9b11
33 changed files with 411 additions and 134 deletions

View file

@ -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* # ANDROID will not be set until after the `project` statement. This is the *ONLY*
# place you need to use `HIFI_ANDROID` instead of `ANDROID` # place you need to use `HIFI_ANDROID` instead of `ANDROID`
if (WIN32 AND NOT HIFI_ANDROID) if (WIN32 AND NOT HIFI_ANDROID)
@ -61,8 +61,6 @@ else()
endif() endif()
option(DISABLE_KTX_CACHE "Disable KTX Cache" OFF) option(DISABLE_KTX_CACHE "Disable KTX Cache" OFF)
set(PLATFORM_QT_GL OpenGL) set(PLATFORM_QT_GL OpenGL)
if (USE_GLES) if (USE_GLES)
@ -132,8 +130,8 @@ set_packaging_parameters()
# FIXME hack to work on the proper Android toolchain # FIXME hack to work on the proper Android toolchain
if (ANDROID) if (ANDROID)
add_subdirectory(android/app) add_subdirectory(android/app)
return() return()
endif() endif()
# add subdirectories for all targets # add subdirectories for all targets
@ -148,16 +146,14 @@ if (BUILD_SERVER)
endif() endif()
if (BUILD_CLIENT) if (BUILD_CLIENT)
add_subdirectory(interface) add_subdirectory(interface)
set_target_properties(interface PROPERTIES FOLDER "Apps") set_target_properties(interface PROPERTIES FOLDER "Apps")
if (ANDROID)
add_subdirectory(gvr-interface) option(USE_SIXENSE "Build Interface with sixense library/plugin" OFF)
set_target_properties(gvr-interface PROPERTIES FOLDER "Apps")
endif()
endif() endif()
if (BUILD_CLIENT OR BUILD_SERVER) if (BUILD_CLIENT OR BUILD_SERVER)
add_subdirectory(plugins) add_subdirectory(plugins)
endif() endif()
# BUILD_TOOLS option will be handled inside the tools's CMakeLists.txt because 'scribe' tool is required for build anyway # BUILD_TOOLS option will be handled inside the tools's CMakeLists.txt because 'scribe' tool is required for build anyway

View file

@ -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 - [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 - [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 - [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. Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System.

View file

@ -46,9 +46,18 @@ macro(GENERATE_INSTALLERS)
set(UNINSTALLER_HEADER_IMAGE "") set(UNINSTALLER_HEADER_IMAGE "")
fix_path_for_nsis(${_UNINSTALLER_HEADER_BAD_PATH} 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 # we use external libraries that still need the 120 (VS2013) redistributables
# will call it during the install # so we include them as well until those external libraries are updated
install(CODE "file(DOWNLOAD https://go.microsoft.com/fwlink/?LinkId=746572 \"\${CMAKE_INSTALL_PREFIX}/vcredist_x64.exe\")") # 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) elseif (APPLE)
# produce a drag and drop DMG on OS X # produce a drag and drop DMG on OS X
set(CPACK_GENERATOR "DragNDrop") set(CPACK_GENERATOR "DragNDrop")

View file

@ -39,7 +39,9 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT)
add_custom_command( add_custom_command(
TARGET ${TARGET_NAME} TARGET ${TARGET_NAME}
POST_BUILD POST_BUILD
COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>:--release> \"$<TARGET_FILE:${TARGET_NAME}>\"" COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND}\
${EXTRA_DEPLOY_OPTIONS} $<$<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>:--release>\
--no-compiler-runtime --no-opengl-sw --no-angle -no-system-d3d-compiler \"$<TARGET_FILE:${TARGET_NAME}>\""
) )
set(QTAUDIO_PATH "$<TARGET_FILE_DIR:${TARGET_NAME}>/audio") set(QTAUDIO_PATH "$<TARGET_FILE_DIR:${TARGET_NAME}>/audio")

View file

@ -149,6 +149,8 @@ macro(SET_PACKAGING_PARAMETERS)
set(CLIENT_LAUNCH_NOW_REG_KEY "ClientLaunchAfterInstall") set(CLIENT_LAUNCH_NOW_REG_KEY "ClientLaunchAfterInstall")
set(SERVER_LAUNCH_NOW_REG_KEY "ServerLaunchAfterInstall") set(SERVER_LAUNCH_NOW_REG_KEY "ServerLaunchAfterInstall")
set(CUSTOM_INSTALL_REG_KEY "CustomInstall") set(CUSTOM_INSTALL_REG_KEY "CustomInstall")
set(CLIENT_ID_REG_KEY "ClientGUID")
set(GA_TRACKING_ID $ENV{GA_TRACKING_ID})
endif () endif ()
# setup component categories for installer # setup component categories for installer

View file

@ -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(SERVER_LAUNCH_NOW_REG_KEY "@SERVER_LAUNCH_NOW_REG_KEY@")
set(CLIENT_LAUNCH_NOW_REG_KEY "@CLIENT_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(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(INSTALLER_HEADER_IMAGE "@INSTALLER_HEADER_IMAGE@")
set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@") set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@")
set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@") set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@")

View file

@ -319,6 +319,78 @@ Function DownloadFile
FunctionEnd FunctionEnd
!endif !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 ; Installation types
@ -342,28 +414,32 @@ SectionEnd
;-------------------------------- ;--------------------------------
;Pages ;Pages
!define MUI_CUSTOMFUNCTION_ABORT OnUserAbort
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageWelcomePre
!insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_WELCOME
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageLicensePre
!insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
Page custom InstallTypesPage ReadInstallTypes Page custom InstallTypesPage ReadInstallTypes
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction !define MUI_PAGE_CUSTOMFUNCTION_PRE PageDirectoryPre
!insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_DIRECTORY
;Start Menu Folder Page Configuration ;Start Menu Folder Page Configuration
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM" !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageStartMenuPre
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
!insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction !define MUI_PAGE_CUSTOMFUNCTION_PRE PageComponentsPre
@CPACK_NSIS_PAGE_COMPONENTS@ @CPACK_NSIS_PAGE_COMPONENTS@
Page custom PostInstallOptionsPage ReadPostInstallOptions Page custom PostInstallOptionsPage ReadPostInstallOptions
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageInstallFilesPre
!insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_CONFIRM
@ -452,8 +528,40 @@ Var CopyFromProductionCheckbox
Var ExpressInstallRadioButton Var ExpressInstallRadioButton
Var CustomInstallRadioButton Var CustomInstallRadioButton
Var InstallTypeDialog Var InstallTypeDialog
Var Express
Var CustomInstallTemporaryState 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 !macro SetInstallOption Checkbox OptionName Default
; reads the value for the given install option to the registry ; reads the value for the given install option to the registry
@ -472,6 +580,8 @@ Var CustomInstallTemporaryState
!macroend !macroend
Function InstallTypesPage Function InstallTypesPage
!insertmacro GoogleAnalytics "Installer" "Install Types" "" ""
!insertmacro MUI_HEADER_TEXT "Choose Installation Type" "Express or Custom Install" !insertmacro MUI_HEADER_TEXT "Choose Installation Type" "Express or Custom Install"
nsDialogs::Create 1018 nsDialogs::Create 1018
@ -523,14 +633,10 @@ Function ChangeCustomLabel
Pop $R1 Pop $R1
FunctionEnd 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 Function PostInstallOptionsPage
!insertmacro MaybeSkipPage
!insertmacro GoogleAnalytics "Installer" "Post Install Options" "" ""
!insertmacro MUI_HEADER_TEXT "Setup Options" "" !insertmacro MUI_HEADER_TEXT "Setup Options" ""
nsDialogs::Create 1018 nsDialogs::Create 1018
@ -540,11 +646,6 @@ Function PostInstallOptionsPage
Abort Abort
${EndIf} ${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 $CurrentOffset 0
StrCpy $OffsetUnits u StrCpy $OffsetUnits u
@ -837,9 +938,6 @@ Section "-Core installation"
Delete "$INSTDIR\ui_resources_200_percent.pak" Delete "$INSTDIR\ui_resources_200_percent.pak"
Delete "$INSTDIR\vccorlib120.dll" Delete "$INSTDIR\vccorlib120.dll"
Delete "$INSTDIR\version" Delete "$INSTDIR\version"
Delete "$INSTDIR\msvcr140.dll"
Delete "$INSTDIR\msvcp140.dll"
Delete "$INSTDIR\vcruntime140.dll"
Delete "$INSTDIR\xinput1_3.dll" Delete "$INSTDIR\xinput1_3.dll"
; Delete old desktop shortcuts before they were renamed during Sandbox rename ; 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 the incorrectly cased Raleway font
Rename "$INSTDIR\resources\qml\styles-uit\RalewaySemibold.qml" "$INSTDIR\resources\qml\styles-uit\RalewaySemiBold.qml" 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) ; Remove the Old Interface directory and vcredist_x64.exe (from installs prior to Server Console)
RMDir /r "$INSTDIR\Interface" RMDir /r "$INSTDIR\Interface"
Delete "$INSTDIR\vcredist_x64.exe"
;Use the entire tree produced by the INSTALL target. Keep the ;Use the entire tree produced by the INSTALL target. Keep the
;list of directories here in sync with the RMDir commands below. ;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 ; Handle whichever post install options were set
Call HandlePostInstallOptions Call HandlePostInstallOptions
!insertmacro GoogleAnalytics "Installer" "Done" "" ""
SectionEnd SectionEnd
!include nsProcess.nsh !include nsProcess.nsh
@ -979,7 +1075,7 @@ SectionEnd
${If} $R0 == 0 ${If} $R0 == 0
; the process is running, ask the user to close it ; the process is running, ask the user to close it
${If} "${displayName}" == "@CONSOLE_DISPLAY_NAME@" ${If} "${displayName}" == "@CONSOLE_DISPLAY_NAME@"
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION \ 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." \ "${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 /SD IDCANCEL IDRETRY Prompt_${UniqueID} IDCANCEL 0
${EndIf} ${EndIf}
!insertmacro GoogleAnalytics "Installer" "Abort" "${displayName} Running" ""
; If the user decided to cancel, stop the current installer/uninstaller ; If the user decided to cancel, stop the current installer/uninstaller
Abort Abort
@ -1219,6 +1317,11 @@ Function .onInit
Quit Quit
!endif !endif
!insertmacro InitGAClientID
!insertmacro GetCampaignName $CampaignName
!insertmacro GoogleAnalytics "Installer" "Start" "$CampaignName" ""
; make sure none of the installed applications are still running ; make sure none of the installed applications are still running
!insertmacro CheckForRunningApplications "installed" "Installer" !insertmacro CheckForRunningApplications "installed" "Installer"
${nsProcess::Unload} ${nsProcess::Unload}

View file

@ -191,7 +191,11 @@ add_dependencies(${TARGET_NAME} resources)
if (WIN32) if (WIN32)
# These are external plugins, but we need to do the 'add dependency' here so that their # These are external plugins, but we need to do the 'add dependency' here so that their
# binary directories get added to the fixup path # 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(sdl2)
add_dependency_external_projects(OpenVR) add_dependency_external_projects(OpenVR)
add_dependency_external_projects(neuron) add_dependency_external_projects(neuron)
@ -328,13 +332,13 @@ if (APPLE)
else() else()
# copy the resources files beside the executable # copy the resources files beside the executable
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_if_different COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${RESOURCES_RCC}" "${RESOURCES_RCC}"
"$<TARGET_FILE_DIR:interface>" "$<TARGET_FILE_DIR:interface>"
# FIXME, the edit script code loads HTML from the scripts folder # FIXME, the edit script code loads HTML from the scripts folder
# which in turn relies on CSS that refers to the fonts. In theory # 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 # 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, # 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 # so we have to retain a copy of the fonts outside of the resources binary
COMMAND "${CMAKE_COMMAND}" -E copy_directory COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${PROJECT_SOURCE_DIR}/resources/fonts" "${PROJECT_SOURCE_DIR}/resources/fonts"
@ -389,3 +393,6 @@ endif()
add_dependency_external_projects(GifCreator) add_dependency_external_projects(GifCreator)
find_package(GifCreator REQUIRED) find_package(GifCreator REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GIFCREATOR_INCLUDE_DIRS}) 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)

View file

@ -2734,6 +2734,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor()); surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data()); surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data()); surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
@ -7448,10 +7449,35 @@ bool Application::isThrottleRendering() const {
} }
bool Application::hasFocus() const { bool Application::hasFocus() const {
if (_displayPlugin) { bool result = (QApplication::activeWindow() != nullptr);
return getActiveDisplayPlugin()->hasFocus(); #if defined(Q_OS_WIN)
// On Windows, QWidget::activateWindow() - as called in setFocus() - makes the application's taskbar icon flash but doesn't
// take user focus away from their current window. So also check whether the application is the user's current foreground
// window.
result = result && (HWND)QApplication::activeWindow()->winId() == GetForegroundWindow();
#endif
return result;
}
void Application::setFocus() {
// Note: Windows doesn't allow a user focus to be taken away from another application. Instead, it changes the color of and
// flashes the taskbar icon.
auto window = qApp->getWindow();
window->activateWindow();
}
void Application::raise() {
auto windowState = qApp->getWindow()->windowState();
if (windowState & Qt::WindowMinimized) {
if (windowState & Qt::WindowMaximized) {
qApp->getWindow()->showMaximized();
} else if (windowState & Qt::WindowFullScreen) {
qApp->getWindow()->showFullScreen();
} else {
qApp->getWindow()->showNormal();
}
} }
return (QApplication::activeWindow() != nullptr); qApp->getWindow()->raise();
} }
void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) { void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) {

View file

@ -161,6 +161,8 @@ public:
QRect getRecommendedHUDRect() const; QRect getRecommendedHUDRect() const;
glm::vec2 getDeviceSize() const; glm::vec2 getDeviceSize() const;
bool hasFocus() const; bool hasFocus() const;
void setFocus();
void raise();
void showCursor(const Cursor::Icon& cursor); void showCursor(const Cursor::Icon& cursor);

View file

@ -74,16 +74,14 @@ QScriptValue WindowScriptingInterface::hasFocus() {
void WindowScriptingInterface::setFocus() { void WindowScriptingInterface::setFocus() {
// It's forbidden to call focus() from another thread. // It's forbidden to call focus() from another thread.
qApp->postLambdaEvent([] { qApp->postLambdaEvent([] {
auto window = qApp->getWindow(); qApp->setFocus();
window->activateWindow();
window->setFocus();
}); });
} }
void WindowScriptingInterface::raiseMainWindow() { void WindowScriptingInterface::raiseMainWindow() {
// It's forbidden to call raise() from another thread. // It's forbidden to call raise() from another thread.
qApp->postLambdaEvent([] { qApp->postLambdaEvent([] {
qApp->getWindow()->raise(); qApp->raise();
}); });
} }

View file

@ -62,13 +62,14 @@ public slots:
QScriptValue hasFocus(); QScriptValue hasFocus();
/**jsdoc /**jsdoc
* Make the Interface window have focus. * Make the Interface window have focus. On Windows, if Interface doesn't already have focus, the task bar icon flashes to
* indicate that Interface wants attention but focus isn't taken away from the application that the user is using.
* @function Window.setFocus * @function Window.setFocus
*/ */
void setFocus(); void setFocus();
/**jsdoc /**jsdoc
* Raise the Interface window if it is minimized, and give it focus. * Raise the Interface window if it is minimized. If raised, the window gains focus.
* @function Window.raiseMainWindow * @function Window.raiseMainWindow
*/ */
void raiseMainWindow(); void raiseMainWindow();

View file

@ -63,6 +63,19 @@ static const float OPAQUE_ALPHA_THRESHOLD = 0.99f;
const QString Web3DOverlay::TYPE = "web3d"; const QString Web3DOverlay::TYPE = "web3d";
const QString Web3DOverlay::QML = "Web3DOverlay.qml"; 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() { Web3DOverlay::Web3DOverlay() {
_touchDevice.setCapabilities(QTouchDevice::Position); _touchDevice.setCapabilities(QTouchDevice::Position);
_touchDevice.setType(QTouchDevice::TouchScreen); _touchDevice.setType(QTouchDevice::TouchScreen);
@ -75,7 +88,8 @@ Web3DOverlay::Web3DOverlay() {
connect(this, &Web3DOverlay::resizeWebSurface, this, &Web3DOverlay::onResizeWebSurface); connect(this, &Web3DOverlay::resizeWebSurface, this, &Web3DOverlay::onResizeWebSurface);
//need to be intialized before Tablet 1st open //need to be intialized before Tablet 1st open
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url); _webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML);
_cachedWebSurface = true;
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data()); _webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED _webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", 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) { if (!_webSurface) {
return; return;
} }
QQuickItem* rootItem = _webSurface->getRootItem(); QQuickItem* rootItem = _webSurface->getRootItem();
if (rootItem && rootItem->objectName() == "tabletRoot") { if (rootItem && rootItem->objectName() == "tabletRoot") {
@ -135,10 +150,15 @@ void Web3DOverlay::destroyWebSurface() {
QObject::disconnect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent); QObject::disconnect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
QObject::disconnect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived); QObject::disconnect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
auto offscreenCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
// FIXME prevents crash on shutdown, but we shoudln't have to do this check // If the web surface was fetched out of the cache, release it back into the cache
if (offscreenCache) { if (_cachedWebSurface) {
offscreenCache->release(QML, _webSurface); auto offscreenCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
// FIXME prevents crash on shutdown, but we shoudln't have to do this check
if (offscreenCache) {
offscreenCache->release(QML, _webSurface);
}
_cachedWebSurface = false;
} }
_webSurface.reset(); _webSurface.reset();
} }
@ -147,6 +167,8 @@ void Web3DOverlay::buildWebSurface() {
if (_webSurface) { if (_webSurface) {
return; 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([&] { gl::withSavedContext([&] {
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces // FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
// and the current rendering load) // and the current rendering load)
@ -156,10 +178,13 @@ void Web3DOverlay::buildWebSurface() {
if (isWebContent()) { if (isWebContent()) {
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML); _webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML);
_cachedWebSurface = true;
_webSurface->getRootItem()->setProperty("url", _url); _webSurface->getRootItem()->setProperty("url", _url);
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL); _webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
} else { } else {
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url); _webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), qmlSurfaceDeleter);
_webSurface->load(_url);
_cachedWebSurface = false;
setupQmlSurface(); setupQmlSurface();
} }
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition())); _webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition()));

View file

@ -88,6 +88,7 @@ private:
InputMode _inputMode { Touch }; InputMode _inputMode { Touch };
QSharedPointer<OffscreenQmlSurface> _webSurface; QSharedPointer<OffscreenQmlSurface> _webSurface;
bool _cachedWebSurface{ false };
gpu::TexturePointer _texture; gpu::TexturePointer _texture;
QString _url; QString _url;
QString _scriptURL; QString _scriptURL;

View file

@ -21,10 +21,6 @@ glm::uvec2 NullDisplayPlugin::getRecommendedRenderSize() const {
return glm::uvec2(100, 100); return glm::uvec2(100, 100);
} }
bool NullDisplayPlugin::hasFocus() const {
return false;
}
void NullDisplayPlugin::submitFrame(const gpu::FramePointer& frame) { void NullDisplayPlugin::submitFrame(const gpu::FramePointer& frame) {
if (frame) { if (frame) {
_gpuContext->consumeFrameUpdates(frame); _gpuContext->consumeFrameUpdates(frame);

View file

@ -16,7 +16,6 @@ public:
grouping getGrouping() const override { return DEVELOPER; } grouping getGrouping() const override { return DEVELOPER; }
glm::uvec2 getRecommendedRenderSize() const override; glm::uvec2 getRecommendedRenderSize() const override;
bool hasFocus() const override;
void submitFrame(const gpu::FramePointer& newFrame) override; void submitFrame(const gpu::FramePointer& newFrame) override;
QImage getScreenshot(float aspectRatio = 0.0f) const override; QImage getScreenshot(float aspectRatio = 0.0f) const override;
QImage getSecondaryCameraScreenshot() const override; QImage getSecondaryCameraScreenshot() const override;

View file

@ -831,11 +831,6 @@ glm::uvec2 OpenGLDisplayPlugin::getSurfaceSize() const {
return result; return result;
} }
bool OpenGLDisplayPlugin::hasFocus() const {
auto window = _container->getPrimaryWidget();
return window ? window->hasFocus() : false;
}
void OpenGLDisplayPlugin::assertNotPresentThread() const { void OpenGLDisplayPlugin::assertNotPresentThread() const {
Q_ASSERT(QThread::currentThread() != _presentThread); Q_ASSERT(QThread::currentThread() != _presentThread);
} }

View file

@ -98,8 +98,6 @@ protected:
virtual void compositePointer(); virtual void compositePointer();
virtual void compositeExtra() {}; virtual void compositeExtra() {};
virtual bool hasFocus() const override;
// These functions must only be called on the presentation thread // These functions must only be called on the presentation thread
virtual void customizeContext(); virtual void customizeContext();
virtual void uncustomizeContext(); virtual void uncustomizeContext();

View file

@ -239,7 +239,7 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
} }
bool WebEntityRenderer::hasWebSurface() { bool WebEntityRenderer::hasWebSurface() {
return (bool)_webSurface; return (bool)_webSurface && _webSurface->getRootItem();
} }
bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
@ -303,7 +303,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
_fadeStartTime = usecTimestampNow(); _fadeStartTime = usecTimestampNow();
_webSurface->resume(); _webSurface->resume();
return true; return _webSurface->getRootItem();
} }
void WebEntityRenderer::destroyWebSurface() { void WebEntityRenderer::destroyWebSurface() {

View file

@ -157,7 +157,7 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u
} }
if (usingUserData) { 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 // Since our material changed, the current name might not be valid anymore, so we need to update
setCurrentMaterialName(_currentMaterialName); setCurrentMaterialName(_currentMaterialName);

View file

@ -20,7 +20,7 @@ void NetworkMaterialResource::downloadFinished(const QByteArray& data) {
parsedMaterials.reset(); parsedMaterials.reset();
if (_url.toString().contains(".json")) { if (_url.toString().contains(".json")) {
parsedMaterials = parseJSONMaterials(QJsonDocument::fromJson(data)); parsedMaterials = parseJSONMaterials(QJsonDocument::fromJson(data), _url);
} }
// TODO: parse other material types // 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. <em>Currently not used.</em> * @property {number} materialVersion=1 - The version of the material. <em>Currently not used.</em>
* @property {Material|Material[]} materials - The details of the material or materials. * @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; ParsedMaterials toReturn;
if (!materialJSON.isNull() && materialJSON.isObject()) { if (!materialJSON.isNull() && materialJSON.isObject()) {
QJsonObject materialJSONObject = materialJSON.object(); QJsonObject materialJSONObject = materialJSON.object();
@ -91,13 +91,13 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater
QJsonArray materials = materialsValue.toArray(); QJsonArray materials = materialsValue.toArray();
for (auto material : materials) { for (auto material : materials) {
if (!material.isNull() && material.isObject()) { if (!material.isNull() && material.isObject()) {
auto parsedMaterial = parseJSONMaterial(material.toObject()); auto parsedMaterial = parseJSONMaterial(material.toObject(), baseUrl);
toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second; toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second;
toReturn.names.push_back(parsedMaterial.first); toReturn.names.push_back(parsedMaterial.first);
} }
} }
} else if (materialsValue.isObject()) { } else if (materialsValue.isObject()) {
auto parsedMaterial = parseJSONMaterial(materialsValue.toObject()); auto parsedMaterial = parseJSONMaterial(materialsValue.toObject(), baseUrl);
toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second; toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second;
toReturn.names.push_back(parsedMaterial.first); toReturn.names.push_back(parsedMaterial.first);
} }
@ -138,7 +138,7 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater
* @property {string} lightMap - URL of light map texture image. <em>Currently not used.</em> * @property {string} lightMap - URL of light map texture image. <em>Currently not used.</em>
*/ */
// Note: See MaterialEntityItem.h for default values used in practice. // Note: See MaterialEntityItem.h for default values used in practice.
std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON) { std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl) {
std::string name = ""; std::string name = "";
std::shared_ptr<NetworkMaterial> material = std::make_shared<NetworkMaterial>(); std::shared_ptr<NetworkMaterial> material = std::make_shared<NetworkMaterial>();
for (auto& key : materialJSON.keys()) { for (auto& key : materialJSON.keys()) {
@ -199,57 +199,58 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
} else if (key == "albedoMap") { } else if (key == "albedoMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
QString urlString = value.toString();
bool useAlphaChannel = false; bool useAlphaChannel = false;
auto opacityMap = materialJSON.find("opacityMap"); 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; useAlphaChannel = true;
} }
material->setAlbedoMap(value.toString(), useAlphaChannel); material->setAlbedoMap(baseUrl.resolved(urlString), useAlphaChannel);
} }
} else if (key == "roughnessMap") { } else if (key == "roughnessMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
material->setRoughnessMap(value.toString(), false); material->setRoughnessMap(baseUrl.resolved(value.toString()), false);
} }
} else if (key == "glossMap") { } else if (key == "glossMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
material->setRoughnessMap(value.toString(), true); material->setRoughnessMap(baseUrl.resolved(value.toString()), true);
} }
} else if (key == "metallicMap") { } else if (key == "metallicMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
material->setMetallicMap(value.toString(), false); material->setMetallicMap(baseUrl.resolved(value.toString()), false);
} }
} else if (key == "specularMap") { } else if (key == "specularMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
material->setMetallicMap(value.toString(), true); material->setMetallicMap(baseUrl.resolved(value.toString()), true);
} }
} else if (key == "normalMap") { } else if (key == "normalMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
material->setNormalMap(value.toString(), false); material->setNormalMap(baseUrl.resolved(value.toString()), false);
} }
} else if (key == "bumpMap") { } else if (key == "bumpMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
material->setNormalMap(value.toString(), true); material->setNormalMap(baseUrl.resolved(value.toString()), true);
} }
} else if (key == "occlusionMap") { } else if (key == "occlusionMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
material->setOcclusionMap(value.toString()); material->setOcclusionMap(baseUrl.resolved(value.toString()));
} }
} else if (key == "scatteringMap") { } else if (key == "scatteringMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
material->setScatteringMap(value.toString()); material->setScatteringMap(baseUrl.resolved(value.toString()));
} }
} else if (key == "lightMap") { } else if (key == "lightMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
material->setLightmapMap(value.toString()); material->setLightmapMap(baseUrl.resolved(value.toString()));
} }
} }
} }

View file

@ -37,8 +37,8 @@ public:
ParsedMaterials parsedMaterials; ParsedMaterials parsedMaterials;
static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON); static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON, const QUrl& baseUrl);
static std::pair<std::string, std::shared_ptr<NetworkMaterial>> parseJSONMaterial(const QJsonObject& materialJSON); static std::pair<std::string, std::shared_ptr<NetworkMaterial>> parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl);
private: private:
static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB);

View file

@ -556,58 +556,58 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, im
return nullptr; return nullptr;
} }
void NetworkMaterial::setAlbedoMap(const QString& url, bool useAlphaChannel) { void NetworkMaterial::setAlbedoMap(const QUrl& url, bool useAlphaChannel) {
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); auto map = fetchTextureMap(url, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
if (map) { if (map) {
map->setUseAlphaChannel(useAlphaChannel); map->setUseAlphaChannel(useAlphaChannel);
setTextureMap(MapChannel::ALBEDO_MAP, map); setTextureMap(MapChannel::ALBEDO_MAP, map);
} }
} }
void NetworkMaterial::setNormalMap(const QString& url, bool isBumpmap) { void NetworkMaterial::setNormalMap(const QUrl& url, bool isBumpmap) {
auto map = fetchTextureMap(QUrl(url), isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP); auto map = fetchTextureMap(url, isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP);
if (map) { if (map) {
setTextureMap(MapChannel::NORMAL_MAP, map); setTextureMap(MapChannel::NORMAL_MAP, map);
} }
} }
void NetworkMaterial::setRoughnessMap(const QString& url, bool isGloss) { void NetworkMaterial::setRoughnessMap(const QUrl& url, bool isGloss) {
auto map = fetchTextureMap(QUrl(url), isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); auto map = fetchTextureMap(url, isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP);
if (map) { if (map) {
setTextureMap(MapChannel::ROUGHNESS_MAP, map); setTextureMap(MapChannel::ROUGHNESS_MAP, map);
} }
} }
void NetworkMaterial::setMetallicMap(const QString& url, bool isSpecular) { void NetworkMaterial::setMetallicMap(const QUrl& url, bool isSpecular) {
auto map = fetchTextureMap(QUrl(url), isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); auto map = fetchTextureMap(url, isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP);
if (map) { if (map) {
setTextureMap(MapChannel::METALLIC_MAP, map); setTextureMap(MapChannel::METALLIC_MAP, map);
} }
} }
void NetworkMaterial::setOcclusionMap(const QString& url) { void NetworkMaterial::setOcclusionMap(const QUrl& url) {
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
if (map) { if (map) {
setTextureMap(MapChannel::OCCLUSION_MAP, map); setTextureMap(MapChannel::OCCLUSION_MAP, map);
} }
} }
void NetworkMaterial::setEmissiveMap(const QString& url) { void NetworkMaterial::setEmissiveMap(const QUrl& url) {
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); auto map = fetchTextureMap(url, image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP);
if (map) { if (map) {
setTextureMap(MapChannel::EMISSIVE_MAP, map); setTextureMap(MapChannel::EMISSIVE_MAP, map);
} }
} }
void NetworkMaterial::setScatteringMap(const QString& url) { void NetworkMaterial::setScatteringMap(const QUrl& url) {
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); auto map = fetchTextureMap(url, image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP);
if (map) { if (map) {
setTextureMap(MapChannel::SCATTERING_MAP, map); setTextureMap(MapChannel::SCATTERING_MAP, map);
} }
} }
void NetworkMaterial::setLightmapMap(const QString& url) { void NetworkMaterial::setLightmapMap(const QUrl& url) {
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); auto map = fetchTextureMap(url, image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP);
if (map) { if (map) {
//map->setTextureTransform(_lightmapTransform); //map->setTextureTransform(_lightmapTransform);
//map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); //map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y);

View file

@ -164,14 +164,14 @@ public:
NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl); NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl);
NetworkMaterial(const NetworkMaterial& material); NetworkMaterial(const NetworkMaterial& material);
void setAlbedoMap(const QString& url, bool useAlphaChannel); void setAlbedoMap(const QUrl& url, bool useAlphaChannel);
void setNormalMap(const QString& url, bool isBumpmap); void setNormalMap(const QUrl& url, bool isBumpmap);
void setRoughnessMap(const QString& url, bool isGloss); void setRoughnessMap(const QUrl& url, bool isGloss);
void setMetallicMap(const QString& url, bool isSpecular); void setMetallicMap(const QUrl& url, bool isSpecular);
void setOcclusionMap(const QString& url); void setOcclusionMap(const QUrl& url);
void setEmissiveMap(const QString& url); void setEmissiveMap(const QUrl& url);
void setScatteringMap(const QString& url); void setScatteringMap(const QUrl& url);
void setLightmapMap(const QString& url); void setLightmapMap(const QUrl& url);
protected: protected:
friend class Geometry; friend class Geometry;

View file

@ -140,9 +140,6 @@ public:
virtual void setContext(const gpu::ContextPointer& context) final { _gpuContext = context; } virtual void setContext(const gpu::ContextPointer& context) final { _gpuContext = context; }
virtual void submitFrame(const gpu::FramePointer& newFrame) = 0; virtual void submitFrame(const gpu::FramePointer& newFrame) = 0;
// Does the rendering surface have current focus?
virtual bool hasFocus() const = 0;
// The size of the rendering target (may be larger than the device size due to distortion) // The size of the rendering target (may be larger than the device size due to distortion)
virtual glm::uvec2 getRecommendedRenderSize() const = 0; virtual glm::uvec2 getRecommendedRenderSize() const = 0;

View file

@ -8,6 +8,9 @@ include_hifi_library_headers(audio)
include_hifi_library_headers(networking) include_hifi_library_headers(networking)
include_hifi_library_headers(octree) 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) if (NOT ANDROID)
target_nsight() target_nsight()
endif () endif ()

View file

@ -47,6 +47,8 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr
} }
} }
const graphics::MaterialPointer MeshPartPayload::DEFAULT_MATERIAL = std::make_shared<graphics::Material>();
MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material) { MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material) {
updateMeshPart(mesh, partIndex); updateMeshPart(mesh, partIndex);
addMaterial(graphics::MaterialLayer(material, 0)); addMaterial(graphics::MaterialLayer(material, 0));
@ -99,7 +101,7 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShad
builder.withSubMetaCulled(); builder.withSubMetaCulled();
} }
if (_drawMaterials.top().material) { if (topMaterialExists()) {
auto matKey = _drawMaterials.top().material->getKey(); auto matKey = _drawMaterials.top().material->getKey();
if (matKey.isTranslucent()) { if (matKey.isTranslucent()) {
builder.withTransparent(); builder.withTransparent();
@ -119,7 +121,7 @@ Item::Bound MeshPartPayload::getBound() const {
ShapeKey MeshPartPayload::getShapeKey() const { ShapeKey MeshPartPayload::getShapeKey() const {
graphics::MaterialKey drawMaterialKey; graphics::MaterialKey drawMaterialKey;
if (_drawMaterials.top().material) { if (topMaterialExists()) {
drawMaterialKey = _drawMaterials.top().material->getKey(); drawMaterialKey = _drawMaterials.top().material->getKey();
} }
@ -171,7 +173,7 @@ void MeshPartPayload::render(RenderArgs* args) {
bindMesh(batch); bindMesh(batch);
// apply material properties // 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++; args->_details._materialSwitches++;
// Draw! // Draw!
@ -356,7 +358,7 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCas
builder.withDeformed(); builder.withDeformed();
} }
if (_drawMaterials.top().material) { if (topMaterialExists()) {
auto matKey = _drawMaterials.top().material->getKey(); auto matKey = _drawMaterials.top().material->getKey();
if (matKey.isTranslucent()) { if (matKey.isTranslucent()) {
builder.withTransparent(); builder.withTransparent();
@ -387,7 +389,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe
} }
graphics::MaterialKey drawMaterialKey; graphics::MaterialKey drawMaterialKey;
if (_drawMaterials.top().material) { if (topMaterialExists()) {
drawMaterialKey = _drawMaterials.top().material->getKey(); drawMaterialKey = _drawMaterials.top().material->getKey();
} }
@ -469,7 +471,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
bindMesh(batch); bindMesh(batch);
// apply material properties // 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++; args->_details._materialSwitches++;
// Draw! // Draw!

View file

@ -65,15 +65,18 @@ public:
graphics::Mesh::Part _drawPart; graphics::Mesh::Part _drawPart;
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
size_t getMaterialTextureSize() { return _drawMaterials.top().material ? _drawMaterials.top().material->getTextureSize() : 0; } size_t getMaterialTextureSize() { return topMaterialExists() ? _drawMaterials.top().material->getTextureSize() : 0; }
int getMaterialTextureCount() { return _drawMaterials.top().material ? _drawMaterials.top().material->getTextureCount() : 0; } int getMaterialTextureCount() { return topMaterialExists() ? _drawMaterials.top().material->getTextureCount() : 0; }
bool hasTextureInfo() const { return _drawMaterials.top().material ? _drawMaterials.top().material->hasTextureInfo() : false; } bool hasTextureInfo() const { return topMaterialExists() ? _drawMaterials.top().material->hasTextureInfo() : false; }
void addMaterial(graphics::MaterialLayer material); void addMaterial(graphics::MaterialLayer material);
void removeMaterial(graphics::MaterialPointer material); void removeMaterial(graphics::MaterialPointer material);
protected: protected:
static const graphics::MaterialPointer DEFAULT_MATERIAL;
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() }; render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
bool topMaterialExists() const { return !_drawMaterials.empty() && _drawMaterials.top().material; }
}; };
namespace render { namespace render {

View file

@ -1604,7 +1604,8 @@ void Model::createVisibleRenderItemSet() {
int numParts = (int)mesh->getNumParts(); int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) { for (int partIndex = 0; partIndex < numParts; partIndex++) {
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(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 }); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
shapeID++; shapeID++;
} }

View file

@ -20,8 +20,12 @@ if (NOT SERVER_ONLY AND NOT ANDROID)
add_subdirectory(${DIR}) add_subdirectory(${DIR})
set(DIR "oculusLegacy") set(DIR "oculusLegacy")
add_subdirectory(${DIR}) add_subdirectory(${DIR})
set(DIR "hifiSixense")
add_subdirectory(${DIR}) if (USE_SIXENSE)
set(DIR "hifiSixense")
add_subdirectory(${DIR})
endif()
set(DIR "hifiSpacemouse") set(DIR "hifiSpacemouse")
add_subdirectory(${DIR}) add_subdirectory(${DIR})
set(DIR "hifiNeuron") set(DIR "hifiNeuron")

View file

@ -19,7 +19,7 @@ if (WIN32 AND (NOT USE_GLES))
set(TARGET_NAME oculus) set(TARGET_NAME oculus)
setup_hifi_plugin(Multimedia) setup_hifi_plugin(Multimedia)
link_hifi_libraries( 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 plugins ui-plugins display-plugins input-plugins
audio-client networking render-utils audio-client networking render-utils
${PLATFORM_GL_BACKEND} ${PLATFORM_GL_BACKEND}

View file

@ -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();

View file

@ -14,7 +14,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
# link in the shared libraries # link in the shared libraries
link_hifi_libraries( link_hifi_libraries(
shared task networking animation shared task networking animation
ktx image octree gl gpu gpu-gl ktx image octree gl gpu ${PLATFORM_GL_BACKEND}
render render-utils render render-utils
graphics fbx model-networking graphics-scripting graphics fbx model-networking graphics-scripting
entities entities-renderer audio avatars script-engine entities entities-renderer audio avatars script-engine