Merge remote-tracking branch 'upstream/master' into bindless

This commit is contained in:
Brad Davis 2018-03-21 19:16:55 -07:00
commit 0e7ee95c95
58 changed files with 983 additions and 513 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*
# place you need to use `HIFI_ANDROID` instead of `ANDROID`
if (WIN32 AND NOT HIFI_ANDROID)
@ -14,8 +14,12 @@ include("cmake/init.cmake")
include("cmake/compiler.cmake")
if (BUILD_SCRIBE_ONLY)
add_subdirectory(tools/scribe)
return()
add_subdirectory(tools/scribe)
return()
endif()
if (NOT DEFINED CLIENT_ONLY)
set(CLIENT_ONLY 0)
endif()
if (NOT DEFINED SERVER_ONLY)
@ -23,46 +27,54 @@ if (NOT DEFINED SERVER_ONLY)
endif()
if (ANDROID OR UWP)
set(MOBILE 1)
set(MOBILE 1)
else()
set(MOBILE 0)
set(MOBILE 0)
endif()
set(BUILD_CLIENT_OPTION ON)
set(BUILD_SERVER_OPTION ON)
set(BUILD_TESTS_OPTION ON)
set(BUILD_TOOLS_OPTION ON)
set(BUILD_INSTALLER_OPTION ON)
set(GLES_OPTION OFF)
set(DISABLE_QML_OPTION OFF)
if (ANDROID OR UWP)
option(BUILD_SERVER "Build server components" OFF)
option(BUILD_TOOLS "Build tools" OFF)
option(BUILD_INSTALLER "Build installer" OFF)
else()
option(BUILD_SERVER "Build server components" ON)
option(BUILD_TOOLS "Build tools" ON)
option(BUILD_INSTALLER "Build installer" ON)
set(BUILD_SERVER_OPTION OFF)
set(BUILD_TOOLS_OPTION OFF)
set(BUILD_INSTALLER OFF)
endif()
if (CLIENT_ONLY)
set(BUILD_SERVER_OPTION OFF)
endif()
if (SERVER_ONLY)
option(BUILD_CLIENT "Build client components" OFF)
option(BUILD_TESTS "Build tests" OFF)
else()
option(BUILD_CLIENT "Build client components" ON)
option(BUILD_TESTS "Build tests" ON)
set(BUILD_CLIENT_OPTION OFF)
set(BUILD_TESTS_OPTION OFF)
endif()
if (ANDROID)
option(USE_GLES "Use OpenGL ES" ON)
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
set(GLES_OPTION ON)
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
else ()
option(USE_GLES "Use OpenGL ES" OFF)
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
endif ()
if (USE_GLES AND (NOT ANDROID))
option(DISABLE_QML "Disable QML" ON)
else()
option(DISABLE_QML "Disable QML" OFF)
set(DISABLE_QML_OPTION ON)
endif()
option(BUILD_CLIENT "Build client components" ${BUILD_CLIENT_OPTION})
option(BUILD_SERVER "Build server components" ${BUILD_SERVER_OPTION})
option(BUILD_TESTS "Build tests" ${BUILD_TESTS_OPTION})
option(BUILD_TOOLS "Build tools" ${BUILD_TOOLS_OPTION})
option(BUILD_INSTALLER "Build installer" ${BUILD_INSTALLER_OPTION})
option(USE_GLES "Use OpenGL ES" ${GLES_OPTION})
option(DISABLE_QML "Disable QML" ${DISABLE_QML_OPTION})
option(DISABLE_KTX_CACHE "Disable KTX Cache" OFF)
set(PLATFORM_QT_GL OpenGL)
if (USE_GLES)
@ -72,12 +84,10 @@ else()
set(PLATFORM_GL_BACKEND gpu-gl-common gpu-gl)
endif()
foreach(PLATFORM_QT_COMPONENT ${PLATFORM_QT_COMPONENTS})
list(APPEND PLATFORM_QT_LIBRARIES "Qt5::${PLATFORM_QT_COMPONENT}")
endforeach()
MESSAGE(STATUS "Build server: " ${BUILD_SERVER})
MESSAGE(STATUS "Build client: " ${BUILD_CLIENT})
MESSAGE(STATUS "Build tests: " ${BUILD_TESTS})
@ -86,17 +96,17 @@ MESSAGE(STATUS "Build installer: " ${BUILD_INSTALLER})
MESSAGE(STATUS "GL ES: " ${USE_GLES})
if (DISABLE_QML)
MESSAGE(STATUS "QML disabled!")
add_definitions(-DDISABLE_QML)
MESSAGE(STATUS "QML disabled!")
add_definitions(-DDISABLE_QML)
endif()
if (DISABLE_KTX_CACHE)
MESSAGE(STATUS "KTX cache disabled!")
add_definitions(-DDISABLE_KTX_CACHE)
MESSAGE(STATUS "KTX cache disabled!")
add_definitions(-DDISABLE_KTX_CACHE)
endif()
if (UNIX AND DEFINED ENV{HIFI_MEMORY_DEBUGGING})
MESSAGE(STATUS "Memory debugging is enabled")
MESSAGE(STATUS "Memory debugging is enabled")
endif()
#
@ -132,8 +142,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,32 +158,30 @@ 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
add_subdirectory(tools)
if (BUILD_TESTS)
add_subdirectory(tests)
add_subdirectory(tests)
endif()
if (BUILD_INSTALLER)
if (UNIX)
install(
DIRECTORY "${CMAKE_SOURCE_DIR}/scripts"
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/interface
COMPONENT ${CLIENT_COMPONENT}
)
endif()
generate_installers()
if (UNIX)
install(
DIRECTORY "${CMAKE_SOURCE_DIR}/scripts"
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/interface
COMPONENT ${CLIENT_COMPONENT}
)
endif()
generate_installers()
endif()

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
- [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.

View file

@ -476,6 +476,7 @@ void EntityScriptServer::clear() {
// do this here (instead of in deleter) to avoid marshalling unload signals back to this thread
_entitiesScriptEngine->unloadAllEntityScripts();
_entitiesScriptEngine->stop();
_entitiesScriptEngine->waitTillDoneRunning();
}
_entityViewer.clear();
@ -565,8 +566,15 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> mess
void EntityScriptServer::aboutToFinish() {
shutdownScriptEngine();
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
// our entity tree is going to go away so tell that to the EntityScriptingInterface
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);
entityScriptingInterface->setEntityTree(nullptr);
// Should always be true as they are singletons.
if (entityScriptingInterface->getPacketSender() == &_entityEditSender) {
// The packet sender is about to go away.
entityScriptingInterface->setPacketSender(nullptr);
}
DependencyManager::get<ResourceManager>()->cleanup();

View file

@ -4,7 +4,7 @@ cmake_policy(SET CMP0046 OLD)
include(ExternalProject)
set(QUAZIP_CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_PREFIX_PATH=${QT_CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_NAME_DIR:PATH=<INSTALL_DIR>/lib -DZLIB_ROOT=${ZLIB_ROOT} -DCMAKE_POSITION_INDEPENDENT_CODE=ON)
set(QUAZIP_CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_PREFIX_PATH=${QT_CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_NAME_DIR:PATH=<INSTALL_DIR>/lib -DZLIB_ROOT=${ZLIB_ROOT} -DCMAKE_POSITION_INDEPENDENT_CODE=ON)
if (APPLE)
else ()

View file

@ -23,7 +23,7 @@ macro(GENERATE_INSTALLERS)
set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME})
set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME})
if (PR_BUILD)
set(CPACK_NSIS_COMPRESSOR "/SOLID bzip2")
set(CPACK_NSIS_COMPRESSOR "bzip2")
endif ()
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME})
@ -46,9 +46,35 @@ 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)
if (CLIENT_ONLY OR SERVER_ONLY)
set(CPACK_MONOLITHIC_INSTALL 1)
endif ()
# setup conditional checks for server component selection depending on
# the inclusion of the server component at all
if (CLIENT_ONLY)
set(SERVER_COMPONENT_CONDITIONAL "0 == 1")
set(CLIENT_COMPONENT_CONDITIONAL "1 == 1")
elseif (SERVER_ONLY)
set(SERVER_COMPONENT_CONDITIONAL "1 == 1")
set(CLIENT_COMPONENT_CONDITIONAL "0 == 1")
else ()
set(SERVER_COMPONENT_CONDITIONAL "\\\${SectionIsSelected} \\\${${SERVER_COMPONENT}}")
set(CLIENT_COMPONENT_CONDITIONAL "\\\${SectionIsSelected} \\\${${CLIENT_COMPONENT}}")
endif ()
elseif (APPLE)
# produce a drag and drop DMG on OS X
set(CPACK_GENERATOR "DragNDrop")
@ -79,8 +105,13 @@ macro(GENERATE_INSTALLERS)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Interface")
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Sandbox")
if (BUILD_CLIENT)
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Interface")
endif ()
if (BUILD_SERVER)
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Sandbox")
endif ()
include(CPack)
endmacro()

