mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 11:45:36 +02:00
Merge remote-tracking branch 'upstream/master' into bindless
This commit is contained in:
commit
0e7ee95c95
58 changed files with 983 additions and 513 deletions
110
CMakeLists.txt
110
CMakeLists.txt
|
@ -1,4 +1,4 @@
|
|||
# If we're running under the gradle build, HIFI_ANDROID will be set here, but
|
||||
# If we're running under the gradle build, HIFI_ANDROID will be set here, but
|
||||
# ANDROID will not be set until after the `project` statement. This is the *ONLY*
|
||||
# place you need to use `HIFI_ANDROID` instead of `ANDROID`
|
||||
if (WIN32 AND NOT HIFI_ANDROID)
|
||||
|
@ -14,8 +14,12 @@ include("cmake/init.cmake")
|
|||
include("cmake/compiler.cmake")
|
||||
|
||||
if (BUILD_SCRIBE_ONLY)
|
||||
add_subdirectory(tools/scribe)
|
||||
return()
|
||||
add_subdirectory(tools/scribe)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED CLIENT_ONLY)
|
||||
set(CLIENT_ONLY 0)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED SERVER_ONLY)
|
||||
|
@ -23,46 +27,54 @@ if (NOT DEFINED SERVER_ONLY)
|
|||
endif()
|
||||
|
||||
if (ANDROID OR UWP)
|
||||
set(MOBILE 1)
|
||||
set(MOBILE 1)
|
||||
else()
|
||||
set(MOBILE 0)
|
||||
set(MOBILE 0)
|
||||
endif()
|
||||
|
||||
set(BUILD_CLIENT_OPTION ON)
|
||||
set(BUILD_SERVER_OPTION ON)
|
||||
set(BUILD_TESTS_OPTION ON)
|
||||
set(BUILD_TOOLS_OPTION ON)
|
||||
set(BUILD_INSTALLER_OPTION ON)
|
||||
set(GLES_OPTION OFF)
|
||||
set(DISABLE_QML_OPTION OFF)
|
||||
|
||||
if (ANDROID OR UWP)
|
||||
option(BUILD_SERVER "Build server components" OFF)
|
||||
option(BUILD_TOOLS "Build tools" OFF)
|
||||
option(BUILD_INSTALLER "Build installer" OFF)
|
||||
else()
|
||||
option(BUILD_SERVER "Build server components" ON)
|
||||
option(BUILD_TOOLS "Build tools" ON)
|
||||
option(BUILD_INSTALLER "Build installer" ON)
|
||||
set(BUILD_SERVER_OPTION OFF)
|
||||
set(BUILD_TOOLS_OPTION OFF)
|
||||
set(BUILD_INSTALLER OFF)
|
||||
endif()
|
||||
|
||||
if (CLIENT_ONLY)
|
||||
set(BUILD_SERVER_OPTION OFF)
|
||||
endif()
|
||||
|
||||
if (SERVER_ONLY)
|
||||
option(BUILD_CLIENT "Build client components" OFF)
|
||||
option(BUILD_TESTS "Build tests" OFF)
|
||||
else()
|
||||
option(BUILD_CLIENT "Build client components" ON)
|
||||
option(BUILD_TESTS "Build tests" ON)
|
||||
set(BUILD_CLIENT_OPTION OFF)
|
||||
set(BUILD_TESTS_OPTION OFF)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
option(USE_GLES "Use OpenGL ES" ON)
|
||||
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
|
||||
set(GLES_OPTION ON)
|
||||
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
|
||||
else ()
|
||||
option(USE_GLES "Use OpenGL ES" OFF)
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
|
||||
endif ()
|
||||
|
||||
if (USE_GLES AND (NOT ANDROID))
|
||||
option(DISABLE_QML "Disable QML" ON)
|
||||
else()
|
||||
option(DISABLE_QML "Disable QML" OFF)
|
||||
set(DISABLE_QML_OPTION ON)
|
||||
endif()
|
||||
|
||||
option(BUILD_CLIENT "Build client components" ${BUILD_CLIENT_OPTION})
|
||||
option(BUILD_SERVER "Build server components" ${BUILD_SERVER_OPTION})
|
||||
option(BUILD_TESTS "Build tests" ${BUILD_TESTS_OPTION})
|
||||
option(BUILD_TOOLS "Build tools" ${BUILD_TOOLS_OPTION})
|
||||
option(BUILD_INSTALLER "Build installer" ${BUILD_INSTALLER_OPTION})
|
||||
option(USE_GLES "Use OpenGL ES" ${GLES_OPTION})
|
||||
option(DISABLE_QML "Disable QML" ${DISABLE_QML_OPTION})
|
||||
option(DISABLE_KTX_CACHE "Disable KTX Cache" OFF)
|
||||
|
||||
|
||||
|
||||
set(PLATFORM_QT_GL OpenGL)
|
||||
|
||||
if (USE_GLES)
|
||||
|
@ -72,12 +84,10 @@ else()
|
|||
set(PLATFORM_GL_BACKEND gpu-gl-common gpu-gl)
|
||||
endif()
|
||||
|
||||
|
||||
foreach(PLATFORM_QT_COMPONENT ${PLATFORM_QT_COMPONENTS})
|
||||
list(APPEND PLATFORM_QT_LIBRARIES "Qt5::${PLATFORM_QT_COMPONENT}")
|
||||
endforeach()
|
||||
|
||||
|
||||
MESSAGE(STATUS "Build server: " ${BUILD_SERVER})
|
||||
MESSAGE(STATUS "Build client: " ${BUILD_CLIENT})
|
||||
MESSAGE(STATUS "Build tests: " ${BUILD_TESTS})
|
||||
|
@ -86,17 +96,17 @@ MESSAGE(STATUS "Build installer: " ${BUILD_INSTALLER})
|
|||
MESSAGE(STATUS "GL ES: " ${USE_GLES})
|
||||
|
||||
if (DISABLE_QML)
|
||||
MESSAGE(STATUS "QML disabled!")
|
||||
add_definitions(-DDISABLE_QML)
|
||||
MESSAGE(STATUS "QML disabled!")
|
||||
add_definitions(-DDISABLE_QML)
|
||||
endif()
|
||||
|
||||
if (DISABLE_KTX_CACHE)
|
||||
MESSAGE(STATUS "KTX cache disabled!")
|
||||
add_definitions(-DDISABLE_KTX_CACHE)
|
||||
MESSAGE(STATUS "KTX cache disabled!")
|
||||
add_definitions(-DDISABLE_KTX_CACHE)
|
||||
endif()
|
||||
|
||||
if (UNIX AND DEFINED ENV{HIFI_MEMORY_DEBUGGING})
|
||||
MESSAGE(STATUS "Memory debugging is enabled")
|
||||
MESSAGE(STATUS "Memory debugging is enabled")
|
||||
endif()
|
||||
|
||||
#
|
||||
|
@ -132,8 +142,8 @@ set_packaging_parameters()
|
|||
|
||||
# FIXME hack to work on the proper Android toolchain
|
||||
if (ANDROID)
|
||||
add_subdirectory(android/app)
|
||||
return()
|
||||
add_subdirectory(android/app)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# add subdirectories for all targets
|
||||
|
@ -148,32 +158,30 @@ if (BUILD_SERVER)
|
|||
endif()
|
||||
|
||||
if (BUILD_CLIENT)
|
||||
add_subdirectory(interface)
|
||||
set_target_properties(interface PROPERTIES FOLDER "Apps")
|
||||
if (ANDROID)
|
||||
add_subdirectory(gvr-interface)
|
||||
set_target_properties(gvr-interface PROPERTIES FOLDER "Apps")
|
||||
endif()
|
||||
add_subdirectory(interface)
|
||||
set_target_properties(interface PROPERTIES FOLDER "Apps")
|
||||
|
||||
option(USE_SIXENSE "Build Interface with sixense library/plugin" OFF)
|
||||
endif()
|
||||
|
||||
if (BUILD_CLIENT OR BUILD_SERVER)
|
||||
add_subdirectory(plugins)
|
||||
add_subdirectory(plugins)
|
||||
endif()
|
||||
|
||||
# BUILD_TOOLS option will be handled inside the tools's CMakeLists.txt because 'scribe' tool is required for build anyway
|
||||
add_subdirectory(tools)
|
||||
|
||||
if (BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if (BUILD_INSTALLER)
|
||||
if (UNIX)
|
||||
install(
|
||||
DIRECTORY "${CMAKE_SOURCE_DIR}/scripts"
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/interface
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
endif()
|
||||
generate_installers()
|
||||
if (UNIX)
|
||||
install(
|
||||
DIRECTORY "${CMAKE_SOURCE_DIR}/scripts"
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/interface
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
endif()
|
||||
generate_installers()
|
||||
endif()
|
||||
|
|
|
@ -17,6 +17,8 @@ To produce an executable installer on Windows, the following are required:
|
|||
- [Nullsoft Scriptable Install System](http://nsis.sourceforge.net/Download) - 3.0b3
|
||||
- [UAC Plug-in for Nullsoft](http://nsis.sourceforge.net/UAC_plug-in) - 0.2.4c
|
||||
- [nsProcess Plug-in for Nullsoft](http://nsis.sourceforge.net/NsProcess_plugin) - 1.6
|
||||
- [Inetc Plug-in for Nullsoft](http://nsis.sourceforge.net/Inetc_plug-in) - 1.0
|
||||
- [NSISpcre Plug-in for Nullsoft](http://nsis.sourceforge.net/NSISpcre_plug-in) - 1.0
|
||||
|
||||
Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System.
|
||||
|
||||
|
|
|
@ -476,6 +476,7 @@ void EntityScriptServer::clear() {
|
|||
// do this here (instead of in deleter) to avoid marshalling unload signals back to this thread
|
||||
_entitiesScriptEngine->unloadAllEntityScripts();
|
||||
_entitiesScriptEngine->stop();
|
||||
_entitiesScriptEngine->waitTillDoneRunning();
|
||||
}
|
||||
|
||||
_entityViewer.clear();
|
||||
|
@ -565,8 +566,15 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> mess
|
|||
void EntityScriptServer::aboutToFinish() {
|
||||
shutdownScriptEngine();
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
// our entity tree is going to go away so tell that to the EntityScriptingInterface
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);
|
||||
entityScriptingInterface->setEntityTree(nullptr);
|
||||
|
||||
// Should always be true as they are singletons.
|
||||
if (entityScriptingInterface->getPacketSender() == &_entityEditSender) {
|
||||
// The packet sender is about to go away.
|
||||
entityScriptingInterface->setPacketSender(nullptr);
|
||||
}
|
||||
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
|
||||
|
|
2
cmake/externals/quazip/CMakeLists.txt
vendored
2
cmake/externals/quazip/CMakeLists.txt
vendored
|
@ -4,7 +4,7 @@ cmake_policy(SET CMP0046 OLD)
|
|||
|
||||
include(ExternalProject)
|
||||
|
||||
set(QUAZIP_CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_PREFIX_PATH=${QT_CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_NAME_DIR:PATH=<INSTALL_DIR>/lib -DZLIB_ROOT=${ZLIB_ROOT} -DCMAKE_POSITION_INDEPENDENT_CODE=ON)
|
||||
set(QUAZIP_CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_PREFIX_PATH=${QT_CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_NAME_DIR:PATH=<INSTALL_DIR>/lib -DZLIB_ROOT=${ZLIB_ROOT} -DCMAKE_POSITION_INDEPENDENT_CODE=ON)
|
||||
|
||||
if (APPLE)
|
||||
else ()
|
||||
|
|
|
@ -23,7 +23,7 @@ macro(GENERATE_INSTALLERS)
|
|||
set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME})
|
||||
set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME})
|
||||
if (PR_BUILD)
|
||||
set(CPACK_NSIS_COMPRESSOR "/SOLID bzip2")
|
||||
set(CPACK_NSIS_COMPRESSOR "bzip2")
|
||||
endif ()
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME})
|
||||
|
||||
|
@ -46,9 +46,35 @@ macro(GENERATE_INSTALLERS)
|
|||
set(UNINSTALLER_HEADER_IMAGE "")
|
||||
fix_path_for_nsis(${_UNINSTALLER_HEADER_BAD_PATH} UNINSTALLER_HEADER_IMAGE)
|
||||
|
||||
# grab the latest VC redist (2017) and add it to the installer, our NSIS template
|
||||
# will call it during the install
|
||||
install(CODE "file(DOWNLOAD https://go.microsoft.com/fwlink/?LinkId=746572 \"\${CMAKE_INSTALL_PREFIX}/vcredist_x64.exe\")")
|
||||
# we use external libraries that still need the 120 (VS2013) redistributables
|
||||
# so we include them as well until those external libraries are updated
|
||||
# to use the redistributables that match what we build our applications for
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
|
||||
"C:/Windows/System32/msvcp120.dll"
|
||||
"C:/Windows/System32/msvcr120.dll"
|
||||
)
|
||||
|
||||
set(CMAKE_INSTALL_UCRT_LIBRARIES TRUE)
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ${INTERFACE_INSTALL_DIR})
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT ${CLIENT_COMPONENT})
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
if (CLIENT_ONLY OR SERVER_ONLY)
|
||||
set(CPACK_MONOLITHIC_INSTALL 1)
|
||||
endif ()
|
||||
|
||||
# setup conditional checks for server component selection depending on
|
||||
# the inclusion of the server component at all
|
||||
if (CLIENT_ONLY)
|
||||
set(SERVER_COMPONENT_CONDITIONAL "0 == 1")
|
||||
set(CLIENT_COMPONENT_CONDITIONAL "1 == 1")
|
||||
elseif (SERVER_ONLY)
|
||||
set(SERVER_COMPONENT_CONDITIONAL "1 == 1")
|
||||
set(CLIENT_COMPONENT_CONDITIONAL "0 == 1")
|
||||
else ()
|
||||
set(SERVER_COMPONENT_CONDITIONAL "\\\${SectionIsSelected} \\\${${SERVER_COMPONENT}}")
|
||||
set(CLIENT_COMPONENT_CONDITIONAL "\\\${SectionIsSelected} \\\${${CLIENT_COMPONENT}}")
|
||||
endif ()
|
||||
elseif (APPLE)
|
||||
# produce a drag and drop DMG on OS X
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
|
@ -79,8 +105,13 @@ macro(GENERATE_INSTALLERS)
|
|||
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
|
||||
|
||||
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Interface")
|
||||
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Sandbox")
|
||||
if (BUILD_CLIENT)
|
||||
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Interface")
|
||||
endif ()
|
||||
|
||||
if (BUILD_SERVER)
|
||||
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Sandbox")
|
||||
endif ()
|
||||
|
||||
include(CPack)
|
||||
endmacro()
|
||||
|
|
|
@ -39,7 +39,9 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT)
|
|||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>:--release> \"$<TARGET_FILE:${TARGET_NAME}>\""
|
||||
COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND}\
|
||||
${EXTRA_DEPLOY_OPTIONS} $<$<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>:--release>\
|
||||
--no-compiler-runtime --no-opengl-sw --no-angle -no-system-d3d-compiler \"$<TARGET_FILE:${TARGET_NAME}>\""
|
||||
)
|
||||
|
||||
set(QTAUDIO_PATH "$<TARGET_FILE_DIR:${TARGET_NAME}>/audio")
|
||||
|
|
|
@ -27,6 +27,11 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
message(STATUS "The BRANCH environment variable is: $ENV{BRANCH}")
|
||||
message(STATUS "The RELEASE_TYPE variable is: ${RELEASE_TYPE}")
|
||||
|
||||
# setup component categories for installer
|
||||
set(DDE_COMPONENT dde)
|
||||
set(CLIENT_COMPONENT client)
|
||||
set(SERVER_COMPONENT server)
|
||||
|
||||
if (RELEASE_TYPE STREQUAL "PRODUCTION")
|
||||
set(DEPLOY_PACKAGE TRUE)
|
||||
set(PRODUCTION_BUILD 1)
|
||||
|
@ -149,13 +154,10 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
set(CLIENT_LAUNCH_NOW_REG_KEY "ClientLaunchAfterInstall")
|
||||
set(SERVER_LAUNCH_NOW_REG_KEY "ServerLaunchAfterInstall")
|
||||
set(CUSTOM_INSTALL_REG_KEY "CustomInstall")
|
||||
set(CLIENT_ID_REG_KEY "ClientGUID")
|
||||
set(GA_TRACKING_ID $ENV{GA_TRACKING_ID})
|
||||
endif ()
|
||||
|
||||
# setup component categories for installer
|
||||
set(DDE_COMPONENT dde)
|
||||
set(CLIENT_COMPONENT client)
|
||||
set(SERVER_COMPONENT server)
|
||||
|
||||
# print out some results for testing this new build feature
|
||||
message(STATUS "The BUILD_GLOBAL_SERVICES variable is: ${BUILD_GLOBAL_SERVICES}")
|
||||
message(STATUS "The USE_STABLE_GLOBAL_SERVICES variable is: ${USE_STABLE_GLOBAL_SERVICES}")
|
||||
|
|
|
@ -41,6 +41,10 @@ set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_REG_KEY@")
|
|||
set(SERVER_LAUNCH_NOW_REG_KEY "@SERVER_LAUNCH_NOW_REG_KEY@")
|
||||
set(CLIENT_LAUNCH_NOW_REG_KEY "@CLIENT_LAUNCH_NOW_REG_KEY@")
|
||||
set(CUSTOM_INSTALL_REG_KEY "@CUSTOM_INSTALL_REG_KEY@")
|
||||
set(GA_TRACKING_ID "@GA_TRACKING_ID@")
|
||||
set(CLIENT_ID_REG_KEY "@CLIENT_ID_REG_KEY@")
|
||||
set(INSTALLER_HEADER_IMAGE "@INSTALLER_HEADER_IMAGE@")
|
||||
set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@")
|
||||
set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@")
|
||||
set(SERVER_COMPONENT_CONDITIONAL "@SERVER_COMPONENT_CONDITIONAL@")
|
||||
set(CLIENT_COMPONENT_CONDITIONAL "@CLIENT_COMPONENT_CONDITIONAL@")
|
||||
|
|
|
@ -319,6 +319,78 @@ Function DownloadFile
|
|||
FunctionEnd
|
||||
!endif
|
||||
|
||||
|
||||
!include NSISpcre.nsh
|
||||
!insertmacro REMatches
|
||||
|
||||
Var CampaignName
|
||||
|
||||
!macro GetCampaignName RetVar
|
||||
Call GetCampaignName
|
||||
Pop ${RetVar}
|
||||
!macroend
|
||||
|
||||
Function GetCampaignName
|
||||
Push $0 ; Stash $0
|
||||
|
||||
; Parse filename out of the path
|
||||
${RECaptureMatches} $0 "([^\\]*\\)*(.*)\.exe" $EXEPATH 0
|
||||
${If} $0 == 2
|
||||
Pop $0 ; Discard Path
|
||||
Pop $0 ; Recover filename
|
||||
; Parse campaign out of the filename
|
||||
${RECaptureMatches} $0 "HighFidelity-([^-]*-)Beta-.*" $0 0
|
||||
${If} $0 == 1
|
||||
Pop $0 ; Recover campaign name
|
||||
StrCpy $0 $0 -1 0 ; Remove trailing - and copy to _RetVar
|
||||
${Else}
|
||||
StrCpy $0 ""
|
||||
${EndIf}
|
||||
${Else}
|
||||
StrCpy $0 ""
|
||||
${EndIf}
|
||||
|
||||
Exch $0 ; Restore $0 and push result
|
||||
FunctionEnd
|
||||
|
||||
!macro CreateGUID RetVar
|
||||
System::Call 'ole32::CoCreateGuid(g .s)'
|
||||
Pop ${RetVar}
|
||||
; Strip opening and closing braces
|
||||
StrCpy ${RetVar} ${RetVar} -1 1
|
||||
!macroend
|
||||
|
||||
Var GAClientID
|
||||
|
||||
!macro InitGAClientID
|
||||
; Generate a new GUID on every run for now
|
||||
!insertmacro CreateGUID $GAClientID
|
||||
!macroend
|
||||
|
||||
!macro GoogleAnalytics Category Action Label Value
|
||||
${If} "@GA_TRACKING_ID@" != ""
|
||||
Push $0
|
||||
Push $1
|
||||
|
||||
StrCpy $0 "https://google-analytics.com/collect?v=1&tid=@GA_TRACKING_ID@"
|
||||
StrCpy $0 "$0&cid=$GAClientID&t=event&ec=${Category}&ea=${Action}"
|
||||
|
||||
${If} "${Label}" != ""
|
||||
StrCpy $0 "$0&el=${Label}"
|
||||
${EndIf}
|
||||
${If} "${Value}" != ""
|
||||
StrCpy $0 "$0&ev=${Value}"
|
||||
${EndIf}
|
||||
|
||||
GetTempFileName $1
|
||||
inetc::get /SILENT $0 $1 /END
|
||||
Delete $1
|
||||
|
||||
Pop $1
|
||||
Pop $0
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
;--------------------------------
|
||||
; Installation types
|
||||
|
||||
|
@ -342,28 +414,38 @@ SectionEnd
|
|||
|
||||
;--------------------------------
|
||||
;Pages
|
||||
!define MUI_CUSTOMFUNCTION_ABORT OnUserAbort
|
||||
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageWelcomePre
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageLicensePre
|
||||
!insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
|
||||
|
||||
Page custom InstallTypesPage ReadInstallTypes
|
||||
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageDirectoryPre
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
|
||||
;Start Menu Folder Page Configuration
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
|
||||
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageStartMenuPre
|
||||
!insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
|
||||
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageComponentsPre
|
||||
@CPACK_NSIS_PAGE_COMPONENTS@
|
||||
|
||||
; the MUI_PAGE_CUSTOMFUNCTION_PRE shouldn't be defined here
|
||||
; which can happen for a component-less (like client only) install
|
||||
!ifdef MUI_PAGE_CUSTOMFUNCTION_PRE
|
||||
!undef MUI_PAGE_CUSTOMFUNCTION_PRE
|
||||
!endif
|
||||
|
||||
Page custom PostInstallOptionsPage ReadPostInstallOptions
|
||||
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageInstallFilesPre
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
|
@ -452,8 +534,40 @@ Var CopyFromProductionCheckbox
|
|||
Var ExpressInstallRadioButton
|
||||
Var CustomInstallRadioButton
|
||||
Var InstallTypeDialog
|
||||
Var Express
|
||||
Var CustomInstallTemporaryState
|
||||
Var Express
|
||||
|
||||
!macro MaybeSkipPage
|
||||
; Check if Express is set, if so, abort the post install options page
|
||||
${If} $Express == "1"
|
||||
Abort
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
Function OnUserAbort
|
||||
!insertmacro GoogleAnalytics "Installer" "Abort" "User Abort" ""
|
||||
FunctionEnd
|
||||
Function PageWelcomePre
|
||||
!insertmacro GoogleAnalytics "Installer" "Welcome" "" ""
|
||||
FunctionEnd
|
||||
Function PageLicensePre
|
||||
!insertmacro GoogleAnalytics "Installer" "License" "" ""
|
||||
FunctionEnd
|
||||
Function PageDirectoryPre
|
||||
!insertmacro MaybeSkipPage
|
||||
!insertmacro GoogleAnalytics "Installer" "Directory" "" ""
|
||||
FunctionEnd
|
||||
Function PageStartMenuPre
|
||||
!insertmacro MaybeSkipPage
|
||||
!insertmacro GoogleAnalytics "Installer" "StartMenu" "" ""
|
||||
FunctionEnd
|
||||
Function PageComponentsPre
|
||||
!insertmacro MaybeSkipPage
|
||||
!insertmacro GoogleAnalytics "Installer" "Components" "" ""
|
||||
FunctionEnd
|
||||
Function PageInstallFilesPre
|
||||
!insertmacro GoogleAnalytics "Installer" "Install" "" ""
|
||||
FunctionEnd
|
||||
|
||||
!macro SetInstallOption Checkbox OptionName Default
|
||||
; reads the value for the given install option to the registry
|
||||
|
@ -472,6 +586,8 @@ Var CustomInstallTemporaryState
|
|||
!macroend
|
||||
|
||||
Function InstallTypesPage
|
||||
!insertmacro GoogleAnalytics "Installer" "Install Types" "" ""
|
||||
|
||||
!insertmacro MUI_HEADER_TEXT "Choose Installation Type" "Express or Custom Install"
|
||||
|
||||
nsDialogs::Create 1018
|
||||
|
@ -502,10 +618,11 @@ Function InstallTypesPage
|
|||
|
||||
${If} $CustomInstallTemporaryState == ${BST_UNCHECKED}
|
||||
${NSD_Check} $ExpressInstallRadioButton
|
||||
Call ChangeExpressLabel
|
||||
${Else}
|
||||
Call ChangeCustomLabel
|
||||
${EndIf}
|
||||
|
||||
Call ChangeExpressLabel
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
|
@ -523,14 +640,10 @@ Function ChangeCustomLabel
|
|||
Pop $R1
|
||||
FunctionEnd
|
||||
|
||||
Function AbortFunction
|
||||
; Check if Express is set, if so, abort the post install options page
|
||||
StrCmp $Express "1" 0 end
|
||||
Abort
|
||||
end:
|
||||
FunctionEnd
|
||||
|
||||
Function PostInstallOptionsPage
|
||||
!insertmacro MaybeSkipPage
|
||||
!insertmacro GoogleAnalytics "Installer" "Post Install Options" "" ""
|
||||
|
||||
!insertmacro MUI_HEADER_TEXT "Setup Options" ""
|
||||
|
||||
nsDialogs::Create 1018
|
||||
|
@ -540,15 +653,10 @@ Function PostInstallOptionsPage
|
|||
Abort
|
||||
${EndIf}
|
||||
|
||||
; Check if Express is set, if so, abort the post install options page
|
||||
StrCmp $Express "1" 0 end
|
||||
Abort
|
||||
end:
|
||||
|
||||
StrCpy $CurrentOffset 0
|
||||
StrCpy $OffsetUnits u
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @INTERFACE_HF_SHORTCUT_NAME@"
|
||||
Pop $DesktopClientCheckbox
|
||||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
|
@ -557,7 +665,7 @@ Function PostInstallOptionsPage
|
|||
!insertmacro SetInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@"
|
||||
Pop $DesktopServerCheckbox
|
||||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
|
@ -566,7 +674,7 @@ Function PostInstallOptionsPage
|
|||
!insertmacro SetInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install"
|
||||
Pop $LaunchServerNowCheckbox
|
||||
|
||||
|
@ -580,7 +688,7 @@ Function PostInstallOptionsPage
|
|||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install"
|
||||
Pop $LaunchClientNowCheckbox
|
||||
IntOp $CurrentOffset $CurrentOffset + 30
|
||||
|
@ -593,7 +701,7 @@ Function PostInstallOptionsPage
|
|||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup"
|
||||
Pop $ServerStartupCheckbox
|
||||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
|
@ -602,7 +710,7 @@ Function PostInstallOptionsPage
|
|||
!insertmacro SetInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)"
|
||||
Pop $CleanInstallCheckbox
|
||||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
|
@ -610,11 +718,11 @@ Function PostInstallOptionsPage
|
|||
|
||||
${If} @PR_BUILD@ == 1
|
||||
; a PR build defaults all install options expect LaunchServerNowCheckbox, LaunchClientNowCheckbox and the settings copy to unchecked
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
${NSD_SetState} $DesktopClientCheckbox ${BST_UNCHECKED}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${NSD_SetState} $DesktopServerCheckbox ${BST_UNCHECKED}
|
||||
${NSD_SetState} $ServerStartupCheckbox ${BST_UNCHECKED}
|
||||
${EndIf}
|
||||
|
@ -673,12 +781,12 @@ Function ReadInstallTypes
|
|||
FunctionEnd
|
||||
|
||||
Function ReadPostInstallOptions
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a desktop shortcut to High Fidelity
|
||||
${NSD_GetState} $DesktopClientCheckbox $DesktopClientState
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a desktop shortcut to Sandbox
|
||||
${NSD_GetState} $DesktopServerCheckbox $DesktopServerState
|
||||
|
||||
|
@ -691,24 +799,24 @@ Function ReadPostInstallOptions
|
|||
${NSD_GetState} $CopyFromProductionCheckbox $CopyFromProductionState
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
; check if we need to launch the server post-install
|
||||
${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
; check if we need to launch the client post-install
|
||||
${NSD_GetState} $LaunchClientNowCheckbox $LaunchClientNowState
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a clean install
|
||||
${NSD_GetState} $CleanInstallCheckbox $CleanInstallState
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function HandlePostInstallOptions
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a desktop shortcut to High Fidelity
|
||||
${If} $DesktopClientState == ${BST_CHECKED}
|
||||
CreateShortCut "$DESKTOP\@INTERFACE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
|
||||
|
@ -719,7 +827,7 @@ Function HandlePostInstallOptions
|
|||
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a desktop shortcut to Sandbox
|
||||
${If} $DesktopServerState == ${BST_CHECKED}
|
||||
CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
|
||||
|
@ -748,7 +856,7 @@ Function HandlePostInstallOptions
|
|||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a clean install
|
||||
${If} $CleanInstallState == ${BST_CHECKED}
|
||||
SetShellVarContext current
|
||||
|
@ -785,7 +893,8 @@ Function HandlePostInstallOptions
|
|||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
${If} $LaunchServerNowState == ${BST_CHECKED}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${AndIf} $LaunchServerNowState == ${BST_CHECKED}
|
||||
!insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ YES
|
||||
|
||||
; both launches use the explorer trick in case the user has elevated permissions for the installer
|
||||
|
@ -799,7 +908,7 @@ Function HandlePostInstallOptions
|
|||
Exec '"$WINDIR\explorer.exe" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"'
|
||||
${EndIf}
|
||||
|
||||
${Else}
|
||||
${ElseIf} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
!insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ NO
|
||||
|
||||
; launch uses the explorer trick in case the user has elevated permissions for the installer
|
||||
|
@ -837,9 +946,6 @@ Section "-Core installation"
|
|||
Delete "$INSTDIR\ui_resources_200_percent.pak"
|
||||
Delete "$INSTDIR\vccorlib120.dll"
|
||||
Delete "$INSTDIR\version"
|
||||
Delete "$INSTDIR\msvcr140.dll"
|
||||
Delete "$INSTDIR\msvcp140.dll"
|
||||
Delete "$INSTDIR\vcruntime140.dll"
|
||||
Delete "$INSTDIR\xinput1_3.dll"
|
||||
|
||||
; Delete old desktop shortcuts before they were renamed during Sandbox rename
|
||||
|
@ -858,11 +964,8 @@ Section "-Core installation"
|
|||
; Rename the incorrectly cased Raleway font
|
||||
Rename "$INSTDIR\resources\qml\styles-uit\RalewaySemibold.qml" "$INSTDIR\resources\qml\styles-uit\RalewaySemiBold.qml"
|
||||
|
||||
ExecWait "$INSTDIR\vcredist_x64.exe /install /q /norestart"
|
||||
|
||||
; Remove the Old Interface directory and vcredist_x64.exe (from installs prior to Server Console)
|
||||
RMDir /r "$INSTDIR\Interface"
|
||||
Delete "$INSTDIR\vcredist_x64.exe"
|
||||
|
||||
;Use the entire tree produced by the INSTALL target. Keep the
|
||||
;list of directories here in sync with the RMDir commands below.
|
||||
|
@ -931,7 +1034,7 @@ Section "-Core installation"
|
|||
@CPACK_NSIS_CREATE_ICONS_EXTRA@
|
||||
|
||||
; Conditional handling for Interface specific options
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@INTERFACE_SHORTCUT_NAME@.lnk" \
|
||||
"$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
|
||||
|
||||
|
@ -946,7 +1049,7 @@ Section "-Core installation"
|
|||
${EndIf}
|
||||
|
||||
; Conditional handling for server console shortcut
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \
|
||||
"$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
|
||||
${EndIf}
|
||||
|
@ -965,6 +1068,7 @@ Section "-Core installation"
|
|||
; Handle whichever post install options were set
|
||||
Call HandlePostInstallOptions
|
||||
|
||||
!insertmacro GoogleAnalytics "Installer" "Done" "" ""
|
||||
SectionEnd
|
||||
|
||||
!include nsProcess.nsh
|
||||
|
@ -979,7 +1083,7 @@ SectionEnd
|
|||
${If} $R0 == 0
|
||||
|
||||
; the process is running, ask the user to close it
|
||||
|
||||
|
||||
${If} "${displayName}" == "@CONSOLE_DISPLAY_NAME@"
|
||||
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION \
|
||||
"${displayName} cannot be ${action} while ${displayName} is running.$\r$\nPlease close it in the system tray and click Retry to continue." \
|
||||
|
@ -992,6 +1096,8 @@ SectionEnd
|
|||
/SD IDCANCEL IDRETRY Prompt_${UniqueID} IDCANCEL 0
|
||||
${EndIf}
|
||||
|
||||
!insertmacro GoogleAnalytics "Installer" "Abort" "${displayName} Running" ""
|
||||
|
||||
; If the user decided to cancel, stop the current installer/uninstaller
|
||||
Abort
|
||||
|
||||
|
@ -1087,8 +1193,8 @@ Function .onSelChange
|
|||
!insertmacro SectionList MaybeSelectionChanged
|
||||
|
||||
; if neither component is selected, disable the install button
|
||||
${IfNot} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${AndIfNot} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${IfNot} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
${AndIfNot} @SERVER_COMPONENT_CONDITIONAL@
|
||||
GetDlgItem $0 $HWNDPARENT 1
|
||||
EnableWindow $0 0
|
||||
${Else}
|
||||
|
@ -1219,6 +1325,11 @@ Function .onInit
|
|||
Quit
|
||||
!endif
|
||||
|
||||
!insertmacro InitGAClientID
|
||||
!insertmacro GetCampaignName $CampaignName
|
||||
|
||||
!insertmacro GoogleAnalytics "Installer" "Start" "$CampaignName" ""
|
||||
|
||||
; make sure none of the installed applications are still running
|
||||
!insertmacro CheckForRunningApplications "installed" "Installer"
|
||||
${nsProcess::Unload}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <QJsonArray>
|
||||
#include <QProcess>
|
||||
#include <QSharedMemory>
|
||||
#include <QRegularExpression>
|
||||
#include <QStandardPaths>
|
||||
#include <QTimer>
|
||||
#include <QUrlQuery>
|
||||
|
@ -727,7 +728,7 @@ void DomainServer::setupNodeListAndAssignments() {
|
|||
packetReceiver.registerListener(PacketType::OctreeDataPersist, this, "processOctreeDataPersistMessage");
|
||||
|
||||
packetReceiver.registerListener(PacketType::OctreeFileReplacement, this, "handleOctreeFileReplacementRequest");
|
||||
packetReceiver.registerListener(PacketType::OctreeFileReplacementFromUrl, this, "handleOctreeFileReplacementFromURLRequest");
|
||||
packetReceiver.registerListener(PacketType::DomainContentReplacementFromUrl, this, "handleDomainContentReplacementFromURLRequest");
|
||||
|
||||
// set a custom packetVersionMatch as the verify packet operator for the udt::Socket
|
||||
nodeList->setPacketFilterOperator(&DomainServer::isPacketVerified);
|
||||
|
@ -736,7 +737,6 @@ void DomainServer::setupNodeListAndAssignments() {
|
|||
auto assetClient = DependencyManager::set<AssetClient>();
|
||||
assetClient->moveToThread(&_assetClientThread);
|
||||
_assetClientThread.start();
|
||||
|
||||
// add whatever static assignments that have been parsed to the queue
|
||||
addStaticAssignmentsToQueue();
|
||||
}
|
||||
|
@ -2136,7 +2136,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
} else if (url.path().startsWith(URI_API_BACKUPS_ID)) {
|
||||
auto id = url.path().mid(QString(URI_API_BACKUPS_ID).length());
|
||||
auto deferred = makePromise("consolidateBackup");
|
||||
deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) {
|
||||
deferred->then([connectionPtr, JSON_MIME_TYPE, id](QString error, QVariantMap result) {
|
||||
if (!connectionPtr) {
|
||||
return;
|
||||
}
|
||||
|
@ -2147,7 +2147,14 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
auto path = result["backupFilePath"].toString();
|
||||
auto file { std::unique_ptr<QFile>(new QFile(path)) };
|
||||
if (file->open(QIODevice::ReadOnly)) {
|
||||
connectionPtr->respond(HTTPConnection::StatusCode200, std::move(file));
|
||||
constexpr const char* CONTENT_TYPE_ZIP = "application/zip";
|
||||
|
||||
auto downloadedFilename = id;
|
||||
downloadedFilename.replace(QRegularExpression(".zip$"), ".content.zip");
|
||||
auto contentDisposition = "attachment; filename=\"" + downloadedFilename + "\"";
|
||||
connectionPtr->respond(HTTPConnection::StatusCode200, std::move(file), CONTENT_TYPE_ZIP, {
|
||||
{ "Content-Disposition", contentDisposition.toUtf8() }
|
||||
});
|
||||
} else {
|
||||
qCritical(domain_server) << "Unable to load consolidated backup at:" << path << result;
|
||||
connectionPtr->respond(HTTPConnection::StatusCode500, "Error opening backup");
|
||||
|
@ -3429,13 +3436,10 @@ void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile) {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainServer::handleOctreeFileReplacementFromURLRequest(QSharedPointer<ReceivedMessage> message) {
|
||||
void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer<ReceivedMessage> message) {
|
||||
qInfo() << "Received request to replace content from a url";
|
||||
auto node = DependencyManager::get<LimitedNodeList>()->findNodeWithAddr(message->getSenderSockAddr());
|
||||
if (node) {
|
||||
qDebug() << "Found node: " << node->getCanReplaceContent();
|
||||
}
|
||||
if (node->getCanReplaceContent()) {
|
||||
if (node && node->getCanReplaceContent()) {
|
||||
// Convert message data into our URL
|
||||
QString url(message->getMessage());
|
||||
QUrl modelsURL = QUrl(url, QUrl::StrictMode);
|
||||
|
@ -3448,7 +3452,12 @@ void DomainServer::handleOctreeFileReplacementFromURLRequest(QSharedPointer<Rece
|
|||
connect(reply, &QNetworkReply::finished, [this, reply, modelsURL]() {
|
||||
QNetworkReply::NetworkError networkError = reply->error();
|
||||
if (networkError == QNetworkReply::NoError) {
|
||||
handleOctreeFileReplacement(reply->readAll());
|
||||
if (modelsURL.fileName().endsWith(".json.gz")) {
|
||||
handleOctreeFileReplacement(reply->readAll());
|
||||
} else if (modelsURL.fileName().endsWith(".zip")) {
|
||||
auto deferred = makePromise("recoverFromUploadedBackup");
|
||||
_contentManager->recoverFromUploadedBackup(deferred, reply->readAll());
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Error downloading JSON from specified file: " << modelsURL;
|
||||
}
|
||||
|
@ -3456,12 +3465,9 @@ void DomainServer::handleOctreeFileReplacementFromURLRequest(QSharedPointer<Rece
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void DomainServer::handleOctreeFileReplacementRequest(QSharedPointer<ReceivedMessage> message) {
|
||||
auto node = DependencyManager::get<NodeList>()->nodeWithUUID(message->getSourceID());
|
||||
if (node->getCanReplaceContent()) {
|
||||
handleOctreeFileReplacement(message->readAll());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -91,7 +91,7 @@ private slots:
|
|||
void processICEServerHeartbeatDenialPacket(QSharedPointer<ReceivedMessage> message);
|
||||
void processICEServerHeartbeatACK(QSharedPointer<ReceivedMessage> message);
|
||||
|
||||
void handleOctreeFileReplacementFromURLRequest(QSharedPointer<ReceivedMessage> message);
|
||||
void handleDomainContentReplacementFromURLRequest(QSharedPointer<ReceivedMessage> message);
|
||||
void handleOctreeFileReplacementRequest(QSharedPointer<ReceivedMessage> message);
|
||||
void handleOctreeFileReplacement(QByteArray octreeFile);
|
||||
|
||||
|
|
|
@ -26,17 +26,17 @@ generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources
|
|||
if (ANDROID)
|
||||
# on Android, don't compress the rcc binary
|
||||
add_custom_command(
|
||||
OUTPUT ${RESOURCES_RCC}
|
||||
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
|
||||
COMMAND "${QT_DIR}/bin/rcc"
|
||||
ARGS ${RESOURCES_QRC} -no-compress -binary -o ${RESOURCES_RCC}
|
||||
OUTPUT ${RESOURCES_RCC}
|
||||
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
|
||||
COMMAND "${QT_DIR}/bin/rcc"
|
||||
ARGS ${RESOURCES_QRC} -no-compress -binary -o ${RESOURCES_RCC}
|
||||
)
|
||||
else ()
|
||||
add_custom_command(
|
||||
OUTPUT ${RESOURCES_RCC}
|
||||
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
|
||||
COMMAND "${QT_DIR}/bin/rcc"
|
||||
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC}
|
||||
OUTPUT ${RESOURCES_RCC}
|
||||
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
|
||||
COMMAND "${QT_DIR}/bin/rcc"
|
||||
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -191,7 +191,11 @@ add_dependencies(${TARGET_NAME} resources)
|
|||
if (WIN32)
|
||||
# These are external plugins, but we need to do the 'add dependency' here so that their
|
||||
# binary directories get added to the fixup path
|
||||
add_dependency_external_projects(sixense)
|
||||
|
||||
if (USE_SIXENSE)
|
||||
add_dependency_external_projects(sixense)
|
||||
endif ()
|
||||
|
||||
add_dependency_external_projects(sdl2)
|
||||
add_dependency_external_projects(OpenVR)
|
||||
add_dependency_external_projects(neuron)
|
||||
|
@ -199,12 +203,6 @@ if (WIN32)
|
|||
add_dependency_external_projects(steamworks)
|
||||
endif()
|
||||
|
||||
# include OPENSSL
|
||||
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
||||
|
||||
# append OpenSSL to our list of libraries to link
|
||||
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})
|
||||
|
||||
# disable /OPT:REF and /OPT:ICF for the Debug builds
|
||||
# This will prevent the following linker warnings
|
||||
# LINK : warning LNK4075: ignoring '/INCREMENTAL' due to '/OPT:ICF' specification
|
||||
|
@ -228,6 +226,9 @@ link_hifi_libraries(
|
|||
# include the binary directory of render-utils for shader includes
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils")
|
||||
|
||||
# include OpenSSL
|
||||
target_openssl()
|
||||
|
||||
target_bullet()
|
||||
target_opengl()
|
||||
add_crashpad()
|
||||
|
@ -328,13 +329,13 @@ if (APPLE)
|
|||
else()
|
||||
# copy the resources files beside the executable
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${RESOURCES_RCC}"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${RESOURCES_RCC}"
|
||||
"$<TARGET_FILE_DIR:interface>"
|
||||
# FIXME, the edit script code loads HTML from the scripts folder
|
||||
# which in turn relies on CSS that refers to the fonts. In theory
|
||||
# we should be able to modify the CSS to reference the QRC path to
|
||||
# the ttf files, but doing so generates a CORS policy violation,
|
||||
# we should be able to modify the CSS to reference the QRC path to
|
||||
# the ttf files, but doing so generates a CORS policy violation,
|
||||
# so we have to retain a copy of the fonts outside of the resources binary
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/resources/fonts"
|
||||
|
@ -389,3 +390,6 @@ endif()
|
|||
add_dependency_external_projects(GifCreator)
|
||||
find_package(GifCreator REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GIFCREATOR_INCLUDE_DIRS})
|
||||
|
||||
# tell CMake to exclude ui_console.h for policy CMP0071
|
||||
set_property(SOURCE ui_console.h PROPERTY SKIP_AUTOMOC ON)
|
||||
|
|
|
@ -351,6 +351,7 @@ static const QString OBJ_EXTENSION = ".obj";
|
|||
static const QString AVA_JSON_EXTENSION = ".ava.json";
|
||||
static const QString WEB_VIEW_TAG = "noDownload=true";
|
||||
static const QString ZIP_EXTENSION = ".zip";
|
||||
static const QString CONTENT_ZIP_EXTENSION = ".content.zip";
|
||||
|
||||
static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f;
|
||||
|
||||
|
@ -378,7 +379,7 @@ static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
|
|||
|
||||
static const QString DOMAIN_SPAWNING_POINT = "/0, -10, 0";
|
||||
|
||||
const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {
|
||||
const std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions {
|
||||
{ SVO_EXTENSION, &Application::importSVOFromURL },
|
||||
{ SVO_JSON_EXTENSION, &Application::importSVOFromURL },
|
||||
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl },
|
||||
|
@ -386,6 +387,7 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi
|
|||
{ JS_EXTENSION, &Application::askToLoadScript },
|
||||
{ FST_EXTENSION, &Application::askToSetAvatarUrl },
|
||||
{ JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent },
|
||||
{ CONTENT_ZIP_EXTENSION, &Application::askToReplaceDomainContent },
|
||||
{ ZIP_EXTENSION, &Application::importFromZIP },
|
||||
{ JPG_EXTENSION, &Application::importImage },
|
||||
{ PNG_EXTENSION, &Application::importImage }
|
||||
|
@ -2704,6 +2706,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
|
||||
surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
|
||||
|
||||
surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
|
||||
surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
|
||||
surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
|
||||
|
@ -6173,11 +6176,9 @@ bool Application::canAcceptURL(const QString& urlString) const {
|
|||
} else if (urlString.startsWith(HIFI_URL_SCHEME)) {
|
||||
return true;
|
||||
}
|
||||
QHashIterator<QString, AcceptURLMethod> i(_acceptedExtensions);
|
||||
QString lowerPath = url.path().toLower();
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (lowerPath.endsWith(i.key(), Qt::CaseInsensitive)) {
|
||||
for (auto& pair : _acceptedExtensions) {
|
||||
if (lowerPath.endsWith(pair.first, Qt::CaseInsensitive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -6194,12 +6195,10 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
|
|||
}
|
||||
|
||||
QUrl url(urlString);
|
||||
QHashIterator<QString, AcceptURLMethod> i(_acceptedExtensions);
|
||||
QString lowerPath = url.path().toLower();
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (lowerPath.endsWith(i.key(), Qt::CaseInsensitive)) {
|
||||
AcceptURLMethod method = i.value();
|
||||
for (auto& pair : _acceptedExtensions) {
|
||||
if (lowerPath.endsWith(pair.first, Qt::CaseInsensitive)) {
|
||||
AcceptURLMethod method = pair.second;
|
||||
return (this->*method)(urlString);
|
||||
}
|
||||
}
|
||||
|
@ -6386,13 +6385,11 @@ void Application::replaceDomainContent(const QString& url) {
|
|||
QByteArray urlData(url.toUtf8());
|
||||
auto limitedNodeList = DependencyManager::get<NodeList>();
|
||||
const auto& domainHandler = limitedNodeList->getDomainHandler();
|
||||
limitedNodeList->eachMatchingNode([](const SharedNodePointer& node) {
|
||||
return node->getType() == NodeType::EntityServer && node->getActiveSocket();
|
||||
}, [&urlData, limitedNodeList, &domainHandler](const SharedNodePointer& octreeNode) {
|
||||
auto octreeFilePacket = NLPacket::create(PacketType::OctreeFileReplacementFromUrl, urlData.size(), true);
|
||||
octreeFilePacket->write(urlData);
|
||||
limitedNodeList->sendPacket(std::move(octreeFilePacket), domainHandler.getSockAddr());
|
||||
});
|
||||
|
||||
auto octreeFilePacket = NLPacket::create(PacketType::DomainContentReplacementFromUrl, urlData.size(), true);
|
||||
octreeFilePacket->write(urlData);
|
||||
limitedNodeList->sendPacket(std::move(octreeFilePacket), domainHandler.getSockAddr());
|
||||
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
addressManager->handleLookupString(DOMAIN_SPAWNING_POINT);
|
||||
QString newHomeAddress = addressManager->getHost() + DOMAIN_SPAWNING_POINT;
|
||||
|
@ -7350,10 +7347,35 @@ bool Application::isThrottleRendering() const {
|
|||
}
|
||||
|
||||
bool Application::hasFocus() const {
|
||||
if (_displayPlugin) {
|
||||
return getActiveDisplayPlugin()->hasFocus();
|
||||
bool result = (QApplication::activeWindow() != nullptr);
|
||||
#if defined(Q_OS_WIN)
|
||||
// On Windows, QWidget::activateWindow() - as called in setFocus() - makes the application's taskbar icon flash but doesn't
|
||||
// take user focus away from their current window. So also check whether the application is the user's current foreground
|
||||
// window.
|
||||
result = result && (HWND)QApplication::activeWindow()->winId() == GetForegroundWindow();
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
void Application::setFocus() {
|
||||
// Note: Windows doesn't allow a user focus to be taken away from another application. Instead, it changes the color of and
|
||||
// flashes the taskbar icon.
|
||||
auto window = qApp->getWindow();
|
||||
window->activateWindow();
|
||||
}
|
||||
|
||||
void Application::raise() {
|
||||
auto windowState = qApp->getWindow()->windowState();
|
||||
if (windowState & Qt::WindowMinimized) {
|
||||
if (windowState & Qt::WindowMaximized) {
|
||||
qApp->getWindow()->showMaximized();
|
||||
} else if (windowState & Qt::WindowFullScreen) {
|
||||
qApp->getWindow()->showFullScreen();
|
||||
} else {
|
||||
qApp->getWindow()->showNormal();
|
||||
}
|
||||
}
|
||||
return (QApplication::activeWindow() != nullptr);
|
||||
qApp->getWindow()->raise();
|
||||
}
|
||||
|
||||
void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) {
|
||||
|
|
|
@ -161,6 +161,8 @@ public:
|
|||
QRect getRecommendedHUDRect() const;
|
||||
glm::vec2 getDeviceSize() const;
|
||||
bool hasFocus() const;
|
||||
void setFocus();
|
||||
void raise();
|
||||
|
||||
void showCursor(const Cursor::Icon& cursor);
|
||||
|
||||
|
@ -603,7 +605,7 @@ private:
|
|||
GLCanvas* _glWidget{ nullptr };
|
||||
|
||||
typedef bool (Application::* AcceptURLMethod)(const QString &);
|
||||
static const QHash<QString, AcceptURLMethod> _acceptedExtensions;
|
||||
static const std::vector<std::pair<QString, Application::AcceptURLMethod>> _acceptedExtensions;
|
||||
|
||||
glm::uvec2 _renderResolution;
|
||||
|
||||
|
|
|
@ -74,16 +74,14 @@ QScriptValue WindowScriptingInterface::hasFocus() {
|
|||
void WindowScriptingInterface::setFocus() {
|
||||
// It's forbidden to call focus() from another thread.
|
||||
qApp->postLambdaEvent([] {
|
||||
auto window = qApp->getWindow();
|
||||
window->activateWindow();
|
||||
window->setFocus();
|
||||
qApp->setFocus();
|
||||
});
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::raiseMainWindow() {
|
||||
// It's forbidden to call raise() from another thread.
|
||||
qApp->postLambdaEvent([] {
|
||||
qApp->getWindow()->raise();
|
||||
qApp->raise();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -62,13 +62,14 @@ public slots:
|
|||
QScriptValue hasFocus();
|
||||
|
||||
/**jsdoc
|
||||
* Make the Interface window have focus.
|
||||
* Make the Interface window have focus. On Windows, if Interface doesn't already have focus, the task bar icon flashes to
|
||||
* indicate that Interface wants attention but focus isn't taken away from the application that the user is using.
|
||||
* @function Window.setFocus
|
||||
*/
|
||||
void setFocus();
|
||||
|
||||
/**jsdoc
|
||||
* Raise the Interface window if it is minimized, and give it focus.
|
||||
* Raise the Interface window if it is minimized. If raised, the window gains focus.
|
||||
* @function Window.raiseMainWindow
|
||||
*/
|
||||
void raiseMainWindow();
|
||||
|
|
|
@ -63,6 +63,19 @@ static const float OPAQUE_ALPHA_THRESHOLD = 0.99f;
|
|||
|
||||
const QString Web3DOverlay::TYPE = "web3d";
|
||||
const QString Web3DOverlay::QML = "Web3DOverlay.qml";
|
||||
|
||||
static auto qmlSurfaceDeleter = [](OffscreenQmlSurface* surface) {
|
||||
AbstractViewStateInterface::instance()->postLambdaEvent([surface] {
|
||||
if (AbstractViewStateInterface::instance()->isAboutToQuit()) {
|
||||
// WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown
|
||||
// if the application has already stopped its event loop, delete must be explicit
|
||||
delete surface;
|
||||
} else {
|
||||
surface->deleteLater();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Web3DOverlay::Web3DOverlay() {
|
||||
_touchDevice.setCapabilities(QTouchDevice::Position);
|
||||
_touchDevice.setType(QTouchDevice::TouchScreen);
|
||||
|
@ -75,7 +88,8 @@ Web3DOverlay::Web3DOverlay() {
|
|||
connect(this, &Web3DOverlay::resizeWebSurface, this, &Web3DOverlay::onResizeWebSurface);
|
||||
|
||||
//need to be intialized before Tablet 1st open
|
||||
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url);
|
||||
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML);
|
||||
_cachedWebSurface = true;
|
||||
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||
|
@ -114,6 +128,7 @@ void Web3DOverlay::destroyWebSurface() {
|
|||
if (!_webSurface) {
|
||||
return;
|
||||
}
|
||||
|
||||
QQuickItem* rootItem = _webSurface->getRootItem();
|
||||
|
||||
if (rootItem && rootItem->objectName() == "tabletRoot") {
|
||||
|
@ -135,10 +150,15 @@ void Web3DOverlay::destroyWebSurface() {
|
|||
|
||||
QObject::disconnect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
|
||||
QObject::disconnect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
|
||||
auto offscreenCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
|
||||
// FIXME prevents crash on shutdown, but we shoudln't have to do this check
|
||||
if (offscreenCache) {
|
||||
offscreenCache->release(QML, _webSurface);
|
||||
|
||||
// If the web surface was fetched out of the cache, release it back into the cache
|
||||
if (_cachedWebSurface) {
|
||||
auto offscreenCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
|
||||
// FIXME prevents crash on shutdown, but we shoudln't have to do this check
|
||||
if (offscreenCache) {
|
||||
offscreenCache->release(QML, _webSurface);
|
||||
}
|
||||
_cachedWebSurface = false;
|
||||
}
|
||||
_webSurface.reset();
|
||||
}
|
||||
|
@ -147,6 +167,8 @@ void Web3DOverlay::buildWebSurface() {
|
|||
if (_webSurface) {
|
||||
return;
|
||||
}
|
||||
// FIXME the context save here is most likely unecessary since the QML surfaces now render
|
||||
// off the main thread, and all GL context work is done off the main thread (I *think*)
|
||||
gl::withSavedContext([&] {
|
||||
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
|
||||
// and the current rendering load)
|
||||
|
@ -156,10 +178,13 @@ void Web3DOverlay::buildWebSurface() {
|
|||
|
||||
if (isWebContent()) {
|
||||
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML);
|
||||
_cachedWebSurface = true;
|
||||
_webSurface->getRootItem()->setProperty("url", _url);
|
||||
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
|
||||
} else {
|
||||
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url);
|
||||
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), qmlSurfaceDeleter);
|
||||
_webSurface->load(_url);
|
||||
_cachedWebSurface = false;
|
||||
setupQmlSurface();
|
||||
}
|
||||
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition()));
|
||||
|
|
|
@ -88,6 +88,7 @@ private:
|
|||
|
||||
InputMode _inputMode { Touch };
|
||||
QSharedPointer<OffscreenQmlSurface> _webSurface;
|
||||
bool _cachedWebSurface{ false };
|
||||
gpu::TexturePointer _texture;
|
||||
QString _url;
|
||||
QString _scriptURL;
|
||||
|
|
|
@ -21,10 +21,6 @@ glm::uvec2 NullDisplayPlugin::getRecommendedRenderSize() const {
|
|||
return glm::uvec2(100, 100);
|
||||
}
|
||||
|
||||
bool NullDisplayPlugin::hasFocus() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void NullDisplayPlugin::submitFrame(const gpu::FramePointer& frame) {
|
||||
if (frame) {
|
||||
_gpuContext->consumeFrameUpdates(frame);
|
||||
|
|
|
@ -16,7 +16,6 @@ public:
|
|||
grouping getGrouping() const override { return DEVELOPER; }
|
||||
|
||||
glm::uvec2 getRecommendedRenderSize() const override;
|
||||
bool hasFocus() const override;
|
||||
void submitFrame(const gpu::FramePointer& newFrame) override;
|
||||
QImage getScreenshot(float aspectRatio = 0.0f) const override;
|
||||
QImage getSecondaryCameraScreenshot() const override;
|
||||
|
|
|
@ -831,11 +831,6 @@ glm::uvec2 OpenGLDisplayPlugin::getSurfaceSize() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool OpenGLDisplayPlugin::hasFocus() const {
|
||||
auto window = _container->getPrimaryWidget();
|
||||
return window ? window->hasFocus() : false;
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::assertNotPresentThread() const {
|
||||
Q_ASSERT(QThread::currentThread() != _presentThread);
|
||||
}
|
||||
|
|
|
@ -98,8 +98,6 @@ protected:
|
|||
virtual void compositePointer();
|
||||
virtual void compositeExtra() {};
|
||||
|
||||
virtual bool hasFocus() const override;
|
||||
|
||||
// These functions must only be called on the presentation thread
|
||||
virtual void customizeContext();
|
||||
virtual void uncustomizeContext();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "RenderableMaterialEntityItem.h"
|
||||
|
||||
#include "RenderPipelines.h"
|
||||
#include "GeometryCache.h"
|
||||
|
||||
using namespace render;
|
||||
using namespace render::entities;
|
||||
|
@ -90,138 +91,6 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
glm::vec3 MaterialEntityRenderer::getVertexPos(float phi, float theta) {
|
||||
return glm::vec3(glm::sin(theta) * glm::cos(phi), glm::cos(theta), glm::sin(theta) * glm::sin(phi));
|
||||
}
|
||||
|
||||
glm::vec3 MaterialEntityRenderer::getTangent(float phi, float theta) {
|
||||
return glm::vec3(-glm::cos(theta) * glm::cos(phi), glm::sin(theta), -glm::cos(theta) * glm::sin(phi));
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv) {
|
||||
buffer.push_back(pos.x); buffer.push_back(pos.y); buffer.push_back(pos.z);
|
||||
buffer.push_back(tan.x); buffer.push_back(tan.y); buffer.push_back(tan.z);
|
||||
buffer.push_back(uv.x); buffer.push_back(uv.y);
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::addTriangleFan(std::vector<float>& buffer, int stack, int step) {
|
||||
float v1 = ((float)stack) / STACKS;
|
||||
float theta1 = v1 * (float)M_PI;
|
||||
glm::vec3 tip = getVertexPos(0, theta1);
|
||||
float v2 = ((float)(stack + step)) / STACKS;
|
||||
float theta2 = v2 * (float)M_PI;
|
||||
for (int i = 0; i < SLICES; i++) {
|
||||
float u1 = ((float)i) / SLICES;
|
||||
float u2 = ((float)(i + step)) / SLICES;
|
||||
float phi1 = u1 * M_PI_TIMES_2;
|
||||
float phi2 = u2 * M_PI_TIMES_2;
|
||||
/* (flipped for negative step)
|
||||
p1
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
p3 ------ p2
|
||||
*/
|
||||
|
||||
glm::vec3 pos2 = getVertexPos(phi2, theta2);
|
||||
glm::vec3 pos3 = getVertexPos(phi1, theta2);
|
||||
|
||||
glm::vec3 tan1 = getTangent(0, theta1);
|
||||
glm::vec3 tan2 = getTangent(phi2, theta2);
|
||||
glm::vec3 tan3 = getTangent(phi1, theta2);
|
||||
|
||||
glm::vec2 uv1 = glm::vec2((u1 + u2) / 2.0f, v1);
|
||||
glm::vec2 uv2 = glm::vec2(u2, v2);
|
||||
glm::vec2 uv3 = glm::vec2(u1, v2);
|
||||
|
||||
addVertex(buffer, tip, tan1, uv1);
|
||||
addVertex(buffer, pos2, tan2, uv2);
|
||||
addVertex(buffer, pos3, tan3, uv3);
|
||||
|
||||
_numVertices += 3;
|
||||
}
|
||||
}
|
||||
|
||||
int MaterialEntityRenderer::_numVertices = 0;
|
||||
std::shared_ptr<gpu::Stream::Format> MaterialEntityRenderer::_streamFormat = nullptr;
|
||||
std::shared_ptr<gpu::BufferStream> MaterialEntityRenderer::_stream = nullptr;
|
||||
std::shared_ptr<gpu::Buffer> MaterialEntityRenderer::_verticesBuffer = nullptr;
|
||||
|
||||
void MaterialEntityRenderer::generateMesh() {
|
||||
_streamFormat = std::make_shared<gpu::Stream::Format>();
|
||||
_stream = std::make_shared<gpu::BufferStream>();
|
||||
_verticesBuffer = std::make_shared<gpu::Buffer>();
|
||||
|
||||
const int NUM_POS_COORDS = 3;
|
||||
const int NUM_TANGENT_COORDS = 3;
|
||||
const int VERTEX_TANGENT_OFFSET = NUM_POS_COORDS * sizeof(float);
|
||||
const int VERTEX_TEXCOORD_OFFSET = VERTEX_TANGENT_OFFSET + NUM_TANGENT_COORDS * sizeof(float);
|
||||
|
||||
_streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
_streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
_streamFormat->setAttribute(gpu::Stream::TANGENT, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_TANGENT_OFFSET);
|
||||
_streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET);
|
||||
|
||||
_stream->addBuffer(_verticesBuffer, 0, _streamFormat->getChannels().at(0)._stride);
|
||||
|
||||
std::vector<float> vertexBuffer;
|
||||
|
||||
// Top
|
||||
addTriangleFan(vertexBuffer, 0, 1);
|
||||
|
||||
// Middle section
|
||||
for (int j = 1; j < STACKS - 1; j++) {
|
||||
float v1 = ((float)j) / STACKS;
|
||||
float v2 = ((float)(j + 1)) / STACKS;
|
||||
float theta1 = v1 * (float)M_PI;
|
||||
float theta2 = v2 * (float)M_PI;
|
||||
for (int i = 0; i < SLICES; i++) {
|
||||
float u1 = ((float)i) / SLICES;
|
||||
float u2 = ((float)(i + 1)) / SLICES;
|
||||
float phi1 = u1 * M_PI_TIMES_2;
|
||||
float phi2 = u2 * M_PI_TIMES_2;
|
||||
|
||||
/*
|
||||
p2 ---- p3
|
||||
| / |
|
||||
| / |
|
||||
| / |
|
||||
p1 ---- p4
|
||||
*/
|
||||
|
||||
glm::vec3 pos1 = getVertexPos(phi1, theta2);
|
||||
glm::vec3 pos2 = getVertexPos(phi1, theta1);
|
||||
glm::vec3 pos3 = getVertexPos(phi2, theta1);
|
||||
glm::vec3 pos4 = getVertexPos(phi2, theta2);
|
||||
|
||||
glm::vec3 tan1 = getTangent(phi1, theta2);
|
||||
glm::vec3 tan2 = getTangent(phi1, theta1);
|
||||
glm::vec3 tan3 = getTangent(phi2, theta1);
|
||||
glm::vec3 tan4 = getTangent(phi2, theta2);
|
||||
|
||||
glm::vec2 uv1 = glm::vec2(u1, v2);
|
||||
glm::vec2 uv2 = glm::vec2(u1, v1);
|
||||
glm::vec2 uv3 = glm::vec2(u2, v1);
|
||||
glm::vec2 uv4 = glm::vec2(u2, v2);
|
||||
|
||||
addVertex(vertexBuffer, pos1, tan1, uv1);
|
||||
addVertex(vertexBuffer, pos2, tan2, uv2);
|
||||
addVertex(vertexBuffer, pos3, tan3, uv3);
|
||||
|
||||
addVertex(vertexBuffer, pos3, tan3, uv3);
|
||||
addVertex(vertexBuffer, pos4, tan4, uv4);
|
||||
addVertex(vertexBuffer, pos1, tan1, uv1);
|
||||
|
||||
_numVertices += 6;
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom
|
||||
addTriangleFan(vertexBuffer, STACKS, -1);
|
||||
|
||||
_verticesBuffer->append(vertexBuffer.size() * sizeof(float), (gpu::Byte*) vertexBuffer.data());
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
|
||||
Q_ASSERT(args->_batch);
|
||||
|
@ -252,14 +121,7 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
args->_details._materialSwitches++;
|
||||
|
||||
// Draw!
|
||||
if (_numVertices == 0) {
|
||||
generateMesh();
|
||||
}
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(batch);
|
||||
|
||||
batch.setInputFormat(_streamFormat);
|
||||
batch.setInputStream(0, *_stream);
|
||||
batch.draw(gpu::TRIANGLES, _numVertices, 0);
|
||||
|
||||
const int NUM_VERTICES_PER_TRIANGLE = 3;
|
||||
args->_details._trianglesRendered += _numVertices / NUM_VERTICES_PER_TRIANGLE;
|
||||
args->_details._trianglesRendered += (int)DependencyManager::get<GeometryCache>()->getSphereTriangleCount();
|
||||
}
|
||||
|
|
|
@ -40,20 +40,6 @@ private:
|
|||
Transform _renderTransform;
|
||||
|
||||
std::shared_ptr<NetworkMaterial> _drawMaterial;
|
||||
|
||||
static int _numVertices;
|
||||
static std::shared_ptr<gpu::Stream::Format> _streamFormat;
|
||||
static std::shared_ptr<gpu::BufferStream> _stream;
|
||||
static std::shared_ptr<gpu::Buffer> _verticesBuffer;
|
||||
|
||||
void generateMesh();
|
||||
void addTriangleFan(std::vector<float>& buffer, int stack, int step);
|
||||
static glm::vec3 getVertexPos(float phi, float theta);
|
||||
static glm::vec3 getTangent(float phi, float theta);
|
||||
static void addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv);
|
||||
const int SLICES = 15;
|
||||
const int STACKS = 9;
|
||||
const float M_PI_TIMES_2 = 2.0f * (float)M_PI;
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "render-utils/simple_vert.h"
|
||||
#include "render-utils/simple_frag.h"
|
||||
|
||||
#include "RenderPipelines.h"
|
||||
|
||||
//#define SHAPE_ENTITY_USE_FADE_EFFECT
|
||||
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT
|
||||
#include <FadeEffect.h>
|
||||
|
@ -108,11 +110,94 @@ bool ShapeEntityRenderer::isTransparent() const {
|
|||
if (_procedural.isEnabled() && _procedural.isFading()) {
|
||||
return Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) < 1.0f;
|
||||
}
|
||||
|
||||
// return _entity->getLocalRenderAlpha() < 1.0f || Parent::isTransparent();
|
||||
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end()) {
|
||||
if (mat->second.top().material) {
|
||||
auto matKey = mat->second.top().material->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Parent::isTransparent();
|
||||
}
|
||||
|
||||
ItemKey ShapeEntityRenderer::getKey() {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
|
||||
withReadLock([&] {
|
||||
if (isTransparent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
});
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
bool ShapeEntityRenderer::useMaterialPipeline() const {
|
||||
bool proceduralReady = resultWithReadLock<bool>([&] {
|
||||
return _procedural.isReady();
|
||||
});
|
||||
if (proceduralReady) {
|
||||
return false;
|
||||
}
|
||||
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end() && mat->second.top().material) {
|
||||
drawMaterialKey = mat->second.top().material->getKey();
|
||||
}
|
||||
|
||||
if (drawMaterialKey.isEmissive() || drawMaterialKey.isUnlit() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the material is using any map, we need to use a material ShapeKey
|
||||
for (int i = 0; i < graphics::Material::MapChannel::NUM_MAP_CHANNELS; i++) {
|
||||
if (drawMaterialKey.isMapChannel(graphics::Material::MapChannel(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ShapeKey ShapeEntityRenderer::getShapeKey() {
|
||||
if (useMaterialPipeline()) {
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
if (_materials["0"].top().material) {
|
||||
drawMaterialKey = _materials["0"].top().material->getKey();
|
||||
}
|
||||
|
||||
bool isTranslucent = drawMaterialKey.isTranslucent();
|
||||
bool hasTangents = drawMaterialKey.isNormalMap();
|
||||
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
||||
bool isUnlit = drawMaterialKey.isUnlit();
|
||||
|
||||
ShapeKey::Builder builder;
|
||||
builder.withMaterial();
|
||||
|
||||
if (isTranslucent) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
if (hasTangents) {
|
||||
builder.withTangents();
|
||||
}
|
||||
if (hasLightmap) {
|
||||
builder.withLightmap();
|
||||
}
|
||||
if (isUnlit) {
|
||||
builder.withUnlit();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
} else {
|
||||
return Parent::getShapeKey();
|
||||
}
|
||||
}
|
||||
|
||||
void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
|
||||
Q_ASSERT(args->_batch);
|
||||
|
@ -149,7 +234,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
} else {
|
||||
geometryCache->renderShape(batch, geometryShape, outColor);
|
||||
}
|
||||
} else {
|
||||
} else if (!useMaterialPipeline()) {
|
||||
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
||||
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
|
||||
|
@ -158,6 +243,11 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
} else {
|
||||
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
||||
}
|
||||
} else {
|
||||
RenderPipelines::bindMaterial(mat, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
|
||||
geometryCache->renderShape(batch, geometryShape);
|
||||
}
|
||||
|
||||
const auto triCount = geometryCache->getShapeTriangleCount(geometryShape);
|
||||
|
|
|
@ -24,6 +24,10 @@ public:
|
|||
|
||||
virtual scriptable::ScriptableModelBase getScriptableModel() override;
|
||||
|
||||
protected:
|
||||
ItemKey getKey() override;
|
||||
ShapeKey getShapeKey() override;
|
||||
|
||||
private:
|
||||
virtual bool needsRenderUpdate() const override;
|
||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
||||
|
@ -32,6 +36,8 @@ private:
|
|||
virtual void doRender(RenderArgs* args) override;
|
||||
virtual bool isTransparent() const override;
|
||||
|
||||
bool useMaterialPipeline() const;
|
||||
|
||||
Procedural _procedural;
|
||||
QString _lastUserData;
|
||||
Transform _renderTransform;
|
||||
|
|
|
@ -239,7 +239,7 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
|
|||
}
|
||||
|
||||
bool WebEntityRenderer::hasWebSurface() {
|
||||
return (bool)_webSurface;
|
||||
return (bool)_webSurface && _webSurface->getRootItem();
|
||||
}
|
||||
|
||||
bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
|
||||
|
@ -303,7 +303,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
|
|||
_fadeStartTime = usecTimestampNow();
|
||||
_webSurface->resume();
|
||||
|
||||
return true;
|
||||
return _webSurface->getRootItem();
|
||||
}
|
||||
|
||||
void WebEntityRenderer::destroyWebSurface() {
|
||||
|
|
|
@ -157,7 +157,7 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u
|
|||
}
|
||||
|
||||
if (usingUserData) {
|
||||
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getUserData().toUtf8()));
|
||||
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getUserData().toUtf8()), materialURLString);
|
||||
|
||||
// Since our material changed, the current name might not be valid anymore, so we need to update
|
||||
setCurrentMaterialName(_currentMaterialName);
|
||||
|
|
|
@ -20,7 +20,7 @@ void NetworkMaterialResource::downloadFinished(const QByteArray& data) {
|
|||
parsedMaterials.reset();
|
||||
|
||||
if (_url.toString().contains(".json")) {
|
||||
parsedMaterials = parseJSONMaterials(QJsonDocument::fromJson(data));
|
||||
parsedMaterials = parseJSONMaterials(QJsonDocument::fromJson(data), _url);
|
||||
}
|
||||
|
||||
// TODO: parse other material types
|
||||
|
@ -75,7 +75,7 @@ bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3&
|
|||
* @property {number} materialVersion=1 - The version of the material. <em>Currently not used.</em>
|
||||
* @property {Material|Material[]} materials - The details of the material or materials.
|
||||
*/
|
||||
NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMaterials(const QJsonDocument& materialJSON) {
|
||||
NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMaterials(const QJsonDocument& materialJSON, const QUrl& baseUrl) {
|
||||
ParsedMaterials toReturn;
|
||||
if (!materialJSON.isNull() && materialJSON.isObject()) {
|
||||
QJsonObject materialJSONObject = materialJSON.object();
|
||||
|
@ -91,13 +91,13 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater
|
|||
QJsonArray materials = materialsValue.toArray();
|
||||
for (auto material : materials) {
|
||||
if (!material.isNull() && material.isObject()) {
|
||||
auto parsedMaterial = parseJSONMaterial(material.toObject());
|
||||
auto parsedMaterial = parseJSONMaterial(material.toObject(), baseUrl);
|
||||
toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second;
|
||||
toReturn.names.push_back(parsedMaterial.first);
|
||||
}
|
||||
}
|
||||
} else if (materialsValue.isObject()) {
|
||||
auto parsedMaterial = parseJSONMaterial(materialsValue.toObject());
|
||||
auto parsedMaterial = parseJSONMaterial(materialsValue.toObject(), baseUrl);
|
||||
toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second;
|
||||
toReturn.names.push_back(parsedMaterial.first);
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater
|
|||
* @property {string} lightMap - URL of light map texture image. <em>Currently not used.</em>
|
||||
*/
|
||||
// Note: See MaterialEntityItem.h for default values used in practice.
|
||||
std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON) {
|
||||
std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl) {
|
||||
std::string name = "";
|
||||
std::shared_ptr<NetworkMaterial> material = std::make_shared<NetworkMaterial>();
|
||||
for (auto& key : materialJSON.keys()) {
|
||||
|
@ -199,57 +199,58 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
|
|||
} else if (key == "albedoMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
QString urlString = value.toString();
|
||||
bool useAlphaChannel = false;
|
||||
auto opacityMap = materialJSON.find("opacityMap");
|
||||
if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == value.toString()) {
|
||||
if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == urlString) {
|
||||
useAlphaChannel = true;
|
||||
}
|
||||
material->setAlbedoMap(value.toString(), useAlphaChannel);
|
||||
material->setAlbedoMap(baseUrl.resolved(urlString), useAlphaChannel);
|
||||
}
|
||||
} else if (key == "roughnessMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setRoughnessMap(value.toString(), false);
|
||||
material->setRoughnessMap(baseUrl.resolved(value.toString()), false);
|
||||
}
|
||||
} else if (key == "glossMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setRoughnessMap(value.toString(), true);
|
||||
material->setRoughnessMap(baseUrl.resolved(value.toString()), true);
|
||||
}
|
||||
} else if (key == "metallicMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setMetallicMap(value.toString(), false);
|
||||
material->setMetallicMap(baseUrl.resolved(value.toString()), false);
|
||||
}
|
||||
} else if (key == "specularMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setMetallicMap(value.toString(), true);
|
||||
material->setMetallicMap(baseUrl.resolved(value.toString()), true);
|
||||
}
|
||||
} else if (key == "normalMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setNormalMap(value.toString(), false);
|
||||
material->setNormalMap(baseUrl.resolved(value.toString()), false);
|
||||
}
|
||||
} else if (key == "bumpMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setNormalMap(value.toString(), true);
|
||||
material->setNormalMap(baseUrl.resolved(value.toString()), true);
|
||||
}
|
||||
} else if (key == "occlusionMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setOcclusionMap(value.toString());
|
||||
material->setOcclusionMap(baseUrl.resolved(value.toString()));
|
||||
}
|
||||
} else if (key == "scatteringMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setScatteringMap(value.toString());
|
||||
material->setScatteringMap(baseUrl.resolved(value.toString()));
|
||||
}
|
||||
} else if (key == "lightMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setLightmapMap(value.toString());
|
||||
material->setLightmapMap(baseUrl.resolved(value.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ public:
|
|||
|
||||
ParsedMaterials parsedMaterials;
|
||||
|
||||
static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON);
|
||||
static std::pair<std::string, std::shared_ptr<NetworkMaterial>> parseJSONMaterial(const QJsonObject& materialJSON);
|
||||
static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON, const QUrl& baseUrl);
|
||||
static std::pair<std::string, std::shared_ptr<NetworkMaterial>> parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl);
|
||||
|
||||
private:
|
||||
static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB);
|
||||
|
|
|
@ -556,58 +556,58 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, im
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void NetworkMaterial::setAlbedoMap(const QString& url, bool useAlphaChannel) {
|
||||
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||
void NetworkMaterial::setAlbedoMap(const QUrl& url, bool useAlphaChannel) {
|
||||
auto map = fetchTextureMap(url, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||
if (map) {
|
||||
map->setUseAlphaChannel(useAlphaChannel);
|
||||
setTextureMap(MapChannel::ALBEDO_MAP, map);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkMaterial::setNormalMap(const QString& url, bool isBumpmap) {
|
||||
auto map = fetchTextureMap(QUrl(url), isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP);
|
||||
void NetworkMaterial::setNormalMap(const QUrl& url, bool isBumpmap) {
|
||||
auto map = fetchTextureMap(url, isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP);
|
||||
if (map) {
|
||||
setTextureMap(MapChannel::NORMAL_MAP, map);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkMaterial::setRoughnessMap(const QString& url, bool isGloss) {
|
||||
auto map = fetchTextureMap(QUrl(url), isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP);
|
||||
void NetworkMaterial::setRoughnessMap(const QUrl& url, bool isGloss) {
|
||||
auto map = fetchTextureMap(url, isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP);
|
||||
if (map) {
|
||||
setTextureMap(MapChannel::ROUGHNESS_MAP, map);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkMaterial::setMetallicMap(const QString& url, bool isSpecular) {
|
||||
auto map = fetchTextureMap(QUrl(url), isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP);
|
||||
void NetworkMaterial::setMetallicMap(const QUrl& url, bool isSpecular) {
|
||||
auto map = fetchTextureMap(url, isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP);
|
||||
if (map) {
|
||||
setTextureMap(MapChannel::METALLIC_MAP, map);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkMaterial::setOcclusionMap(const QString& url) {
|
||||
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
|
||||
void NetworkMaterial::setOcclusionMap(const QUrl& url) {
|
||||
auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
|
||||
if (map) {
|
||||
setTextureMap(MapChannel::OCCLUSION_MAP, map);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkMaterial::setEmissiveMap(const QString& url) {
|
||||
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP);
|
||||
void NetworkMaterial::setEmissiveMap(const QUrl& url) {
|
||||
auto map = fetchTextureMap(url, image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP);
|
||||
if (map) {
|
||||
setTextureMap(MapChannel::EMISSIVE_MAP, map);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkMaterial::setScatteringMap(const QString& url) {
|
||||
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP);
|
||||
void NetworkMaterial::setScatteringMap(const QUrl& url) {
|
||||
auto map = fetchTextureMap(url, image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP);
|
||||
if (map) {
|
||||
setTextureMap(MapChannel::SCATTERING_MAP, map);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkMaterial::setLightmapMap(const QString& url) {
|
||||
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP);
|
||||
void NetworkMaterial::setLightmapMap(const QUrl& url) {
|
||||
auto map = fetchTextureMap(url, image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP);
|
||||
if (map) {
|
||||
//map->setTextureTransform(_lightmapTransform);
|
||||
//map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y);
|
||||
|
|
|
@ -164,14 +164,14 @@ public:
|
|||
NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl);
|
||||
NetworkMaterial(const NetworkMaterial& material);
|
||||
|
||||
void setAlbedoMap(const QString& url, bool useAlphaChannel);
|
||||
void setNormalMap(const QString& url, bool isBumpmap);
|
||||
void setRoughnessMap(const QString& url, bool isGloss);
|
||||
void setMetallicMap(const QString& url, bool isSpecular);
|
||||
void setOcclusionMap(const QString& url);
|
||||
void setEmissiveMap(const QString& url);
|
||||
void setScatteringMap(const QString& url);
|
||||
void setLightmapMap(const QString& url);
|
||||
void setAlbedoMap(const QUrl& url, bool useAlphaChannel);
|
||||
void setNormalMap(const QUrl& url, bool isBumpmap);
|
||||
void setRoughnessMap(const QUrl& url, bool isGloss);
|
||||
void setMetallicMap(const QUrl& url, bool isSpecular);
|
||||
void setOcclusionMap(const QUrl& url);
|
||||
void setEmissiveMap(const QUrl& url);
|
||||
void setScatteringMap(const QUrl& url);
|
||||
void setLightmapMap(const QUrl& url);
|
||||
|
||||
protected:
|
||||
friend class Geometry;
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
ReplicatedAvatarIdentity,
|
||||
ReplicatedKillAvatar,
|
||||
ReplicatedBulkAvatarData,
|
||||
OctreeFileReplacementFromUrl,
|
||||
DomainContentReplacementFromUrl,
|
||||
ChallengeOwnership,
|
||||
EntityScriptCallMethod,
|
||||
ChallengeOwnershipRequest,
|
||||
|
@ -171,7 +171,7 @@ public:
|
|||
<< PacketTypeEnum::Value::DomainServerPathResponse << PacketTypeEnum::Value::DomainServerAddedNode
|
||||
<< PacketTypeEnum::Value::DomainServerConnectionToken << PacketTypeEnum::Value::DomainSettingsRequest
|
||||
<< PacketTypeEnum::Value::OctreeDataFileRequest << PacketTypeEnum::Value::OctreeDataFileReply
|
||||
<< PacketTypeEnum::Value::OctreeDataPersist << PacketTypeEnum::Value::OctreeFileReplacementFromUrl
|
||||
<< PacketTypeEnum::Value::OctreeDataPersist << PacketTypeEnum::Value::DomainContentReplacementFromUrl
|
||||
<< PacketTypeEnum::Value::DomainSettings << PacketTypeEnum::Value::ICEServerPeerInformation
|
||||
<< PacketTypeEnum::Value::ICEServerQuery << PacketTypeEnum::Value::ICEServerHeartbeat
|
||||
<< PacketTypeEnum::Value::ICEServerHeartbeatACK << PacketTypeEnum::Value::ICEPing
|
||||
|
|
|
@ -140,9 +140,6 @@ public:
|
|||
virtual void setContext(const gpu::ContextPointer& context) final { _gpuContext = context; }
|
||||
virtual void submitFrame(const gpu::FramePointer& newFrame) = 0;
|
||||
|
||||
// Does the rendering surface have current focus?
|
||||
virtual bool hasFocus() const = 0;
|
||||
|
||||
// The size of the rendering target (may be larger than the device size due to distortion)
|
||||
virtual glm::uvec2 getRecommendedRenderSize() const = 0;
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ include_hifi_library_headers(audio)
|
|||
include_hifi_library_headers(networking)
|
||||
include_hifi_library_headers(octree)
|
||||
|
||||
# tell CMake to exclude qrc_fonts.cpp for policy CMP0071
|
||||
set_property(SOURCE qrc_fonts.cpp PROPERTY SKIP_AUTOMOC ON)
|
||||
|
||||
if (NOT ANDROID)
|
||||
target_nsight()
|
||||
endif ()
|
||||
|
|
|
@ -100,6 +100,8 @@ static const int VERTICES_PER_TRIANGLE = 3;
|
|||
|
||||
static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
|
||||
static const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
|
||||
static const gpu::Element TEXCOORD0_ELEMENT { gpu::VEC2, gpu::FLOAT, gpu::UV };
|
||||
static const gpu::Element TANGENT_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
|
||||
static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA };
|
||||
static const gpu::Element TEXCOORD4_ELEMENT { gpu::VEC4, gpu::FLOAT, gpu::XYZW };
|
||||
|
||||
|
@ -107,8 +109,10 @@ static gpu::Stream::FormatPointer SOLID_STREAM_FORMAT;
|
|||
static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT;
|
||||
static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT;
|
||||
|
||||
static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals
|
||||
static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);
|
||||
static const uint SHAPE_VERTEX_STRIDE = sizeof(GeometryCache::ShapeVertex); // position, normal, texcoords, tangent
|
||||
static const uint SHAPE_NORMALS_OFFSET = offsetof(GeometryCache::ShapeVertex, normal);
|
||||
static const uint SHAPE_TEXCOORD0_OFFSET = offsetof(GeometryCache::ShapeVertex, uv);
|
||||
static const uint SHAPE_TANGENT_OFFSET = offsetof(GeometryCache::ShapeVertex, tangent);
|
||||
|
||||
void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) {
|
||||
|
||||
|
@ -167,16 +171,20 @@ std::vector<vec3> polygon() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices) {
|
||||
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<ShapeVertex>& vertices) {
|
||||
gpu::Buffer::Size offset = vertexBuffer->getSize();
|
||||
vertexBuffer->append(vertices);
|
||||
|
||||
gpu::Buffer::Size viewSize = vertices.size() * sizeof(glm::vec3);
|
||||
gpu::Buffer::Size viewSize = vertices.size() * sizeof(ShapeVertex);
|
||||
|
||||
_positionView = gpu::BufferView(vertexBuffer, offset,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT);
|
||||
_normalView = gpu::BufferView(vertexBuffer, offset + SHAPE_NORMALS_OFFSET,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, NORMAL_ELEMENT);
|
||||
_texCoordView = gpu::BufferView(vertexBuffer, offset + SHAPE_TEXCOORD0_OFFSET,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, TEXCOORD0_ELEMENT);
|
||||
_tangentView = gpu::BufferView(vertexBuffer, offset + SHAPE_TANGENT_OFFSET,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, TANGENT_ELEMENT);
|
||||
}
|
||||
|
||||
void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices) {
|
||||
|
@ -202,6 +210,8 @@ void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, con
|
|||
void GeometryCache::ShapeData::setupBatch(gpu::Batch& batch) const {
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, _positionView);
|
||||
batch.setInputBuffer(gpu::Stream::NORMAL, _normalView);
|
||||
batch.setInputBuffer(gpu::Stream::TEXCOORD, _texCoordView);
|
||||
batch.setInputBuffer(gpu::Stream::TANGENT, _tangentView);
|
||||
batch.setIndexBuffer(_indicesView);
|
||||
}
|
||||
|
||||
|
@ -268,14 +278,14 @@ static IndexPair indexToken(geometry::Index a, geometry::Index b) {
|
|||
template <size_t N>
|
||||
void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
|
||||
using namespace geometry;
|
||||
VertexVector vertices;
|
||||
std::vector<GeometryCache::ShapeVertex> vertices;
|
||||
IndexVector solidIndices, wireIndices;
|
||||
IndexPairs wireSeenIndices;
|
||||
|
||||
size_t faceCount = shape.faces.size();
|
||||
size_t faceIndexCount = triangulatedFaceIndexCount<N>();
|
||||
|
||||
vertices.reserve(N * faceCount * 2);
|
||||
vertices.reserve(N * faceCount);
|
||||
solidIndices.reserve(faceIndexCount * faceCount);
|
||||
|
||||
Index baseVertex = 0;
|
||||
|
@ -284,11 +294,35 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
|
|||
// Compute the face normal
|
||||
vec3 faceNormal = shape.getFaceNormal(f);
|
||||
|
||||
// Find two points on this face with the same Y tex coords, and find the vector going from the one with the smaller X tex coord to the one with the larger X tex coord
|
||||
vec3 faceTangent = vec3(0.0f);
|
||||
Index i1 = 0;
|
||||
Index i2 = i1 + 1;
|
||||
while (i1 < N) {
|
||||
if (shape.texCoords[f * N + i1].y == shape.texCoords[f * N + i2].y) {
|
||||
break;
|
||||
}
|
||||
if (i2 == N - 1) {
|
||||
i1++;
|
||||
i2 = i1 + 1;
|
||||
} else {
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i1 < N && i2 < N) {
|
||||
vec3 p1 = shape.vertices[face[i1]];
|
||||
vec3 p2 = shape.vertices[face[i2]];
|
||||
faceTangent = glm::normalize(p1 - p2);
|
||||
if (shape.texCoords[f * N + i1].x < shape.texCoords[f * N + i2].x) {
|
||||
faceTangent *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the vertices for the face
|
||||
for (Index i = 0; i < N; i++) {
|
||||
Index originalIndex = face[i];
|
||||
vertices.push_back(shape.vertices[originalIndex]);
|
||||
vertices.push_back(faceNormal);
|
||||
vertices.emplace_back(shape.vertices[originalIndex], faceNormal, shape.texCoords[f * N + i], faceTangent);
|
||||
}
|
||||
|
||||
// Create the wire indices for unseen edges
|
||||
|
@ -316,21 +350,95 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
|
|||
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
|
||||
}
|
||||
|
||||
vec2 calculateSphereTexCoord(const vec3& vertex) {
|
||||
float u = 1.0f - (std::atan2(-vertex.z, -vertex.x) / ((float)M_PI) + 1.0f) * 0.5f;
|
||||
if (vertex.y == 1.0f || vertex.y == -1.0f) {
|
||||
// Remember points at the top so we don't treat them as being along the seam
|
||||
u = NAN;
|
||||
}
|
||||
float v = 0.5f - std::asin(vertex.y) / (float)M_PI;
|
||||
return vec2(u, v);
|
||||
}
|
||||
|
||||
const float M_PI_TIMES_2 = 2.0f * (float)M_PI;
|
||||
|
||||
vec3 calculateSphereTangent(float u) {
|
||||
float phi = u * M_PI_TIMES_2;
|
||||
return -glm::normalize(glm::vec3(glm::sin(phi), 0.0f, glm::cos(phi)));
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
|
||||
using namespace geometry;
|
||||
|
||||
VertexVector vertices;
|
||||
vertices.reserve(shape.vertices.size() * 2);
|
||||
std::vector<GeometryCache::ShapeVertex> vertices;
|
||||
vertices.reserve(shape.vertices.size());
|
||||
for (const auto& vertex : shape.vertices) {
|
||||
vertices.push_back(vertex);
|
||||
vertices.push_back(vertex);
|
||||
// We'll fill in the correct tangents later, once we correct the UVs
|
||||
vertices.emplace_back(vertex, vertex, calculateSphereTexCoord(vertex), vec3(0.0f));
|
||||
}
|
||||
|
||||
// We need to fix up the sphere's UVs because it's actually a tesselated icosahedron. See http://mft-dev.dk/uv-mapping-sphere/
|
||||
size_t faceCount = shape.faces.size();
|
||||
for (size_t f = 0; f < faceCount; f++) {
|
||||
// Fix zipper
|
||||
{
|
||||
float& u1 = vertices[shape.faces[f][0]].uv.x;
|
||||
float& u2 = vertices[shape.faces[f][1]].uv.x;
|
||||
float& u3 = vertices[shape.faces[f][2]].uv.x;
|
||||
|
||||
if (glm::isnan(u1)) {
|
||||
u1 = (u2 + u3) / 2.0f;
|
||||
}
|
||||
if (glm::isnan(u2)) {
|
||||
u2 = (u1 + u3) / 2.0f;
|
||||
}
|
||||
if (glm::isnan(u3)) {
|
||||
u3 = (u1 + u2) / 2.0f;
|
||||
}
|
||||
|
||||
const float U_THRESHOLD = 0.25f;
|
||||
float max = glm::max(u1, glm::max(u2, u3));
|
||||
float min = glm::min(u1, glm::min(u2, u3));
|
||||
|
||||
if (max - min > U_THRESHOLD) {
|
||||
if (u1 < U_THRESHOLD) {
|
||||
u1 += 1.0f;
|
||||
}
|
||||
if (u2 < U_THRESHOLD) {
|
||||
u2 += 1.0f;
|
||||
}
|
||||
if (u3 < U_THRESHOLD) {
|
||||
u3 += 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fix swirling at poles
|
||||
for (Index i = 0; i < N; i++) {
|
||||
Index originalIndex = shape.faces[f][i];
|
||||
if (shape.vertices[originalIndex].y == 1.0f || shape.vertices[originalIndex].y == -1.0f) {
|
||||
float uSum = 0.0f;
|
||||
for (Index i2 = 1; i2 <= N - 1; i2++) {
|
||||
float u = vertices[shape.faces[f][(i + i2) % N]].uv.x;
|
||||
uSum += u;
|
||||
}
|
||||
uSum /= (float)(N - 1);
|
||||
vertices[originalIndex].uv.x = uSum;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in tangents
|
||||
for (Index i = 0; i < N; i++) {
|
||||
vec3 tangent = calculateSphereTangent(vertices[shape.faces[f][i]].uv.x);
|
||||
vertices[shape.faces[f][i]].tangent = tangent;
|
||||
}
|
||||
}
|
||||
|
||||
IndexVector solidIndices, wireIndices;
|
||||
IndexPairs wireSeenIndices;
|
||||
|
||||
size_t faceCount = shape.faces.size();
|
||||
size_t faceIndexCount = triangulatedFaceIndexCount<N>();
|
||||
|
||||
solidIndices.reserve(faceIndexCount * faceCount);
|
||||
|
@ -365,25 +473,22 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
|
|||
template <uint32_t N>
|
||||
void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) {
|
||||
using namespace geometry;
|
||||
VertexVector vertices;
|
||||
std::vector<GeometryCache::ShapeVertex> vertices;
|
||||
IndexVector solidIndices, wireIndices;
|
||||
|
||||
// Top (if not conical) and bottom faces
|
||||
std::vector<vec3> shape = polygon<N>();
|
||||
if (isConical) {
|
||||
for (uint32_t i = 0; i < N; i++) {
|
||||
vertices.push_back(vec3(0.0f, 0.5f, 0.0f));
|
||||
vertices.push_back(vec3(0.0f, 1.0f, 0.0f));
|
||||
vertices.emplace_back(vec3(0.0f, 0.5f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec2((float)i / (float)N, 1.0f), vec3(0.0f));
|
||||
}
|
||||
} else {
|
||||
for (const vec3& v : shape) {
|
||||
vertices.push_back(vec3(v.x, 0.5f, v.z));
|
||||
vertices.push_back(vec3(0.0f, 1.0f, 0.0f));
|
||||
vertices.emplace_back(vec3(v.x, 0.5f, v.z), vec3(0.0f, 1.0f, 0.0f), vec2(v.x, v.z) + vec2(0.5f), vec3(1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
for (const vec3& v : shape) {
|
||||
vertices.push_back(vec3(v.x, -0.5f, v.z));
|
||||
vertices.push_back(vec3(0.0f, -1.0f, 0.0f));
|
||||
vertices.emplace_back(vec3(v.x, -0.5f, v.z), vec3(0.0f, -1.0f, 0.0f), vec2(-v.x, v.z) + vec2(0.5f), vec3(-1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
Index baseVertex = 0;
|
||||
for (uint32_t i = 2; i < N; i++) {
|
||||
|
@ -412,15 +517,16 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
|
|||
vec3 topRight = (isConical ? vec3(0.0f, 0.5f, 0.0f) : vec3(right.x, 0.5f, right.z));
|
||||
vec3 bottomLeft = vec3(left.x, -0.5f, left.z);
|
||||
vec3 bottomRight = vec3(right.x, -0.5f, right.z);
|
||||
vec3 tangent = glm::normalize(bottomLeft - bottomRight);
|
||||
|
||||
vertices.push_back(topLeft);
|
||||
vertices.push_back(normal);
|
||||
vertices.push_back(bottomLeft);
|
||||
vertices.push_back(normal);
|
||||
vertices.push_back(topRight);
|
||||
vertices.push_back(normal);
|
||||
vertices.push_back(bottomRight);
|
||||
vertices.push_back(normal);
|
||||
// Our tex coords go in the opposite direction as our vertices
|
||||
float u = 1.0f - (float)i / (float)N;
|
||||
float u2 = 1.0f - (float)(i + 1) / (float)N;
|
||||
|
||||
vertices.emplace_back(topLeft, normal, vec2(u, 0.0f), tangent);
|
||||
vertices.emplace_back(bottomLeft, normal, vec2(u, 1.0f), tangent);
|
||||
vertices.emplace_back(topRight, normal, vec2(u2, 0.0f), tangent);
|
||||
vertices.emplace_back(bottomRight, normal, vec2(u2, 1.0f), tangent);
|
||||
|
||||
solidIndices.push_back(baseVertex + 0);
|
||||
solidIndices.push_back(baseVertex + 2);
|
||||
|
@ -439,41 +545,6 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
|
|||
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
|
||||
}
|
||||
|
||||
void drawCircle(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
|
||||
// Draw a circle with radius 1/4th the size of the bounding box
|
||||
using namespace geometry;
|
||||
|
||||
VertexVector vertices;
|
||||
IndexVector solidIndices, wireIndices;
|
||||
const int NUM_CIRCLE_VERTICES = 64;
|
||||
|
||||
std::vector<vec3> shape = polygon<NUM_CIRCLE_VERTICES>();
|
||||
for (const vec3& v : shape) {
|
||||
vertices.push_back(vec3(v.x, 0.0f, v.z));
|
||||
vertices.push_back(vec3(0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
Index baseVertex = 0;
|
||||
for (uint32_t i = 2; i < NUM_CIRCLE_VERTICES; i++) {
|
||||
solidIndices.push_back(baseVertex + 0);
|
||||
solidIndices.push_back(baseVertex + i);
|
||||
solidIndices.push_back(baseVertex + i - 1);
|
||||
solidIndices.push_back(baseVertex + NUM_CIRCLE_VERTICES);
|
||||
solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES - 1);
|
||||
solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES);
|
||||
}
|
||||
|
||||
for (uint32_t i = 1; i <= NUM_CIRCLE_VERTICES; i++) {
|
||||
wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES));
|
||||
wireIndices.push_back(baseVertex + i - 1);
|
||||
wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES) + NUM_CIRCLE_VERTICES);
|
||||
wireIndices.push_back(baseVertex + (i - 1) + NUM_CIRCLE_VERTICES);
|
||||
}
|
||||
|
||||
shapeData.setupVertices(vertexBuffer, vertices);
|
||||
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
|
||||
}
|
||||
|
||||
// FIXME solids need per-face vertices, but smooth shaded
|
||||
// components do not. Find a way to support using draw elements
|
||||
// or draw arrays as appropriate
|
||||
|
@ -506,9 +577,9 @@ void GeometryCache::buildShapes() {
|
|||
// Line
|
||||
{
|
||||
ShapeData& shapeData = _shapes[Line];
|
||||
shapeData.setupVertices(_shapeVertices, VertexVector {
|
||||
vec3(-0.5f, 0.0f, 0.0f), vec3(-0.5f, 0.0f, 0.0f),
|
||||
vec3(0.5f, 0.0f, 0.0f), vec3(0.5f, 0.0f, 0.0f)
|
||||
shapeData.setupVertices(_shapeVertices, std::vector<ShapeVertex> {
|
||||
ShapeVertex(vec3(-0.5f, 0.0f, 0.0f), vec3(-0.5f, 0.0f, 0.0f), vec2(0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f)),
|
||||
ShapeVertex(vec3(0.5f, 0.0f, 0.0f), vec3(0.5f, 0.0f, 0.0f), vec2(0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f))
|
||||
});
|
||||
IndexVector wireIndices;
|
||||
// Only two indices
|
||||
|
@ -572,6 +643,8 @@ gpu::Stream::FormatPointer& getSolidStreamFormat() {
|
|||
SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
|
||||
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
|
||||
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
|
||||
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
|
||||
}
|
||||
return SOLID_STREAM_FORMAT;
|
||||
}
|
||||
|
@ -581,6 +654,8 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() {
|
|||
INSTANCED_SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
|
||||
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
|
||||
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
|
||||
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
|
||||
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
|
||||
}
|
||||
return INSTANCED_SOLID_STREAM_FORMAT;
|
||||
|
@ -591,6 +666,8 @@ gpu::Stream::FormatPointer& getInstancedSolidFadeStreamFormat() {
|
|||
INSTANCED_SOLID_FADE_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD2, gpu::Stream::TEXCOORD2, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD3, gpu::Stream::TEXCOORD3, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
|
||||
|
@ -893,6 +970,7 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, con
|
|||
|
||||
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
|
||||
details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET);
|
||||
// TODO: circle3D overlays use this to define their vertices, so they need tex coords
|
||||
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
|
||||
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
|
||||
|
|
|
@ -354,13 +354,24 @@ public:
|
|||
/// Set a batch to the simple pipeline, returning the previous pipeline
|
||||
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false);
|
||||
|
||||
struct ShapeVertex {
|
||||
ShapeVertex(const vec3& pos, const vec3& normal, const vec2& uv, const vec3& tangent) : pos(pos), normal(normal), uv(uv), tangent(tangent) {}
|
||||
|
||||
vec3 pos;
|
||||
vec3 normal;
|
||||
vec2 uv;
|
||||
vec3 tangent;
|
||||
};
|
||||
|
||||
struct ShapeData {
|
||||
gpu::BufferView _positionView;
|
||||
gpu::BufferView _normalView;
|
||||
gpu::BufferView _texCoordView;
|
||||
gpu::BufferView _tangentView;
|
||||
gpu::BufferView _indicesView;
|
||||
gpu::BufferView _wireIndicesView;
|
||||
|
||||
void setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices);
|
||||
void setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<ShapeVertex>& vertices);
|
||||
void setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices);
|
||||
void setupBatch(gpu::Batch& batch) const;
|
||||
void draw(gpu::Batch& batch) const;
|
||||
|
|
|
@ -218,25 +218,25 @@ vec3 fetchLightmapMap(vec2 uv) {
|
|||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func tangentToViewSpace(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
|
||||
<@func evalMaterialNormal(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
|
||||
{
|
||||
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
|
||||
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
|
||||
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
|
||||
vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
|
||||
vec3 localNormal = <$fetchedNormal$>;
|
||||
<$normal$> = vec3(normalizedTangent * localNormal.x + normalizedNormal * localNormal.y + normalizedBitangent * localNormal.z);
|
||||
<$normal$> = vec3(normalizedBitangent * localNormal.x + normalizedNormal * localNormal.y + normalizedTangent * localNormal.z);
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func tangentToViewSpaceLOD(fragPos, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
|
||||
<@func evalMaterialNormalLOD(fragPos, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
|
||||
{
|
||||
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
|
||||
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
|
||||
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
|
||||
vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
|
||||
// attenuate the normal map divergence from the mesh normal based on distance
|
||||
// THe attenuation range [20,100] meters from the eye is arbitrary for now
|
||||
// The attenuation range [20,100] meters from the eye is arbitrary for now
|
||||
vec3 localNormal = mix(<$fetchedNormal$>, vec3(0.0, 1.0, 0.0), smoothstep(20.0, 100.0, (-<$fragPos$>).z));
|
||||
<$normal$> = vec3(normalizedTangent * localNormal.x + normalizedNormal * localNormal.y + normalizedBitangent * localNormal.z);
|
||||
<$normal$> = vec3(normalizedBitangent * localNormal.x + normalizedNormal * localNormal.y + normalizedTangent * localNormal.z);
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr
|
|||
}
|
||||
}
|
||||
|
||||
const graphics::MaterialPointer MeshPartPayload::DEFAULT_MATERIAL = std::make_shared<graphics::Material>();
|
||||
|
||||
MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material) {
|
||||
updateMeshPart(mesh, partIndex);
|
||||
addMaterial(graphics::MaterialLayer(material, 0));
|
||||
|
@ -99,7 +101,7 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShad
|
|||
builder.withSubMetaCulled();
|
||||
}
|
||||
|
||||
if (_drawMaterials.top().material) {
|
||||
if (topMaterialExists()) {
|
||||
auto matKey = _drawMaterials.top().material->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
builder.withTransparent();
|
||||
|
@ -119,7 +121,7 @@ Item::Bound MeshPartPayload::getBound() const {
|
|||
|
||||
ShapeKey MeshPartPayload::getShapeKey() const {
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
if (_drawMaterials.top().material) {
|
||||
if (topMaterialExists()) {
|
||||
drawMaterialKey = _drawMaterials.top().material->getKey();
|
||||
}
|
||||
|
||||
|
@ -171,7 +173,7 @@ void MeshPartPayload::render(RenderArgs* args) {
|
|||
bindMesh(batch);
|
||||
|
||||
// apply material properties
|
||||
RenderPipelines::bindMaterial(_drawMaterials.top().material, batch, args->_enableTexturing);
|
||||
RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
|
||||
// Draw!
|
||||
|
@ -356,7 +358,7 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCas
|
|||
builder.withDeformed();
|
||||
}
|
||||
|
||||
if (_drawMaterials.top().material) {
|
||||
if (topMaterialExists()) {
|
||||
auto matKey = _drawMaterials.top().material->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
builder.withTransparent();
|
||||
|
@ -387,7 +389,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe
|
|||
}
|
||||
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
if (_drawMaterials.top().material) {
|
||||
if (topMaterialExists()) {
|
||||
drawMaterialKey = _drawMaterials.top().material->getKey();
|
||||
}
|
||||
|
||||
|
@ -469,7 +471,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
|
|||
bindMesh(batch);
|
||||
|
||||
// apply material properties
|
||||
RenderPipelines::bindMaterial(_drawMaterials.top().material, batch, args->_enableTexturing);
|
||||
RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
|
||||
// Draw!
|
||||
|
|
|
@ -65,15 +65,18 @@ public:
|
|||
graphics::Mesh::Part _drawPart;
|
||||
|
||||
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
|
||||
size_t getMaterialTextureSize() { return _drawMaterials.top().material ? _drawMaterials.top().material->getTextureSize() : 0; }
|
||||
int getMaterialTextureCount() { return _drawMaterials.top().material ? _drawMaterials.top().material->getTextureCount() : 0; }
|
||||
bool hasTextureInfo() const { return _drawMaterials.top().material ? _drawMaterials.top().material->hasTextureInfo() : false; }
|
||||
size_t getMaterialTextureSize() { return topMaterialExists() ? _drawMaterials.top().material->getTextureSize() : 0; }
|
||||
int getMaterialTextureCount() { return topMaterialExists() ? _drawMaterials.top().material->getTextureCount() : 0; }
|
||||
bool hasTextureInfo() const { return topMaterialExists() ? _drawMaterials.top().material->hasTextureInfo() : false; }
|
||||
|
||||
void addMaterial(graphics::MaterialLayer material);
|
||||
void removeMaterial(graphics::MaterialPointer material);
|
||||
|
||||
protected:
|
||||
static const graphics::MaterialPointer DEFAULT_MATERIAL;
|
||||
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
|
||||
|
||||
bool topMaterialExists() const { return !_drawMaterials.empty() && _drawMaterials.top().material; }
|
||||
};
|
||||
|
||||
namespace render {
|
||||
|
|
|
@ -1604,7 +1604,8 @@ void Model::createVisibleRenderItemSet() {
|
|||
int numParts = (int)mesh->getNumParts();
|
||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
||||
_modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName());
|
||||
auto material = getGeometry()->getShapeMaterial(shapeID);
|
||||
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
|
||||
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
|
||||
shapeID++;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ void main(void) {
|
|||
|
||||
vec3 fragPosition = _position.xyz;
|
||||
vec3 fragNormal;
|
||||
<$tangentToViewSpace(normalTex, _normal, _tangent, fragNormal)$>
|
||||
<$evalMaterialNormal(normalTex, _normal, _tangent, fragNormal)$>
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
|
||||
|
|
|
@ -33,11 +33,11 @@ void main(void) {
|
|||
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$>
|
||||
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
|
||||
|
||||
vec3 viewNormal;
|
||||
<$tangentToViewSpaceLOD(_position, normalTexel, _normal, _tangent, viewNormal)$>
|
||||
vec3 fragNormal;
|
||||
<$evalMaterialNormalLOD(_position, normalTexel, _normal, _tangent, fragNormal)$>
|
||||
|
||||
packDeferredFragmentLightmap(
|
||||
normalize(viewNormal.xyz),
|
||||
normalize(fragNormal.xyz),
|
||||
evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a),
|
||||
getMaterialAlbedo(mat) * albedo.rgb * _color,
|
||||
getMaterialRoughness(mat) * roughness,
|
||||
|
|
|
@ -43,11 +43,11 @@ void main(void) {
|
|||
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$>
|
||||
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
|
||||
|
||||
vec3 viewNormal;
|
||||
<$tangentToViewSpaceLOD(_position, normalTexel, _normal, _tangent, viewNormal)$>
|
||||
vec3 fragNormal;
|
||||
<$evalMaterialNormalLOD(_position, normalTexel, _normal, _tangent, fragNormal)$>
|
||||
|
||||
packDeferredFragmentLightmap(
|
||||
normalize(viewNormal.xyz),
|
||||
normalize(fragNormal.xyz),
|
||||
evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a),
|
||||
getMaterialAlbedo(mat) * albedo.rgb * _color,
|
||||
getMaterialRoughness(mat) * roughness,
|
||||
|
|
|
@ -46,8 +46,8 @@ void main(void) {
|
|||
vec3 emissive = getMaterialEmissive(mat);
|
||||
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
||||
|
||||
vec3 viewNormal;
|
||||
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
|
||||
vec3 fragNormal;
|
||||
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
|
||||
|
||||
float metallic = getMaterialMetallic(mat);
|
||||
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
|
||||
|
@ -56,7 +56,7 @@ void main(void) {
|
|||
<$evalMaterialScattering(scatteringTex, scattering, matKey, scattering)$>;
|
||||
|
||||
packDeferredFragment(
|
||||
normalize(viewNormal.xyz),
|
||||
normalize(fragNormal.xyz),
|
||||
opacity,
|
||||
albedo,
|
||||
roughness,
|
||||
|
|
|
@ -56,8 +56,8 @@ void main(void) {
|
|||
vec3 emissive = getMaterialEmissive(mat);
|
||||
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
||||
|
||||
vec3 viewNormal;
|
||||
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
|
||||
vec3 fragNormal;
|
||||
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
|
||||
|
||||
float metallic = getMaterialMetallic(mat);
|
||||
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
|
||||
|
@ -65,7 +65,7 @@ void main(void) {
|
|||
float scattering = getMaterialScattering(mat);
|
||||
|
||||
packDeferredFragment(
|
||||
normalize(viewNormal.xyz),
|
||||
normalize(fragNormal.xyz),
|
||||
opacity,
|
||||
albedo,
|
||||
roughness,
|
||||
|
|
|
@ -61,7 +61,7 @@ void main(void) {
|
|||
|
||||
vec3 fragPosition = _position.xyz;
|
||||
vec3 fragNormal;
|
||||
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
|
||||
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));
|
||||
|
|
|
@ -71,7 +71,7 @@ void main(void) {
|
|||
vec3 fragPosition = _position.xyz;
|
||||
// Lighting is done in world space
|
||||
vec3 fragNormal;
|
||||
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
|
||||
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));
|
||||
|
|
|
@ -8,8 +8,11 @@
|
|||
|
||||
#include "Shapes.h"
|
||||
|
||||
#include "qmath.h"
|
||||
|
||||
namespace geometry {
|
||||
|
||||
using glm::vec2;
|
||||
using glm::vec3;
|
||||
|
||||
// The golden ratio
|
||||
|
@ -19,8 +22,8 @@ Solid<3> tesselate(const Solid<3>& solid_, int count) {
|
|||
Solid<3> solid = solid_;
|
||||
float length = glm::length(solid.vertices[0]);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Solid<3> result { solid.vertices, {} };
|
||||
result.vertices.reserve(solid.vertices.size() + solid.faces.size() * 3);
|
||||
Solid<3> result { solid.vertices, {}, {} };
|
||||
result.vertices.reserve(solid.vertices.size() + solid.faces.size() * 6);
|
||||
for (size_t f = 0; f < solid.faces.size(); ++f) {
|
||||
Index baseVertex = (Index)result.vertices.size();
|
||||
const Face<3>& oldFace = solid.faces[f];
|
||||
|
@ -30,13 +33,26 @@ Solid<3> tesselate(const Solid<3>& solid_, int count) {
|
|||
vec3 ab = glm::normalize(a + b) * length;
|
||||
vec3 bc = glm::normalize(b + c) * length;
|
||||
vec3 ca = glm::normalize(c + a) * length;
|
||||
|
||||
result.vertices.push_back(a);
|
||||
result.vertices.push_back(ab);
|
||||
result.vertices.push_back(ca);
|
||||
result.faces.push_back(Face<3>{ { baseVertex, baseVertex + 1, baseVertex + 2 } });
|
||||
|
||||
result.vertices.push_back(ab);
|
||||
result.vertices.push_back(b);
|
||||
result.vertices.push_back(bc);
|
||||
result.faces.push_back(Face<3>{ { baseVertex + 3, baseVertex + 4, baseVertex + 5 } });
|
||||
|
||||
result.vertices.push_back(bc);
|
||||
result.vertices.push_back(c);
|
||||
result.vertices.push_back(ca);
|
||||
result.faces.push_back(Face<3>{ { baseVertex + 6, baseVertex + 7, baseVertex + 8 } });
|
||||
|
||||
result.vertices.push_back(ab);
|
||||
result.vertices.push_back(bc);
|
||||
result.vertices.push_back(ca);
|
||||
result.faces.push_back(Face<3>{ { oldFace[0], baseVertex, baseVertex + 2 } });
|
||||
result.faces.push_back(Face<3>{ { baseVertex, oldFace[1], baseVertex + 1 } });
|
||||
result.faces.push_back(Face<3>{ { baseVertex + 1, oldFace[2], baseVertex + 2 } });
|
||||
result.faces.push_back(Face<3>{ { baseVertex, baseVertex + 1, baseVertex + 2 } });
|
||||
result.faces.push_back(Face<3>{ { baseVertex + 9, baseVertex + 10, baseVertex + 11 } });
|
||||
}
|
||||
solid = result;
|
||||
}
|
||||
|
@ -50,6 +66,10 @@ const Solid<3>& tetrahedron() {
|
|||
static const auto D = vec3(-1, -1, 1);
|
||||
static const Solid<3> TETRAHEDRON = Solid<3>{
|
||||
{ A, B, C, D },
|
||||
{ vec2(0.75f, 0.5f), vec2(0.5f, 0.0f), vec2(0.25f, 0.5f),
|
||||
vec2(0.5f, 1.0f), vec2(1.0f, 1.0f), vec2(0.75f, 0.5f),
|
||||
vec2(0.25f, 0.5f), vec2(0.5f, 1.0f), vec2(0.75f, 0.5f),
|
||||
vec2(0.25f, 0.5f), vec2(0.0f, 1.0f), vec2(0.5f, 1.0f) },
|
||||
FaceVector<3>{
|
||||
Face<3> { { 0, 1, 2 } },
|
||||
Face<3> { { 3, 1, 0 } },
|
||||
|
@ -65,8 +85,15 @@ const Solid<4>& cube() {
|
|||
static const auto B = vec3(-1, 1, 1);
|
||||
static const auto C = vec3(-1, 1, -1);
|
||||
static const auto D = vec3(1, 1, -1);
|
||||
static const float THIRD = 1.0f / 3.0f;
|
||||
static const Solid<4> CUBE = Solid<4>{
|
||||
{ A, B, C, D, -A, -B, -C, -D },
|
||||
{ vec2(0.5f, 0.0f), vec2(0.25f, 0.0f), vec2(0.25f, THIRD), vec2(0.5f, THIRD),
|
||||
vec2(0.5f, THIRD), vec2(0.25f, THIRD), vec2(0.25f, 2.0f * THIRD), vec2(0.5f, 2.0f * THIRD),
|
||||
vec2(0.25f, THIRD), vec2(0.0f, THIRD), vec2(0.0f, 2.0f * THIRD), vec2(0.25f, 2.0f * THIRD),
|
||||
vec2(1.0f, THIRD), vec2(0.75f, THIRD), vec2(0.75f, 2.0f * THIRD), vec2(1.0f, 2.0f * THIRD),
|
||||
vec2(0.75f, THIRD), vec2(0.5f, THIRD), vec2(0.5f, 2.0f * THIRD), vec2(0.75f, 2.0f * THIRD),
|
||||
vec2(0.25f, 1.0f), vec2(0.5f, 1.0f), vec2(0.5f, 2.0f * THIRD), vec2(0.25f, 2.0f * THIRD) },
|
||||
FaceVector<4>{
|
||||
Face<4> { { 3, 2, 1, 0 } },
|
||||
Face<4> { { 0, 1, 7, 6 } },
|
||||
|
@ -86,8 +113,18 @@ const Solid<3>& octahedron() {
|
|||
static const auto D = vec3(0, 0, -1);
|
||||
static const auto E = vec3(1, 0, 0);
|
||||
static const auto F = vec3(-1, 0, 0);
|
||||
static const float THIRD = 1.0f / 3.0f;
|
||||
static const float SEVENTH = 1.0f / 7.0f;
|
||||
static const Solid<3> OCTAHEDRON = Solid<3>{
|
||||
{ A, B, C, D, E, F},
|
||||
{ vec2(2.0f * SEVENTH, THIRD), vec2(SEVENTH, 2.0f * THIRD), vec2(3.0f * SEVENTH, 2.0f * THIRD),
|
||||
vec2(2.0f * SEVENTH, THIRD), vec2(3.0f * SEVENTH, 2.0f * THIRD), vec2(4.0f * SEVENTH, THIRD),
|
||||
vec2(5.0f * SEVENTH, 0.0f), vec2(4.0f * SEVENTH, THIRD), vec2(6.0f * SEVENTH, THIRD),
|
||||
vec2(2.0f * SEVENTH, THIRD), vec2(0.0f, THIRD), vec2(1.0f * SEVENTH, 2.0f * THIRD),
|
||||
vec2(2.0f * SEVENTH, 1.0f), vec2(3.0f * SEVENTH, 2.0f * THIRD), vec2(1.0f * SEVENTH, 2.0f * THIRD),
|
||||
vec2(5.0f * SEVENTH, 2.0f * THIRD), vec2(4.0f * SEVENTH, THIRD), vec2(3.0f * SEVENTH, 2.0f * THIRD),
|
||||
vec2(5.0f * SEVENTH, 2.0f * THIRD), vec2(6.0f * SEVENTH, THIRD), vec2(4.0f * SEVENTH, THIRD),
|
||||
vec2(5.0f * SEVENTH, 2.0f * THIRD), vec2(1.0f, 2.0f * THIRD), vec2(6.0f * SEVENTH, THIRD) },
|
||||
FaceVector<3> {
|
||||
Face<3> { { 0, 2, 4, } },
|
||||
Face<3> { { 0, 4, 3, } },
|
||||
|
@ -116,11 +153,52 @@ const Solid<5>& dodecahedron() {
|
|||
static const vec3 I = vec3(0, -IP, P);
|
||||
static const vec3 J = vec3(P, 0, IP);
|
||||
|
||||
|
||||
/* _
|
||||
/ \ |
|
||||
/ \ y2
|
||||
/ \ |
|
||||
/ \ _
|
||||
\ / |
|
||||
\ / y1
|
||||
\ / |
|
||||
___________ _
|
||||
|x3|- - x1 - -||x3|
|
||||
|- - - - x2- - - -|
|
||||
*/
|
||||
|
||||
// x1, x2, and x3 are the solutions to the following system of equations:
|
||||
// 1 = 3 * x1 + 3 * x2 + x3
|
||||
// x1 + 2 * x3 = (golden ratio) * x1
|
||||
// x2 = x1 + 2 * x3
|
||||
static const float x1 = 4.0f / (17.0f + 7.0f * sqrtf(5.0f));
|
||||
static const float x2 = (1.0f / 11.0f) * (5.0f * sqrtf(5.0f) - 9.0f);
|
||||
static const float x2_2 = x2 / 2.0f;
|
||||
static const float x3 = (1.0f / 11.0f) * (6.0f * sqrtf(5.0f) - 13.0f);
|
||||
// y1 and y2 are the solutions to the following system of equations (x is the sidelength, but is different than x1 because the scale in the y direction is different):
|
||||
// 1 = 3 * y1 + 2 * y2
|
||||
// y1 = sin(108 deg) * x
|
||||
// y1 + y2 = x * sqrtf(5 + 2 * sqrtf(5)) / 2
|
||||
static const float y1 = sqrtf(2.0f * (5.0f + sqrtf(5.0f))) / (sqrtf(2.0f * (5.0f + sqrtf(5.0f))) + 4.0f * sqrtf(5.0f + 2.0f * sqrtf(5.0f)));
|
||||
static const float y2 = -(sqrtf(2.0f * (5.0f + sqrtf(5.0f))) - 2.0f * sqrtf(5.0f + 2.0f * sqrtf(5.0f))) / (sqrtf(2.0f * (5.0f + sqrtf(5.0f))) + 4.0f * sqrtf(5.0f + 2.0f * sqrtf(5.0f)));
|
||||
|
||||
static const Solid<5> DODECAHEDRON = Solid<5>{
|
||||
{
|
||||
A, B, C, D, E, F, G, H, I, J,
|
||||
-A, -B, -C, -D, -E, -F, -G, -H, -I, -J,
|
||||
},
|
||||
{ vec2(x1 + x2_2, 0.0f), vec2(x2_2, 0.0f), vec2(x2_2 - x3, y1), vec2(x3 + x1, y1 + y2), vec2(x3 + x1 + x2_2, y1),
|
||||
vec2(1.0f - (x2 - x3 + x2_2), 0.0f), vec2(1.0f - (x2 + x1 + x3), y2), vec2(1.0f - (x2 + x1), y1 + y2), vec2(1.0f - x2, y1 + y2), vec2(1.0f - (x2 - x3), y2),
|
||||
vec2(1.0f - x2_2, y1), vec2(1.0f - x2, y1 + y2), vec2(1.0f - (x3 + x1), y1 + y2 + y1), vec2(1.0f - x3, y1 + y2 + y1), vec2(1.0f, y1 + y2),
|
||||
vec2(x3, y1 + y2), vec2(0.0f, y1 + y2 + y1), vec2(x2_2, y1 + y2 + y1 + y2), vec2(x2, y1 + y2 + y1), vec2(x1 + x3, y1 + y2),
|
||||
vec2(x3 + x1, y1 + y2), vec2(x2, y1 + y2 + y1), vec2(x2 + x1, y1 + y2 + y1), vec2(x3 + x1 + x2, y1 + y2), vec2(x3 + x1 + x2_2, y1),
|
||||
vec2(x3 + x1 + x2_2, y1), vec2(x3 + x1 + x2, y1 + y2), vec2(x3 + x1 + x2 + x2_2, y1), vec2(x1 + x2 + x2_2, 0.0f), vec2(x3 + x1 + x2_2 + x3, 0.0f),
|
||||
vec2(1.0f - (x3 + x1 + x2_2), 1.0f - y1), vec2(1.0f - (x3 + x1 + x2), 1.0f - (y1 + y2)), vec2(1.0f - (x3 + x1 + x2 + x2_2), 1.0f - y1), vec2(1.0f - (x1 + x2 + x2_2), 1.0f), vec2(1.0f - (x3 + x1 + x2_2 + x3), 1.0f),
|
||||
vec2(x2 + x1 + x3, 1.0f - y2), vec2(x2 + x1, 1.0f - (y1 + y2)), vec2(x2, 1.0f - (y1 + y2)), vec2(x2 - x3, 1.0f - y2), vec2(x2 - x3 + x2_2, 1.0f),
|
||||
vec2(x2 + x1 + x2, y1 + y2 + y1), vec2(x3 + x1 + x2 + x1, y1 + y2), vec2(x3 + x1 + x2, y1 + y2), vec2(x2 + x1, y1 + y2 + y1), vec2(x2 + x1 + x2_2, y1 + y2 + y1 + y2),
|
||||
vec2(1.0f - (x3 + x1 + x2), y1 + y2 + y1), vec2(1.0f - (x2 + x1), y1 + y2), vec2(1.0f - (x2 + x1 + x2_2), y1), vec2(1.0f - (x2 + x1 + x2), y1 + y2), vec2(1.0f - (x3 + x1 + x2 + x1), y1 + y2 + y1),
|
||||
vec2(1.0f - (x3 + x1 + x2_2), y1 + y2 + y1 + y2), vec2(1.0f - (x3 + x1), y1 + y2 + y1), vec2(1.0f - x2, y1 + y2), vec2(1.0f - (x2 + x1), y2 + y1), vec2(1.0f - (x3 + x1 + x2), y1 + y2 + y1),
|
||||
vec2(1.0f - (x1 + x2_2), 1.0f), vec2(1.0f - x2_2, 1.0f), vec2(1.0f - (x2_2 - x3), 1.0f - y1), vec2(1.0f - (x1 + x3), 1.0f - (y1 + y2)), vec2(1.0f - (x3 + x1 + x2_2), 1.0f - y1) },
|
||||
FaceVector<5> {
|
||||
Face<5> { { 0, 1, 2, 3, 4 } },
|
||||
Face<5> { { 0, 5, 18, 6, 1 } },
|
||||
|
@ -148,12 +226,33 @@ const Solid<3>& icosahedron() {
|
|||
static const auto D = vec3(P, 0, N);
|
||||
static const auto E = vec3(P, 0, -N);
|
||||
static const auto F = vec3(0, N, -P);
|
||||
|
||||
static const float THIRD = 1.0f / 3.0f;
|
||||
static const float ELEVENTH = 1.0f / 11.0f;
|
||||
static const Solid<3> ICOSAHEDRON = Solid<3> {
|
||||
{
|
||||
A, B, C, D, E, F,
|
||||
-A, -B, -C, -D, -E, -F,
|
||||
},
|
||||
{ vec2(3.0f * ELEVENTH, 0.0f), vec2(2.0f * ELEVENTH, THIRD), vec2(4.0f * ELEVENTH, THIRD),
|
||||
vec2(2.0f * ELEVENTH, THIRD), vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(4.0f * ELEVENTH, THIRD),
|
||||
vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(4.0f * ELEVENTH, THIRD),
|
||||
vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(6.0f * ELEVENTH, THIRD), vec2(4.0f * ELEVENTH, THIRD),
|
||||
vec2(6.0f * ELEVENTH, THIRD), vec2(5.0f * ELEVENTH, 0.0f), vec2(4.0f * ELEVENTH, THIRD),
|
||||
vec2(1.0f * ELEVENTH, 0.0f), vec2(0.0f, THIRD), vec2(2.0f * ELEVENTH, THIRD),
|
||||
vec2(1.0f * ELEVENTH, 2.0f * THIRD), vec2(2.0f * ELEVENTH, THIRD), vec2(0.0f, THIRD),
|
||||
vec2(2.0f * ELEVENTH, THIRD), vec2(1.0f * ELEVENTH, 2.0f * THIRD), vec2(3.0f * ELEVENTH, 2.0f * THIRD),
|
||||
vec2(2.0f * ELEVENTH, 1.0f), vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(1.0f * ELEVENTH, 2.0f * THIRD),
|
||||
vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(4.0f * ELEVENTH, 1.0f), vec2(5.0f * ELEVENTH, 2.0f * THIRD),
|
||||
vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(6.0f * ELEVENTH, 1.0f),
|
||||
vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(6.0f * ELEVENTH, THIRD),
|
||||
vec2(8.0f * ELEVENTH, THIRD), vec2(6.0f * ELEVENTH, THIRD), vec2(7.0f * ELEVENTH, 2.0f * THIRD),
|
||||
vec2(6.0f * ELEVENTH, THIRD), vec2(8.0f * ELEVENTH, THIRD), vec2(7.0f * ELEVENTH, 0.0f),
|
||||
vec2(10.0f * ELEVENTH, THIRD), vec2(9.0f * ELEVENTH, 0.0f), vec2(8.0f * ELEVENTH, THIRD),
|
||||
vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(8.0f * ELEVENTH, 1.0f), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
|
||||
vec2(8.0f * ELEVENTH, THIRD), vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
|
||||
vec2(10.0f * ELEVENTH, THIRD), vec2(8.0f * ELEVENTH, THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
|
||||
vec2(1.0f, 2.0f * THIRD), vec2(10.0f * ELEVENTH, THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
|
||||
vec2(10.0f * ELEVENTH, 1.0f), vec2(1.0f, 2.0f * THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD) },
|
||||
FaceVector<3> {
|
||||
Face<3> { { 1, 2, 0 } },
|
||||
Face<3> { { 2, 3, 0 } },
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace geometry {
|
|||
using Index = uint32_t;
|
||||
using Vec = glm::vec3;
|
||||
using VertexVector = std::vector<Vec>;
|
||||
using TexCoordVector = std::vector<glm::vec2>;
|
||||
using IndexVector = std::vector<Index>;
|
||||
|
||||
template <size_t N>
|
||||
|
@ -33,6 +34,7 @@ namespace geometry {
|
|||
template <size_t N>
|
||||
struct Solid {
|
||||
VertexVector vertices;
|
||||
TexCoordVector texCoords;
|
||||
FaceVector<N> faces;
|
||||
|
||||
Solid<N>& fitDimension(float newMaxDimension) {
|
||||
|
|
|
@ -20,8 +20,12 @@ if (NOT SERVER_ONLY AND NOT ANDROID)
|
|||
add_subdirectory(${DIR})
|
||||
set(DIR "oculusLegacy")
|
||||
add_subdirectory(${DIR})
|
||||
set(DIR "hifiSixense")
|
||||
add_subdirectory(${DIR})
|
||||
|
||||
if (USE_SIXENSE)
|
||||
set(DIR "hifiSixense")
|
||||
add_subdirectory(${DIR})
|
||||
endif()
|
||||
|
||||
set(DIR "hifiSpacemouse")
|
||||
add_subdirectory(${DIR})
|
||||
set(DIR "hifiNeuron")
|
||||
|
|
|
@ -12,5 +12,7 @@ link_hifi_libraries(audio plugins)
|
|||
add_dependency_external_projects(hifiAudioCodec)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAUDIOCODEC_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${HIFIAUDIOCODEC_LIBRARIES})
|
||||
install_beside_console()
|
||||
|
||||
if (BUILD_SERVER)
|
||||
install_beside_console()
|
||||
endif ()
|
||||
|
|
|
@ -19,7 +19,7 @@ if (WIN32 AND (NOT USE_GLES))
|
|||
set(TARGET_NAME oculus)
|
||||
setup_hifi_plugin(Multimedia)
|
||||
link_hifi_libraries(
|
||||
shared task gl gpu gpu-gl controllers ui qml
|
||||
shared task gl gpu ${PLATFORM_GL_BACKEND} controllers ui qml
|
||||
plugins ui-plugins display-plugins input-plugins
|
||||
audio-client networking render-utils
|
||||
${PLATFORM_GL_BACKEND}
|
||||
|
|
|
@ -9,5 +9,7 @@
|
|||
set(TARGET_NAME pcmCodec)
|
||||
setup_hifi_client_server_plugin()
|
||||
link_hifi_libraries(shared plugins)
|
||||
install_beside_console()
|
||||
|
||||
if (BUILD_SERVER)
|
||||
install_beside_console()
|
||||
endif ()
|
||||
|
|
102
scripts/developer/tests/webOverlayTool.js
Normal file
102
scripts/developer/tests/webOverlayTool.js
Normal 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();
|
|
@ -14,7 +14,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
|||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
shared task networking animation
|
||||
ktx image octree gl gpu gpu-gl
|
||||
ktx image octree gl gpu ${PLATFORM_GL_BACKEND}
|
||||
render render-utils
|
||||
graphics fbx model-networking graphics-scripting
|
||||
entities entities-renderer audio avatars script-engine
|
||||
|
|
|
@ -18,4 +18,6 @@ elseif (APPLE)
|
|||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
|
||||
endif()
|
||||
|
||||
install_beside_console()
|
||||
if (BUILD_SERVER)
|
||||
install_beside_console()
|
||||
endif ()
|
||||
|
|
|
@ -40,6 +40,8 @@ Oven::Oven() {
|
|||
}
|
||||
|
||||
Oven::~Oven() {
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
|
||||
// quit all worker threads and wait on them
|
||||
for (auto& thread : _workerThreads) {
|
||||
thread->quit();
|
||||
|
|
Loading…
Reference in a new issue