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

@ -18,6 +18,10 @@ if (BUILD_SCRIBE_ONLY)
return() return()
endif() endif()
if (NOT DEFINED CLIENT_ONLY)
set(CLIENT_ONLY 0)
endif()
if (NOT DEFINED SERVER_ONLY) if (NOT DEFINED SERVER_ONLY)
set(SERVER_ONLY 0) set(SERVER_ONLY 0)
endif() endif()
@ -28,41 +32,49 @@ else()
set(MOBILE 0) set(MOBILE 0)
endif() 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) if (ANDROID OR UWP)
option(BUILD_SERVER "Build server components" OFF) set(BUILD_SERVER_OPTION OFF)
option(BUILD_TOOLS "Build tools" OFF) set(BUILD_TOOLS_OPTION OFF)
option(BUILD_INSTALLER "Build installer" OFF) set(BUILD_INSTALLER OFF)
else() endif()
option(BUILD_SERVER "Build server components" ON)
option(BUILD_TOOLS "Build tools" ON) if (CLIENT_ONLY)
option(BUILD_INSTALLER "Build installer" ON) set(BUILD_SERVER_OPTION OFF)
endif() endif()
if (SERVER_ONLY) if (SERVER_ONLY)
option(BUILD_CLIENT "Build client components" OFF) set(BUILD_CLIENT_OPTION OFF)
option(BUILD_TESTS "Build tests" OFF) set(BUILD_TESTS_OPTION OFF)
else()
option(BUILD_CLIENT "Build client components" ON)
option(BUILD_TESTS "Build tests" ON)
endif() endif()
if (ANDROID) if (ANDROID)
option(USE_GLES "Use OpenGL ES" ON) set(GLES_OPTION ON)
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView) set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
else () else ()
option(USE_GLES "Use OpenGL ES" OFF)
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets) set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
endif () endif ()
if (USE_GLES AND (NOT ANDROID)) if (USE_GLES AND (NOT ANDROID))
option(DISABLE_QML "Disable QML" ON) set(DISABLE_QML_OPTION ON)
else()
option(DISABLE_QML "Disable QML" OFF)
endif() 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) option(DISABLE_KTX_CACHE "Disable KTX Cache" OFF)
set(PLATFORM_QT_GL OpenGL) set(PLATFORM_QT_GL OpenGL)
if (USE_GLES) if (USE_GLES)
@ -72,12 +84,10 @@ else()
set(PLATFORM_GL_BACKEND gpu-gl-common gpu-gl) set(PLATFORM_GL_BACKEND gpu-gl-common gpu-gl)
endif() endif()
foreach(PLATFORM_QT_COMPONENT ${PLATFORM_QT_COMPONENTS}) foreach(PLATFORM_QT_COMPONENT ${PLATFORM_QT_COMPONENTS})
list(APPEND PLATFORM_QT_LIBRARIES "Qt5::${PLATFORM_QT_COMPONENT}") list(APPEND PLATFORM_QT_LIBRARIES "Qt5::${PLATFORM_QT_COMPONENT}")
endforeach() endforeach()
MESSAGE(STATUS "Build server: " ${BUILD_SERVER}) MESSAGE(STATUS "Build server: " ${BUILD_SERVER})
MESSAGE(STATUS "Build client: " ${BUILD_CLIENT}) MESSAGE(STATUS "Build client: " ${BUILD_CLIENT})
MESSAGE(STATUS "Build tests: " ${BUILD_TESTS}) MESSAGE(STATUS "Build tests: " ${BUILD_TESTS})
@ -86,13 +96,13 @@ MESSAGE(STATUS "Build installer: " ${BUILD_INSTALLER})
MESSAGE(STATUS "GL ES: " ${USE_GLES}) MESSAGE(STATUS "GL ES: " ${USE_GLES})
if (DISABLE_QML) if (DISABLE_QML)
MESSAGE(STATUS "QML disabled!") MESSAGE(STATUS "QML disabled!")
add_definitions(-DDISABLE_QML) add_definitions(-DDISABLE_QML)
endif() endif()
if (DISABLE_KTX_CACHE) if (DISABLE_KTX_CACHE)
MESSAGE(STATUS "KTX cache disabled!") MESSAGE(STATUS "KTX cache disabled!")
add_definitions(-DDISABLE_KTX_CACHE) add_definitions(-DDISABLE_KTX_CACHE)
endif() endif()
if (UNIX AND DEFINED ENV{HIFI_MEMORY_DEBUGGING}) if (UNIX AND DEFINED ENV{HIFI_MEMORY_DEBUGGING})
@ -150,10 +160,8 @@ endif()
if (BUILD_CLIENT) if (BUILD_CLIENT)
add_subdirectory(interface) add_subdirectory(interface)
set_target_properties(interface PROPERTIES FOLDER "Apps") set_target_properties(interface PROPERTIES FOLDER "Apps")
if (ANDROID)
add_subdirectory(gvr-interface) option(USE_SIXENSE "Build Interface with sixense library/plugin" OFF)
set_target_properties(gvr-interface PROPERTIES FOLDER "Apps")
endif()
endif() endif()
if (BUILD_CLIENT OR BUILD_SERVER) if (BUILD_CLIENT OR BUILD_SERVER)

View file

@ -17,6 +17,8 @@ To produce an executable installer on Windows, the following are required:
- [Nullsoft Scriptable Install System](http://nsis.sourceforge.net/Download) - 3.0b3 - [Nullsoft Scriptable Install System](http://nsis.sourceforge.net/Download) - 3.0b3
- [UAC Plug-in for Nullsoft](http://nsis.sourceforge.net/UAC_plug-in) - 0.2.4c - [UAC Plug-in for Nullsoft](http://nsis.sourceforge.net/UAC_plug-in) - 0.2.4c
- [nsProcess Plug-in for Nullsoft](http://nsis.sourceforge.net/NsProcess_plugin) - 1.6 - [nsProcess Plug-in for Nullsoft](http://nsis.sourceforge.net/NsProcess_plugin) - 1.6
- [Inetc Plug-in for Nullsoft](http://nsis.sourceforge.net/Inetc_plug-in) - 1.0
- [NSISpcre Plug-in for Nullsoft](http://nsis.sourceforge.net/NSISpcre_plug-in) - 1.0
Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System. Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System.

View file

@ -476,6 +476,7 @@ void EntityScriptServer::clear() {
// do this here (instead of in deleter) to avoid marshalling unload signals back to this thread // do this here (instead of in deleter) to avoid marshalling unload signals back to this thread
_entitiesScriptEngine->unloadAllEntityScripts(); _entitiesScriptEngine->unloadAllEntityScripts();
_entitiesScriptEngine->stop(); _entitiesScriptEngine->stop();
_entitiesScriptEngine->waitTillDoneRunning();
} }
_entityViewer.clear(); _entityViewer.clear();
@ -565,8 +566,15 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> mess
void EntityScriptServer::aboutToFinish() { void EntityScriptServer::aboutToFinish() {
shutdownScriptEngine(); shutdownScriptEngine();
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
// our entity tree is going to go away so tell that to the 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(); DependencyManager::get<ResourceManager>()->cleanup();

View file

@ -4,7 +4,7 @@ cmake_policy(SET CMP0046 OLD)
include(ExternalProject) 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) if (APPLE)
else () else ()

View file

@ -23,7 +23,7 @@ macro(GENERATE_INSTALLERS)
set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME})
set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME})
if (PR_BUILD) if (PR_BUILD)
set(CPACK_NSIS_COMPRESSOR "/SOLID bzip2") set(CPACK_NSIS_COMPRESSOR "bzip2")
endif () endif ()
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME})
@ -46,9 +46,35 @@ macro(GENERATE_INSTALLERS)
set(UNINSTALLER_HEADER_IMAGE "") set(UNINSTALLER_HEADER_IMAGE "")
fix_path_for_nsis(${_UNINSTALLER_HEADER_BAD_PATH} UNINSTALLER_HEADER_IMAGE) fix_path_for_nsis(${_UNINSTALLER_HEADER_BAD_PATH} UNINSTALLER_HEADER_IMAGE)
# grab the latest VC redist (2017) and add it to the installer, our NSIS template # we use external libraries that still need the 120 (VS2013) redistributables
# will call it during the install # so we include them as well until those external libraries are updated
install(CODE "file(DOWNLOAD https://go.microsoft.com/fwlink/?LinkId=746572 \"\${CMAKE_INSTALL_PREFIX}/vcredist_x64.exe\")") # to use the redistributables that match what we build our applications for
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
"C:/Windows/System32/msvcp120.dll"
"C:/Windows/System32/msvcr120.dll"
)
set(CMAKE_INSTALL_UCRT_LIBRARIES TRUE)
set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ${INTERFACE_INSTALL_DIR})
set(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT ${CLIENT_COMPONENT})
include(InstallRequiredSystemLibraries)
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) elseif (APPLE)
# produce a drag and drop DMG on OS X # produce a drag and drop DMG on OS X
set(CPACK_GENERATOR "DragNDrop") set(CPACK_GENERATOR "DragNDrop")
@ -79,8 +105,13 @@ macro(GENERATE_INSTALLERS)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
if (BUILD_CLIENT)
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Interface") cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Interface")
endif ()
if (BUILD_SERVER)
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Sandbox") cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Sandbox")
endif ()
include(CPack) include(CPack)
endmacro() endmacro()