View file

@ -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} $<$<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")

View file

@ -27,6 +27,11 @@ macro(SET_PACKAGING_PARAMETERS)
message(STATUS "The BRANCH environment variable is: $ENV{BRANCH}")
message(STATUS "The RELEASE_TYPE variable is: ${RELEASE_TYPE}")
# setup component categories for installer
set(DDE_COMPONENT dde)
set(CLIENT_COMPONENT client)
set(SERVER_COMPONENT server)
if (RELEASE_TYPE STREQUAL "PRODUCTION")
set(DEPLOY_PACKAGE TRUE)
set(PRODUCTION_BUILD 1)
@ -149,13 +154,10 @@ 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
set(DDE_COMPONENT dde)
set(CLIENT_COMPONENT client)
set(SERVER_COMPONENT server)
# print out some results for testing this new build feature
message(STATUS "The BUILD_GLOBAL_SERVICES variable is: ${BUILD_GLOBAL_SERVICES}")
message(STATUS "The USE_STABLE_GLOBAL_SERVICES variable is: ${USE_STABLE_GLOBAL_SERVICES}")

View file

@ -41,6 +41,10 @@ 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@")
set(SERVER_COMPONENT_CONDITIONAL "@SERVER_COMPONENT_CONDITIONAL@")
set(CLIENT_COMPONENT_CONDITIONAL "@CLIENT_COMPONENT_CONDITIONAL@")

View file

@ -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,38 @@ 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@
; the MUI_PAGE_CUSTOMFUNCTION_PRE shouldn't be defined here
; which can happen for a component-less (like client only) install
!ifdef MUI_PAGE_CUSTOMFUNCTION_PRE
!undef MUI_PAGE_CUSTOMFUNCTION_PRE
!endif
Page custom PostInstallOptionsPage ReadPostInstallOptions
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageInstallFilesPre
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM
@ -452,8 +534,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 +586,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
@ -502,10 +618,11 @@ Function InstallTypesPage
${If} $CustomInstallTemporaryState == ${BST_UNCHECKED}
${NSD_Check} $ExpressInstallRadioButton
Call ChangeExpressLabel
${Else}
Call ChangeCustomLabel
${EndIf}
Call ChangeExpressLabel
nsDialogs::Show
FunctionEnd
@ -523,14 +640,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,15 +653,10 @@ 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
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${If} @CLIENT_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @INTERFACE_HF_SHORTCUT_NAME@"
Pop $DesktopClientCheckbox
IntOp $CurrentOffset $CurrentOffset + 15
@ -557,7 +665,7 @@ Function PostInstallOptionsPage
!insertmacro SetInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED}
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${If} @SERVER_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@"
Pop $DesktopServerCheckbox
IntOp $CurrentOffset $CurrentOffset + 15
@ -566,7 +674,7 @@ Function PostInstallOptionsPage
!insertmacro SetInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED}
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${If} @SERVER_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install"
Pop $LaunchServerNowCheckbox
@ -580,7 +688,7 @@ Function PostInstallOptionsPage
IntOp $CurrentOffset $CurrentOffset + 15
${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${If} @CLIENT_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install"
Pop $LaunchClientNowCheckbox
IntOp $CurrentOffset $CurrentOffset + 30
@ -593,7 +701,7 @@ Function PostInstallOptionsPage
${EndIf}
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${If} @SERVER_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup"
Pop $ServerStartupCheckbox
IntOp $CurrentOffset $CurrentOffset + 15
@ -602,7 +710,7 @@ Function PostInstallOptionsPage
!insertmacro SetInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED}
${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${If} @SERVER_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)"
Pop $CleanInstallCheckbox
IntOp $CurrentOffset $CurrentOffset + 15
@ -610,11 +718,11 @@ Function PostInstallOptionsPage
${If} @PR_BUILD@ == 1
; a PR build defaults all install options expect LaunchServerNowCheckbox, LaunchClientNowCheckbox and the settings copy to unchecked
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${If} @CLIENT_COMPONENT_CONDITIONAL@
${NSD_SetState} $DesktopClientCheckbox ${BST_UNCHECKED}
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${If} @SERVER_COMPONENT_CONDITIONAL@
${NSD_SetState} $DesktopServerCheckbox ${BST_UNCHECKED}
${NSD_SetState} $ServerStartupCheckbox ${BST_UNCHECKED}
${EndIf}
@ -673,12 +781,12 @@ Function ReadInstallTypes
FunctionEnd
Function ReadPostInstallOptions
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${If} @CLIENT_COMPONENT_CONDITIONAL@
; check if the user asked for a desktop shortcut to High Fidelity
${NSD_GetState} $DesktopClientCheckbox $DesktopClientState
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${If} @SERVER_COMPONENT_CONDITIONAL@
; check if the user asked for a desktop shortcut to Sandbox
${NSD_GetState} $DesktopServerCheckbox $DesktopServerState
@ -691,24 +799,24 @@ Function ReadPostInstallOptions
${NSD_GetState} $CopyFromProductionCheckbox $CopyFromProductionState
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${If} @SERVER_COMPONENT_CONDITIONAL@
; check if we need to launch the server post-install
${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState
${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${If} @CLIENT_COMPONENT_CONDITIONAL@
; check if we need to launch the client post-install
${NSD_GetState} $LaunchClientNowCheckbox $LaunchClientNowState
${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${If} @CLIENT_COMPONENT_CONDITIONAL@
; check if the user asked for a clean install
${NSD_GetState} $CleanInstallCheckbox $CleanInstallState
${EndIf}
FunctionEnd
Function HandlePostInstallOptions
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${If} @CLIENT_COMPONENT_CONDITIONAL@
; check if the user asked for a desktop shortcut to High Fidelity
${If} $DesktopClientState == ${BST_CHECKED}
CreateShortCut "$DESKTOP\@INTERFACE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
@ -719,7 +827,7 @@ Function HandlePostInstallOptions
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${If} @SERVER_COMPONENT_CONDITIONAL@
; check if the user asked for a desktop shortcut to Sandbox
${If} $DesktopServerState == ${BST_CHECKED}
CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
@ -748,7 +856,7 @@ Function HandlePostInstallOptions
${EndIf}
${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${If} @CLIENT_COMPONENT_CONDITIONAL@
; check if the user asked for a clean install
${If} $CleanInstallState == ${BST_CHECKED}
SetShellVarContext current
@ -785,7 +893,8 @@ Function HandlePostInstallOptions
${EndIf}
${EndIf}
${If} $LaunchServerNowState == ${BST_CHECKED}
${If} @SERVER_COMPONENT_CONDITIONAL@
${AndIf} $LaunchServerNowState == ${BST_CHECKED}
!insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ YES
; both launches use the explorer trick in case the user has elevated permissions for the installer
@ -799,7 +908,7 @@ Function HandlePostInstallOptions
Exec '"$WINDIR\explorer.exe" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"'
${EndIf}
${Else}
${ElseIf} @CLIENT_COMPONENT_CONDITIONAL@
!insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ NO
; launch uses the explorer trick in case the user has elevated permissions for the installer
@ -837,9 +946,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 +964,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.
@ -931,7 +1034,7 @@ Section "-Core installation"
@CPACK_NSIS_CREATE_ICONS_EXTRA@
; Conditional handling for Interface specific options
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${If} @CLIENT_COMPONENT_CONDITIONAL@
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@INTERFACE_SHORTCUT_NAME@.lnk" \
"$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
@ -946,7 +1049,7 @@ Section "-Core installation"
${EndIf}
; Conditional handling for server console shortcut
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${If} @SERVER_COMPONENT_CONDITIONAL@
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \
"$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
${EndIf}
@ -965,6 +1068,7 @@ Section "-Core installation"
; Handle whichever post install options were set
Call HandlePostInstallOptions
!insertmacro GoogleAnalytics "Installer" "Done" "" ""
SectionEnd
!include nsProcess.nsh
@ -979,7 +1083,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 +1096,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
@ -1087,8 +1193,8 @@ Function .onSelChange
!insertmacro SectionList MaybeSelectionChanged
; if neither component is selected, disable the install button
${IfNot} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${AndIfNot} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${IfNot} @CLIENT_COMPONENT_CONDITIONAL@
${AndIfNot} @SERVER_COMPONENT_CONDITIONAL@
GetDlgItem $0 $HWNDPARENT 1
EnableWindow $0 0
${Else}
@ -1219,6 +1325,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}

View file

@ -20,6 +20,7 @@
#include <QJsonArray>
#include <QProcess>
#include <QSharedMemory>
#include <QRegularExpression>
#include <QStandardPaths>
#include <QTimer>
#include <QUrlQuery>
@ -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>();
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<QFile>(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<ReceivedMessage> message) {
void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer<ReceivedMessage> message) {
qInfo() << "Received request to replace content from a url";
auto node = DependencyManager::get<LimitedNodeList>()->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(QSharedPointer<Rece
connect(reply, &QNetworkReply::finished, [this, reply, modelsURL]() {
QNetworkReply::NetworkError networkError = reply->error();
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<Rece
}
}
void DomainServer::handleOctreeFileReplacementRequest(QSharedPointer<ReceivedMessage> message) {
auto node = DependencyManager::get<NodeList>()->nodeWithUUID(message->getSourceID());
if (node->getCanReplaceContent()) {
handleOctreeFileReplacement(message->readAll());
}
}
}

View file

@ -91,7 +91,7 @@ private slots:
void processICEServerHeartbeatDenialPacket(QSharedPointer<ReceivedMessage> message);
void processICEServerHeartbeatACK(QSharedPointer<ReceivedMessage> message);
void handleOctreeFileReplacementFromURLRequest(QSharedPointer<ReceivedMessage> message);
void handleDomainContentReplacementFromURLRequest(QSharedPointer<ReceivedMessage> message);
void handleOctreeFileReplacementRequest(QSharedPointer<ReceivedMessage> message);
void handleOctreeFileReplacement(QByteArray octreeFile);

View file

@ -26,17 +26,17 @@ generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources
if (ANDROID)
# on Android, don't compress the rcc binary
add_custom_command(
OUTPUT ${RESOURCES_RCC}
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
COMMAND "${QT_DIR}/bin/rcc"
ARGS ${RESOURCES_QRC} -no-compress -binary -o ${RESOURCES_RCC}
OUTPUT ${RESOURCES_RCC}
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
COMMAND "${QT_DIR}/bin/rcc"
ARGS ${RESOURCES_QRC} -no-compress -binary -o ${RESOURCES_RCC}
)
else ()
add_custom_command(
OUTPUT ${RESOURCES_RCC}
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
COMMAND "${QT_DIR}/bin/rcc"
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC}
OUTPUT ${RESOURCES_RCC}
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
COMMAND "${QT_DIR}/bin/rcc"
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC}
)
endif()
@ -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)
@ -199,12 +203,6 @@ if (WIN32)
add_dependency_external_projects(steamworks)
endif()
# include OPENSSL
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
# append OpenSSL to our list of libraries to link
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})
# disable /OPT:REF and /OPT:ICF for the Debug builds
# This will prevent the following linker warnings
# LINK : warning LNK4075: ignoring '/INCREMENTAL' due to '/OPT:ICF' specification
@ -228,6 +226,9 @@ link_hifi_libraries(
# include the binary directory of render-utils for shader includes
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils")
# include OpenSSL
target_openssl()
target_bullet()
target_opengl()
add_crashpad()
@ -328,13 +329,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}"
"$<TARGET_FILE_DIR:interface>"
# 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"
@ -389,3 +390,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)