View file

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

View file

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

View file

@ -319,6 +319,78 @@ Function DownloadFile
FunctionEnd FunctionEnd
!endif !endif
!include NSISpcre.nsh
!insertmacro REMatches
Var CampaignName
!macro GetCampaignName RetVar
Call GetCampaignName
Pop ${RetVar}
!macroend
Function GetCampaignName
Push $0 ; Stash $0
; Parse filename out of the path
${RECaptureMatches} $0 "([^\\]*\\)*(.*)\.exe" $EXEPATH 0
${If} $0 == 2
Pop $0 ; Discard Path
Pop $0 ; Recover filename
; Parse campaign out of the filename
${RECaptureMatches} $0 "HighFidelity-([^-]*-)Beta-.*" $0 0
${If} $0 == 1
Pop $0 ; Recover campaign name
StrCpy $0 $0 -1 0 ; Remove trailing - and copy to _RetVar
${Else}
StrCpy $0 ""
${EndIf}
${Else}
StrCpy $0 ""
${EndIf}
Exch $0 ; Restore $0 and push result
FunctionEnd
!macro CreateGUID RetVar
System::Call 'ole32::CoCreateGuid(g .s)'
Pop ${RetVar}
; Strip opening and closing braces
StrCpy ${RetVar} ${RetVar} -1 1
!macroend
Var GAClientID
!macro InitGAClientID
; Generate a new GUID on every run for now
!insertmacro CreateGUID $GAClientID
!macroend
!macro GoogleAnalytics Category Action Label Value
${If} "@GA_TRACKING_ID@" != ""
Push $0
Push $1
StrCpy $0 "https://google-analytics.com/collect?v=1&tid=@GA_TRACKING_ID@"
StrCpy $0 "$0&cid=$GAClientID&t=event&ec=${Category}&ea=${Action}"
${If} "${Label}" != ""
StrCpy $0 "$0&el=${Label}"
${EndIf}
${If} "${Value}" != ""
StrCpy $0 "$0&ev=${Value}"
${EndIf}
GetTempFileName $1
inetc::get /SILENT $0 $1 /END
Delete $1
Pop $1
Pop $0
${EndIf}
!macroend
;-------------------------------- ;--------------------------------
; Installation types ; Installation types
@ -342,28 +414,38 @@ SectionEnd
;-------------------------------- ;--------------------------------
;Pages ;Pages
!define MUI_CUSTOMFUNCTION_ABORT OnUserAbort
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageWelcomePre
!insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_WELCOME
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageLicensePre
!insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
Page custom InstallTypesPage ReadInstallTypes Page custom InstallTypesPage ReadInstallTypes
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction !define MUI_PAGE_CUSTOMFUNCTION_PRE PageDirectoryPre
!insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_DIRECTORY
;Start Menu Folder Page Configuration ;Start Menu Folder Page Configuration
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM" !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageStartMenuPre
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
!insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction !define MUI_PAGE_CUSTOMFUNCTION_PRE PageComponentsPre
@CPACK_NSIS_PAGE_COMPONENTS@ @CPACK_NSIS_PAGE_COMPONENTS@
; 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 Page custom PostInstallOptionsPage ReadPostInstallOptions
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageInstallFilesPre
!insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_CONFIRM
@ -452,8 +534,40 @@ Var CopyFromProductionCheckbox
Var ExpressInstallRadioButton Var ExpressInstallRadioButton
Var CustomInstallRadioButton Var CustomInstallRadioButton
Var InstallTypeDialog Var InstallTypeDialog
Var Express
Var CustomInstallTemporaryState Var CustomInstallTemporaryState
Var Express
!macro MaybeSkipPage
; Check if Express is set, if so, abort the post install options page
${If} $Express == "1"
Abort
${EndIf}
!macroend
Function OnUserAbort
!insertmacro GoogleAnalytics "Installer" "Abort" "User Abort" ""
FunctionEnd
Function PageWelcomePre
!insertmacro GoogleAnalytics "Installer" "Welcome" "" ""
FunctionEnd
Function PageLicensePre
!insertmacro GoogleAnalytics "Installer" "License" "" ""
FunctionEnd
Function PageDirectoryPre
!insertmacro MaybeSkipPage
!insertmacro GoogleAnalytics "Installer" "Directory" "" ""
FunctionEnd
Function PageStartMenuPre
!insertmacro MaybeSkipPage
!insertmacro GoogleAnalytics "Installer" "StartMenu" "" ""
FunctionEnd
Function PageComponentsPre
!insertmacro MaybeSkipPage
!insertmacro GoogleAnalytics "Installer" "Components" "" ""
FunctionEnd
Function PageInstallFilesPre
!insertmacro GoogleAnalytics "Installer" "Install" "" ""
FunctionEnd
!macro SetInstallOption Checkbox OptionName Default !macro SetInstallOption Checkbox OptionName Default
; reads the value for the given install option to the registry ; reads the value for the given install option to the registry
@ -472,6 +586,8 @@ Var CustomInstallTemporaryState
!macroend !macroend
Function InstallTypesPage Function InstallTypesPage
!insertmacro GoogleAnalytics "Installer" "Install Types" "" ""
!insertmacro MUI_HEADER_TEXT "Choose Installation Type" "Express or Custom Install" !insertmacro MUI_HEADER_TEXT "Choose Installation Type" "Express or Custom Install"
nsDialogs::Create 1018 nsDialogs::Create 1018
@ -502,9 +618,10 @@ Function InstallTypesPage
${If} $CustomInstallTemporaryState == ${BST_UNCHECKED} ${If} $CustomInstallTemporaryState == ${BST_UNCHECKED}
${NSD_Check} $ExpressInstallRadioButton ${NSD_Check} $ExpressInstallRadioButton
${EndIf}
Call ChangeExpressLabel Call ChangeExpressLabel
${Else}
Call ChangeCustomLabel
${EndIf}
nsDialogs::Show nsDialogs::Show
FunctionEnd FunctionEnd
@ -523,14 +640,10 @@ Function ChangeCustomLabel
Pop $R1 Pop $R1
FunctionEnd FunctionEnd
Function AbortFunction
; Check if Express is set, if so, abort the post install options page
StrCmp $Express "1" 0 end
Abort
end:
FunctionEnd
Function PostInstallOptionsPage Function PostInstallOptionsPage
!insertmacro MaybeSkipPage
!insertmacro GoogleAnalytics "Installer" "Post Install Options" "" ""
!insertmacro MUI_HEADER_TEXT "Setup Options" "" !insertmacro MUI_HEADER_TEXT "Setup Options" ""
nsDialogs::Create 1018 nsDialogs::Create 1018
@ -540,15 +653,10 @@ Function PostInstallOptionsPage
Abort Abort
${EndIf} ${EndIf}
; Check if Express is set, if so, abort the post install options page
StrCmp $Express "1" 0 end
Abort
end:
StrCpy $CurrentOffset 0 StrCpy $CurrentOffset 0
StrCpy $OffsetUnits u StrCpy $OffsetUnits u
${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@" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @INTERFACE_HF_SHORTCUT_NAME@"
Pop $DesktopClientCheckbox Pop $DesktopClientCheckbox
IntOp $CurrentOffset $CurrentOffset + 15 IntOp $CurrentOffset $CurrentOffset + 15
@ -557,7 +665,7 @@ Function PostInstallOptionsPage
!insertmacro SetInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED} !insertmacro SetInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED}
${EndIf} ${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@" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@"
Pop $DesktopServerCheckbox Pop $DesktopServerCheckbox
IntOp $CurrentOffset $CurrentOffset + 15 IntOp $CurrentOffset $CurrentOffset + 15
@ -566,7 +674,7 @@ Function PostInstallOptionsPage
!insertmacro SetInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED} !insertmacro SetInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED}
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${If} @SERVER_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install"
Pop $LaunchServerNowCheckbox Pop $LaunchServerNowCheckbox
@ -580,7 +688,7 @@ Function PostInstallOptionsPage
IntOp $CurrentOffset $CurrentOffset + 15 IntOp $CurrentOffset $CurrentOffset + 15
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} @CLIENT_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install"
Pop $LaunchClientNowCheckbox Pop $LaunchClientNowCheckbox
IntOp $CurrentOffset $CurrentOffset + 30 IntOp $CurrentOffset $CurrentOffset + 30
@ -593,7 +701,7 @@ Function PostInstallOptionsPage
${EndIf} ${EndIf}
${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" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup"
Pop $ServerStartupCheckbox Pop $ServerStartupCheckbox
IntOp $CurrentOffset $CurrentOffset + 15 IntOp $CurrentOffset $CurrentOffset + 15
@ -602,7 +710,7 @@ Function PostInstallOptionsPage
!insertmacro SetInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED} !insertmacro SetInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED}
${EndIf} ${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)" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)"
Pop $CleanInstallCheckbox Pop $CleanInstallCheckbox
IntOp $CurrentOffset $CurrentOffset + 15 IntOp $CurrentOffset $CurrentOffset + 15
@ -610,11 +718,11 @@ Function PostInstallOptionsPage
${If} @PR_BUILD@ == 1 ${If} @PR_BUILD@ == 1
; a PR build defaults all install options expect LaunchServerNowCheckbox, LaunchClientNowCheckbox and the settings copy to unchecked ; 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} ${NSD_SetState} $DesktopClientCheckbox ${BST_UNCHECKED}
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${If} @SERVER_COMPONENT_CONDITIONAL@
${NSD_SetState} $DesktopServerCheckbox ${BST_UNCHECKED} ${NSD_SetState} $DesktopServerCheckbox ${BST_UNCHECKED}
${NSD_SetState} $ServerStartupCheckbox ${BST_UNCHECKED} ${NSD_SetState} $ServerStartupCheckbox ${BST_UNCHECKED}
${EndIf} ${EndIf}
@ -673,12 +781,12 @@ Function ReadInstallTypes
FunctionEnd FunctionEnd
Function ReadPostInstallOptions Function ReadPostInstallOptions
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} @CLIENT_COMPONENT_CONDITIONAL@
; check if the user asked for a desktop shortcut to High Fidelity ; check if the user asked for a desktop shortcut to High Fidelity
${NSD_GetState} $DesktopClientCheckbox $DesktopClientState ${NSD_GetState} $DesktopClientCheckbox $DesktopClientState
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${If} @SERVER_COMPONENT_CONDITIONAL@
; check if the user asked for a desktop shortcut to Sandbox ; check if the user asked for a desktop shortcut to Sandbox
${NSD_GetState} $DesktopServerCheckbox $DesktopServerState ${NSD_GetState} $DesktopServerCheckbox $DesktopServerState
@ -691,24 +799,24 @@ Function ReadPostInstallOptions
${NSD_GetState} $CopyFromProductionCheckbox $CopyFromProductionState ${NSD_GetState} $CopyFromProductionCheckbox $CopyFromProductionState
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${If} @SERVER_COMPONENT_CONDITIONAL@
; check if we need to launch the server post-install ; check if we need to launch the server post-install
${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState ${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} @CLIENT_COMPONENT_CONDITIONAL@
; check if we need to launch the client post-install ; check if we need to launch the client post-install
${NSD_GetState} $LaunchClientNowCheckbox $LaunchClientNowState ${NSD_GetState} $LaunchClientNowCheckbox $LaunchClientNowState
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} @CLIENT_COMPONENT_CONDITIONAL@
; check if the user asked for a clean install ; check if the user asked for a clean install
${NSD_GetState} $CleanInstallCheckbox $CleanInstallState ${NSD_GetState} $CleanInstallCheckbox $CleanInstallState
${EndIf} ${EndIf}
FunctionEnd FunctionEnd
Function HandlePostInstallOptions Function HandlePostInstallOptions
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} @CLIENT_COMPONENT_CONDITIONAL@
; check if the user asked for a desktop shortcut to High Fidelity ; check if the user asked for a desktop shortcut to High Fidelity
${If} $DesktopClientState == ${BST_CHECKED} ${If} $DesktopClientState == ${BST_CHECKED}
CreateShortCut "$DESKTOP\@INTERFACE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" CreateShortCut "$DESKTOP\@INTERFACE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
@ -719,7 +827,7 @@ Function HandlePostInstallOptions
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${If} @SERVER_COMPONENT_CONDITIONAL@
; check if the user asked for a desktop shortcut to Sandbox ; check if the user asked for a desktop shortcut to Sandbox
${If} $DesktopServerState == ${BST_CHECKED} ${If} $DesktopServerState == ${BST_CHECKED}
CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
@ -748,7 +856,7 @@ Function HandlePostInstallOptions
${EndIf} ${EndIf}
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} @CLIENT_COMPONENT_CONDITIONAL@
; check if the user asked for a clean install ; check if the user asked for a clean install
${If} $CleanInstallState == ${BST_CHECKED} ${If} $CleanInstallState == ${BST_CHECKED}
SetShellVarContext current SetShellVarContext current
@ -785,7 +893,8 @@ Function HandlePostInstallOptions
${EndIf} ${EndIf}
${EndIf} ${EndIf}
${If} $LaunchServerNowState == ${BST_CHECKED} ${If} @SERVER_COMPONENT_CONDITIONAL@
${AndIf} $LaunchServerNowState == ${BST_CHECKED}
!insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ YES !insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ YES
; both launches use the explorer trick in case the user has elevated permissions for the installer ; 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@"' Exec '"$WINDIR\explorer.exe" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"'
${EndIf} ${EndIf}
${Else} ${ElseIf} @CLIENT_COMPONENT_CONDITIONAL@
!insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ NO !insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ NO
; launch uses the explorer trick in case the user has elevated permissions for the installer ; 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\ui_resources_200_percent.pak"
Delete "$INSTDIR\vccorlib120.dll" Delete "$INSTDIR\vccorlib120.dll"
Delete "$INSTDIR\version" Delete "$INSTDIR\version"
Delete "$INSTDIR\msvcr140.dll"
Delete "$INSTDIR\msvcp140.dll"
Delete "$INSTDIR\vcruntime140.dll"
Delete "$INSTDIR\xinput1_3.dll" Delete "$INSTDIR\xinput1_3.dll"
; Delete old desktop shortcuts before they were renamed during Sandbox rename ; Delete old desktop shortcuts before they were renamed during Sandbox rename
@ -858,11 +964,8 @@ Section "-Core installation"
; Rename the incorrectly cased Raleway font ; Rename the incorrectly cased Raleway font
Rename "$INSTDIR\resources\qml\styles-uit\RalewaySemibold.qml" "$INSTDIR\resources\qml\styles-uit\RalewaySemiBold.qml" Rename "$INSTDIR\resources\qml\styles-uit\RalewaySemibold.qml" "$INSTDIR\resources\qml\styles-uit\RalewaySemiBold.qml"
ExecWait "$INSTDIR\vcredist_x64.exe /install /q /norestart"
; Remove the Old Interface directory and vcredist_x64.exe (from installs prior to Server Console) ; Remove the Old Interface directory and vcredist_x64.exe (from installs prior to Server Console)
RMDir /r "$INSTDIR\Interface" RMDir /r "$INSTDIR\Interface"
Delete "$INSTDIR\vcredist_x64.exe"
;Use the entire tree produced by the INSTALL target. Keep the ;Use the entire tree produced by the INSTALL target. Keep the
;list of directories here in sync with the RMDir commands below. ;list of directories here in sync with the RMDir commands below.
@ -931,7 +1034,7 @@ Section "-Core installation"
@CPACK_NSIS_CREATE_ICONS_EXTRA@ @CPACK_NSIS_CREATE_ICONS_EXTRA@
; Conditional handling for Interface specific options ; Conditional handling for Interface specific options
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} @CLIENT_COMPONENT_CONDITIONAL@
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@INTERFACE_SHORTCUT_NAME@.lnk" \ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@INTERFACE_SHORTCUT_NAME@.lnk" \
"$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
@ -946,7 +1049,7 @@ Section "-Core installation"
${EndIf} ${EndIf}
; Conditional handling for server console shortcut ; Conditional handling for server console shortcut
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${If} @SERVER_COMPONENT_CONDITIONAL@
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \
"$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
${EndIf} ${EndIf}
@ -965,6 +1068,7 @@ Section "-Core installation"
; Handle whichever post install options were set ; Handle whichever post install options were set
Call HandlePostInstallOptions Call HandlePostInstallOptions
!insertmacro GoogleAnalytics "Installer" "Done" "" ""
SectionEnd SectionEnd
!include nsProcess.nsh !include nsProcess.nsh
@ -992,6 +1096,8 @@ SectionEnd
/SD IDCANCEL IDRETRY Prompt_${UniqueID} IDCANCEL 0 /SD IDCANCEL IDRETRY Prompt_${UniqueID} IDCANCEL 0
${EndIf} ${EndIf}
!insertmacro GoogleAnalytics "Installer" "Abort" "${displayName} Running" ""
; If the user decided to cancel, stop the current installer/uninstaller ; If the user decided to cancel, stop the current installer/uninstaller
Abort Abort
@ -1087,8 +1193,8 @@ Function .onSelChange
!insertmacro SectionList MaybeSelectionChanged !insertmacro SectionList MaybeSelectionChanged
; if neither component is selected, disable the install button ; if neither component is selected, disable the install button
${IfNot} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${IfNot} @CLIENT_COMPONENT_CONDITIONAL@
${AndIfNot} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${AndIfNot} @SERVER_COMPONENT_CONDITIONAL@
GetDlgItem $0 $HWNDPARENT 1 GetDlgItem $0 $HWNDPARENT 1
EnableWindow $0 0 EnableWindow $0 0
${Else} ${Else}
@ -1219,6 +1325,11 @@ Function .onInit
Quit Quit
!endif !endif
!insertmacro InitGAClientID
!insertmacro GetCampaignName $CampaignName
!insertmacro GoogleAnalytics "Installer" "Start" "$CampaignName" ""
; make sure none of the installed applications are still running ; make sure none of the installed applications are still running
!insertmacro CheckForRunningApplications "installed" "Installer" !insertmacro CheckForRunningApplications "installed" "Installer"
${nsProcess::Unload} ${nsProcess::Unload}

View file

@ -20,6 +20,7 @@
#include <QJsonArray> #include <QJsonArray>
#include <QProcess> #include <QProcess>
#include <QSharedMemory> #include <QSharedMemory>
#include <QRegularExpression>
#include <QStandardPaths> #include <QStandardPaths>
#include <QTimer> #include <QTimer>
#include <QUrlQuery> #include <QUrlQuery>
@ -727,7 +728,7 @@ void DomainServer::setupNodeListAndAssignments() {
packetReceiver.registerListener(PacketType::OctreeDataPersist, this, "processOctreeDataPersistMessage"); packetReceiver.registerListener(PacketType::OctreeDataPersist, this, "processOctreeDataPersistMessage");
packetReceiver.registerListener(PacketType::OctreeFileReplacement, this, "handleOctreeFileReplacementRequest"); 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 // set a custom packetVersionMatch as the verify packet operator for the udt::Socket
nodeList->setPacketFilterOperator(&DomainServer::isPacketVerified); nodeList->setPacketFilterOperator(&DomainServer::isPacketVerified);
@ -736,7 +737,6 @@ void DomainServer::setupNodeListAndAssignments() {
auto assetClient = DependencyManager::set<AssetClient>(); auto assetClient = DependencyManager::set<AssetClient>();
assetClient->moveToThread(&_assetClientThread); assetClient->moveToThread(&_assetClientThread);
_assetClientThread.start(); _assetClientThread.start();
// add whatever static assignments that have been parsed to the queue // add whatever static assignments that have been parsed to the queue
addStaticAssignmentsToQueue(); addStaticAssignmentsToQueue();
} }
@ -2136,7 +2136,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
} else if (url.path().startsWith(URI_API_BACKUPS_ID)) { } else if (url.path().startsWith(URI_API_BACKUPS_ID)) {
auto id = url.path().mid(QString(URI_API_BACKUPS_ID).length()); auto id = url.path().mid(QString(URI_API_BACKUPS_ID).length());
auto deferred = makePromise("consolidateBackup"); 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) { if (!connectionPtr) {
return; return;
} }
@ -2147,7 +2147,14 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
auto path = result["backupFilePath"].toString(); auto path = result["backupFilePath"].toString();
auto file { std::unique_ptr<QFile>(new QFile(path)) }; auto file { std::unique_ptr<QFile>(new QFile(path)) };
if (file->open(QIODevice::ReadOnly)) { 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 { } else {
qCritical(domain_server) << "Unable to load consolidated backup at:" << path << result; qCritical(domain_server) << "Unable to load consolidated backup at:" << path << result;
connectionPtr->respond(HTTPConnection::StatusCode500, "Error opening backup"); 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"; qInfo() << "Received request to replace content from a url";
auto node = DependencyManager::get<LimitedNodeList>()->findNodeWithAddr(message->getSenderSockAddr()); auto node = DependencyManager::get<LimitedNodeList>()->findNodeWithAddr(message->getSenderSockAddr());
if (node) { if (node && node->getCanReplaceContent()) {
qDebug() << "Found node: " << node->getCanReplaceContent();
}
if (node->getCanReplaceContent()) {
// Convert message data into our URL // Convert message data into our URL
QString url(message->getMessage()); QString url(message->getMessage());
QUrl modelsURL = QUrl(url, QUrl::StrictMode); QUrl modelsURL = QUrl(url, QUrl::StrictMode);
@ -3448,7 +3452,12 @@ void DomainServer::handleOctreeFileReplacementFromURLRequest(QSharedPointer<Rece
connect(reply, &QNetworkReply::finished, [this, reply, modelsURL]() { connect(reply, &QNetworkReply::finished, [this, reply, modelsURL]() {
QNetworkReply::NetworkError networkError = reply->error(); QNetworkReply::NetworkError networkError = reply->error();
if (networkError == QNetworkReply::NoError) { if (networkError == QNetworkReply::NoError) {
if (modelsURL.fileName().endsWith(".json.gz")) {
handleOctreeFileReplacement(reply->readAll()); handleOctreeFileReplacement(reply->readAll());
} else if (modelsURL.fileName().endsWith(".zip")) {
auto deferred = makePromise("recoverFromUploadedBackup");
_contentManager->recoverFromUploadedBackup(deferred, reply->readAll());
}
} else { } else {
qDebug() << "Error downloading JSON from specified file: " << modelsURL; qDebug() << "Error downloading JSON from specified file: " << modelsURL;
} }
@ -3456,9 +3465,6 @@ void DomainServer::handleOctreeFileReplacementFromURLRequest(QSharedPointer<Rece
} }
} }
void DomainServer::handleOctreeFileReplacementRequest(QSharedPointer<ReceivedMessage> message) { void DomainServer::handleOctreeFileReplacementRequest(QSharedPointer<ReceivedMessage> message) {
auto node = DependencyManager::get<NodeList>()->nodeWithUUID(message->getSourceID()); auto node = DependencyManager::get<NodeList>()->nodeWithUUID(message->getSourceID());
if (node->getCanReplaceContent()) { if (node->getCanReplaceContent()) {

View file

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

View file

@ -191,7 +191,11 @@ add_dependencies(${TARGET_NAME} resources)
if (WIN32) if (WIN32)
# These are external plugins, but we need to do the 'add dependency' here so that their # These are external plugins, but we need to do the 'add dependency' here so that their
# binary directories get added to the fixup path # binary directories get added to the fixup path
if (USE_SIXENSE)
add_dependency_external_projects(sixense) add_dependency_external_projects(sixense)
endif ()
add_dependency_external_projects(sdl2) add_dependency_external_projects(sdl2)
add_dependency_external_projects(OpenVR) add_dependency_external_projects(OpenVR)
add_dependency_external_projects(neuron) add_dependency_external_projects(neuron)
@ -199,12 +203,6 @@ if (WIN32)
add_dependency_external_projects(steamworks) add_dependency_external_projects(steamworks)
endif() 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 # disable /OPT:REF and /OPT:ICF for the Debug builds
# This will prevent the following linker warnings # This will prevent the following linker warnings
# LINK : warning LNK4075: ignoring '/INCREMENTAL' due to '/OPT:ICF' specification # 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 # include the binary directory of render-utils for shader includes
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils") target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils")
# include OpenSSL
target_openssl()
target_bullet() target_bullet()
target_opengl() target_opengl()
add_crashpad() add_crashpad()
@ -389,3 +390,6 @@ endif()
add_dependency_external_projects(GifCreator) add_dependency_external_projects(GifCreator)
find_package(GifCreator REQUIRED) find_package(GifCreator REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GIFCREATOR_INCLUDE_DIRS}) target_include_directories(${TARGET_NAME} PUBLIC ${GIFCREATOR_INCLUDE_DIRS})
# tell CMake to exclude ui_console.h for policy CMP0071
set_property(SOURCE ui_console.h PROPERTY SKIP_AUTOMOC ON)

View file

@ -351,6 +351,7 @@ static const QString OBJ_EXTENSION = ".obj";
static const QString AVA_JSON_EXTENSION = ".ava.json"; static const QString AVA_JSON_EXTENSION = ".ava.json";
static const QString WEB_VIEW_TAG = "noDownload=true"; static const QString WEB_VIEW_TAG = "noDownload=true";
static const QString ZIP_EXTENSION = ".zip"; static const QString ZIP_EXTENSION = ".zip";
static const QString CONTENT_ZIP_EXTENSION = ".content.zip";
static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f; 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"; 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_EXTENSION, &Application::importSVOFromURL },
{ SVO_JSON_EXTENSION, &Application::importSVOFromURL }, { SVO_JSON_EXTENSION, &Application::importSVOFromURL },
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }, { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl },
@ -386,6 +387,7 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi
{ JS_EXTENSION, &Application::askToLoadScript }, { JS_EXTENSION, &Application::askToLoadScript },
{ FST_EXTENSION, &Application::askToSetAvatarUrl }, { FST_EXTENSION, &Application::askToSetAvatarUrl },
{ JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent },
{ CONTENT_ZIP_EXTENSION, &Application::askToReplaceDomainContent },
{ ZIP_EXTENSION, &Application::importFromZIP }, { ZIP_EXTENSION, &Application::importFromZIP },
{ JPG_EXTENSION, &Application::importImage }, { JPG_EXTENSION, &Application::importImage },
{ PNG_EXTENSION, &Application::importImage } { PNG_EXTENSION, &Application::importImage }
@ -2704,6 +2706,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor()); surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data()); surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data()); surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
@ -6173,11 +6176,9 @@ bool Application::canAcceptURL(const QString& urlString) const {
} else if (urlString.startsWith(HIFI_URL_SCHEME)) { } else if (urlString.startsWith(HIFI_URL_SCHEME)) {
return true; return true;
} }
QHashIterator<QString, AcceptURLMethod> i(_acceptedExtensions);
QString lowerPath = url.path().toLower(); QString lowerPath = url.path().toLower();
while (i.hasNext()) { for (auto& pair : _acceptedExtensions) {
i.next(); if (lowerPath.endsWith(pair.first, Qt::CaseInsensitive)) {
if (lowerPath.endsWith(i.key(), Qt::CaseInsensitive)) {
return true; return true;
} }
} }
@ -6194,12 +6195,10 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
} }
QUrl url(urlString); QUrl url(urlString);
QHashIterator<QString, AcceptURLMethod> i(_acceptedExtensions);
QString lowerPath = url.path().toLower(); QString lowerPath = url.path().toLower();
while (i.hasNext()) { for (auto& pair : _acceptedExtensions) {
i.next(); if (lowerPath.endsWith(pair.first, Qt::CaseInsensitive)) {
if (lowerPath.endsWith(i.key(), Qt::CaseInsensitive)) { AcceptURLMethod method = pair.second;
AcceptURLMethod method = i.value();
return (this->*method)(urlString); return (this->*method)(urlString);
} }
} }
@ -6386,13 +6385,11 @@ void Application::replaceDomainContent(const QString& url) {
QByteArray urlData(url.toUtf8()); QByteArray urlData(url.toUtf8());
auto limitedNodeList = DependencyManager::get<NodeList>(); auto limitedNodeList = DependencyManager::get<NodeList>();
const auto& domainHandler = limitedNodeList->getDomainHandler(); const auto& domainHandler = limitedNodeList->getDomainHandler();
limitedNodeList->eachMatchingNode([](const SharedNodePointer& node) {
return node->getType() == NodeType::EntityServer && node->getActiveSocket(); auto octreeFilePacket = NLPacket::create(PacketType::DomainContentReplacementFromUrl, urlData.size(), true);
}, [&urlData, limitedNodeList, &domainHandler](const SharedNodePointer& octreeNode) {
auto octreeFilePacket = NLPacket::create(PacketType::OctreeFileReplacementFromUrl, urlData.size(), true);
octreeFilePacket->write(urlData); octreeFilePacket->write(urlData);
limitedNodeList->sendPacket(std::move(octreeFilePacket), domainHandler.getSockAddr()); limitedNodeList->sendPacket(std::move(octreeFilePacket), domainHandler.getSockAddr());
});
auto addressManager = DependencyManager::get<AddressManager>(); auto addressManager = DependencyManager::get<AddressManager>();
addressManager->handleLookupString(DOMAIN_SPAWNING_POINT); addressManager->handleLookupString(DOMAIN_SPAWNING_POINT);
QString newHomeAddress = addressManager->getHost() + DOMAIN_SPAWNING_POINT; QString newHomeAddress = addressManager->getHost() + DOMAIN_SPAWNING_POINT;
@ -7350,10 +7347,35 @@ bool Application::isThrottleRendering() const {
} }
bool Application::hasFocus() const { bool Application::hasFocus() const {
if (_displayPlugin) { bool result = (QApplication::activeWindow() != nullptr);
return getActiveDisplayPlugin()->hasFocus(); #if defined(Q_OS_WIN)
// On Windows, QWidget::activateWindow() - as called in setFocus() - makes the application's taskbar icon flash but doesn't
// take user focus away from their current window. So also check whether the application is the user's current foreground
// window.
result = result && (HWND)QApplication::activeWindow()->winId() == GetForegroundWindow();
#endif
return result;
}
void Application::setFocus() {
// Note: Windows doesn't allow a user focus to be taken away from another application. Instead, it changes the color of and
// flashes the taskbar icon.
auto window = qApp->getWindow();
window->activateWindow();
}
void Application::raise() {
auto windowState = qApp->getWindow()->windowState();
if (windowState & Qt::WindowMinimized) {
if (windowState & Qt::WindowMaximized) {
qApp->getWindow()->showMaximized();
} else if (windowState & Qt::WindowFullScreen) {
qApp->getWindow()->showFullScreen();
} else {
qApp->getWindow()->showNormal();
} }
return (QApplication::activeWindow() != nullptr); }
qApp->getWindow()->raise();
} }
void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) { void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) {

View file

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

View file

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

View file

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

View file

@ -63,6 +63,19 @@ static const float OPAQUE_ALPHA_THRESHOLD = 0.99f;
const QString Web3DOverlay::TYPE = "web3d"; const QString Web3DOverlay::TYPE = "web3d";
const QString Web3DOverlay::QML = "Web3DOverlay.qml"; const QString Web3DOverlay::QML = "Web3DOverlay.qml";
static auto qmlSurfaceDeleter = [](OffscreenQmlSurface* surface) {
AbstractViewStateInterface::instance()->postLambdaEvent([surface] {
if (AbstractViewStateInterface::instance()->isAboutToQuit()) {
// WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown
// if the application has already stopped its event loop, delete must be explicit
delete surface;
} else {
surface->deleteLater();
}
});
};
Web3DOverlay::Web3DOverlay() { Web3DOverlay::Web3DOverlay() {
_touchDevice.setCapabilities(QTouchDevice::Position); _touchDevice.setCapabilities(QTouchDevice::Position);
_touchDevice.setType(QTouchDevice::TouchScreen); _touchDevice.setType(QTouchDevice::TouchScreen);
@ -75,7 +88,8 @@ Web3DOverlay::Web3DOverlay() {
connect(this, &Web3DOverlay::resizeWebSurface, this, &Web3DOverlay::onResizeWebSurface); connect(this, &Web3DOverlay::resizeWebSurface, this, &Web3DOverlay::onResizeWebSurface);
//need to be intialized before Tablet 1st open //need to be intialized before Tablet 1st open
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url); _webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML);
_cachedWebSurface = true;
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data()); _webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED _webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED _webSurface->getSurfaceContext()->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
@ -114,6 +128,7 @@ void Web3DOverlay::destroyWebSurface() {
if (!_webSurface) { if (!_webSurface) {
return; return;
} }
QQuickItem* rootItem = _webSurface->getRootItem(); QQuickItem* rootItem = _webSurface->getRootItem();
if (rootItem && rootItem->objectName() == "tabletRoot") { if (rootItem && rootItem->objectName() == "tabletRoot") {
@ -135,11 +150,16 @@ void Web3DOverlay::destroyWebSurface() {
QObject::disconnect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent); QObject::disconnect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
QObject::disconnect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived); QObject::disconnect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
// If the web surface was fetched out of the cache, release it back into the cache
if (_cachedWebSurface) {
auto offscreenCache = DependencyManager::get<OffscreenQmlSurfaceCache>(); auto offscreenCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
// FIXME prevents crash on shutdown, but we shoudln't have to do this check // FIXME prevents crash on shutdown, but we shoudln't have to do this check
if (offscreenCache) { if (offscreenCache) {
offscreenCache->release(QML, _webSurface); offscreenCache->release(QML, _webSurface);
} }
_cachedWebSurface = false;
}
_webSurface.reset(); _webSurface.reset();
} }
@ -147,6 +167,8 @@ void Web3DOverlay::buildWebSurface() {
if (_webSurface) { if (_webSurface) {
return; return;
} }
// FIXME the context save here is most likely unecessary since the QML surfaces now render
// off the main thread, and all GL context work is done off the main thread (I *think*)
gl::withSavedContext([&] { gl::withSavedContext([&] {
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces // FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
// and the current rendering load) // and the current rendering load)
@ -156,10 +178,13 @@ void Web3DOverlay::buildWebSurface() {
if (isWebContent()) { if (isWebContent()) {
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML); _webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML);
_cachedWebSurface = true;
_webSurface->getRootItem()->setProperty("url", _url); _webSurface->getRootItem()->setProperty("url", _url);
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL); _webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
} else { } else {
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url); _webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), qmlSurfaceDeleter);
_webSurface->load(_url);
_cachedWebSurface = false;
setupQmlSurface(); setupQmlSurface();
} }
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition())); _webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition()));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,6 +9,7 @@
#include "RenderableMaterialEntityItem.h" #include "RenderableMaterialEntityItem.h"
#include "RenderPipelines.h" #include "RenderPipelines.h"
#include "GeometryCache.h"
using namespace render; using namespace render;
using namespace render::entities; using namespace render::entities;
@ -90,138 +91,6 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
return builder.build(); 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) { void MaterialEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render"); PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
Q_ASSERT(args->_batch); Q_ASSERT(args->_batch);
@ -252,14 +121,7 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
args->_details._materialSwitches++; args->_details._materialSwitches++;
// Draw! // Draw!
if (_numVertices == 0) { DependencyManager::get<GeometryCache>()->renderSphere(batch);
generateMesh();
}
batch.setInputFormat(_streamFormat); args->_details._trianglesRendered += (int)DependencyManager::get<GeometryCache>()->getSphereTriangleCount();
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;
} }