View file

@ -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<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {
const std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions {
{ SVO_EXTENSION, &Application::importSVOFromURL },
{ SVO_JSON_EXTENSION, &Application::importSVOFromURL },
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl },
@ -386,6 +387,7 @@ const QHash<QString, Application::AcceptURLMethod> 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 }
@ -2704,6 +2706,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
@ -6173,11 +6176,9 @@ bool Application::canAcceptURL(const QString& urlString) const {
} else if (urlString.startsWith(HIFI_URL_SCHEME)) {
return true;
}
QHashIterator<QString, AcceptURLMethod> 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;
}
}
@ -6194,12 +6195,10 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
}
QUrl url(urlString);
QHashIterator<QString, AcceptURLMethod> 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);
}
}
@ -6386,13 +6385,11 @@ void Application::replaceDomainContent(const QString& url) {
QByteArray urlData(url.toUtf8());
auto limitedNodeList = DependencyManager::get<NodeList>();
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>();
addressManager->handleLookupString(DOMAIN_SPAWNING_POINT);
QString newHomeAddress = addressManager->getHost() + DOMAIN_SPAWNING_POINT;
@ -7350,10 +7347,35 @@ bool Application::isThrottleRendering() const {
}
bool Application::hasFocus() const {
if (_displayPlugin) {
return getActiveDisplayPlugin()->hasFocus();
bool result = (QApplication::activeWindow() != nullptr);
#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) {

View file

@ -161,6 +161,8 @@ public:
QRect getRecommendedHUDRect() const;
glm::vec2 getDeviceSize() const;
bool hasFocus() const;
void setFocus();
void raise();
void showCursor(const Cursor::Icon& cursor);
@ -603,7 +605,7 @@ private:
GLCanvas* _glWidget{ nullptr };
typedef bool (Application::* AcceptURLMethod)(const QString &);
static const QHash<QString, AcceptURLMethod> _acceptedExtensions;
static const std::vector<std::pair<QString, Application::AcceptURLMethod>> _acceptedExtensions;
glm::uvec2 _renderResolution;

View file

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

View file

@ -62,13 +62,14 @@ public slots:
QScriptValue hasFocus();
/**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
*/
void setFocus();
/**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
*/
void raiseMainWindow();

View file

@ -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<OffscreenQmlSurfaceCache>()->acquire(_url);
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML);
_cachedWebSurface = true;
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().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<OffscreenQmlSurfaceCache>();
// 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<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();
}
@ -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<OffscreenQmlSurfaceCache>()->acquire(QML);
_cachedWebSurface = true;
_webSurface->getRootItem()->setProperty("url", _url);
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
} else {
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url);
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), qmlSurfaceDeleter);
_webSurface->load(_url);
_cachedWebSurface = false;
setupQmlSurface();
}
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition()));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,6 +9,7 @@
#include "RenderableMaterialEntityItem.h"
#include "RenderPipelines.h"
#include "GeometryCache.h"
using namespace render;
using namespace render::entities;
@ -90,138 +91,6 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
return builder.build();
}
glm::vec3 MaterialEntityRenderer::getVertexPos(float phi, float theta) {
return glm::vec3(glm::sin(theta) * glm::cos(phi), glm::cos(theta), glm::sin(theta) * glm::sin(phi));
}
glm::vec3 MaterialEntityRenderer::getTangent(float phi, float theta) {
return glm::vec3(-glm::cos(theta) * glm::cos(phi), glm::sin(theta), -glm::cos(theta) * glm::sin(phi));
}
void MaterialEntityRenderer::addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv) {
buffer.push_back(pos.x); buffer.push_back(pos.y); buffer.push_back(pos.z);
buffer.push_back(tan.x); buffer.push_back(tan.y); buffer.push_back(tan.z);
buffer.push_back(uv.x); buffer.push_back(uv.y);
}
void MaterialEntityRenderer::addTriangleFan(std::vector<float>& buffer, int stack, int step) {
float v1 = ((float)stack) / STACKS;
float theta1 = v1 * (float)M_PI;
glm::vec3 tip = getVertexPos(0, theta1);
float v2 = ((float)(stack + step)) / STACKS;
float theta2 = v2 * (float)M_PI;
for (int i = 0; i < SLICES; i++) {
float u1 = ((float)i) / SLICES;
float u2 = ((float)(i + step)) / SLICES;
float phi1 = u1 * M_PI_TIMES_2;
float phi2 = u2 * M_PI_TIMES_2;
/* (flipped for negative step)
p1
/ \
/ \
/ \
p3 ------ p2
*/
glm::vec3 pos2 = getVertexPos(phi2, theta2);
glm::vec3 pos3 = getVertexPos(phi1, theta2);
glm::vec3 tan1 = getTangent(0, theta1);
glm::vec3 tan2 = getTangent(phi2, theta2);
glm::vec3 tan3 = getTangent(phi1, theta2);
glm::vec2 uv1 = glm::vec2((u1 + u2) / 2.0f, v1);
glm::vec2 uv2 = glm::vec2(u2, v2);
glm::vec2 uv3 = glm::vec2(u1, v2);
addVertex(buffer, tip, tan1, uv1);
addVertex(buffer, pos2, tan2, uv2);
addVertex(buffer, pos3, tan3, uv3);
_numVertices += 3;
}
}
int MaterialEntityRenderer::_numVertices = 0;
std::shared_ptr<gpu::Stream::Format> MaterialEntityRenderer::_streamFormat = nullptr;
std::shared_ptr<gpu::BufferStream> MaterialEntityRenderer::_stream = nullptr;
std::shared_ptr<gpu::Buffer> MaterialEntityRenderer::_verticesBuffer = nullptr;
void MaterialEntityRenderer::generateMesh() {
_streamFormat = std::make_shared<gpu::Stream::Format>();
_stream = std::make_shared<gpu::BufferStream>();
_verticesBuffer = std::make_shared<gpu::Buffer>();
const int NUM_POS_COORDS = 3;
const int NUM_TANGENT_COORDS = 3;
const int VERTEX_TANGENT_OFFSET = NUM_POS_COORDS * sizeof(float);
const int VERTEX_TEXCOORD_OFFSET = VERTEX_TANGENT_OFFSET + NUM_TANGENT_COORDS * sizeof(float);
_streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
_streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
_streamFormat->setAttribute(gpu::Stream::TANGENT, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_TANGENT_OFFSET);
_streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET);
_stream->addBuffer(_verticesBuffer, 0, _streamFormat->getChannels().at(0)._stride);
std::vector<float> vertexBuffer;
// Top
addTriangleFan(vertexBuffer, 0, 1);
// Middle section
for (int j = 1; j < STACKS - 1; j++) {
float v1 = ((float)j) / STACKS;
float v2 = ((float)(j + 1)) / STACKS;
float theta1 = v1 * (float)M_PI;
float theta2 = v2 * (float)M_PI;
for (int i = 0; i < SLICES; i++) {
float u1 = ((float)i) / SLICES;
float u2 = ((float)(i + 1)) / SLICES;
float phi1 = u1 * M_PI_TIMES_2;
float phi2 = u2 * M_PI_TIMES_2;
/*
p2 ---- p3
| / |
| / |
| / |
p1 ---- p4
*/
glm::vec3 pos1 = getVertexPos(phi1, theta2);
glm::vec3 pos2 = getVertexPos(phi1, theta1);
glm::vec3 pos3 = getVertexPos(phi2, theta1);
glm::vec3 pos4 = getVertexPos(phi2, theta2);
glm::vec3 tan1 = getTangent(phi1, theta2);
glm::vec3 tan2 = getTangent(phi1, theta1);
glm::vec3 tan3 = getTangent(phi2, theta1);
glm::vec3 tan4 = getTangent(phi2, theta2);
glm::vec2 uv1 = glm::vec2(u1, v2);
glm::vec2 uv2 = glm::vec2(u1, v1);
glm::vec2 uv3 = glm::vec2(u2, v1);
glm::vec2 uv4 = glm::vec2(u2, v2);
addVertex(vertexBuffer, pos1, tan1, uv1);
addVertex(vertexBuffer, pos2, tan2, uv2);
addVertex(vertexBuffer, pos3, tan3, uv3);
addVertex(vertexBuffer, pos3, tan3, uv3);
addVertex(vertexBuffer, pos4, tan4, uv4);
addVertex(vertexBuffer, pos1, tan1, uv1);
_numVertices += 6;
}
}
// Bottom
addTriangleFan(vertexBuffer, STACKS, -1);
_verticesBuffer->append(vertexBuffer.size() * sizeof(float), (gpu::Byte*) vertexBuffer.data());
}
void MaterialEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
Q_ASSERT(args->_batch);
@ -252,14 +121,7 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
args->_details._materialSwitches++;
// Draw!
if (_numVertices == 0) {
generateMesh();
}
DependencyManager::get<GeometryCache>()->renderSphere(batch);
batch.setInputFormat(_streamFormat);
batch.setInputStream(0, *_stream);
batch.draw(gpu::TRIANGLES, _numVertices, 0);
const int NUM_VERTICES_PER_TRIANGLE = 3;
args->_details._trianglesRendered += _numVertices / NUM_VERTICES_PER_TRIANGLE;
args->_details._trianglesRendered += (int)DependencyManager::get<GeometryCache>()->getSphereTriangleCount();
}