View file

@ -40,20 +40,6 @@ private:
Transform _renderTransform; Transform _renderTransform;
std::shared_ptr<NetworkMaterial> _drawMaterial; 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_vert.h"
#include "render-utils/simple_frag.h" #include "render-utils/simple_frag.h"
#include "RenderPipelines.h"
//#define SHAPE_ENTITY_USE_FADE_EFFECT //#define SHAPE_ENTITY_USE_FADE_EFFECT
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT #ifdef SHAPE_ENTITY_USE_FADE_EFFECT
#include <FadeEffect.h> #include <FadeEffect.h>
@ -109,10 +111,93 @@ bool ShapeEntityRenderer::isTransparent() const {
return Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) < 1.0f; 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(); 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) { void ShapeEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableShapeEntityItem::render"); PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
Q_ASSERT(args->_batch); Q_ASSERT(args->_batch);
@ -149,7 +234,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
} else { } else {
geometryCache->renderShape(batch, geometryShape, outColor); geometryCache->renderShape(batch, geometryShape, outColor);
} }
} else { } else if (!useMaterialPipeline()) {
// FIXME, support instanced multi-shape rendering using multidraw indirect // FIXME, support instanced multi-shape rendering using multidraw indirect
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
@ -158,6 +243,11 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
} else { } else {
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline); 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); const auto triCount = geometryCache->getShapeTriangleCount(geometryShape);

View file

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

View file

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

View file

@ -157,7 +157,7 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u
} }
if (usingUserData) { if (usingUserData) {
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getUserData().toUtf8())); _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getUserData().toUtf8()), materialURLString);
// Since our material changed, the current name might not be valid anymore, so we need to update // Since our material changed, the current name might not be valid anymore, so we need to update
setCurrentMaterialName(_currentMaterialName); setCurrentMaterialName(_currentMaterialName);

View file

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

View file

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

View file

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

View file

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

View file

@ -121,7 +121,7 @@ public:
ReplicatedAvatarIdentity, ReplicatedAvatarIdentity,
ReplicatedKillAvatar, ReplicatedKillAvatar,
ReplicatedBulkAvatarData, ReplicatedBulkAvatarData,
OctreeFileReplacementFromUrl, DomainContentReplacementFromUrl,
ChallengeOwnership, ChallengeOwnership,
EntityScriptCallMethod, EntityScriptCallMethod,
ChallengeOwnershipRequest, ChallengeOwnershipRequest,
@ -171,7 +171,7 @@ public:
<< PacketTypeEnum::Value::DomainServerPathResponse << PacketTypeEnum::Value::DomainServerAddedNode << PacketTypeEnum::Value::DomainServerPathResponse << PacketTypeEnum::Value::DomainServerAddedNode
<< PacketTypeEnum::Value::DomainServerConnectionToken << PacketTypeEnum::Value::DomainSettingsRequest << PacketTypeEnum::Value::DomainServerConnectionToken << PacketTypeEnum::Value::DomainSettingsRequest
<< PacketTypeEnum::Value::OctreeDataFileRequest << PacketTypeEnum::Value::OctreeDataFileReply << 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::DomainSettings << PacketTypeEnum::Value::ICEServerPeerInformation
<< PacketTypeEnum::Value::ICEServerQuery << PacketTypeEnum::Value::ICEServerHeartbeat << PacketTypeEnum::Value::ICEServerQuery << PacketTypeEnum::Value::ICEServerHeartbeat
<< PacketTypeEnum::Value::ICEServerHeartbeatACK << PacketTypeEnum::Value::ICEPing << 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 setContext(const gpu::ContextPointer& context) final { _gpuContext = context; }
virtual void submitFrame(const gpu::FramePointer& newFrame) = 0; virtual void submitFrame(const gpu::FramePointer& newFrame) = 0;
// Does the rendering surface have current focus?
virtual bool hasFocus() const = 0;
// The size of the rendering target (may be larger than the device size due to distortion) // The size of the rendering target (may be larger than the device size due to distortion)
virtual glm::uvec2 getRecommendedRenderSize() const = 0; virtual glm::uvec2 getRecommendedRenderSize() const = 0;