View file

@ -40,20 +40,6 @@ private:
Transform _renderTransform;
std::shared_ptr<NetworkMaterial> _drawMaterial;
static int _numVertices;
static std::shared_ptr<gpu::Stream::Format> _streamFormat;
static std::shared_ptr<gpu::BufferStream> _stream;
static std::shared_ptr<gpu::Buffer> _verticesBuffer;
void generateMesh();
void addTriangleFan(std::vector<float>& buffer, int stack, int step);
static glm::vec3 getVertexPos(float phi, float theta);
static glm::vec3 getTangent(float phi, float theta);
static void addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv);
const int SLICES = 15;
const int STACKS = 9;
const float M_PI_TIMES_2 = 2.0f * (float)M_PI;
};
} }

View file

@ -19,6 +19,8 @@
#include "render-utils/simple_vert.h"
#include "render-utils/simple_frag.h"
#include "RenderPipelines.h"
//#define SHAPE_ENTITY_USE_FADE_EFFECT
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT
#include <FadeEffect.h>
@ -108,11 +110,94 @@ bool ShapeEntityRenderer::isTransparent() const {
if (_procedural.isEnabled() && _procedural.isFading()) {
return Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) < 1.0f;
}
// return _entity->getLocalRenderAlpha() < 1.0f || Parent::isTransparent();
auto mat = _materials.find("0");
if (mat != _materials.end()) {
if (mat->second.top().material) {
auto matKey = mat->second.top().material->getKey();
if (matKey.isTranslucent()) {
return true;
}
}
}
return Parent::isTransparent();
}
ItemKey ShapeEntityRenderer::getKey() {
ItemKey::Builder builder;
builder.withTypeShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
withReadLock([&] {
if (isTransparent()) {
builder.withTransparent();
}
});
return builder.build();
}
bool ShapeEntityRenderer::useMaterialPipeline() const {
bool proceduralReady = resultWithReadLock<bool>([&] {
return _procedural.isReady();
});
if (proceduralReady) {
return false;
}
graphics::MaterialKey drawMaterialKey;
auto mat = _materials.find("0");
if (mat != _materials.end() && mat->second.top().material) {
drawMaterialKey = mat->second.top().material->getKey();
}
if (drawMaterialKey.isEmissive() || drawMaterialKey.isUnlit() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
return true;
}
// If the material is using any map, we need to use a material ShapeKey
for (int i = 0; i < graphics::Material::MapChannel::NUM_MAP_CHANNELS; i++) {
if (drawMaterialKey.isMapChannel(graphics::Material::MapChannel(i))) {
return true;
}
}
return false;
}
ShapeKey ShapeEntityRenderer::getShapeKey() {
if (useMaterialPipeline()) {
graphics::MaterialKey drawMaterialKey;
if (_materials["0"].top().material) {
drawMaterialKey = _materials["0"].top().material->getKey();
}
bool isTranslucent = drawMaterialKey.isTranslucent();
bool hasTangents = drawMaterialKey.isNormalMap();
bool hasLightmap = drawMaterialKey.isLightmapMap();
bool isUnlit = drawMaterialKey.isUnlit();
ShapeKey::Builder builder;
builder.withMaterial();
if (isTranslucent) {
builder.withTranslucent();
}
if (hasTangents) {
builder.withTangents();
}
if (hasLightmap) {
builder.withLightmap();
}
if (isUnlit) {
builder.withUnlit();
}
return builder.build();
} else {
return Parent::getShapeKey();
}
}
void ShapeEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
Q_ASSERT(args->_batch);
@ -149,7 +234,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
} else {
geometryCache->renderShape(batch, geometryShape, outColor);
}
} else {
} else if (!useMaterialPipeline()) {
// FIXME, support instanced multi-shape rendering using multidraw indirect
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
@ -158,6 +243,11 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
} else {
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
}
} else {
RenderPipelines::bindMaterial(mat, batch, args->_enableTexturing);
args->_details._materialSwitches++;
geometryCache->renderShape(batch, geometryShape);
}
const auto triCount = geometryCache->getShapeTriangleCount(geometryShape);

View file

@ -24,6 +24,10 @@ public:
virtual scriptable::ScriptableModelBase getScriptableModel() override;
protected:
ItemKey getKey() override;
ShapeKey getShapeKey() override;
private:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
@ -32,6 +36,8 @@ private:
virtual void doRender(RenderArgs* args) override;
virtual bool isTransparent() const override;
bool useMaterialPipeline() const;
Procedural _procedural;
QString _lastUserData;
Transform _renderTransform;

View file

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

View file

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

View file

@ -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. <em>Currently not used.</em>
* @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. <em>Currently not used.</em>
*/
// 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::shared_ptr<NetworkMaterial> material = std::make_shared<NetworkMaterial>();
for (auto& key : materialJSON.keys()) {
@ -199,57 +199,58 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> 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()));
}
}
}

View file

@ -37,8 +37,8 @@ public:
ParsedMaterials parsedMaterials;
static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON);
static std::pair<std::string, std::shared_ptr<NetworkMaterial>> parseJSONMaterial(const QJsonObject& materialJSON);
static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON, const QUrl& baseUrl);
static std::pair<std::string, std::shared_ptr<NetworkMaterial>> parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl);
private:
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;
}
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);

View file

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

View file

@ -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

View file