View file

@ -8,6 +8,9 @@ include_hifi_library_headers(audio)
include_hifi_library_headers(networking) include_hifi_library_headers(networking)
include_hifi_library_headers(octree) include_hifi_library_headers(octree)
# tell CMake to exclude qrc_fonts.cpp for policy CMP0071
set_property(SOURCE qrc_fonts.cpp PROPERTY SKIP_AUTOMOC ON)
if (NOT ANDROID) if (NOT ANDROID)
target_nsight() target_nsight()
endif () endif ()

View file

@ -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 POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element NORMAL_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 COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA };
static const gpu::Element TEXCOORD4_ELEMENT { gpu::VEC4, gpu::FLOAT, gpu::XYZW }; 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_STREAM_FORMAT;
static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_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_VERTEX_STRIDE = sizeof(GeometryCache::ShapeVertex); // position, normal, texcoords, tangent
static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3); 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) { void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) {
@ -167,16 +171,20 @@ std::vector<vec3> polygon() {
return result; 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(); gpu::Buffer::Size offset = vertexBuffer->getSize();
vertexBuffer->append(vertices); 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, _positionView = gpu::BufferView(vertexBuffer, offset,
viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT); viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT);
_normalView = gpu::BufferView(vertexBuffer, offset + SHAPE_NORMALS_OFFSET, _normalView = gpu::BufferView(vertexBuffer, offset + SHAPE_NORMALS_OFFSET,
viewSize, SHAPE_VERTEX_STRIDE, NORMAL_ELEMENT); 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) { 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 { void GeometryCache::ShapeData::setupBatch(gpu::Batch& batch) const {
batch.setInputBuffer(gpu::Stream::POSITION, _positionView); batch.setInputBuffer(gpu::Stream::POSITION, _positionView);
batch.setInputBuffer(gpu::Stream::NORMAL, _normalView); batch.setInputBuffer(gpu::Stream::NORMAL, _normalView);
batch.setInputBuffer(gpu::Stream::TEXCOORD, _texCoordView);
batch.setInputBuffer(gpu::Stream::TANGENT, _tangentView);
batch.setIndexBuffer(_indicesView); batch.setIndexBuffer(_indicesView);
} }
@ -268,14 +278,14 @@ static IndexPair indexToken(geometry::Index a, geometry::Index b) {
template <size_t N> template <size_t N>
void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
using namespace geometry; using namespace geometry;
VertexVector vertices; std::vector<GeometryCache::ShapeVertex> vertices;
IndexVector solidIndices, wireIndices; IndexVector solidIndices, wireIndices;
IndexPairs wireSeenIndices; IndexPairs wireSeenIndices;
size_t faceCount = shape.faces.size(); size_t faceCount = shape.faces.size();
size_t faceIndexCount = triangulatedFaceIndexCount<N>(); size_t faceIndexCount = triangulatedFaceIndexCount<N>();
vertices.reserve(N * faceCount * 2); vertices.reserve(N * faceCount);
solidIndices.reserve(faceIndexCount * faceCount); solidIndices.reserve(faceIndexCount * faceCount);
Index baseVertex = 0; Index baseVertex = 0;
@ -284,11 +294,35 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
// Compute the face normal // Compute the face normal
vec3 faceNormal = shape.getFaceNormal(f); 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 // Create the vertices for the face
for (Index i = 0; i < N; i++) { for (Index i = 0; i < N; i++) {
Index originalIndex = face[i]; Index originalIndex = face[i];
vertices.push_back(shape.vertices[originalIndex]); vertices.emplace_back(shape.vertices[originalIndex], faceNormal, shape.texCoords[f * N + i], faceTangent);
vertices.push_back(faceNormal);
} }
// Create the wire indices for unseen edges // 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); 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> template <size_t N>
void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
using namespace geometry; using namespace geometry;
VertexVector vertices; std::vector<GeometryCache::ShapeVertex> vertices;
vertices.reserve(shape.vertices.size() * 2); vertices.reserve(shape.vertices.size());
for (const auto& vertex : shape.vertices) { for (const auto& vertex : shape.vertices) {
vertices.push_back(vertex); // We'll fill in the correct tangents later, once we correct the UVs
vertices.push_back(vertex); 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; IndexVector solidIndices, wireIndices;
IndexPairs wireSeenIndices; IndexPairs wireSeenIndices;
size_t faceCount = shape.faces.size();
size_t faceIndexCount = triangulatedFaceIndexCount<N>(); size_t faceIndexCount = triangulatedFaceIndexCount<N>();
solidIndices.reserve(faceIndexCount * faceCount); solidIndices.reserve(faceIndexCount * faceCount);
@ -365,25 +473,22 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
template <uint32_t N> template <uint32_t N>
void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) { void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) {
using namespace geometry; using namespace geometry;
VertexVector vertices; std::vector<GeometryCache::ShapeVertex> vertices;
IndexVector solidIndices, wireIndices; IndexVector solidIndices, wireIndices;
// Top (if not conical) and bottom faces // Top (if not conical) and bottom faces
std::vector<vec3> shape = polygon<N>(); std::vector<vec3> shape = polygon<N>();
if (isConical) { if (isConical) {
for (uint32_t i = 0; i < N; i++) { for (uint32_t i = 0; i < N; i++) {
vertices.push_back(vec3(0.0f, 0.5f, 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));
vertices.push_back(vec3(0.0f, 1.0f, 0.0f));
} }
} else { } else {
for (const vec3& v : shape) { for (const vec3& v : shape) {
vertices.push_back(vec3(v.x, 0.5f, v.z)); 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));
vertices.push_back(vec3(0.0f, 1.0f, 0.0f));
} }
} }
for (const vec3& v : shape) { for (const vec3& v : shape) {
vertices.push_back(vec3(v.x, -0.5f, v.z)); 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));
vertices.push_back(vec3(0.0f, -1.0f, 0.0f));
} }
Index baseVertex = 0; Index baseVertex = 0;
for (uint32_t i = 2; i < N; i++) { 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 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 bottomLeft = vec3(left.x, -0.5f, left.z);
vec3 bottomRight = vec3(right.x, -0.5f, right.z); vec3 bottomRight = vec3(right.x, -0.5f, right.z);
vec3 tangent = glm::normalize(bottomLeft - bottomRight);
vertices.push_back(topLeft); // Our tex coords go in the opposite direction as our vertices
vertices.push_back(normal); float u = 1.0f - (float)i / (float)N;
vertices.push_back(bottomLeft); float u2 = 1.0f - (float)(i + 1) / (float)N;
vertices.push_back(normal);
vertices.push_back(topRight); vertices.emplace_back(topLeft, normal, vec2(u, 0.0f), tangent);
vertices.push_back(normal); vertices.emplace_back(bottomLeft, normal, vec2(u, 1.0f), tangent);
vertices.push_back(bottomRight); vertices.emplace_back(topRight, normal, vec2(u2, 0.0f), tangent);
vertices.push_back(normal); vertices.emplace_back(bottomRight, normal, vec2(u2, 1.0f), tangent);
solidIndices.push_back(baseVertex + 0); solidIndices.push_back(baseVertex + 0);
solidIndices.push_back(baseVertex + 2); solidIndices.push_back(baseVertex + 2);
@ -439,41 +545,6 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices); 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 // FIXME solids need per-face vertices, but smooth shaded
// components do not. Find a way to support using draw elements // components do not. Find a way to support using draw elements
// or draw arrays as appropriate // or draw arrays as appropriate
@ -506,9 +577,9 @@ void GeometryCache::buildShapes() {
// Line // Line
{ {
ShapeData& shapeData = _shapes[Line]; ShapeData& shapeData = _shapes[Line];
shapeData.setupVertices(_shapeVertices, VertexVector { shapeData.setupVertices(_shapeVertices, std::vector<ShapeVertex> {
vec3(-0.5f, 0.0f, 0.0f), vec3(-0.5f, 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)),
vec3(0.5f, 0.0f, 0.0f), vec3(0.5f, 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; IndexVector wireIndices;
// Only two indices // 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 = 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::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_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; 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 = 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::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::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); INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
} }
return INSTANCED_SOLID_STREAM_FORMAT; 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 = 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::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::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::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::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); 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::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); 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.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); 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 /// Set a batch to the simple pipeline, returning the previous pipeline
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false); 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 { struct ShapeData {
gpu::BufferView _positionView; gpu::BufferView _positionView;
gpu::BufferView _normalView; gpu::BufferView _normalView;
gpu::BufferView _texCoordView;
gpu::BufferView _tangentView;
gpu::BufferView _indicesView; gpu::BufferView _indicesView;
gpu::BufferView _wireIndicesView; 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 setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices);
void setupBatch(gpu::Batch& batch) const; void setupBatch(gpu::Batch& batch) const;
void draw(gpu::Batch& batch) const; void draw(gpu::Batch& batch) const;

View file

@ -218,25 +218,25 @@ vec3 fetchLightmapMap(vec2 uv) {
} }
<@endfunc@> <@endfunc@>
<@func tangentToViewSpace(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@> <@func evalMaterialNormal(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
{ {
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz); vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz); vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
vec3 localNormal = <$fetchedNormal$>; 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@> <@endfunc@>
<@func tangentToViewSpaceLOD(fragPos, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@> <@func evalMaterialNormalLOD(fragPos, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
{ {
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz); vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.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 // 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)); 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@> <@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) { MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material) {
updateMeshPart(mesh, partIndex); updateMeshPart(mesh, partIndex);
addMaterial(graphics::MaterialLayer(material, 0)); addMaterial(graphics::MaterialLayer(material, 0));
@ -99,7 +101,7 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShad
builder.withSubMetaCulled(); builder.withSubMetaCulled();
} }
if (_drawMaterials.top().material) { if (topMaterialExists()) {
auto matKey = _drawMaterials.top().material->getKey(); auto matKey = _drawMaterials.top().material->getKey();
if (matKey.isTranslucent()) { if (matKey.isTranslucent()) {
builder.withTransparent(); builder.withTransparent();
@ -119,7 +121,7 @@ Item::Bound MeshPartPayload::getBound() const {
ShapeKey MeshPartPayload::getShapeKey() const { ShapeKey MeshPartPayload::getShapeKey() const {
graphics::MaterialKey drawMaterialKey; graphics::MaterialKey drawMaterialKey;
if (_drawMaterials.top().material) { if (topMaterialExists()) {
drawMaterialKey = _drawMaterials.top().material->getKey(); drawMaterialKey = _drawMaterials.top().material->getKey();
} }
@ -171,7 +173,7 @@ void MeshPartPayload::render(RenderArgs* args) {
bindMesh(batch); bindMesh(batch);
// apply material properties // apply material properties
RenderPipelines::bindMaterial(_drawMaterials.top().material, batch, args->_enableTexturing); RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing);
args->_details._materialSwitches++; args->_details._materialSwitches++;
// Draw! // Draw!
@ -356,7 +358,7 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCas
builder.withDeformed(); builder.withDeformed();
} }
if (_drawMaterials.top().material) { if (topMaterialExists()) {
auto matKey = _drawMaterials.top().material->getKey(); auto matKey = _drawMaterials.top().material->getKey();
if (matKey.isTranslucent()) { if (matKey.isTranslucent()) {
builder.withTransparent(); builder.withTransparent();
@ -387,7 +389,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe
} }
graphics::MaterialKey drawMaterialKey; graphics::MaterialKey drawMaterialKey;
if (_drawMaterials.top().material) { if (topMaterialExists()) {
drawMaterialKey = _drawMaterials.top().material->getKey(); drawMaterialKey = _drawMaterials.top().material->getKey();
} }
@ -469,7 +471,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
bindMesh(batch); bindMesh(batch);
// apply material properties // apply material properties
RenderPipelines::bindMaterial(_drawMaterials.top().material, batch, args->_enableTexturing); RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing);
args->_details._materialSwitches++; args->_details._materialSwitches++;
// Draw! // Draw!

View file

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

View file

@ -1604,7 +1604,8 @@ void Model::createVisibleRenderItemSet() {
int numParts = (int)mesh->getNumParts(); int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) { for (int partIndex = 0; partIndex < numParts; partIndex++) {
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
_modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName()); auto material = getGeometry()->getShapeMaterial(shapeID);
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
shapeID++; shapeID++;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,8 +8,11 @@
#include "Shapes.h" #include "Shapes.h"
#include "qmath.h"
namespace geometry { namespace geometry {
using glm::vec2;
using glm::vec3; using glm::vec3;
// The golden ratio // The golden ratio
@ -19,8 +22,8 @@ Solid<3> tesselate(const Solid<3>& solid_, int count) {
Solid<3> solid = solid_; Solid<3> solid = solid_;
float length = glm::length(solid.vertices[0]); float length = glm::length(solid.vertices[0]);
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
Solid<3> result { solid.vertices, {} }; Solid<3> result { solid.vertices, {}, {} };
result.vertices.reserve(solid.vertices.size() + solid.faces.size() * 3); result.vertices.reserve(solid.vertices.size() + solid.faces.size() * 6);
for (size_t f = 0; f < solid.faces.size(); ++f) { for (size_t f = 0; f < solid.faces.size(); ++f) {
Index baseVertex = (Index)result.vertices.size(); Index baseVertex = (Index)result.vertices.size();
const Face<3>& oldFace = solid.faces[f]; 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 ab = glm::normalize(a + b) * length;
vec3 bc = glm::normalize(b + c) * length; vec3 bc = glm::normalize(b + c) * length;
vec3 ca = glm::normalize(c + a) * 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(ab);
result.vertices.push_back(bc); result.vertices.push_back(bc);
result.vertices.push_back(ca); result.vertices.push_back(ca);
result.faces.push_back(Face<3>{ { oldFace[0], baseVertex, baseVertex + 2 } }); result.faces.push_back(Face<3>{ { baseVertex + 9, baseVertex + 10, baseVertex + 11 } });
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 } });
} }
solid = result; solid = result;
} }
@ -50,6 +66,10 @@ const Solid<3>& tetrahedron() {
static const auto D = vec3(-1, -1, 1); static const auto D = vec3(-1, -1, 1);
static const Solid<3> TETRAHEDRON = Solid<3>{ static const Solid<3> TETRAHEDRON = Solid<3>{
{ A, B, C, D }, { 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>{ FaceVector<3>{
Face<3> { { 0, 1, 2 } }, Face<3> { { 0, 1, 2 } },
Face<3> { { 3, 1, 0 } }, Face<3> { { 3, 1, 0 } },
@ -65,8 +85,15 @@ const Solid<4>& cube() {
static const auto B = vec3(-1, 1, 1); static const auto B = vec3(-1, 1, 1);
static const auto C = vec3(-1, 1, -1); static const auto C = vec3(-1, 1, -1);
static const auto D = 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>{ static const Solid<4> CUBE = Solid<4>{
{ A, B, C, D, -A, -B, -C, -D }, { 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>{ FaceVector<4>{
Face<4> { { 3, 2, 1, 0 } }, Face<4> { { 3, 2, 1, 0 } },
Face<4> { { 0, 1, 7, 6 } }, 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 D = vec3(0, 0, -1);
static const auto E = vec3(1, 0, 0); static const auto E = vec3(1, 0, 0);
static const auto F = 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>{ static const Solid<3> OCTAHEDRON = Solid<3>{
{ A, B, C, D, E, F}, { 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> { FaceVector<3> {
Face<3> { { 0, 2, 4, } }, Face<3> { { 0, 2, 4, } },
Face<3> { { 0, 4, 3, } }, Face<3> { { 0, 4, 3, } },
@ -116,11 +153,52 @@ const Solid<5>& dodecahedron() {
static const vec3 I = vec3(0, -IP, P); static const vec3 I = vec3(0, -IP, P);
static const vec3 J = vec3(P, 0, IP); 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>{ 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,
-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> { FaceVector<5> {
Face<5> { { 0, 1, 2, 3, 4 } }, Face<5> { { 0, 1, 2, 3, 4 } },
Face<5> { { 0, 5, 18, 6, 1 } }, 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 D = vec3(P, 0, N);
static const auto E = vec3(P, 0, -N); static const auto E = vec3(P, 0, -N);
static const auto F = vec3(0, N, -P); 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> { static const Solid<3> ICOSAHEDRON = Solid<3> {
{ {
A, B, C, D, E, F, A, B, C, D, E, F,
-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> { FaceVector<3> {
Face<3> { { 1, 2, 0 } }, Face<3> { { 1, 2, 0 } },
Face<3> { { 2, 3, 0 } }, Face<3> { { 2, 3, 0 } },

View file

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

View file

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

View file

@ -12,5 +12,7 @@ link_hifi_libraries(audio plugins)
add_dependency_external_projects(hifiAudioCodec) add_dependency_external_projects(hifiAudioCodec)
target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAUDIOCODEC_INCLUDE_DIRS}) target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAUDIOCODEC_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${HIFIAUDIOCODEC_LIBRARIES}) 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) set(TARGET_NAME oculus)
setup_hifi_plugin(Multimedia) setup_hifi_plugin(Multimedia)
link_hifi_libraries( link_hifi_libraries(
shared task gl gpu gpu-gl controllers ui qml shared task gl gpu ${PLATFORM_GL_BACKEND} controllers ui qml
plugins ui-plugins display-plugins input-plugins plugins ui-plugins display-plugins input-plugins
audio-client networking render-utils audio-client networking render-utils
${PLATFORM_GL_BACKEND} ${PLATFORM_GL_BACKEND}

View file

@ -9,5 +9,7 @@
set(TARGET_NAME pcmCodec) set(TARGET_NAME pcmCodec)
setup_hifi_client_server_plugin() setup_hifi_client_server_plugin()
link_hifi_libraries(shared plugins) 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 in the shared libraries
link_hifi_libraries( link_hifi_libraries(
shared task networking animation shared task networking animation
ktx image octree gl gpu gpu-gl ktx image octree gl gpu ${PLATFORM_GL_BACKEND}
render render-utils render render-utils
graphics fbx model-networking graphics-scripting graphics fbx model-networking graphics-scripting
entities entities-renderer audio avatars script-engine entities entities-renderer audio avatars script-engine

View file

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

View file

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