@ -140,9 +140,6 @@ public:
virtual void setContext(const gpu::ContextPointer& context) final { _gpuContext = context; }
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)
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(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 ()

View file

@ -100,6 +100,8 @@ static const int VERTICES_PER_TRIANGLE = 3;
static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element TEXCOORD0_ELEMENT { gpu::VEC2, gpu::FLOAT, gpu::UV };
static const gpu::Element TANGENT_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA };
static const gpu::Element TEXCOORD4_ELEMENT { gpu::VEC4, gpu::FLOAT, gpu::XYZW };
@ -107,8 +109,10 @@ static gpu::Stream::FormatPointer SOLID_STREAM_FORMAT;
static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT;
static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT;
static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals
static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);
static const uint SHAPE_VERTEX_STRIDE = sizeof(GeometryCache::ShapeVertex); // position, normal, texcoords, tangent
static const uint SHAPE_NORMALS_OFFSET = offsetof(GeometryCache::ShapeVertex, normal);
static const uint SHAPE_TEXCOORD0_OFFSET = offsetof(GeometryCache::ShapeVertex, uv);
static const uint SHAPE_TANGENT_OFFSET = offsetof(GeometryCache::ShapeVertex, tangent);
void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) {
@ -167,16 +171,20 @@ std::vector<vec3> polygon() {
return result;
}
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices) {
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<ShapeVertex>& vertices) {
gpu::Buffer::Size offset = vertexBuffer->getSize();
vertexBuffer->append(vertices);
gpu::Buffer::Size viewSize = vertices.size() * sizeof(glm::vec3);
gpu::Buffer::Size viewSize = vertices.size() * sizeof(ShapeVertex);
_positionView = gpu::BufferView(vertexBuffer, offset,
viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT);
_normalView = gpu::BufferView(vertexBuffer, offset + SHAPE_NORMALS_OFFSET,
viewSize, SHAPE_VERTEX_STRIDE, NORMAL_ELEMENT);
_texCoordView = gpu::BufferView(vertexBuffer, offset + SHAPE_TEXCOORD0_OFFSET,
viewSize, SHAPE_VERTEX_STRIDE, TEXCOORD0_ELEMENT);
_tangentView = gpu::BufferView(vertexBuffer, offset + SHAPE_TANGENT_OFFSET,
viewSize, SHAPE_VERTEX_STRIDE, TANGENT_ELEMENT);
}
void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices) {
@ -202,6 +210,8 @@ void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, con
void GeometryCache::ShapeData::setupBatch(gpu::Batch& batch) const {
batch.setInputBuffer(gpu::Stream::POSITION, _positionView);
batch.setInputBuffer(gpu::Stream::NORMAL, _normalView);
batch.setInputBuffer(gpu::Stream::TEXCOORD, _texCoordView);
batch.setInputBuffer(gpu::Stream::TANGENT, _tangentView);
batch.setIndexBuffer(_indicesView);
}
@ -268,14 +278,14 @@ static IndexPair indexToken(geometry::Index a, geometry::Index b) {
template <size_t N>
void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
using namespace geometry;
VertexVector vertices;
std::vector<GeometryCache::ShapeVertex> vertices;
IndexVector solidIndices, wireIndices;
IndexPairs wireSeenIndices;
size_t faceCount = shape.faces.size();
size_t faceIndexCount = triangulatedFaceIndexCount<N>();
vertices.reserve(N * faceCount * 2);
vertices.reserve(N * faceCount);
solidIndices.reserve(faceIndexCount * faceCount);
Index baseVertex = 0;
@ -284,11 +294,35 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
// Compute the face normal
vec3 faceNormal = shape.getFaceNormal(f);
// Find two points on this face with the same Y tex coords, and find the vector going from the one with the smaller X tex coord to the one with the larger X tex coord
vec3 faceTangent = vec3(0.0f);
Index i1 = 0;
Index i2 = i1 + 1;
while (i1 < N) {
if (shape.texCoords[f * N + i1].y == shape.texCoords[f * N + i2].y) {
break;
}
if (i2 == N - 1) {
i1++;
i2 = i1 + 1;
} else {
i2++;
}
}
if (i1 < N && i2 < N) {
vec3 p1 = shape.vertices[face[i1]];
vec3 p2 = shape.vertices[face[i2]];
faceTangent = glm::normalize(p1 - p2);
if (shape.texCoords[f * N + i1].x < shape.texCoords[f * N + i2].x) {
faceTangent *= -1.0f;
}
}
// Create the vertices for the face
for (Index i = 0; i < N; i++) {
Index originalIndex = face[i];
vertices.push_back(shape.vertices[originalIndex]);
vertices.push_back(faceNormal);
vertices.emplace_back(shape.vertices[originalIndex], faceNormal, shape.texCoords[f * N + i], faceTangent);
}
// Create the wire indices for unseen edges
@ -316,21 +350,95 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
}
vec2 calculateSphereTexCoord(const vec3& vertex) {
float u = 1.0f - (std::atan2(-vertex.z, -vertex.x) / ((float)M_PI) + 1.0f) * 0.5f;
if (vertex.y == 1.0f || vertex.y == -1.0f) {
// Remember points at the top so we don't treat them as being along the seam
u = NAN;
}
float v = 0.5f - std::asin(vertex.y) / (float)M_PI;
return vec2(u, v);
}
const float M_PI_TIMES_2 = 2.0f * (float)M_PI;
vec3 calculateSphereTangent(float u) {
float phi = u * M_PI_TIMES_2;
return -glm::normalize(glm::vec3(glm::sin(phi), 0.0f, glm::cos(phi)));
}
template <size_t N>
void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
using namespace geometry;
VertexVector vertices;
vertices.reserve(shape.vertices.size() * 2);
std::vector<GeometryCache::ShapeVertex> vertices;
vertices.reserve(shape.vertices.size());
for (const auto& vertex : shape.vertices) {
vertices.push_back(vertex);
vertices.push_back(vertex);
// We'll fill in the correct tangents later, once we correct the UVs
vertices.emplace_back(vertex, vertex, calculateSphereTexCoord(vertex), vec3(0.0f));
}
// We need to fix up the sphere's UVs because it's actually a tesselated icosahedron. See http://mft-dev.dk/uv-mapping-sphere/
size_t faceCount = shape.faces.size();
for (size_t f = 0; f < faceCount; f++) {
// Fix zipper
{
float& u1 = vertices[shape.faces[f][0]].uv.x;
float& u2 = vertices[shape.faces[f][1]].uv.x;
float& u3 = vertices[shape.faces[f][2]].uv.x;
if (glm::isnan(u1)) {
u1 = (u2 + u3) / 2.0f;
}
if (glm::isnan(u2)) {
u2 = (u1 + u3) / 2.0f;
}
if (glm::isnan(u3)) {
u3 = (u1 + u2) / 2.0f;
}
const float U_THRESHOLD = 0.25f;
float max = glm::max(u1, glm::max(u2, u3));
float min = glm::min(u1, glm::min(u2, u3));
if (max - min > U_THRESHOLD) {
if (u1 < U_THRESHOLD) {
u1 += 1.0f;
}
if (u2 < U_THRESHOLD) {
u2 += 1.0f;
}
if (u3 < U_THRESHOLD) {
u3 += 1.0f;
}
}
}
// Fix swirling at poles
for (Index i = 0; i < N; i++) {
Index originalIndex = shape.faces[f][i];
if (shape.vertices[originalIndex].y == 1.0f || shape.vertices[originalIndex].y == -1.0f) {
float uSum = 0.0f;
for (Index i2 = 1; i2 <= N - 1; i2++) {
float u = vertices[shape.faces[f][(i + i2) % N]].uv.x;
uSum += u;
}
uSum /= (float)(N - 1);
vertices[originalIndex].uv.x = uSum;
break;
}
}
// Fill in tangents
for (Index i = 0; i < N; i++) {
vec3 tangent = calculateSphereTangent(vertices[shape.faces[f][i]].uv.x);
vertices[shape.faces[f][i]].tangent = tangent;
}
}
IndexVector solidIndices, wireIndices;
IndexPairs wireSeenIndices;
size_t faceCount = shape.faces.size();
size_t faceIndexCount = triangulatedFaceIndexCount<N>();
solidIndices.reserve(faceIndexCount * faceCount);
@ -365,25 +473,22 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
template <uint32_t N>
void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) {
using namespace geometry;
VertexVector vertices;
std::vector<GeometryCache::ShapeVertex> vertices;
IndexVector solidIndices, wireIndices;
// Top (if not conical) and bottom faces
std::vector<vec3> shape = polygon<N>();
if (isConical) {
for (uint32_t i = 0; i < N; i++) {
vertices.push_back(vec3(0.0f, 0.5f, 0.0f));
vertices.push_back(vec3(0.0f, 1.0f, 0.0f));
vertices.emplace_back(vec3(0.0f, 0.5f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec2((float)i / (float)N, 1.0f), vec3(0.0f));
}
} else {
for (const vec3& v : shape) {
vertices.push_back(vec3(v.x, 0.5f, v.z));
vertices.push_back(vec3(0.0f, 1.0f, 0.0f));
vertices.emplace_back(vec3(v.x, 0.5f, v.z), vec3(0.0f, 1.0f, 0.0f), vec2(v.x, v.z) + vec2(0.5f), vec3(1.0f, 0.0f, 0.0f));
}
}
for (const vec3& v : shape) {
vertices.push_back(vec3(v.x, -0.5f, v.z));
vertices.push_back(vec3(0.0f, -1.0f, 0.0f));
vertices.emplace_back(vec3(v.x, -0.5f, v.z), vec3(0.0f, -1.0f, 0.0f), vec2(-v.x, v.z) + vec2(0.5f), vec3(-1.0f, 0.0f, 0.0f));
}
Index baseVertex = 0;
for (uint32_t i = 2; i < N; i++) {
@ -412,15 +517,16 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
vec3 topRight = (isConical ? vec3(0.0f, 0.5f, 0.0f) : vec3(right.x, 0.5f, right.z));
vec3 bottomLeft = vec3(left.x, -0.5f, left.z);
vec3 bottomRight = vec3(right.x, -0.5f, right.z);
vec3 tangent = glm::normalize(bottomLeft - bottomRight);
vertices.push_back(topLeft);
vertices.push_back(normal);
vertices.push_back(bottomLeft);
vertices.push_back(normal);
vertices.push_back(topRight);
vertices.push_back(normal);
vertices.push_back(bottomRight);
vertices.push_back(normal);
// Our tex coords go in the opposite direction as our vertices
float u = 1.0f - (float)i / (float)N;
float u2 = 1.0f - (float)(i + 1) / (float)N;
vertices.emplace_back(topLeft, normal, vec2(u, 0.0f), tangent);
vertices.emplace_back(bottomLeft, normal, vec2(u, 1.0f), tangent);
vertices.emplace_back(topRight, normal, vec2(u2, 0.0f), tangent);
vertices.emplace_back(bottomRight, normal, vec2(u2, 1.0f), tangent);
solidIndices.push_back(baseVertex + 0);
solidIndices.push_back(baseVertex + 2);
@ -439,41 +545,6 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
}
void drawCircle(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
// Draw a circle with radius 1/4th the size of the bounding box
using namespace geometry;
VertexVector vertices;
IndexVector solidIndices, wireIndices;
const int NUM_CIRCLE_VERTICES = 64;
std::vector<vec3> shape = polygon<NUM_CIRCLE_VERTICES>();
for (const vec3& v : shape) {
vertices.push_back(vec3(v.x, 0.0f, v.z));
vertices.push_back(vec3(0.0f, 0.0f, 0.0f));
}
Index baseVertex = 0;
for (uint32_t i = 2; i < NUM_CIRCLE_VERTICES; i++) {
solidIndices.push_back(baseVertex + 0);
solidIndices.push_back(baseVertex + i);
solidIndices.push_back(baseVertex + i - 1);
solidIndices.push_back(baseVertex + NUM_CIRCLE_VERTICES);
solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES - 1);
solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES);
}
for (uint32_t i = 1; i <= NUM_CIRCLE_VERTICES; i++) {
wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES));
wireIndices.push_back(baseVertex + i - 1);
wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES) + NUM_CIRCLE_VERTICES);
wireIndices.push_back(baseVertex + (i - 1) + NUM_CIRCLE_VERTICES);
}
shapeData.setupVertices(vertexBuffer, vertices);
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
}
// FIXME solids need per-face vertices, but smooth shaded
// components do not. Find a way to support using draw elements
// or draw arrays as appropriate
@ -506,9 +577,9 @@ void GeometryCache::buildShapes() {
// Line
{
ShapeData& shapeData = _shapes[Line];
shapeData.setupVertices(_shapeVertices, VertexVector {
vec3(-0.5f, 0.0f, 0.0f), vec3(-0.5f, 0.0f, 0.0f),
vec3(0.5f, 0.0f, 0.0f), vec3(0.5f, 0.0f, 0.0f)
shapeData.setupVertices(_shapeVertices, std::vector<ShapeVertex> {
ShapeVertex(vec3(-0.5f, 0.0f, 0.0f), vec3(-0.5f, 0.0f, 0.0f), vec2(0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f)),
ShapeVertex(vec3(0.5f, 0.0f, 0.0f), vec3(0.5f, 0.0f, 0.0f), vec2(0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f))
});
IndexVector wireIndices;
// Only two indices
@ -572,6 +643,8 @@ gpu::Stream::FormatPointer& getSolidStreamFormat() {
SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
}
return SOLID_STREAM_FORMAT;
}
@ -581,6 +654,8 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() {
INSTANCED_SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
}
return INSTANCED_SOLID_STREAM_FORMAT;
@ -591,6 +666,8 @@ gpu::Stream::FormatPointer& getInstancedSolidFadeStreamFormat() {
INSTANCED_SOLID_FADE_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD2, gpu::Stream::TEXCOORD2, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD3, gpu::Stream::TEXCOORD3, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
@ -893,6 +970,7 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, con
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET);
// TODO: circle3D overlays use this to define their vertices, so they need tex coords
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);

View file

@ -354,13 +354,24 @@ public:
/// Set a batch to the simple pipeline, returning the previous pipeline
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false);
struct ShapeVertex {
ShapeVertex(const vec3& pos, const vec3& normal, const vec2& uv, const vec3& tangent) : pos(pos), normal(normal), uv(uv), tangent(tangent) {}
vec3 pos;
vec3 normal;
vec2 uv;
vec3 tangent;
};
struct ShapeData {
gpu::BufferView _positionView;
gpu::BufferView _normalView;
gpu::BufferView _texCoordView;
gpu::BufferView _tangentView;
gpu::BufferView _indicesView;
gpu::BufferView _wireIndicesView;
void setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices);
void setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<ShapeVertex>& vertices);
void setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices);
void setupBatch(gpu::Batch& batch) const;
void draw(gpu::Batch& batch) const;

View file

@ -218,25 +218,25 @@ vec3 fetchLightmapMap(vec2 uv) {
}
<@endfunc@>
<@func tangentToViewSpace(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
<@func evalMaterialNormal(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
{
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
vec3 localNormal = <$fetchedNormal$>;
<$normal$> = vec3(normalizedTangent * localNormal.x + normalizedNormal * localNormal.y + normalizedBitangent * localNormal.z);
<$normal$> = vec3(normalizedBitangent * localNormal.x + normalizedNormal * localNormal.y + normalizedTangent * localNormal.z);
}
<@endfunc@>
<@func tangentToViewSpaceLOD(fragPos, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
<@func evalMaterialNormalLOD(fragPos, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
{
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
// attenuate the normal map divergence from the mesh normal based on distance
// THe attenuation range [20,100] meters from the eye is arbitrary for now
// The attenuation range [20,100] meters from the eye is arbitrary for now
vec3 localNormal = mix(<$fetchedNormal$>, vec3(0.0, 1.0, 0.0), smoothstep(20.0, 100.0, (-<$fragPos$>).z));
<$normal$> = vec3(normalizedTangent * localNormal.x + normalizedNormal * localNormal.y + normalizedBitangent * localNormal.z);
<$normal$> = vec3(normalizedBitangent * localNormal.x + normalizedNormal * localNormal.y + normalizedTangent * localNormal.z);
}
<@endfunc@>

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) {
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!

View file

@ -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 {

View file

@ -1604,7 +1604,8 @@ void Model::createVisibleRenderItemSet() {
int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) {
_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 });
shapeID++;
}

View file

@ -58,7 +58,7 @@ void main(void) {
vec3 fragPosition = _position.xyz;
vec3 fragNormal;
<$tangentToViewSpace(normalTex, _normal, _tangent, fragNormal)$>
<$evalMaterialNormal(normalTex, _normal, _tangent, fragNormal)$>
TransformCamera cam = getTransformCamera();

View file

@ -33,11 +33,11 @@ void main(void) {
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTexel, _normal, _tangent, viewNormal)$>
vec3 fragNormal;
<$evalMaterialNormalLOD(_position, normalTexel, _normal, _tangent, fragNormal)$>
packDeferredFragmentLightmap(
normalize(viewNormal.xyz),
normalize(fragNormal.xyz),
evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a),
getMaterialAlbedo(mat) * albedo.rgb * _color,
getMaterialRoughness(mat) * roughness,

View file

@ -43,11 +43,11 @@ void main(void) {
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTexel, _normal, _tangent, viewNormal)$>
vec3 fragNormal;
<$evalMaterialNormalLOD(_position, normalTexel, _normal, _tangent, fragNormal)$>
packDeferredFragmentLightmap(
normalize(viewNormal.xyz),
normalize(fragNormal.xyz),
evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a),
getMaterialAlbedo(mat) * albedo.rgb * _color,
getMaterialRoughness(mat) * roughness,

View file

@ -46,8 +46,8 @@ void main(void) {
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
vec3 fragNormal;
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
float metallic = getMaterialMetallic(mat);
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
@ -56,7 +56,7 @@ void main(void) {
<$evalMaterialScattering(scatteringTex, scattering, matKey, scattering)$>;
packDeferredFragment(
normalize(viewNormal.xyz),
normalize(fragNormal.xyz),
opacity,
albedo,
roughness,

View file

@ -56,8 +56,8 @@ void main(void) {
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
vec3 fragNormal;
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
float metallic = getMaterialMetallic(mat);
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
@ -65,7 +65,7 @@ void main(void) {
float scattering = getMaterialScattering(mat);
packDeferredFragment(
normalize(viewNormal.xyz),
normalize(fragNormal.xyz),
opacity,
albedo,
roughness,

View file

@ -61,7 +61,7 @@ void main(void) {
vec3 fragPosition = _position.xyz;
vec3 fragNormal;
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
TransformCamera cam = getTransformCamera();
vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));

View file

@ -71,7 +71,7 @@ void main(void) {
vec3 fragPosition = _position.xyz;
// Lighting is done in world space
vec3 fragNormal;
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
TransformCamera cam = getTransformCamera();
vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));

View file

@ -8,8 +8,11 @@
#include "Shapes.h"
#include "qmath.h"
namespace geometry {
using glm::vec2;
using glm::vec3;
// The golden ratio
@ -19,8 +22,8 @@ Solid<3> tesselate(const Solid<3>& solid_, int count) {
Solid<3> solid = solid_;
float length = glm::length(solid.vertices[0]);
for (int i = 0; i < count; ++i) {
Solid<3> result { solid.vertices, {} };
result.vertices.reserve(solid.vertices.size() + solid.faces.size() * 3);
Solid<3> result { solid.vertices, {}, {} };
result.vertices.reserve(solid.vertices.size() + solid.faces.size() * 6);
for (size_t f = 0; f < solid.faces.size(); ++f) {
Index baseVertex = (Index)result.vertices.size();
const Face<3>& oldFace = solid.faces[f];
@ -30,13 +33,26 @@ Solid<3> tesselate(const Solid<3>& solid_, int count) {
vec3 ab = glm::normalize(a + b) * length;
vec3 bc = glm::normalize(b + c) * length;
vec3 ca = glm::normalize(c + a) * length;
result.vertices.push_back(a);
result.vertices.push_back(ab);
result.vertices.push_back(ca);
result.faces.push_back(Face<3>{ { baseVertex, baseVertex + 1, baseVertex + 2 } });
result.vertices.push_back(ab);
result.vertices.push_back(b);
result.vertices.push_back(bc);
result.faces.push_back(Face<3>{ { baseVertex + 3, baseVertex + 4, baseVertex + 5 } });
result.vertices.push_back(bc);
result.vertices.push_back(c);
result.vertices.push_back(ca);
result.faces.push_back(Face<3>{ { baseVertex + 6, baseVertex + 7, baseVertex + 8 } });
result.vertices.push_back(ab);
result.vertices.push_back(bc);
result.vertices.push_back(ca);
result.faces.push_back(Face<3>{ { oldFace[0], baseVertex, baseVertex + 2 } });
result.faces.push_back(Face<3>{ { baseVertex, oldFace[1], baseVertex + 1 } });
result.faces.push_back(Face<3>{ { baseVertex + 1, oldFace[2], baseVertex + 2 } });
result.faces.push_back(Face<3>{ { baseVertex, baseVertex + 1, baseVertex + 2 } });
result.faces.push_back(Face<3>{ { baseVertex + 9, baseVertex + 10, baseVertex + 11 } });
}
solid = result;
}
@ -50,6 +66,10 @@ const Solid<3>& tetrahedron() {
static const auto D = vec3(-1, -1, 1);
static const Solid<3> TETRAHEDRON = Solid<3>{
{ A, B, C, D },
{ vec2(0.75f, 0.5f), vec2(0.5f, 0.0f), vec2(0.25f, 0.5f),
vec2(0.5f, 1.0f), vec2(1.0f, 1.0f), vec2(0.75f, 0.5f),
vec2(0.25f, 0.5f), vec2(0.5f, 1.0f), vec2(0.75f, 0.5f),
vec2(0.25f, 0.5f), vec2(0.0f, 1.0f), vec2(0.5f, 1.0f) },
FaceVector<3>{
Face<3> { { 0, 1, 2 } },
Face<3> { { 3, 1, 0 } },
@ -65,8 +85,15 @@ const Solid<4>& cube() {
static const auto B = vec3(-1, 1, 1);
static const auto C = vec3(-1, 1, -1);
static const auto D = vec3(1, 1, -1);
static const float THIRD = 1.0f / 3.0f;
static const Solid<4> CUBE = Solid<4>{
{ A, B, C, D, -A, -B, -C, -D },
{ vec2(0.5f, 0.0f), vec2(0.25f, 0.0f), vec2(0.25f, THIRD), vec2(0.5f, THIRD),
vec2(0.5f, THIRD), vec2(0.25f, THIRD), vec2(0.25f, 2.0f * THIRD), vec2(0.5f, 2.0f * THIRD),
vec2(0.25f, THIRD), vec2(0.0f, THIRD), vec2(0.0f, 2.0f * THIRD), vec2(0.25f, 2.0f * THIRD),
vec2(1.0f, THIRD), vec2(0.75f, THIRD), vec2(0.75f, 2.0f * THIRD), vec2(1.0f, 2.0f * THIRD),
vec2(0.75f, THIRD), vec2(0.5f, THIRD), vec2(0.5f, 2.0f * THIRD), vec2(0.75f, 2.0f * THIRD),
vec2(0.25f, 1.0f), vec2(0.5f, 1.0f), vec2(0.5f, 2.0f * THIRD), vec2(0.25f, 2.0f * THIRD) },
FaceVector<4>{
Face<4> { { 3, 2, 1, 0 } },
Face<4> { { 0, 1, 7, 6 } },
@ -86,8 +113,18 @@ const Solid<3>& octahedron() {
static const auto D = vec3(0, 0, -1);
static const auto E = vec3(1, 0, 0);
static const auto F = vec3(-1, 0, 0);
static const float THIRD = 1.0f / 3.0f;
static const float SEVENTH = 1.0f / 7.0f;
static const Solid<3> OCTAHEDRON = Solid<3>{
{ A, B, C, D, E, F},
{ vec2(2.0f * SEVENTH, THIRD), vec2(SEVENTH, 2.0f * THIRD), vec2(3.0f * SEVENTH, 2.0f * THIRD),
vec2(2.0f * SEVENTH, THIRD), vec2(3.0f * SEVENTH, 2.0f * THIRD), vec2(4.0f * SEVENTH, THIRD),
vec2(5.0f * SEVENTH, 0.0f), vec2(4.0f * SEVENTH, THIRD), vec2(6.0f * SEVENTH, THIRD),
vec2(2.0f * SEVENTH, THIRD), vec2(0.0f, THIRD), vec2(1.0f * SEVENTH, 2.0f * THIRD),
vec2(2.0f * SEVENTH, 1.0f), vec2(3.0f * SEVENTH, 2.0f * THIRD), vec2(1.0f * SEVENTH, 2.0f * THIRD),
vec2(5.0f * SEVENTH, 2.0f * THIRD), vec2(4.0f * SEVENTH, THIRD), vec2(3.0f * SEVENTH, 2.0f * THIRD),
vec2(5.0f * SEVENTH, 2.0f * THIRD), vec2(6.0f * SEVENTH, THIRD), vec2(4.0f * SEVENTH, THIRD),
vec2(5.0f * SEVENTH, 2.0f * THIRD), vec2(1.0f, 2.0f * THIRD), vec2(6.0f * SEVENTH, THIRD) },
FaceVector<3> {
Face<3> { { 0, 2, 4, } },
Face<3> { { 0, 4, 3, } },
@ -116,11 +153,52 @@ const Solid<5>& dodecahedron() {
static const vec3 I = vec3(0, -IP, P);
static const vec3 J = vec3(P, 0, IP);
/* _
/ \ |
/ \ y2
/ \ |
/ \ _
\ / |
\ / y1
\ / |
___________ _
|x3|- - x1 - -||x3|
|- - - - x2- - - -|
*/
// x1, x2, and x3 are the solutions to the following system of equations:
// 1 = 3 * x1 + 3 * x2 + x3
// x1 + 2 * x3 = (golden ratio) * x1
// x2 = x1 + 2 * x3
static const float x1 = 4.0f / (17.0f + 7.0f * sqrtf(5.0f));
static const float x2 = (1.0f / 11.0f) * (5.0f * sqrtf(5.0f) - 9.0f);
static const float x2_2 = x2 / 2.0f;
static const float x3 = (1.0f / 11.0f) * (6.0f * sqrtf(5.0f) - 13.0f);
// y1 and y2 are the solutions to the following system of equations (x is the sidelength, but is different than x1 because the scale in the y direction is different):
// 1 = 3 * y1 + 2 * y2
// y1 = sin(108 deg) * x
// y1 + y2 = x * sqrtf(5 + 2 * sqrtf(5)) / 2
static const float y1 = sqrtf(2.0f * (5.0f + sqrtf(5.0f))) / (sqrtf(2.0f * (5.0f + sqrtf(5.0f))) + 4.0f * sqrtf(5.0f + 2.0f * sqrtf(5.0f)));
static const float y2 = -(sqrtf(2.0f * (5.0f + sqrtf(5.0f))) - 2.0f * sqrtf(5.0f + 2.0f * sqrtf(5.0f))) / (sqrtf(2.0f * (5.0f + sqrtf(5.0f))) + 4.0f * sqrtf(5.0f + 2.0f * sqrtf(5.0f)));
static const Solid<5> DODECAHEDRON = Solid<5>{
{
A, B, C, D, E, F, G, H, I, J,
-A, -B, -C, -D, -E, -F, -G, -H, -I, -J,
},
{ vec2(x1 + x2_2, 0.0f), vec2(x2_2, 0.0f), vec2(x2_2 - x3, y1), vec2(x3 + x1, y1 + y2), vec2(x3 + x1 + x2_2, y1),
vec2(1.0f - (x2 - x3 + x2_2), 0.0f), vec2(1.0f - (x2 + x1 + x3), y2), vec2(1.0f - (x2 + x1), y1 + y2), vec2(1.0f - x2, y1 + y2), vec2(1.0f - (x2 - x3), y2),
vec2(1.0f - x2_2, y1), vec2(1.0f - x2, y1 + y2), vec2(1.0f - (x3 + x1), y1 + y2 + y1), vec2(1.0f - x3, y1 + y2 + y1), vec2(1.0f, y1 + y2),
vec2(x3, y1 + y2), vec2(0.0f, y1 + y2 + y1), vec2(x2_2, y1 + y2 + y1 + y2), vec2(x2, y1 + y2 + y1), vec2(x1 + x3, y1 + y2),
vec2(x3 + x1, y1 + y2), vec2(x2, y1 + y2 + y1), vec2(x2 + x1, y1 + y2 + y1), vec2(x3 + x1 + x2, y1 + y2), vec2(x3 + x1 + x2_2, y1),
vec2(x3 + x1 + x2_2, y1), vec2(x3 + x1 + x2, y1 + y2), vec2(x3 + x1 + x2 + x2_2, y1), vec2(x1 + x2 + x2_2, 0.0f), vec2(x3 + x1 + x2_2 + x3, 0.0f),
vec2(1.0f - (x3 + x1 + x2_2), 1.0f - y1), vec2(1.0f - (x3 + x1 + x2), 1.0f - (y1 + y2)), vec2(1.0f - (x3 + x1 + x2 + x2_2), 1.0f - y1), vec2(1.0f - (x1 + x2 + x2_2), 1.0f), vec2(1.0f - (x3 + x1 + x2_2 + x3), 1.0f),
vec2(x2 + x1 + x3, 1.0f - y2), vec2(x2 + x1, 1.0f - (y1 + y2)), vec2(x2, 1.0f - (y1 + y2)), vec2(x2 - x3, 1.0f - y2), vec2(x2 - x3 + x2_2, 1.0f),
vec2(x2 + x1 + x2, y1 + y2 + y1), vec2(x3 + x1 + x2 + x1, y1 + y2), vec2(x3 + x1 + x2, y1 + y2), vec2(x2 + x1, y1 + y2 + y1), vec2(x2 + x1 + x2_2, y1 + y2 + y1 + y2),
vec2(1.0f - (x3 + x1 + x2), y1 + y2 + y1), vec2(1.0f - (x2 + x1), y1 + y2), vec2(1.0f - (x2 + x1 + x2_2), y1), vec2(1.0f - (x2 + x1 + x2), y1 + y2), vec2(1.0f - (x3 + x1 + x2 + x1), y1 + y2 + y1),
vec2(1.0f - (x3 + x1 + x2_2), y1 + y2 + y1 + y2), vec2(1.0f - (x3 + x1), y1 + y2 + y1), vec2(1.0f - x2, y1 + y2), vec2(1.0f - (x2 + x1), y2 + y1), vec2(1.0f - (x3 + x1 + x2), y1 + y2 + y1),
vec2(1.0f - (x1 + x2_2), 1.0f), vec2(1.0f - x2_2, 1.0f), vec2(1.0f - (x2_2 - x3), 1.0f - y1), vec2(1.0f - (x1 + x3), 1.0f - (y1 + y2)), vec2(1.0f - (x3 + x1 + x2_2), 1.0f - y1) },
FaceVector<5> {
Face<5> { { 0, 1, 2, 3, 4 } },
Face<5> { { 0, 5, 18, 6, 1 } },
@ -148,12 +226,33 @@ const Solid<3>& icosahedron() {
static const auto D = vec3(P, 0, N);
static const auto E = vec3(P, 0, -N);
static const auto F = vec3(0, N, -P);
static const float THIRD = 1.0f / 3.0f;
static const float ELEVENTH = 1.0f / 11.0f;
static const Solid<3> ICOSAHEDRON = Solid<3> {
{
A, B, C, D, E, F,
-A, -B, -C, -D, -E, -F,
},
{ vec2(3.0f * ELEVENTH, 0.0f), vec2(2.0f * ELEVENTH, THIRD), vec2(4.0f * ELEVENTH, THIRD),
vec2(2.0f * ELEVENTH, THIRD), vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(4.0f * ELEVENTH, THIRD),
vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(4.0f * ELEVENTH, THIRD),
vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(6.0f * ELEVENTH, THIRD), vec2(4.0f * ELEVENTH, THIRD),
vec2(6.0f * ELEVENTH, THIRD), vec2(5.0f * ELEVENTH, 0.0f), vec2(4.0f * ELEVENTH, THIRD),
vec2(1.0f * ELEVENTH, 0.0f), vec2(0.0f, THIRD), vec2(2.0f * ELEVENTH, THIRD),
vec2(1.0f * ELEVENTH, 2.0f * THIRD), vec2(2.0f * ELEVENTH, THIRD), vec2(0.0f, THIRD),
vec2(2.0f * ELEVENTH, THIRD), vec2(1.0f * ELEVENTH, 2.0f * THIRD), vec2(3.0f * ELEVENTH, 2.0f * THIRD),
vec2(2.0f * ELEVENTH, 1.0f), vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(1.0f * ELEVENTH, 2.0f * THIRD),
vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(4.0f * ELEVENTH, 1.0f), vec2(5.0f * ELEVENTH, 2.0f * THIRD),
vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(6.0f * ELEVENTH, 1.0f),
vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(6.0f * ELEVENTH, THIRD),
vec2(8.0f * ELEVENTH, THIRD), vec2(6.0f * ELEVENTH, THIRD), vec2(7.0f * ELEVENTH, 2.0f * THIRD),
vec2(6.0f * ELEVENTH, THIRD), vec2(8.0f * ELEVENTH, THIRD), vec2(7.0f * ELEVENTH, 0.0f),
vec2(10.0f * ELEVENTH, THIRD), vec2(9.0f * ELEVENTH, 0.0f), vec2(8.0f * ELEVENTH, THIRD),
vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(8.0f * ELEVENTH, 1.0f), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
vec2(8.0f * ELEVENTH, THIRD), vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
vec2(10.0f * ELEVENTH, THIRD), vec2(8.0f * ELEVENTH, THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
vec2(1.0f, 2.0f * THIRD), vec2(10.0f * ELEVENTH, THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
vec2(10.0f * ELEVENTH, 1.0f), vec2(1.0f, 2.0f * THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD) },
FaceVector<3> {
Face<3> { { 1, 2, 0 } },
Face<3> { { 2, 3, 0 } },

View file

@ -22,6 +22,7 @@ namespace geometry {
using Index = uint32_t;
using Vec = glm::vec3;
using VertexVector = std::vector<Vec>;
using TexCoordVector = std::vector<glm::vec2>;
using IndexVector = std::vector<Index>;
template <size_t N>
@ -33,6 +34,7 @@ namespace geometry {
template <size_t N>
struct Solid {
VertexVector vertices;
TexCoordVector texCoords;
FaceVector<N> faces;
Solid<N>& fitDimension(float newMaxDimension) {

View file

@ -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")

View file

@ -12,5 +12,7 @@ link_hifi_libraries(audio plugins)
add_dependency_external_projects(hifiAudioCodec)
target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAUDIOCODEC_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${HIFIAUDIOCODEC_LIBRARIES})
install_beside_console()
if (BUILD_SERVER)
install_beside_console()
endif ()

View file

@ -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}

View file

@ -9,5 +9,7 @@
set(TARGET_NAME pcmCodec)
setup_hifi_client_server_plugin()
link_hifi_libraries(shared plugins)
install_beside_console()
if (BUILD_SERVER)
install_beside_console()
endif ()

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_hifi_libraries(
shared task networking animation
ktx image octree gl gpu gpu-gl
ktx image octree gl gpu ${PLATFORM_GL_BACKEND}
render render-utils
graphics fbx model-networking graphics-scripting
entities entities-renderer audio avatars script-engine

View file

@ -18,4 +18,6 @@ elseif (APPLE)
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
endif()
install_beside_console()
if (BUILD_SERVER)
install_beside_console()
endif ()

View file

@ -40,6 +40,8 @@ Oven::Oven() {
}
Oven::~Oven() {
DependencyManager::get<ResourceManager>()->cleanup();
// quit all worker threads and wait on them
for (auto& thread : _workerThreads) {
thread->quit();