diff --git a/android/app/build.gradle b/android/app/build.gradle
index 980d197397..d5058a7f40 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,3 +1,5 @@
+import org.apache.tools.ant.taskdefs.condition.Os
+
apply plugin: 'com.android.application'
android {
@@ -74,10 +76,12 @@ android {
// so our merge has to depend on the external native build
variant.externalNativeBuildTasks.each { task ->
variant.mergeResources.dependsOn(task)
- def uploadDumpSymsTask = rootProject.getTasksByName("uploadBreakpadDumpSyms${variant.name.capitalize()}", false).first()
- def runDumpSymsTask = rootProject.getTasksByName("runBreakpadDumpSyms${variant.name.capitalize()}", false).first()
- runDumpSymsTask.dependsOn(task)
- variant.assemble.dependsOn(uploadDumpSymsTask)
+ if (Os.isFamily(Os.FAMILY_UNIX)) {
+ def uploadDumpSymsTask = rootProject.getTasksByName("uploadBreakpadDumpSyms${variant.name.capitalize()}", false).first()
+ def runDumpSymsTask = rootProject.getTasksByName("runBreakpadDumpSyms${variant.name.capitalize()}", false).first()
+ runDumpSymsTask.dependsOn(task)
+ variant.assemble.dependsOn(uploadDumpSymsTask)
+ }
}
variant.mergeAssets.doLast {
diff --git a/android/app/src/main/cpp/native.cpp b/android/app/src/main/cpp/native.cpp
index f94e5f2bbf..42124bf154 100644
--- a/android/app/src/main/cpp/native.cpp
+++ b/android/app/src/main/cpp/native.cpp
@@ -304,6 +304,11 @@ Java_io_highfidelity_hifiinterface_MainActivity_nativeGetDisplayName(JNIEnv *env
return env->NewStringUTF(username.toLatin1().data());
}
+JNIEXPORT void JNICALL
+Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeBeforeEnterBackground(JNIEnv *env, jobject obj) {
+ AndroidHelper::instance().notifyBeforeEnterBackground();
+}
+
JNIEXPORT void JNICALL
Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeEnterBackground(JNIEnv *env, jobject obj) {
AndroidHelper::instance().notifyEnterBackground();
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
index aafde836c1..8fd8b9d0e6 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
@@ -59,6 +59,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
private native long nativeOnCreate(InterfaceActivity instance, AssetManager assetManager);
private native void nativeOnDestroy();
private native void nativeGotoUrl(String url);
+ private native void nativeBeforeEnterBackground();
private native void nativeEnterBackground();
private native void nativeEnterForeground();
private native long nativeOnExitVr();
@@ -291,6 +292,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
case "Home":
case "Privacy Policy":
case "Login": {
+ nativeBeforeEnterBackground();
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(MainActivity.EXTRA_FRAGMENT, activityName);
intent.putExtra(MainActivity.EXTRA_BACK_TO_SCENE, backToScene);
diff --git a/android/build.gradle b/android/build.gradle
index 39265327b2..bc39c30472 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -71,17 +71,17 @@ def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a')
def baseUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/android/'
def breakpadDumpSymsDir = new File("${appDir}/build/tmp/breakpadDumpSyms")
-def qtFile='qt-5.9.3_linux_armv8-libcpp_openssl.tgz'
-def qtChecksum='04599670ccca84bd2b15f6915568eb2d'
-def qtVersionId='8QbCma4ryEPgBYn_8kgYgB10IvNx9I1W'
+def qtFile='qt-5.11.1_linux_armv8-libcpp_openssl.tgz'
+def qtChecksum='f312c47cd8b8dbca824c32af4eec5e66'
+def qtVersionId='nyCGcb91S4QbYeJhUkawO5x1lrLdSNB_'
if (Os.isFamily(Os.FAMILY_MAC)) {
- qtFile = 'qt-5.9.3_osx_armv8-libcpp_openssl.tgz'
- qtChecksum='4b02de9d67d6bfb202355a808d2d9c59'
- qtVersionId='2gfgoYCggJGyXxKiazaPGsMs1Gn9j4og'
+ qtFile = 'qt-5.11.1_osx_armv8-libcpp_openssl.tgz'
+ qtChecksum='a0c8b394aec5b0fcd46714ca3a53278a'
+ qtVersionId='QNa.lwNJaPc0eGuIL.xZ8ebeTuLL7rh8'
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
- qtFile = 'qt-5.9.3_win_armv8-libcpp_openssl.tgz'
- qtChecksum='c3e25db64002d0f43cf565e0ef708911'
- qtVersionId='xKIteC6HO0xrmcWeMmhQcmKyPEsnUrcZ'
+ qtFile = 'qt-5.11.1_win_armv8-libcpp_openssl.tgz'
+ qtChecksum='d80aed4233ce9e222aae8376e7a94bf9'
+ qtVersionId='iDVXu0i3WEXRFIxQCtzcJ2XuKrE8RIqB'
}
def packages = [
diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake
index 968a65a6dd..de9f8a22fa 100644
--- a/cmake/compiler.cmake
+++ b/cmake/compiler.cmake
@@ -66,6 +66,13 @@ elseif ((NOT MSVC12) AND (NOT MSVC14))
endif()
endif ()
+if (CMAKE_GENERATOR STREQUAL "Xcode")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
+ set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Release] "YES")
+ set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=Release] "dwarf-with-dsym")
+ set(CMAKE_XCODE_ATTRIBUTE_DEPLOYMENT_POSTPROCESSING[variant=Release] "YES")
+endif()
+
if (APPLE)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
diff --git a/cmake/externals/crashpad/CMakeLists.txt b/cmake/externals/crashpad/CMakeLists.txt
index e509e115e4..648ec83280 100644
--- a/cmake/externals/crashpad/CMakeLists.txt
+++ b/cmake/externals/crashpad/CMakeLists.txt
@@ -16,19 +16,46 @@ if (WIN32)
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
- set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of Crashpad include directories")
-
+ set(BIN_RELEASE_PATH "${SOURCE_DIR}/out/Release_x64")
+ set(BIN_EXT ".exe")
+ set(LIB_RELEASE_PATH "${SOURCE_DIR}/out/Release_x64/lib_MD")
+ set(LIB_DEBUG_PATH "${SOURCE_DIR}/out/Debug_x64/lib_MD")
+ set(LIB_PREFIX "")
set(LIB_EXT "lib")
+elseif (APPLE)
+ ExternalProject_Add(
+ ${EXTERNAL_NAME}
+ URL http://public.highfidelity.com/dependencies/crashpad_mac_070318.zip
+ URL_MD5 ba1501dc163591ac2d1be74946967e2a
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ LOG_DOWNLOAD 1
+ )
- set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad release library")
- set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base release library")
- set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util release library")
+ ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
- set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad debug library")
- set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base debug library")
- set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util debug library")
+ set(BIN_RELEASE_PATH "${SOURCE_DIR}/out/Release")
+ set(BIN_EXT "")
+ set(LIB_RELEASE_PATH "${SOURCE_DIR}/out/Release/lib")
+ set(LIB_DEBUG_PATH "${SOURCE_DIR}/out/Debug/lib")
+ set(LIB_PREFIX "lib")
+ set(LIB_EXT "a")
+endif ()
- set(CRASHPAD_HANDLER_EXE_PATH ${SOURCE_DIR}/out/Release_x64/crashpad_handler.exe CACHE FILEPATH "Path to the Crashpad handler executable")
+if (WIN32 OR APPLE)
+
+ set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of Crashpad include directories")
+
+ set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${LIB_RELEASE_PATH}/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad release library")
+ set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_RELEASE ${LIB_RELEASE_PATH}/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base release library")
+ set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_RELEASE ${LIB_RELEASE_PATH}/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util release library")
+
+ set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${LIB_DEBUG_PATH}/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad debug library")
+ set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_DEBUG ${LIB_DEBUG_PATH}/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base debug library")
+ set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_DEBUG ${LIB_DEBUG_PATH}/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util debug library")
+
+ set(CRASHPAD_HANDLER_EXE_PATH ${BIN_RELEASE_PATH}/crashpad_handler${BIN_EXT} CACHE FILEPATH "Path to the Crashpad handler binary")
endif ()
# Hide this external target (for ide users)
diff --git a/cmake/macros/AddCrashpad.cmake b/cmake/macros/AddCrashpad.cmake
index 7d161be7f0..113ab53aae 100644
--- a/cmake/macros/AddCrashpad.cmake
+++ b/cmake/macros/AddCrashpad.cmake
@@ -23,7 +23,7 @@ macro(add_crashpad)
set(CMAKE_BACKTRACE_TOKEN $ENV{CMAKE_BACKTRACE_TOKEN})
endif()
- if (WIN32 AND USE_CRASHPAD)
+ if ((WIN32 OR APPLE) AND USE_CRASHPAD)
get_property(CRASHPAD_CHECKED GLOBAL PROPERTY CHECKED_FOR_CRASHPAD_ONCE)
if (NOT CRASHPAD_CHECKED)
@@ -42,6 +42,10 @@ macro(add_crashpad)
if (WIN32)
set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS "/ignore:4099")
+ elseif (APPLE)
+ find_library(Security Security)
+ target_link_libraries(${TARGET_NAME} ${Security})
+ target_link_libraries(${TARGET_NAME} "-lbsm")
endif()
add_custom_command(
diff --git a/interface/resources/html/img/tablet-help-gamepad.jpg b/interface/resources/html/img/tablet-help-gamepad.jpg
index 2594cbd86c..bc6dcacee0 100644
Binary files a/interface/resources/html/img/tablet-help-gamepad.jpg and b/interface/resources/html/img/tablet-help-gamepad.jpg differ
diff --git a/interface/resources/html/img/tablet-help-keyboard.jpg b/interface/resources/html/img/tablet-help-keyboard.jpg
index 1c257f83e2..7045abed75 100644
Binary files a/interface/resources/html/img/tablet-help-keyboard.jpg and b/interface/resources/html/img/tablet-help-keyboard.jpg differ
diff --git a/interface/resources/html/img/tablet-help-oculus.jpg b/interface/resources/html/img/tablet-help-oculus.jpg
index bbff760e96..7e2062400a 100644
Binary files a/interface/resources/html/img/tablet-help-oculus.jpg and b/interface/resources/html/img/tablet-help-oculus.jpg differ
diff --git a/interface/resources/html/img/tablet-help-vive.jpg b/interface/resources/html/img/tablet-help-vive.jpg
index 849e3a5588..27b97d71bd 100644
Binary files a/interface/resources/html/img/tablet-help-vive.jpg and b/interface/resources/html/img/tablet-help-vive.jpg differ
diff --git a/interface/resources/html/img/tablet-help-windowsMR.jpg b/interface/resources/html/img/tablet-help-windowsMR.jpg
new file mode 100644
index 0000000000..b9d0241bec
Binary files /dev/null and b/interface/resources/html/img/tablet-help-windowsMR.jpg differ
diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html
index a6588be083..279213bbcb 100644
--- a/interface/resources/html/tabletHelp.html
+++ b/interface/resources/html/tabletHelp.html
@@ -66,7 +66,7 @@
diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml
index 2406fa048d..bff13cea54 100644
--- a/interface/resources/qml/Stats.qml
+++ b/interface/resources/qml/Stats.qml
@@ -263,6 +263,12 @@ Item {
}
StatText {
text: "GPU: " + root.gpuFrameTime.toFixed(1) + " ms"
+ }
+ StatText {
+ text: "GPU (Per pixel): " + root.gpuFrameTimePerPixel.toFixed(5) + " ns/pp"
+ }
+ StatText {
+ text: "GPU frame size: " + root.gpuFrameSize.x + " x " + root.gpuFrameSize.y
}
StatText {
text: "Triangles: " + root.triangles +
diff --git a/interface/resources/qml/controls-uit/+android/Button.qml b/interface/resources/qml/controls-uit/+android/Button.qml
deleted file mode 100644
index 2f05b35685..0000000000
--- a/interface/resources/qml/controls-uit/+android/Button.qml
+++ /dev/null
@@ -1,125 +0,0 @@
-//
-// Button.qml
-//
-// Created by David Rowe on 16 Feb 2016
-// Copyright 2016 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-import QtQuick 2.5
-import QtQuick.Controls 1.4 as Original
-import QtQuick.Controls.Styles 1.4
-import TabletScriptingInterface 1.0
-
-import "../styles-uit"
-
-Original.Button {
- id: root;
-
- property int color: 0
- property int colorScheme: hifi.colorSchemes.light
- property string buttonGlyph: "";
-
- width: hifi.dimensions.buttonWidth
- height: hifi.dimensions.controlLineHeight
-
- HifiConstants { id: hifi }
-
- onHoveredChanged: {
- if (hovered) {
- Tablet.playSound(TabletEnums.ButtonHover);
- }
- }
-
- onFocusChanged: {
- if (focus) {
- Tablet.playSound(TabletEnums.ButtonHover);
- }
- }
-
- onClicked: {
- Tablet.playSound(TabletEnums.ButtonClick);
- }
-
- style: ButtonStyle {
-
- background: Rectangle {
- radius: hifi.buttons.radius
-
- border.width: (control.color === hifi.buttons.none ||
- (control.color === hifi.buttons.noneBorderless && control.hovered) ||
- (control.color === hifi.buttons.noneBorderlessWhite && control.hovered) ||
- (control.color === hifi.buttons.noneBorderlessGray && control.hovered)) ? 1 : 0;
- border.color: control.color === hifi.buttons.noneBorderless ? hifi.colors.blueHighlight :
- (control.color === hifi.buttons.noneBorderlessGray ? hifi.colors.baseGray : hifi.colors.white);
-
- gradient: Gradient {
- GradientStop {
- position: 0.2
- color: {
- if (!control.enabled) {
- hifi.buttons.disabledColorStart[control.colorScheme]
- } else if (control.pressed) {
- hifi.buttons.pressedColor[control.color]
- } else if (control.hovered) {
- hifi.buttons.hoveredColor[control.color]
- } else if (!control.hovered && control.focus) {
- hifi.buttons.focusedColor[control.color]
- } else {
- hifi.buttons.colorStart[control.color]
- }
- }
- }
- GradientStop {
- position: 1.0
- color: {
- if (!control.enabled) {
- hifi.buttons.disabledColorFinish[control.colorScheme]
- } else if (control.pressed) {
- hifi.buttons.pressedColor[control.color]
- } else if (control.hovered) {
- hifi.buttons.hoveredColor[control.color]
- } else if (!control.hovered && control.focus) {
- hifi.buttons.focusedColor[control.color]
- } else {
- hifi.buttons.colorFinish[control.color]
- }
- }
- }
- }
- }
-
- label: Item {
- HiFiGlyphs {
- id: buttonGlyph;
- visible: root.buttonGlyph !== "";
- text: root.buttonGlyph === "" ? hifi.glyphs.question : root.buttonGlyph;
- // Size
- size: 34;
- // Anchors
- anchors.right: buttonText.left;
- anchors.top: parent.top;
- anchors.bottom: parent.bottom;
- // Style
- color: enabled ? hifi.buttons.textColor[control.color]
- : hifi.buttons.disabledTextColor[control.colorScheme];
- // Alignment
- horizontalAlignment: Text.AlignHCenter;
- verticalAlignment: Text.AlignVCenter;
- }
- RalewayBold {
- id: buttonText;
- anchors.centerIn: parent;
- font.capitalization: Font.AllUppercase
- color: enabled ? hifi.buttons.textColor[control.color]
- : hifi.buttons.disabledTextColor[control.colorScheme]
- size: hifi.fontSizes.buttonLabel
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
- text: control.text
- }
- }
- }
-}
diff --git a/interface/resources/qml/controls-uit/+android/Table.qml b/interface/resources/qml/controls-uit/+android/Table.qml
deleted file mode 100644
index 3c1d0fcd3c..0000000000
--- a/interface/resources/qml/controls-uit/+android/Table.qml
+++ /dev/null
@@ -1,165 +0,0 @@
-//
-// Table.qml
-//
-// Created by David Rowe on 18 Feb 2016
-// Copyright 2016 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-import QtQuick 2.5
-import QtQuick.Controls 1.4
-import QtQuick.Controls.Styles 1.4
-import QtQuick.Controls 2.2 as QQC2
-
-import "../styles-uit"
-
-TableView {
- id: tableView
-
- property int colorScheme: hifi.colorSchemes.light
- readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
- property bool expandSelectedRow: false
- property bool centerHeaderText: false
- readonly property real headerSpacing: 3 //spacing between sort indicator and table header title
- property var titlePaintedPos: [] // storing extra data position behind painted
- // title text and sort indicatorin table's header
- signal titlePaintedPosSignal(int column) //signal that extradata position gets changed
-
- model: ListModel { }
-
- Component.onCompleted: {
- if (flickableItem !== null && flickableItem !== undefined) {
- tableView.flickableItem.QQC2.ScrollBar.vertical = scrollbar
- }
- }
-
- QQC2.ScrollBar {
- id: scrollbar
- parent: tableView.flickableItem
- policy: QQC2.ScrollBar.AsNeeded
- orientation: Qt.Vertical
- visible: size < 1.0
- topPadding: tableView.headerVisible ? hifi.dimensions.tableHeaderHeight + 1 : 1
- anchors.top: tableView.top
- anchors.left: tableView.right
- anchors.bottom: tableView.bottom
-
- background: Item {
- implicitWidth: hifi.dimensions.scrollbarBackgroundWidth
- Rectangle {
- anchors {
- fill: parent;
- topMargin: tableView.headerVisible ? hifi.dimensions.tableHeaderHeight : 0
- }
- color: isLightColorScheme ? hifi.colors.tableScrollBackgroundLight
- : hifi.colors.tableScrollBackgroundDark
- }
- }
-
- contentItem: Item {
- implicitWidth: hifi.dimensions.scrollbarHandleWidth
- Rectangle {
- anchors.fill: parent
- radius: (width - 4)/2
- color: isLightColorScheme ? hifi.colors.tableScrollHandleLight : hifi.colors.tableScrollHandleDark
- }
- }
- }
-
- headerVisible: false
- headerDelegate: Rectangle {
- height: hifi.dimensions.tableHeaderHeight
- color: isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark
-
-
- RalewayRegular {
- id: titleText
- x: centerHeaderText ? (parent.width - paintedWidth -
- ((sortIndicatorVisible &&
- sortIndicatorColumn === styleData.column) ?
- (titleSort.paintedWidth / 5 + tableView.headerSpacing) : 0)) / 2 :
- hifi.dimensions.tablePadding
- text: styleData.value
- size: hifi.fontSizes.tableHeading
- font.capitalization: Font.AllUppercase
- color: hifi.colors.baseGrayHighlight
- horizontalAlignment: (centerHeaderText ? Text.AlignHCenter : Text.AlignLeft)
- anchors.verticalCenter: parent.verticalCenter
- }
-
- //actual image of sort indicator in glyph font only 20% of real font size
- //i.e. if the charachter size set to 60 pixels, actual image is 12 pixels
- HiFiGlyphs {
- id: titleSort
- text: sortIndicatorOrder == Qt.AscendingOrder ? hifi.glyphs.caratUp : hifi.glyphs.caratDn
- color: hifi.colors.darkGray
- opacity: 0.6;
- size: hifi.fontSizes.tableHeadingIcon
- anchors.verticalCenter: titleText.verticalCenter
- anchors.left: titleText.right
- anchors.leftMargin: -(hifi.fontSizes.tableHeadingIcon / 2.5) + tableView.headerSpacing
- visible: sortIndicatorVisible && sortIndicatorColumn === styleData.column
- onXChanged: {
- titlePaintedPos[styleData.column] = titleText.x + titleText.paintedWidth +
- paintedWidth / 5 + tableView.headerSpacing*2
- titlePaintedPosSignal(styleData.column)
- }
- }
-
- Rectangle {
- width: 1
- anchors {
- left: parent.left
- top: parent.top
- topMargin: 1
- bottom: parent.bottom
- bottomMargin: 2
- }
- color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
- visible: styleData.column > 0
- }
-
- Rectangle {
- height: 1
- anchors {
- left: parent.left
- right: parent.right
- bottom: parent.bottom
- }
- color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
- }
- }
-
- // Use rectangle to draw border with rounded corners.
- frameVisible: false
- Rectangle {
- color: "#00000000"
- anchors { fill: parent; margins: -2 }
- border.color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
- border.width: 2
- }
- anchors.margins: 2 // Shrink TableView to lie within border.
-
- backgroundVisible: true
-
- horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
- verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff
-
- style: TableViewStyle {
- // Needed in order for rows to keep displaying rows after end of table entries.
- backgroundColor: tableView.isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark
- alternateBackgroundColor: tableView.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
- padding.top: headerVisible ? hifi.dimensions.tableHeaderHeight: 0
- }
-
- rowDelegate: Rectangle {
- height: (styleData.selected && expandSelectedRow ? 1.8 : 1) * hifi.dimensions.tableRowHeight
- color: styleData.selected
- ? hifi.colors.primaryHighlight
- : tableView.isLightColorScheme
- ? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd)
- : (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd)
- }
-}
diff --git a/interface/resources/qml/desktop/+android/Desktop.qml b/interface/resources/qml/desktop/+android/Desktop.qml
deleted file mode 100644
index 6a68f63d0a..0000000000
--- a/interface/resources/qml/desktop/+android/Desktop.qml
+++ /dev/null
@@ -1,575 +0,0 @@
-//
-// Desktop.qml
-//
-// Created by Bradley Austin Davis on 15 Apr 2015
-// Copyright 2015 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-import QtQuick 2.7
-import QtQuick.Controls 1.4
-
-import "../dialogs"
-import "../js/Utils.js" as Utils
-
-// This is our primary 'desktop' object to which all VR dialogs and windows are childed.
-FocusScope {
- id: desktop
- objectName: "desktop"
- anchors.fill: parent
-
- readonly property int invalid_position: -9999;
- property rect recommendedRect: Qt.rect(0,0,0,0);
- property var expectedChildren;
- property bool repositionLocked: true
- property bool hmdHandMouseActive: false
-
- onRepositionLockedChanged: {
- if (!repositionLocked) {
- d.handleSizeChanged();
- }
-
- }
-
- onHeightChanged: d.handleSizeChanged();
-
- onWidthChanged: d.handleSizeChanged();
-
- // Controls and windows can trigger this signal to ensure the desktop becomes visible
- // when they're opened.
- signal showDesktop();
-
- // This is for JS/QML communication, which is unused in the Desktop,
- // but not having this here results in spurious warnings about a
- // missing signal
- signal sendToScript(var message);
-
- // Allows QML/JS to find the desktop through the parent chain
- property bool desktopRoot: true
-
- // The VR version of the primary menu
- property var rootMenu: Menu {
- id: rootMenuId
- objectName: "rootMenu"
-
- property var exclusionGroups: ({});
- property Component exclusiveGroupMaker: Component {
- ExclusiveGroup {
- }
- }
-
- function addExclusionGroup(qmlAction, exclusionGroup) {
-
- var exclusionGroupId = exclusionGroup.toString();
- if(!exclusionGroups[exclusionGroupId]) {
- exclusionGroups[exclusionGroupId] = exclusiveGroupMaker.createObject(rootMenuId);
- }
-
- qmlAction.exclusiveGroup = exclusionGroups[exclusionGroupId]
- }
- }
-
- // FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX/AMD
- // because shaders are 4.2, and do not include #version declarations.
- property bool gradientsSupported: Qt.platform.os != "osx" && !~GL.vendor.indexOf("ATI")
-
- readonly property alias zLevels: zLevels
- QtObject {
- id: zLevels;
- readonly property real normal: 1 // make windows always appear higher than QML overlays and other non-window controls.
- readonly property real top: 2000
- readonly property real modal: 4000
- readonly property real menu: 8000
- }
-
- QtObject {
- id: d
-
- function handleSizeChanged() {
- if (desktop.repositionLocked) {
- return;
- }
- var oldRecommendedRect = recommendedRect;
- var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect();
- var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
- newRecommendedRectJS.width,
- newRecommendedRectJS.height);
-
- var oldChildren = expectedChildren;
- var newChildren = d.getRepositionChildren();
- if (oldRecommendedRect != Qt.rect(0,0,0,0) && oldRecommendedRect != Qt.rect(0,0,1,1)
- && (oldRecommendedRect != newRecommendedRect
- || oldChildren != newChildren)
- ) {
- expectedChildren = newChildren;
- d.repositionAll();
- }
- recommendedRect = newRecommendedRect;
- }
-
- function findChild(item, name) {
- for (var i = 0; i < item.children.length; ++i) {
- if (item.children[i].objectName === name) {
- return item.children[i];
- }
- }
- return null;
- }
-
- function findParentMatching(item, predicate) {
- while (item) {
- if (predicate(item)) {
- break;
- }
- item = item.parent;
- }
- return item;
- }
-
- function findMatchingChildren(item, predicate) {
- var results = [];
- for (var i in item.children) {
- var child = item.children[i];
- if (predicate(child)) {
- results.push(child);
- }
- }
- return results;
- }
-
- function isTopLevelWindow(item) {
- return item.topLevelWindow;
- }
-
- function isAlwaysOnTopWindow(window) {
- return window.alwaysOnTop;
- }
-
- function isModalWindow(window) {
- return window.modality !== Qt.NonModal;
- }
-
- function getTopLevelWindows(predicate) {
- return findMatchingChildren(desktop, function(child) {
- return (isTopLevelWindow(child) && (!predicate || predicate(child)));
- });
- }
-
- function getDesktopWindow(item) {
- return findParentMatching(item, isTopLevelWindow)
- }
-
- function fixupZOrder(windows, basis, topWindow) {
- windows.sort(function(a, b){ return a.z - b.z; });
-
- if ((topWindow.z >= basis) && (windows[windows.length - 1] === topWindow)) {
- return;
- }
-
- var lastZ = -1;
- var lastTargetZ = basis - 1;
- for (var i = 0; i < windows.length; ++i) {
- var window = windows[i];
- if (!window.visible) {
- continue
- }
-
- if (topWindow && (topWindow === window)) {
- continue
- }
-
- if (window.z > lastZ) {
- lastZ = window.z;
- ++lastTargetZ;
- }
- if (DebugQML) {
- console.log("Assigning z order " + lastTargetZ + " to " + window)
- }
-
- window.z = lastTargetZ;
- }
- if (topWindow) {
- ++lastTargetZ;
- if (DebugQML) {
- console.log("Assigning z order " + lastTargetZ + " to " + topWindow)
- }
- topWindow.z = lastTargetZ;
- }
-
- return lastTargetZ;
- }
-
- function raiseWindow(targetWindow) {
- var predicate;
- var zBasis;
- if (isModalWindow(targetWindow)) {
- predicate = isModalWindow;
- zBasis = zLevels.modal
- } else if (isAlwaysOnTopWindow(targetWindow)) {
- predicate = function(window) {
- return (isAlwaysOnTopWindow(window) && !isModalWindow(window));
- }
- zBasis = zLevels.top
- } else {
- predicate = function(window) {
- return (!isAlwaysOnTopWindow(window) && !isModalWindow(window));
- }
- zBasis = zLevels.normal
- }
-
- var windows = getTopLevelWindows(predicate);
- fixupZOrder(windows, zBasis, targetWindow);
- }
-
- Component.onCompleted: {
- //offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged);
- focusHack.start();
- }
-
- function onWindowFocusChanged() {
- //console.log("Focus item is " + offscreenWindow.activeFocusItem);
-
- // FIXME this needs more testing before it can go into production
- // and I already cant produce any way to have a modal dialog lose focus
- // to a non-modal one.
- /*
- var focusedWindow = getDesktopWindow(offscreenWindow.activeFocusItem);
-
- if (isModalWindow(focusedWindow)) {
- return;
- }
-
- // new focused window is not modal... check if there are any modal windows
- var windows = getTopLevelWindows(isModalWindow);
- if (0 === windows.length) {
- return;
- }
-
- // There are modal windows present, force focus back to the top-most modal window
- windows.sort(function(a, b){ return a.z - b.z; });
- windows[windows.length - 1].focus = true;
- */
-
-// var focusedItem = offscreenWindow.activeFocusItem ;
-// if (DebugQML && focusedItem) {
-// var rect = desktop.mapFromItem(focusedItem, 0, 0, focusedItem.width, focusedItem.height);
-// focusDebugger.x = rect.x;
-// focusDebugger.y = rect.y;
-// focusDebugger.width = rect.width
-// focusDebugger.height = rect.height
-// }
- }
-
- function getRepositionChildren(predicate) {
- return findMatchingChildren(desktop, function(child) {
- return (child.shouldReposition === true && (!predicate || predicate(child)));
- });
- }
-
- function repositionAll() {
- if (desktop.repositionLocked) {
- return;
- }
-
- var oldRecommendedRect = recommendedRect;
- var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
- var newRecommendedRect = Controller.getRecommendedHUDRect();
- var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
- var windows = d.getTopLevelWindows();
- for (var i = 0; i < windows.length; ++i) {
- var targetWindow = windows[i];
- if (targetWindow.visible) {
- repositionWindow(targetWindow, true, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
- }
- }
-
- // also reposition the other children that aren't top level windows but want to be repositioned
- var otherChildren = d.getRepositionChildren();
- for (var i = 0; i < otherChildren.length; ++i) {
- var child = otherChildren[i];
- repositionWindow(child, true, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
- }
-
- }
- }
-
- property bool pinned: false
- property var hiddenChildren: []
-
- function togglePinned() {
- pinned = !pinned
- }
-
- function isPointOnWindow(point) {
- for (var i = 0; i < desktop.visibleChildren.length; i++) {
- var child = desktop.visibleChildren[i];
- if (child.hasOwnProperty("modality")) {
- var mappedPoint = mapToItem(child, point.x, point.y);
- if (child.hasOwnProperty("frame")) {
- var outLine = child.frame.children[2];
- var framePoint = outLine.mapFromGlobal(point.x, point.y);
- if (outLine.contains(framePoint)) {
- return true;
- }
- }
-
- if (child.contains(mappedPoint)) {
- return true;
- }
- }
- }
- return false;
- }
-
- function setPinned(newPinned) {
- pinned = newPinned
- }
-
- property real unpinnedAlpha: 1.0;
-
- Behavior on unpinnedAlpha {
- NumberAnimation {
- easing.type: Easing.Linear;
- duration: 300
- }
- }
-
- state: "NORMAL"
- states: [
- State {
- name: "NORMAL"
- PropertyChanges { target: desktop; unpinnedAlpha: 1.0 }
- },
- State {
- name: "PINNED"
- PropertyChanges { target: desktop; unpinnedAlpha: 0.0 }
- }
- ]
-
- transitions: [
- Transition {
- NumberAnimation { properties: "unpinnedAlpha"; duration: 300 }
- }
- ]
-
- onPinnedChanged: {
- if (pinned) {
- d.raiseWindow(desktop);
- desktop.focus = true;
- desktop.forceActiveFocus();
-
- // recalculate our non-pinned children
- hiddenChildren = d.findMatchingChildren(desktop, function(child){
- return !d.isTopLevelWindow(child) && child.visible && !child.pinned;
- });
-
- hiddenChildren.forEach(function(child){
- child.opacity = Qt.binding(function(){ return desktop.unpinnedAlpha });
- });
- }
- state = pinned ? "PINNED" : "NORMAL"
- }
-
- onShowDesktop: pinned = false
-
- function raise(item) {
- var targetWindow = d.getDesktopWindow(item);
- if (!targetWindow) {
- console.warn("Could not find top level window for " + item);
- return;
- }
-
- // Fix up the Z-order (takes into account if this is a modal window)
- d.raiseWindow(targetWindow);
- var setFocus = true;
- if (!d.isModalWindow(targetWindow)) {
- var modalWindows = d.getTopLevelWindows(d.isModalWindow);
- if (modalWindows.length) {
- setFocus = false;
- }
- }
-
- if (setFocus) {
- targetWindow.focus = true;
- }
-
- showDesktop();
- }
-
- function ensureTitleBarVisible(targetWindow) {
- // Reposition window to ensure that title bar is vertically inside window.
- if (targetWindow.frame && targetWindow.frame.decoration) {
- var topMargin = -targetWindow.frame.decoration.anchors.topMargin; // Frame's topMargin is a negative value.
- targetWindow.y = Math.max(targetWindow.y, topMargin);
- }
- }
-
- function centerOnVisible(item) {
- var targetWindow = d.getDesktopWindow(item);
- if (!targetWindow) {
- console.warn("Could not find top level window for " + item);
- return;
- }
-
- if (typeof Controller === "undefined") {
- console.warn("Controller not yet available... can't center");
- return;
- }
-
- var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect();
- var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
- newRecommendedRectJS.width,
- newRecommendedRectJS.height);
- var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
- var newX = newRecommendedRect.x + ((newRecommendedRect.width - targetWindow.width) / 2);
- var newY = newRecommendedRect.y + ((newRecommendedRect.height - targetWindow.height) / 2);
- targetWindow.x = newX;
- targetWindow.y = newY;
-
- ensureTitleBarVisible(targetWindow);
-
- // If we've noticed that our recommended desktop rect has changed, record that change here.
- if (recommendedRect != newRecommendedRect) {
- recommendedRect = newRecommendedRect;
- }
- }
-
- function repositionOnVisible(item) {
- var targetWindow = d.getDesktopWindow(item);
- if (!targetWindow) {
- console.warn("Could not find top level window for " + item);
- return;
- }
-
- if (typeof Controller === "undefined") {
- console.warn("Controller not yet available... can't reposition targetWindow:" + targetWindow);
- return;
- }
-
- var oldRecommendedRect = recommendedRect;
- var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
- var newRecommendedRect = Controller.getRecommendedHUDRect();
- var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
- repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
- }
-
- function repositionWindow(targetWindow, forceReposition,
- oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions) {
-
- if (desktop.width === 0 || desktop.height === 0) {
- return;
- }
-
- if (!targetWindow) {
- console.warn("Could not find top level window for " + item);
- return;
- }
-
- var recommended = Controller.getRecommendedHUDRect();
- var maxX = recommended.x + recommended.width;
- var maxY = recommended.y + recommended.height;
- var newPosition = Qt.vector2d(targetWindow.x, targetWindow.y);
-
- // if we asked to force reposition, or if the window is completely outside of the recommended rectangle, reposition it
- if (forceReposition || (targetWindow.x > maxX || (targetWindow.x + targetWindow.width) < recommended.x) ||
- (targetWindow.y > maxY || (targetWindow.y + targetWindow.height) < recommended.y)) {
- newPosition.x = -1
- newPosition.y = -1
- }
-
- if (newPosition.x === -1 && newPosition.y === -1) {
- var originRelativeX = (targetWindow.x - oldRecommendedRect.x);
- var originRelativeY = (targetWindow.y - oldRecommendedRect.y);
- if (isNaN(originRelativeX)) {
- originRelativeX = 0;
- }
- if (isNaN(originRelativeY)) {
- originRelativeY = 0;
- }
- var fractionX = Utils.clamp(originRelativeX / oldRecommendedDimmensions.x, 0, 1);
- var fractionY = Utils.clamp(originRelativeY / oldRecommendedDimmensions.y, 0, 1);
- var newX = (fractionX * newRecommendedDimmensions.x) + newRecommendedRect.x;
- var newY = (fractionY * newRecommendedDimmensions.y) + newRecommendedRect.y;
- newPosition = Qt.vector2d(newX, newY);
- }
- targetWindow.x = newPosition.x;
- targetWindow.y = newPosition.y;
-
- ensureTitleBarVisible(targetWindow);
- }
-
- Component { id: messageDialogBuilder; MessageDialog { } }
- function messageBox(properties) {
- return messageDialogBuilder.createObject(desktop, properties);
- }
-
- Component { id: inputDialogBuilder; QueryDialog { } }
- function inputDialog(properties) {
- return inputDialogBuilder.createObject(desktop, properties);
- }
-
- Component { id: customInputDialogBuilder; CustomQueryDialog { } }
- function customInputDialog(properties) {
- return customInputDialogBuilder.createObject(desktop, properties);
- }
-
- Component { id: fileDialogBuilder; FileDialog { } }
- function fileDialog(properties) {
- return fileDialogBuilder.createObject(desktop, properties);
- }
-
- Component { id: assetDialogBuilder; AssetDialog { } }
- function assetDialog(properties) {
- return assetDialogBuilder.createObject(desktop, properties);
- }
-
- function unfocusWindows() {
- // First find the active focus item, and unfocus it, all the way
- // up the parent chain to the window
- var currentFocus = offscreenWindow.activeFocusItem;
- var targetWindow = d.getDesktopWindow(currentFocus);
- while (currentFocus) {
- if (currentFocus === targetWindow) {
- break;
- }
- currentFocus.focus = false;
- currentFocus = currentFocus.parent;
- }
-
- // Unfocus all windows
- var windows = d.getTopLevelWindows();
- for (var i = 0; i < windows.length; ++i) {
- windows[i].focus = false;
- }
-
- // For the desktop to have active focus
- desktop.focus = true;
- desktop.forceActiveFocus();
- }
-
- function openBrowserWindow(request, profile) {
- var component = Qt.createComponent("../Browser.qml");
- var newWindow = component.createObject(desktop);
- newWindow.webView.profile = profile;
- request.openIn(newWindow.webView);
- }
-
- FocusHack { id: focusHack; }
-
- Rectangle {
- id: focusDebugger;
- objectName: "focusDebugger"
- z: 9999; visible: false; color: "red"
- ColorAnimation on color { from: "#7fffff00"; to: "#7f0000ff"; duration: 1000; loops: 9999 }
- }
-
- Action {
- text: "Toggle Focus Debugger"
- shortcut: "Ctrl+Shift+F"
- enabled: DebugQML
- onTriggered: focusDebugger.visible = !focusDebugger.visible
- }
-
-}
diff --git a/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml b/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml
deleted file mode 100644
index aadd7c88ae..0000000000
--- a/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml
+++ /dev/null
@@ -1,338 +0,0 @@
-//
-// CustomQueryDialog.qml
-//
-// Created by Zander Otavka on 7/14/16
-// Copyright 2016 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-import QtQuick 2.7;
-import QtQuick.Dialogs 1.2 as OriginalDialogs;
-import QtQuick.Controls 1.4;
-
-import "../controls-uit";
-import "../styles-uit";
-import "../windows";
-
-ModalWindow {
- id: root;
- HifiConstants { id: hifi; }
- implicitWidth: 640;
- implicitHeight: 320;
- visible: true;
- keyboardOverride: true // Disable ModalWindow's keyboard.
-
- signal selected(var result);
- signal canceled();
-
- property int icon: hifi.icons.none;
- property string iconText: "";
- property int iconSize: 35;
- onIconChanged: updateIcon();
-
- property var textInput;
- property var comboBox;
- property var checkBox;
- onTextInputChanged: {
- if (textInput && textInput.text !== undefined) {
- textField.text = textInput.text;
- }
- }
- onComboBoxChanged: {
- if (comboBox && comboBox.index !== undefined) {
- comboBoxField.currentIndex = comboBox.index;
- }
- }
- onCheckBoxChanged: {
- if (checkBox && checkBox.checked !== undefined) {
- checkBoxField.checked = checkBox.checked;
- }
- }
-
- property bool keyboardEnabled: false
- property bool keyboardRaised: false
- property bool punctuationMode: false
- onKeyboardRaisedChanged: d.resize();
-
- property var warning: "";
- property var result;
-
- property var implicitCheckState: null;
-
- property int titleWidth: 0;
- onTitleWidthChanged: d.resize();
-
- function updateIcon() {
- if (!root) {
- return;
- }
- iconText = hifi.glyphForIcon(root.icon);
- }
-
- function updateCheckbox() {
- if (checkBox.disableForItems) {
- var currentItemInDisableList = false;
- for (var i in checkBox.disableForItems) {
- if (comboBoxField.currentIndex === checkBox.disableForItems[i]) {
- currentItemInDisableList = true;
- break;
- }
- }
-
- if (currentItemInDisableList) {
- checkBoxField.enabled = false;
- if (checkBox.checkStateOnDisable !== null && checkBox.checkStateOnDisable !== undefined) {
- root.implicitCheckState = checkBoxField.checked;
- checkBoxField.checked = checkBox.checkStateOnDisable;
- }
- root.warning = checkBox.warningOnDisable;
- } else {
- checkBoxField.enabled = true;
- if (root.implicitCheckState !== null) {
- checkBoxField.checked = root.implicitCheckState;
- root.implicitCheckState = null;
- }
- root.warning = "";
- }
- }
- }
-
- Item {
- clip: true;
- width: pane.width;
- height: pane.height;
- anchors.margins: 0;
-
- QtObject {
- id: d;
- readonly property int minWidth: 480
- readonly property int maxWdith: 1280
- readonly property int minHeight: 120
- readonly property int maxHeight: 720
-
- function resize() {
- var targetWidth = Math.max(titleWidth, pane.width);
- var targetHeight = (textField.visible ? textField.controlHeight + hifi.dimensions.contentSpacing.y : 0) +
- (extraInputs.visible ? extraInputs.height + hifi.dimensions.contentSpacing.y : 0) +
- (buttons.height + 3 * hifi.dimensions.contentSpacing.y) +
- ((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + hifi.dimensions.contentSpacing.y) : 0);
-
- root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
- root.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ?
- d.maxHeight : targetHeight);
- }
- }
-
- Item {
- anchors {
- top: parent.top;
- bottom: extraInputs.visible ? extraInputs.top : buttons.top;
- left: parent.left;
- right: parent.right;
- margins: 0;
- }
-
- // FIXME make a text field type that can be bound to a history for autocompletion
- TextField {
- id: textField;
- label: root.textInput.label;
- focus: root.textInput ? true : false;
- visible: root.textInput ? true : false;
- anchors {
- left: parent.left;
- right: parent.right;
- bottom: keyboard.top;
- bottomMargin: hifi.dimensions.contentSpacing.y;
- }
- }
-
- Keyboard {
- id: keyboard
- raised: keyboardEnabled && keyboardRaised
- numeric: punctuationMode
- anchors {
- left: parent.left
- right: parent.right
- bottom: parent.bottom
- bottomMargin: raised ? hifi.dimensions.contentSpacing.y : 0
- }
- }
- }
-
- Item {
- id: extraInputs;
- visible: Boolean(root.checkBox || root.comboBox);
- anchors {
- left: parent.left;
- right: parent.right;
- bottom: buttons.top;
- bottomMargin: hifi.dimensions.contentSpacing.y;
- }
- height: comboBoxField.controlHeight;
- onHeightChanged: d.resize();
- onWidthChanged: d.resize();
-
- CheckBox {
- id: checkBoxField;
- text: root.checkBox.label;
- focus: Boolean(root.checkBox);
- visible: Boolean(root.checkBox);
- anchors {
- left: parent.left;
- bottom: parent.bottom;
- leftMargin: 6; // Magic number to align with warning icon
- bottomMargin: 6;
- }
- }
-
- ComboBox {
- id: comboBoxField;
- label: root.comboBox.label;
- focus: Boolean(root.comboBox);
- visible: Boolean(root.comboBox);
- Binding on x {
- when: comboBoxField.visible
- value: !checkBoxField.visible ? buttons.x : acceptButton.x
- }
-
- Binding on width {
- when: comboBoxField.visible
- value: !checkBoxField.visible ? buttons.width : buttons.width - acceptButton.x
- }
- anchors {
- right: parent.right;
- bottom: parent.bottom;
- }
- model: root.comboBox ? root.comboBox.items : [];
- onAccepted: {
- updateCheckbox();
- focus = true;
- }
- }
- }
-
- Row {
- id: buttons;
- focus: true;
- spacing: hifi.dimensions.contentSpacing.x;
- layoutDirection: Qt.RightToLeft;
- onHeightChanged: d.resize();
- onWidthChanged: {
- d.resize();
- resizeWarningText();
- }
-
- anchors {
- bottom: parent.bottom;
- left: parent.left;
- right: parent.right;
- bottomMargin: hifi.dimensions.contentSpacing.y;
- }
-
- function resizeWarningText() {
- var rowWidth = buttons.width;
- var buttonsWidth = acceptButton.width + cancelButton.width + hifi.dimensions.contentSpacing.x * 2;
- var warningIconWidth = warningIcon.width + hifi.dimensions.contentSpacing.x;
- warningText.width = rowWidth - buttonsWidth - warningIconWidth;
- }
-
- Button {
- id: cancelButton;
- action: cancelAction;
- }
-
- Button {
- id: acceptButton;
- action: acceptAction;
- }
-
- Text {
- id: warningText;
- visible: Boolean(root.warning);
- text: root.warning;
- wrapMode: Text.WordWrap;
- font.italic: true;
- maximumLineCount: 3;
- }
-
- HiFiGlyphs {
- id: warningIcon;
- visible: Boolean(root.warning);
- text: hifi.glyphs.alert;
- size: hifi.dimensions.controlLineHeight;
- width: 20 // Line up with checkbox.
- }
- }
-
- Action {
- id: cancelAction;
- text: qsTr("Cancel");
- shortcut: "Esc";
- onTriggered: {
- root.result = null;
- root.canceled();
- // FIXME we are leaking memory to avoid a crash
- // root.destroy();
-
- root.disableFade = true
- visible = false;
- }
- }
-
- Action {
- id: acceptAction;
- text: qsTr("Add");
- shortcut: "Return"
- onTriggered: {
- var result = {};
- if (textInput) {
- result.textInput = textField.text;
- }
- if (comboBox) {
- result.comboBox = comboBoxField.currentIndex;
- result.comboBoxText = comboBoxField.currentText;
- }
- if (checkBox) {
- result.checkBox = checkBoxField.enabled ? checkBoxField.checked : null;
- }
- root.result = JSON.stringify(result);
- root.selected(root.result);
- // FIXME we are leaking memory to avoid a crash
- // root.destroy();
-
- root.disableFade = true
- visible = false;
- }
- }
- }
-
- Keys.onPressed: {
- if (!visible) {
- return;
- }
-
- switch (event.key) {
- case Qt.Key_Escape:
- case Qt.Key_Back:
- cancelAction.trigger();
- event.accepted = true;
- break;
-
- case Qt.Key_Return:
- case Qt.Key_Enter:
- acceptAction.trigger();
- event.accepted = true;
- break;
- }
- }
-
- Component.onCompleted: {
- keyboardEnabled = HMD.active;
- updateIcon();
- updateCheckbox();
- d.resize();
- textField.forceActiveFocus();
- }
-}
diff --git a/interface/resources/qml/dialogs/+android/FileDialog.qml b/interface/resources/qml/dialogs/+android/FileDialog.qml
deleted file mode 100644
index be6524d2b8..0000000000
--- a/interface/resources/qml/dialogs/+android/FileDialog.qml
+++ /dev/null
@@ -1,840 +0,0 @@
-//
-// FileDialog.qml
-//
-// Created by Bradley Austin Davis on 14 Jan 2016
-// Copyright 2015 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-import QtQuick 2.7
-import Qt.labs.folderlistmodel 2.1
-import Qt.labs.settings 1.0
-import QtQuick.Dialogs 1.2 as OriginalDialogs
-import QtQuick.Controls 1.4
-
-import ".."
-import "../controls-uit"
-import "../styles-uit"
-import "../windows"
-
-import "fileDialog"
-
-//FIXME implement shortcuts for favorite location
-ModalWindow {
- id: root
- resizable: true
- implicitWidth: 480
- implicitHeight: 360 + (fileDialogItem.keyboardEnabled && fileDialogItem.keyboardRaised ? keyboard.raisedHeight + hifi.dimensions.contentSpacing.y : 0)
-
- minSize: Qt.vector2d(360, 240)
- draggable: true
-
- HifiConstants { id: hifi }
-
- property var filesModel: ListModel { }
-
- Settings {
- category: "FileDialog"
- property alias width: root.width
- property alias height: root.height
- property alias x: root.x
- property alias y: root.y
- }
-
-
- // Set from OffscreenUi::getOpenFile()
- property alias caption: root.title;
- // Set from OffscreenUi::getOpenFile()
- property alias dir: fileTableModel.folder;
- // Set from OffscreenUi::getOpenFile()
- property alias filter: selectionType.filtersString;
- // Set from OffscreenUi::getOpenFile()
- property int options; // <-- FIXME unused
-
- property string iconText: root.title !== "" ? hifi.glyphs.scriptUpload : ""
- property int iconSize: 40
-
- property bool selectDirectory: false;
- property bool showHidden: true;
- // FIXME implement
- property bool multiSelect: false;
- property bool saveDialog: false;
- property var helper: fileDialogHelper
- property alias model: fileTableView.model
- property var drives: helper.drives()
-
- property int titleWidth: 0
-
- signal selectedFile(var file);
- signal canceled();
- signal selected(int button);
- function click(button) {
- clickedButton = button;
- selected(button);
- destroy();
- }
-
- property int clickedButton: OriginalDialogs.StandardButton.NoButton;
-
- Component.onCompleted: {
- console.log("Helper " + helper + " drives " + drives);
-
- fileDialogItem.keyboardEnabled = HMD.active;
-
- // HACK: The following lines force the model to initialize properly such that the go-up button
- // works properly from the initial screen.
- var initialFolder = folderListModel.folder;
- fileTableModel.folder = helper.pathToUrl(drives[0]);
- fileTableModel.folder = initialFolder;
-
- iconText = root.title !== "" ? hifi.glyphs.scriptUpload : "";
-
- // Clear selection when click on external frame.
- frameClicked.connect(function() { d.clearSelection(); });
-
- if (selectDirectory) {
- currentSelection.text = d.capitalizeDrive(helper.urlToPath(initialFolder));
- d.currentSelectionIsFolder = true;
- d.currentSelectionUrl = initialFolder;
- }
-
- helper.contentsChanged.connect(function() {
- if (folderListModel) {
- // Make folderListModel refresh.
- var save = folderListModel.folder;
- folderListModel.folder = "";
- folderListModel.folder = save;
- }
- });
-
- focusTimer.start();
- }
-
- Timer {
- id: focusTimer
- interval: 10
- running: false
- repeat: false
- onTriggered: {
- fileTableView.contentItem.forceActiveFocus();
- }
- }
-
- Item {
- id: fileDialogItem
- clip: true
- width: pane.width
- height: pane.height
- anchors.margins: 0
-
- property bool keyboardEnabled: false
- property bool keyboardRaised: false
- property bool punctuationMode: false
-
- MouseArea {
- // Clear selection when click on internal unused area.
- anchors.fill: parent
- drag.target: root
- onClicked: {
- d.clearSelection();
- // Defocus text field so that the keyboard gets hidden.
- // Clicking also breaks keyboard navigation apart from backtabbing to cancel
- frame.forceActiveFocus();
- }
- }
-
- Row {
- id: navControls
- anchors {
- top: parent.top
- topMargin: hifi.dimensions.contentMargin.y
- left: parent.left
- }
- spacing: hifi.dimensions.contentSpacing.x
-
- GlyphButton {
- id: upButton
- glyph: hifi.glyphs.levelUp
- width: height
- size: 30
- enabled: fileTableModel.parentFolder && fileTableModel.parentFolder !== ""
- onClicked: d.navigateUp();
- Keys.onReturnPressed: { d.navigateUp(); }
- KeyNavigation.tab: homeButton
- KeyNavigation.backtab: upButton
- KeyNavigation.left: upButton
- KeyNavigation.right: homeButton
- }
-
- GlyphButton {
- id: homeButton
- property var destination: helper.home();
- glyph: hifi.glyphs.home
- size: 28
- width: height
- enabled: d.homeDestination ? true : false
- onClicked: d.navigateHome();
- Keys.onReturnPressed: { d.navigateHome(); }
- KeyNavigation.tab: fileTableView.contentItem
- KeyNavigation.backtab: upButton
- KeyNavigation.left: upButton
- }
- }
-
- ComboBox {
- id: pathSelector
- anchors {
- top: parent.top
- topMargin: hifi.dimensions.contentMargin.y
- left: navControls.right
- leftMargin: hifi.dimensions.contentSpacing.x
- right: parent.right
- }
-
- property var lastValidFolder: helper.urlToPath(fileTableModel.folder)
-
- function calculatePathChoices(folder) {
- var folders = folder.split("/"),
- choices = [],
- i, length;
-
- if (folders[folders.length - 1] === "") {
- folders.pop();
- }
-
- choices.push(folders[0]);
-
- for (i = 1, length = folders.length; i < length; i++) {
- choices.push(choices[i - 1] + "/" + folders[i]);
- }
-
- if (folders[0] === "") {
- // Special handling for OSX root dir.
- choices[0] = "/";
- }
-
- choices.reverse();
-
- if (drives && drives.length > 1) {
- choices.push("This PC");
- }
-
- if (choices.length > 0) {
- pathSelector.model = choices;
- }
- }
-
- onLastValidFolderChanged: {
- var folder = d.capitalizeDrive(lastValidFolder);
- calculatePathChoices(folder);
- }
-
- onCurrentTextChanged: {
- var folder = currentText;
-
- if (/^[a-zA-z]:$/.test(folder)) {
- folder = "file:///" + folder + "/";
- } else if (folder === "This PC") {
- folder = "file:///";
- } else {
- folder = helper.pathToUrl(folder);
- }
-
- if (helper.urlToPath(folder).toLowerCase() !== helper.urlToPath(fileTableModel.folder).toLowerCase()) {
- if (root.selectDirectory) {
- currentSelection.text = currentText !== "This PC" ? currentText : "";
- d.currentSelectionUrl = helper.pathToUrl(currentText);
- }
- fileTableModel.folder = folder;
- }
- }
-
- KeyNavigation.up: fileTableView.contentItem
- KeyNavigation.down: fileTableView.contentItem
- KeyNavigation.tab: fileTableView.contentItem
- KeyNavigation.backtab: fileTableView.contentItem
- KeyNavigation.left: fileTableView.contentItem
- KeyNavigation.right: fileTableView.contentItem
- }
-
- QtObject {
- id: d
- property var currentSelectionUrl;
- readonly property string currentSelectionPath: helper.urlToPath(currentSelectionUrl);
- property bool currentSelectionIsFolder;
- property var backStack: []
- property var tableViewConnection: Connections { target: fileTableView; onCurrentRowChanged: d.update(); }
- property var modelConnection: Connections { target: fileTableModel; onFolderChanged: d.update(); }
- property var homeDestination: helper.home();
-
- function capitalizeDrive(path) {
- // Consistently capitalize drive letter for Windows.
- if (/[a-zA-Z]:/.test(path)) {
- return path.charAt(0).toUpperCase() + path.slice(1);
- }
- return path;
- }
-
- function update() {
- var row = fileTableView.currentRow;
-
- if (row === -1) {
- if (!root.selectDirectory) {
- currentSelection.text = "";
- currentSelectionIsFolder = false;
- }
- return;
- }
-
- currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath);
- currentSelectionIsFolder = fileTableView.model !== filesModel ?
- fileTableView.model.isFolder(row) :
- fileTableModel.isFolder(row);
- if (root.selectDirectory || !currentSelectionIsFolder) {
- currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl));
- } else {
- currentSelection.text = "";
- }
- }
-
- function navigateUp() {
- if (fileTableModel.parentFolder && fileTableModel.parentFolder !== "") {
- fileTableModel.folder = fileTableModel.parentFolder;
- return true;
- }
- }
-
- function navigateHome() {
- fileTableModel.folder = homeDestination;
- return true;
- }
-
- function clearSelection() {
- fileTableView.selection.clear();
- fileTableView.currentRow = -1;
- update();
- }
- }
-
- FolderListModel {
- id: folderListModel
- nameFilters: selectionType.currentFilter
- showDirsFirst: true
- showDotAndDotDot: false
- showFiles: !root.selectDirectory
- showHidden: root.showHidden
- Component.onCompleted: {
- showFiles = !root.selectDirectory
- showHidden = root.showHidden
- }
-
- onFolderChanged: {
- d.clearSelection();
- fileTableModel.update(); // Update once the data from the folder change is available.
- }
-
- function getItem(index, field) {
- return get(index, field);
- }
- }
-
- ListModel {
- // Emulates FolderListModel but contains drive data.
- id: driveListModel
-
- property int count: 1
-
- Component.onCompleted: initialize();
-
- function initialize() {
- var drive,
- i;
-
- count = drives.length;
-
- for (i = 0; i < count; i++) {
- drive = drives[i].slice(0, -1); // Remove trailing "/".
- append({
- fileName: drive,
- fileModified: new Date(0),
- fileSize: 0,
- filePath: drive + "/",
- fileIsDir: true,
- fileNameSort: drive.toLowerCase()
- });
- }
- }
-
- function getItem(index, field) {
- return get(index)[field];
- }
- }
-
- Component {
- id: filesModelBuilder
- ListModel { }
- }
-
- QtObject {
- id: fileTableModel
-
- // FolderListModel has a couple of problems:
- // 1) Files and directories sort case-sensitively: https://bugreports.qt.io/browse/QTBUG-48757
- // 2) Cannot browse up to the "computer" level to view Windows drives: https://bugreports.qt.io/browse/QTBUG-42901
- //
- // To solve these problems an intermediary ListModel is used that implements proper sorting and can be populated with
- // drive information when viewing at the computer level.
-
- property var folder
- property int sortOrder: Qt.AscendingOrder
- property int sortColumn: 0
- property var model: folderListModel
- property string parentFolder: calculateParentFolder();
-
- readonly property string rootFolder: "file:///"
-
- function calculateParentFolder() {
- if (model === folderListModel) {
- if (folderListModel.parentFolder.toString() === "" && driveListModel.count > 1) {
- return rootFolder;
- } else {
- return folderListModel.parentFolder;
- }
- } else {
- return "";
- }
- }
-
- onFolderChanged: {
- if (folder === rootFolder) {
- model = driveListModel;
- helper.monitorDirectory("");
- update();
- } else {
- var needsUpdate = model === driveListModel && folder === folderListModel.folder;
-
- model = folderListModel;
- folderListModel.folder = folder;
- helper.monitorDirectory(helper.urlToPath(folder));
-
- if (needsUpdate) {
- update();
- }
- }
- }
-
- function isFolder(row) {
- if (row === -1) {
- return false;
- }
- return filesModel.get(row).fileIsDir;
- }
-
- function get(row) {
- return filesModel.get(row)
- }
-
- function update() {
- var dataFields = ["fileName", "fileModified", "fileSize"],
- sortFields = ["fileNameSort", "fileModified", "fileSize"],
- dataField = dataFields[sortColumn],
- sortField = sortFields[sortColumn],
- sortValue,
- fileName,
- fileIsDir,
- comparisonFunction,
- lower,
- middle,
- upper,
- rows = 0,
- i;
-
- filesModel = filesModelBuilder.createObject(root);
-
- comparisonFunction = sortOrder === Qt.AscendingOrder
- ? function(a, b) { return a < b; }
- : function(a, b) { return a > b; }
-
- for (i = 0; i < model.count; i++) {
- fileName = model.getItem(i, "fileName");
- fileIsDir = model.getItem(i, "fileIsDir");
-
- sortValue = model.getItem(i, dataField);
- if (dataField === "fileName") {
- // Directories first by prefixing a "*".
- // Case-insensitive.
- sortValue = (fileIsDir ? "*" : "") + sortValue.toLowerCase();
- }
-
- lower = 0;
- upper = rows;
- while (lower < upper) {
- middle = Math.floor((lower + upper) / 2);
- var lessThan;
- if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
- lessThan = true;
- upper = middle;
- } else {
- lessThan = false;
- lower = middle + 1;
- }
- }
-
- filesModel.insert(lower, {
- fileName: fileName,
- fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
- fileSize: model.getItem(i, "fileSize"),
- filePath: model.getItem(i, "filePath"),
- fileIsDir: fileIsDir,
- fileNameSort: (fileIsDir ? "*" : "") + fileName.toLowerCase()
- });
-
- rows++;
- }
- }
- }
-
- Table {
- id: fileTableView
- colorScheme: hifi.colorSchemes.light
- anchors {
- top: navControls.bottom
- topMargin: hifi.dimensions.contentSpacing.y
- left: parent.left
- right: parent.right
- bottom: currentSelection.top
- bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height
- }
- headerVisible: !selectDirectory
- onDoubleClicked: navigateToRow(row);
- Keys.onReturnPressed: navigateToCurrentRow();
- Keys.onEnterPressed: navigateToCurrentRow();
-
- sortIndicatorColumn: 0
- sortIndicatorOrder: Qt.AscendingOrder
- sortIndicatorVisible: true
-
- model: filesModel
-
- function updateSort() {
- fileTableModel.sortOrder = sortIndicatorOrder;
- fileTableModel.sortColumn = sortIndicatorColumn;
- fileTableModel.update();
- }
-
- onSortIndicatorColumnChanged: { updateSort(); }
-
- onSortIndicatorOrderChanged: { updateSort(); }
-
- itemDelegate: Item {
- clip: true
-
- FiraSansSemiBold {
- text: getText();
- elide: styleData.elideMode
- anchors {
- left: parent.left
- leftMargin: hifi.dimensions.tablePadding
- right: parent.right
- rightMargin: hifi.dimensions.tablePadding
- verticalCenter: parent.verticalCenter
- }
- size: hifi.fontSizes.tableText
- color: hifi.colors.baseGrayHighlight
- font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir)
- ? "Fira Sans SemiBold" : "Fira Sans"
-
- function getText() {
- if (styleData.row === -1) {
- return styleData.value;
- }
-
- switch (styleData.column) {
- case 1: return fileTableView.model.get(styleData.row).fileIsDir ? "" : styleData.value;
- case 2: return fileTableView.model.get(styleData.row).fileIsDir ? "" : formatSize(styleData.value);
- default: return styleData.value;
- }
- }
- function formatSize(size) {
- var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ];
- var suffixIndex = 0
- while ((size / 1024.0) > 1.1) {
- size /= 1024.0;
- ++suffixIndex;
- }
-
- size = Math.round(size*1000)/1000;
- size = size.toLocaleString()
-
- return size + " " + suffixes[suffixIndex];
- }
- }
- }
-
- TableViewColumn {
- id: fileNameColumn
- role: "fileName"
- title: "Name"
- width: (selectDirectory ? 1.0 : 0.5) * fileTableView.width
- movable: false
- resizable: true
- }
- TableViewColumn {
- id: fileModifiedColumn
- role: "fileModified"
- title: "Date"
- width: 0.3 * fileTableView.width
- movable: false
- resizable: true
- visible: !selectDirectory
- }
- TableViewColumn {
- role: "fileSize"
- title: "Size"
- width: fileTableView.width - fileNameColumn.width - fileModifiedColumn.width
- movable: false
- resizable: true
- visible: !selectDirectory
- }
-
- function navigateToRow(row) {
- currentRow = row;
- navigateToCurrentRow();
- }
-
- function navigateToCurrentRow() {
- var currentModel = fileTableView.model !== filesModel ? fileTableView.model : fileTableModel
- var row = fileTableView.currentRow
- var isFolder = currentModel.isFolder(row);
- var file = currentModel.get(row).filePath;
- if (isFolder) {
- currentModel.folder = helper.pathToUrl(file);
- } else {
- okAction.trigger();
- }
- }
-
- property string prefix: ""
-
- function addToPrefix(event) {
- if (!event.text || event.text === "") {
- return false;
- }
- var newPrefix = prefix + event.text.toLowerCase();
- var matchedIndex = -1;
- for (var i = 0; i < model.count; ++i) {
- var name = model !== filesModel ? model.get(i).fileName.toLowerCase() :
- filesModel.get(i).fileName.toLowerCase();
- if (0 === name.indexOf(newPrefix)) {
- matchedIndex = i;
- break;
- }
- }
-
- if (matchedIndex !== -1) {
- fileTableView.selection.clear();
- fileTableView.selection.select(matchedIndex);
- fileTableView.currentRow = matchedIndex;
- fileTableView.prefix = newPrefix;
- }
- prefixClearTimer.restart();
- return true;
- }
-
- Timer {
- id: prefixClearTimer
- interval: 1000
- repeat: false
- running: false
- onTriggered: fileTableView.prefix = "";
- }
-
- Keys.onPressed: {
- switch (event.key) {
- case Qt.Key_Backspace:
- case Qt.Key_Tab:
- case Qt.Key_Backtab:
- event.accepted = false;
- break;
- case Qt.Key_Escape:
- event.accepted = true;
- root.click(OriginalDialogs.StandardButton.Cancel);
- break;
- default:
- if (addToPrefix(event)) {
- event.accepted = true
- } else {
- event.accepted = false;
- }
- break;
- }
- }
-
- KeyNavigation.tab: root.saveDialog ? currentSelection : openButton
- }
-
- TextField {
- id: currentSelection
- label: selectDirectory ? "Directory:" : "File name:"
- anchors {
- left: parent.left
- right: selectionType.visible ? selectionType.left: parent.right
- rightMargin: selectionType.visible ? hifi.dimensions.contentSpacing.x : 0
- bottom: keyboard.top
- bottomMargin: hifi.dimensions.contentSpacing.y
- }
- readOnly: !root.saveDialog
- activeFocusOnTab: !readOnly
- onActiveFocusChanged: if (activeFocus) { selectAll(); }
- onAccepted: okAction.trigger();
- KeyNavigation.up: fileTableView.contentItem
- KeyNavigation.down: openButton
- KeyNavigation.tab: openButton
- KeyNavigation.backtab: fileTableView.contentItem
- }
-
- FileTypeSelection {
- id: selectionType
- anchors {
- top: currentSelection.top
- left: buttonRow.left
- right: parent.right
- }
- visible: !selectDirectory && filtersCount > 1
- }
-
- Keyboard {
- id: keyboard
- raised: parent.keyboardEnabled && parent.keyboardRaised
- numeric: parent.punctuationMode
- anchors {
- left: parent.left
- right: parent.right
- bottom: buttonRow.top
- bottomMargin: visible ? hifi.dimensions.contentSpacing.y : 0
- }
- }
-
- Row {
- id: buttonRow
- anchors {
- right: parent.right
- bottom: parent.bottom
- }
- spacing: hifi.dimensions.contentSpacing.y
-
- Button {
- id: openButton
- color: hifi.buttons.blue
- action: okAction
- Keys.onReturnPressed: okAction.trigger()
- KeyNavigation.right: cancelButton
- KeyNavigation.up: root.saveDialog ? currentSelection : fileTableView.contentItem
- KeyNavigation.tab: cancelButton
- }
-
- Button {
- id: cancelButton
- action: cancelAction
- Keys.onReturnPressed: { cancelAction.trigger() }
- KeyNavigation.left: openButton
- KeyNavigation.up: root.saveDialog ? currentSelection : fileTableView.contentItem
- KeyNavigation.backtab: openButton
- }
- }
-
- Action {
- id: okAction
- text: currentSelection.text ? (root.selectDirectory && fileTableView.currentRow === -1 ? "Choose" : (root.saveDialog ? "Save" : "Open")) : "Open"
- enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false
- onTriggered: {
- if (!root.selectDirectory && !d.currentSelectionIsFolder
- || root.selectDirectory && fileTableView.currentRow === -1) {
- okActionTimer.start();
- } else {
- fileTableView.navigateToCurrentRow();
- }
- }
- }
-
- Timer {
- id: okActionTimer
- interval: 50
- running: false
- repeat: false
- onTriggered: {
- if (!root.saveDialog) {
- selectedFile(d.currentSelectionUrl);
- root.destroy()
- return;
- }
-
- // Handle the ambiguity between different cases
- // * typed name (with or without extension)
- // * full path vs relative vs filename only
- var selection = helper.saveHelper(currentSelection.text, root.dir, selectionType.currentFilter);
-
- if (!selection) {
- desktop.messageBox({ icon: OriginalDialogs.StandardIcon.Warning, text: "Unable to parse selection" })
- return;
- }
-
- if (helper.urlIsDir(selection)) {
- root.dir = selection;
- currentSelection.text = "";
- return;
- }
-
- // Check if the file is a valid target
- if (!helper.urlIsWritable(selection)) {
- desktop.messageBox({
- icon: OriginalDialogs.StandardIcon.Warning,
- text: "Unable to write to location " + selection
- })
- return;
- }
-
- if (helper.urlExists(selection)) {
- var messageBox = desktop.messageBox({
- icon: OriginalDialogs.StandardIcon.Question,
- buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No,
- text: "Do you wish to overwrite " + selection + "?",
- });
- var result = messageBox.exec();
- if (OriginalDialogs.StandardButton.Yes !== result) {
- return;
- }
- }
-
- console.log("Selecting " + selection)
- selectedFile(selection);
- root.destroy();
- }
- }
-
- Action {
- id: cancelAction
- text: "Cancel"
- onTriggered: { canceled(); root.shown = false; }
- }
- }
-
- Keys.onPressed: {
- switch (event.key) {
- case Qt.Key_Backspace:
- event.accepted = d.navigateUp();
- break;
-
- case Qt.Key_Home:
- event.accepted = d.navigateHome();
- break;
-
- case Qt.Key_Escape:
- event.accepted = true;
- root.click(OriginalDialogs.StandardButton.Cancel);
- break;
- }
- }
-}
diff --git a/interface/resources/qml/dialogs/+android/QueryDialog.qml b/interface/resources/qml/dialogs/+android/QueryDialog.qml
deleted file mode 100644
index aec6d8a286..0000000000
--- a/interface/resources/qml/dialogs/+android/QueryDialog.qml
+++ /dev/null
@@ -1,231 +0,0 @@
-//
-// QueryDialog.qml
-//
-// Created by Bradley Austin Davis on 22 Jan 2016
-// Copyright 2015 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-import QtQuick 2.7
-import QtQuick.Controls 1.4
-
-import "../controls-uit"
-import "../styles-uit"
-import "../windows"
-
-ModalWindow {
- id: root
- HifiConstants { id: hifi }
- implicitWidth: 640
- implicitHeight: 320
- visible: true
- keyboardOverride: true // Disable ModalWindow's keyboard.
-
- signal selected(var result);
- signal canceled();
-
- property int icon: hifi.icons.none
- property string iconText: ""
- property int iconSize: 35
- onIconChanged: updateIcon();
-
- property var items;
- property string label
- property var result;
- property alias current: textResult.text
-
- // For text boxes
- property alias placeholderText: textResult.placeholderText
-
- // For combo boxes
- property bool editable: true;
-
- property int titleWidth: 0
- onTitleWidthChanged: d.resize();
-
- property bool keyboardEnabled: false
- property bool keyboardRaised: false
- property bool punctuationMode: false
-
- onKeyboardRaisedChanged: d.resize();
-
- function updateIcon() {
- if (!root) {
- return;
- }
- iconText = hifi.glyphForIcon(root.icon);
- }
-
- Item {
- id: modalWindowItem
- clip: true
- width: pane.width
- height: pane.height
- anchors.margins: 0
-
- QtObject {
- id: d
- readonly property int minWidth: 480
- readonly property int maxWdith: 1280
- readonly property int minHeight: 120
- readonly property int maxHeight: 720
-
- function resize() {
- var targetWidth = Math.max(titleWidth, pane.width)
- var targetHeight = (items ? comboBox.controlHeight : textResult.controlHeight) + 5 * hifi.dimensions.contentSpacing.y + buttons.height
- root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
- root.height = ((targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)) + ((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + 2 * hifi.dimensions.contentSpacing.y) : 0)
- }
- }
-
- Item {
- anchors {
- top: parent.top
- bottom: keyboard.top;
- left: parent.left;
- right: parent.right;
- margins: 0
- bottomMargin: 2 * hifi.dimensions.contentSpacing.y
- }
-
- // FIXME make a text field type that can be bound to a history for autocompletion
- TextField {
- id: textResult
- label: root.label
- visible: items ? false : true
- anchors {
- left: parent.left;
- right: parent.right;
- bottom: parent.bottom
- }
- KeyNavigation.down: acceptButton
- KeyNavigation.tab: acceptButton
- }
-
- ComboBox {
- id: comboBox
- label: root.label
- visible: items ? true : false
- anchors {
- left: parent.left
- right: parent.right
- bottom: parent.bottom
- }
- model: items ? items : []
- KeyNavigation.down: acceptButton
- KeyNavigation.tab: acceptButton
- }
- }
-
- property alias keyboardOverride: root.keyboardOverride
- property alias keyboardRaised: root.keyboardRaised
- property alias punctuationMode: root.punctuationMode
- Keyboard {
- id: keyboard
- raised: keyboardEnabled && keyboardRaised
- numeric: punctuationMode
- anchors {
- left: parent.left
- right: parent.right
- bottom: buttons.top
- bottomMargin: raised ? 2 * hifi.dimensions.contentSpacing.y : 0
- }
- }
-
- Flow {
- id: buttons
- spacing: hifi.dimensions.contentSpacing.x
- onHeightChanged: d.resize(); onWidthChanged: d.resize();
- layoutDirection: Qt.RightToLeft
- anchors {
- bottom: parent.bottom
- right: parent.right
- margins: 0
- bottomMargin: hifi.dimensions.contentSpacing.y
- }
- Button {
- id: cancelButton
- action: cancelAction
- KeyNavigation.left: acceptButton
- KeyNavigation.up: items ? comboBox : textResult
- KeyNavigation.backtab: acceptButton
- }
- Button {
- id: acceptButton
- action: acceptAction
- KeyNavigation.right: cancelButton
- KeyNavigation.up: items ? comboBox : textResult
- KeyNavigation.tab: cancelButton
- KeyNavigation.backtab: items ? comboBox : textResult
- }
- }
-
- Action {
- id: cancelAction
- text: qsTr("Cancel");
- shortcut: "Esc"
- onTriggered: {
- root.canceled();
- // FIXME we are leaking memory to avoid a crash
- // root.destroy();
-
- root.disableFade = true
- visible = false;
- }
- }
-
- Action {
- id: acceptAction
- text: qsTr("OK");
- shortcut: "Return"
- onTriggered: {
- root.result = items ? comboBox.currentText : textResult.text
- root.selected(root.result);
- // FIXME we are leaking memory to avoid a crash
- // root.destroy();
-
- root.disableFade = true
- visible = false;
- }
- }
- }
-
- Keys.onPressed: {
- if (!visible) {
- return
- }
-
- switch (event.key) {
- case Qt.Key_Escape:
- case Qt.Key_Back:
- cancelAction.trigger()
- event.accepted = true;
- break;
-
- case Qt.Key_Return:
- case Qt.Key_Enter:
- if (acceptButton.focus) {
- acceptAction.trigger()
- } else if (cancelButton.focus) {
- cancelAction.trigger()
- } else if (comboBox.focus || comboBox.popup.focus) {
- comboBox.showList()
- }
- event.accepted = true;
- break;
- }
- }
-
- Component.onCompleted: {
- keyboardEnabled = HMD.active;
- updateIcon();
- d.resize();
- if (items) {
- comboBox.forceActiveFocus()
- } else {
- textResult.forceActiveFocus()
- }
- }
-}
diff --git a/interface/resources/qml/dialogs/assetDialog/+android/AssetDialogContent.qml b/interface/resources/qml/dialogs/assetDialog/+android/AssetDialogContent.qml
deleted file mode 100644
index 54bdb0a888..0000000000
--- a/interface/resources/qml/dialogs/assetDialog/+android/AssetDialogContent.qml
+++ /dev/null
@@ -1,533 +0,0 @@
-//
-// AssetDialogContent.qml
-//
-// Created by David Rowe on 19 Apr 2017
-// Copyright 2017 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-import QtQuick 2.7
-import QtQuick.Controls 1.5
-
-import "../../controls-uit"
-import "../../styles-uit"
-
-import "../fileDialog"
-
-Item {
- // Set from OffscreenUi::assetDialog()
- property alias dir: assetTableModel.folder
- property alias filter: selectionType.filtersString // FIXME: Currently only supports simple filters, "*.xxx".
- property int options // Not used.
-
- property bool selectDirectory: false
-
- // Not implemented.
- //property bool saveDialog: false;
- //property bool multiSelect: false;
-
- property bool singleClickNavigate: false
-
- HifiConstants { id: hifi }
-
- Component.onCompleted: {
- homeButton.destination = dir;
-
- if (selectDirectory) {
- d.currentSelectionIsFolder = true;
- d.currentSelectionPath = assetTableModel.folder;
- }
-
- assetTableView.forceActiveFocus();
- }
-
- Item {
- id: assetDialogItem
- anchors.fill: parent
- clip: true
-
- MouseArea {
- // Clear selection when click on internal unused area.
- anchors.fill: parent
- drag.target: root
- onClicked: {
- d.clearSelection();
- frame.forceActiveFocus();
- assetTableView.forceActiveFocus();
- }
- }
-
- Row {
- id: navControls
- anchors {
- top: parent.top
- topMargin: hifi.dimensions.contentMargin.y
- left: parent.left
- }
- spacing: hifi.dimensions.contentSpacing.x
-
- GlyphButton {
- id: upButton
- glyph: hifi.glyphs.levelUp
- width: height
- size: 30
- enabled: assetTableModel.parentFolder !== ""
- onClicked: d.navigateUp();
- }
-
- GlyphButton {
- id: homeButton
- property string destination: ""
- glyph: hifi.glyphs.home
- size: 28
- width: height
- enabled: destination !== ""
- //onClicked: d.navigateHome();
- onClicked: assetTableModel.folder = destination;
- }
- }
-
- ComboBox {
- id: pathSelector
- anchors {
- top: parent.top
- topMargin: hifi.dimensions.contentMargin.y
- left: navControls.right
- leftMargin: hifi.dimensions.contentSpacing.x
- right: parent.right
- }
- z: 10
-
- property string lastValidFolder: assetTableModel.folder
-
- function calculatePathChoices(folder) {
- var folders = folder.split("/"),
- choices = [],
- i, length;
-
- if (folders[folders.length - 1] === "") {
- folders.pop();
- }
-
- choices.push(folders[0]);
-
- for (i = 1, length = folders.length; i < length; i++) {
- choices.push(choices[i - 1] + "/" + folders[i]);
- }
-
- if (folders[0] === "") {
- choices[0] = "/";
- }
-
- choices.reverse();
-
- if (choices.length > 0) {
- pathSelector.model = choices;
- }
- }
-
- onLastValidFolderChanged: {
- var folder = lastValidFolder;
- calculatePathChoices(folder);
- }
-
- onCurrentTextChanged: {
- var folder = currentText;
-
- if (folder !== "/") {
- folder += "/";
- }
-
- if (folder !== assetTableModel.folder) {
- if (root.selectDirectory) {
- currentSelection.text = currentText;
- d.currentSelectionPath = currentText;
- }
- assetTableModel.folder = folder;
- assetTableView.forceActiveFocus();
- }
- }
- }
-
- QtObject {
- id: d
-
- property string currentSelectionPath
- property bool currentSelectionIsFolder
- property var tableViewConnection: Connections { target: assetTableView; onCurrentRowChanged: d.update(); }
-
- function update() {
- var row = assetTableView.currentRow;
-
- if (row === -1) {
- if (!root.selectDirectory) {
- currentSelection.text = "";
- currentSelectionIsFolder = false;
- }
- return;
- }
-
- var rowInfo = assetTableModel.get(row);
- currentSelectionPath = rowInfo.filePath;
- currentSelectionIsFolder = rowInfo.fileIsDir;
- if (root.selectDirectory || !currentSelectionIsFolder) {
- currentSelection.text = currentSelectionPath;
- } else {
- currentSelection.text = "";
- }
- }
-
- function navigateUp() {
- if (assetTableModel.parentFolder !== "") {
- assetTableModel.folder = assetTableModel.parentFolder;
- return true;
- }
- return false;
- }
-
- function navigateHome() {
- assetTableModel.folder = homeButton.destination;
- return true;
- }
-
- function clearSelection() {
- assetTableView.selection.clear();
- assetTableView.currentRow = -1;
- update();
- }
- }
-
- ListModel {
- id: assetTableModel
-
- property string folder
- property string parentFolder: ""
- readonly property string rootFolder: "/"
-
- onFolderChanged: {
- parentFolder = calculateParentFolder();
- update();
- }
-
- function calculateParentFolder() {
- if (folder !== "/") {
- return folder.slice(0, folder.slice(0, -1).lastIndexOf("/") + 1);
- }
- return "";
- }
-
- function isFolder(row) {
- if (row === -1) {
- return false;
- }
- return get(row).fileIsDir;
- }
-
- function onGetAllMappings(error, map) {
- var mappings,
- fileTypeFilter,
- index,
- path,
- fileName,
- fileType,
- fileIsDir,
- isValid,
- subDirectory,
- subDirectories = [],
- fileNameSort,
- rows = 0,
- lower,
- middle,
- upper,
- i,
- length;
-
- clear();
-
- if (error === "") {
- mappings = Object.keys(map);
- fileTypeFilter = filter.replace("*", "").toLowerCase();
-
- for (i = 0, length = mappings.length; i < length; i++) {
- index = mappings[i].lastIndexOf("/");
-
- path = mappings[i].slice(0, mappings[i].lastIndexOf("/") + 1);
- fileName = mappings[i].slice(path.length);
- fileType = fileName.slice(fileName.lastIndexOf("."));
- fileIsDir = false;
- isValid = false;
-
- if (fileType.toLowerCase() === fileTypeFilter) {
- if (path === folder) {
- isValid = !selectDirectory;
- } else if (path.length > folder.length) {
- subDirectory = path.slice(folder.length);
- index = subDirectory.indexOf("/");
- if (index === subDirectory.lastIndexOf("/")) {
- fileName = subDirectory.slice(0, index);
- if (subDirectories.indexOf(fileName) === -1) {
- fileIsDir = true;
- isValid = true;
- subDirectories.push(fileName);
- }
- }
- }
- }
-
- if (isValid) {
- fileNameSort = (fileIsDir ? "*" : "") + fileName.toLowerCase();
-
- lower = 0;
- upper = rows;
- while (lower < upper) {
- middle = Math.floor((lower + upper) / 2);
- var lessThan;
- if (fileNameSort < get(middle)["fileNameSort"]) {
- lessThan = true;
- upper = middle;
- } else {
- lessThan = false;
- lower = middle + 1;
- }
- }
-
- insert(lower, {
- fileName: fileName,
- filePath: path + (fileIsDir ? "" : fileName),
- fileIsDir: fileIsDir,
- fileNameSort: fileNameSort
- });
-
- rows++;
- }
- }
-
- } else {
- console.log("Error getting mappings from Asset Server");
- }
- }
-
- function update() {
- d.clearSelection();
- clear();
- Assets.getAllMappings(onGetAllMappings);
- }
- }
-
- Table {
- id: assetTableView
- colorScheme: hifi.colorSchemes.light
- anchors {
- top: navControls.bottom
- topMargin: hifi.dimensions.contentSpacing.y
- left: parent.left
- right: parent.right
- bottom: currentSelection.top
- bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height
- }
-
- model: assetTableModel
-
- focus: true
-
- onClicked: {
- if (singleClickNavigate) {
- navigateToRow(row);
- }
- }
-
- onDoubleClicked: navigateToRow(row);
- Keys.onReturnPressed: navigateToCurrentRow();
- Keys.onEnterPressed: navigateToCurrentRow();
-
- itemDelegate: Item {
- clip: true
-
- FiraSansSemiBold {
- text: styleData.value
- elide: styleData.elideMode
- anchors {
- left: parent.left
- leftMargin: hifi.dimensions.tablePadding
- right: parent.right
- rightMargin: hifi.dimensions.tablePadding
- verticalCenter: parent.verticalCenter
- }
- size: hifi.fontSizes.tableText
- color: hifi.colors.baseGrayHighlight
- font.family: (styleData.row !== -1 && assetTableView.model.get(styleData.row).fileIsDir)
- ? "Fira Sans SemiBold" : "Fira Sans"
- }
- }
-
- TableViewColumn {
- id: fileNameColumn
- role: "fileName"
- title: "Name"
- width: assetTableView.width
- movable: false
- resizable: false
- }
-
- function navigateToRow(row) {
- currentRow = row;
- navigateToCurrentRow();
- }
-
- function navigateToCurrentRow() {
- if (model.isFolder(currentRow)) {
- model.folder = model.get(currentRow).filePath;
- } else {
- okAction.trigger();
- }
- }
-
- Timer {
- id: prefixClearTimer
- interval: 1000
- repeat: false
- running: false
- onTriggered: assetTableView.prefix = "";
- }
-
- property string prefix: ""
-
- function addToPrefix(event) {
- if (!event.text || event.text === "") {
- return false;
- }
- var newPrefix = prefix + event.text.toLowerCase();
- var matchedIndex = -1;
- for (var i = 0; i < model.count; ++i) {
- var name = model.get(i).fileName.toLowerCase();
- if (0 === name.indexOf(newPrefix)) {
- matchedIndex = i;
- break;
- }
- }
-
- if (matchedIndex !== -1) {
- assetTableView.selection.clear();
- assetTableView.selection.select(matchedIndex);
- assetTableView.currentRow = matchedIndex;
- assetTableView.prefix = newPrefix;
- }
- prefixClearTimer.restart();
- return true;
- }
-
- Keys.onPressed: {
- switch (event.key) {
- case Qt.Key_Backspace:
- case Qt.Key_Tab:
- case Qt.Key_Backtab:
- event.accepted = false;
- break;
-
- default:
- if (addToPrefix(event)) {
- event.accepted = true
- } else {
- event.accepted = false;
- }
- break;
- }
- }
- }
-
- TextField {
- id: currentSelection
- label: selectDirectory ? "Directory:" : "File name:"
- anchors {
- left: parent.left
- right: selectionType.visible ? selectionType.left: parent.right
- rightMargin: selectionType.visible ? hifi.dimensions.contentSpacing.x : 0
- bottom: buttonRow.top
- bottomMargin: hifi.dimensions.contentSpacing.y
- }
- readOnly: true
- activeFocusOnTab: !readOnly
- onActiveFocusChanged: if (activeFocus) { selectAll(); }
- onAccepted: okAction.trigger();
- }
-
- FileTypeSelection {
- id: selectionType
- anchors {
- top: currentSelection.top
- left: buttonRow.left
- right: parent.right
- }
- visible: !selectDirectory && filtersCount > 1
- KeyNavigation.left: assetTableView
- KeyNavigation.right: openButton
- }
-
- Action {
- id: okAction
- text: currentSelection.text && root.selectDirectory && assetTableView.currentRow === -1 ? "Choose" : "Open"
- enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false
- onTriggered: {
- if (!root.selectDirectory && !d.currentSelectionIsFolder
- || root.selectDirectory && assetTableView.currentRow === -1) {
- selectedAsset(d.currentSelectionPath);
- root.destroy();
- } else {
- assetTableView.navigateToCurrentRow();
- }
- }
- }
-
- Action {
- id: cancelAction
- text: "Cancel"
- onTriggered: {
- canceled();
- root.destroy();
- }
- }
-
- Row {
- id: buttonRow
- anchors {
- right: parent.right
- bottom: parent.bottom
- }
- spacing: hifi.dimensions.contentSpacing.y
-
- Button {
- id: openButton
- color: hifi.buttons.blue
- action: okAction
- Keys.onReturnPressed: okAction.trigger()
- KeyNavigation.up: selectionType
- KeyNavigation.left: selectionType
- KeyNavigation.right: cancelButton
- }
-
- Button {
- id: cancelButton
- action: cancelAction
- KeyNavigation.up: selectionType
- KeyNavigation.left: openButton
- KeyNavigation.right: assetTableView.contentItem
- Keys.onReturnPressed: { canceled(); root.enabled = false }
- }
- }
- }
-
- Keys.onPressed: {
- switch (event.key) {
- case Qt.Key_Backspace:
- event.accepted = d.navigateUp();
- break;
-
- case Qt.Key_Home:
- event.accepted = d.navigateHome();
- break;
-
- }
- }
-}
diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
index 653d814020..cac62d3976 100644
--- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
+++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
@@ -129,7 +129,7 @@ Rectangle {
}
onAppInstalled: {
- if (appHref === root.itemHref) {
+ if (appID === root.itemId) {
root.isInstalled = true;
}
}
diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
index 9f1d307f0e..0a69b8b3b5 100644
--- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
+++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
@@ -67,13 +67,13 @@ Item {
}
onAppInstalled: {
- if (appHref === root.itemHref) {
+ if (appID === root.itemId) {
root.isInstalled = true;
}
}
onAppUninstalled: {
- if (appHref === root.itemHref) {
+ if (appID === root.itemId) {
root.isInstalled = false;
}
}
diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
index 8a5b1fb0e7..16ad01a56d 100644
--- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
+++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
@@ -98,7 +98,7 @@ Rectangle {
}
onAppInstalled: {
- root.installedApps = Commerce.getInstalledApps();
+ root.installedApps = Commerce.getInstalledApps(appID);
}
onAppUninstalled: {
diff --git a/interface/src/AndroidHelper.cpp b/interface/src/AndroidHelper.cpp
index 1e73d58939..419382f2cb 100644
--- a/interface/src/AndroidHelper.cpp
+++ b/interface/src/AndroidHelper.cpp
@@ -35,6 +35,10 @@ void AndroidHelper::notifyEnterForeground() {
emit enterForeground();
}
+void AndroidHelper::notifyBeforeEnterBackground() {
+ emit beforeEnterBackground();
+}
+
void AndroidHelper::notifyEnterBackground() {
emit enterBackground();
}
diff --git a/interface/src/AndroidHelper.h b/interface/src/AndroidHelper.h
index 2c536268d6..03d92f91d9 100644
--- a/interface/src/AndroidHelper.h
+++ b/interface/src/AndroidHelper.h
@@ -24,6 +24,7 @@ public:
void requestActivity(const QString &activityName, const bool backToScene, QList args = QList());
void notifyLoadComplete();
void notifyEnterForeground();
+ void notifyBeforeEnterBackground();
void notifyEnterBackground();
void performHapticFeedback(int duration);
@@ -39,6 +40,7 @@ signals:
void androidActivityRequested(const QString &activityName, const bool backToScene, QList args = QList());
void qtAppLoadComplete();
void enterForeground();
+ void beforeEnterBackground();
void enterBackground();
void hapticFeedbackRequested(int duration);
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 5980f46523..0ad27e0dd3 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -1387,8 +1387,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// add firstRun flag from settings to launch event
Setting::Handle firstRun { Settings::firstRun, true };
- QString machineFingerPrint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint());
-
auto& userActivityLogger = UserActivityLogger::getInstance();
if (userActivityLogger.isEnabled()) {
// sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value.
@@ -1440,13 +1438,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
properties["first_run"] = firstRun.get();
// add the user's machine ID to the launch event
+ QString machineFingerPrint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint());
properties["machine_fingerprint"] = machineFingerPrint;
userActivityLogger.logAction("launch", properties);
}
- setCrashAnnotation("machine_fingerprint", machineFingerPrint.toStdString());
-
_entityEditSender.setMyAvatar(myAvatar.get());
// The entity octree will have to know about MyAvatar for the parentJointName import
@@ -2201,6 +2198,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID());
#if defined(Q_OS_ANDROID)
+ connect(&AndroidHelper::instance(), &AndroidHelper::beforeEnterBackground, this, &Application::beforeEnterBackground);
connect(&AndroidHelper::instance(), &AndroidHelper::enterBackground, this, &Application::enterBackground);
connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground);
AndroidHelper::instance().notifyLoadComplete();
@@ -3167,6 +3165,7 @@ void Application::setSettingConstrainToolbarPosition(bool setting) {
void Application::showHelp() {
static const QString HAND_CONTROLLER_NAME_VIVE = "vive";
static const QString HAND_CONTROLLER_NAME_OCULUS_TOUCH = "oculus";
+ static const QString HAND_CONTROLLER_NAME_WINDOWS_MR = "windowsMR";
static const QString TAB_KEYBOARD_MOUSE = "kbm";
static const QString TAB_GAMEPAD = "gamepad";
@@ -3181,9 +3180,13 @@ void Application::showHelp() {
} else if (PluginUtils::isOculusTouchControllerAvailable()) {
defaultTab = TAB_HAND_CONTROLLERS;
handControllerName = HAND_CONTROLLER_NAME_OCULUS_TOUCH;
+ } else if (qApp->getActiveDisplayPlugin()->getName() == "WindowMS") {
+ defaultTab = TAB_HAND_CONTROLLERS;
+ handControllerName = HAND_CONTROLLER_NAME_WINDOWS_MR;
} else if (PluginUtils::isXboxControllerAvailable()) {
defaultTab = TAB_GAMEPAD;
}
+ // TODO need some way to detect windowsMR to load controls reference default tab in Help > Controls Reference menu.
QUrlQuery queryString;
queryString.addQueryItem("handControllerName", handControllerName);
@@ -3209,13 +3212,22 @@ void Application::resizeGL() {
// Set the desired FBO texture size. If it hasn't changed, this does nothing.
// Otherwise, it must rebuild the FBOs
uvec2 framebufferSize = displayPlugin->getRecommendedRenderSize();
- float renderResolutionScale = getRenderResolutionScale();
- uvec2 renderSize = uvec2(vec2(framebufferSize) * renderResolutionScale);
+ uvec2 renderSize = uvec2(framebufferSize);
if (_renderResolution != renderSize) {
_renderResolution = renderSize;
DependencyManager::get()->setFrameBufferSize(fromGlm(renderSize));
}
+ auto renderResolutionScale = getRenderResolutionScale();
+ if (displayPlugin->getRenderResolutionScale() != renderResolutionScale) {
+ auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
+ assert(renderConfig);
+ auto mainView = renderConfig->getConfig("RenderMainView.RenderDeferredTask");
+ assert(mainView);
+ mainView->setProperty("resolutionScale", renderResolutionScale);
+ displayPlugin->setRenderResolutionScale(renderResolutionScale);
+ }
+
// FIXME the aspect ratio for stereo displays is incorrect based on this.
float aspectRatio = displayPlugin->getRecommendedAspectRatio();
_myCamera.setProjection(glm::perspective(glm::radians(_fieldOfView.get()), aspectRatio,
@@ -3227,7 +3239,6 @@ void Application::resizeGL() {
}
DependencyManager::get()->resize(fromGlm(displayPlugin->getRecommendedUiSize()));
- displayPlugin->setRenderResolutionScale(renderResolutionScale);
}
void Application::handleSandboxStatus(QNetworkReply* reply) {
@@ -8284,6 +8295,13 @@ void Application::copyToClipboard(const QString& text) {
}
#if defined(Q_OS_ANDROID)
+void Application::beforeEnterBackground() {
+ auto nodeList = DependencyManager::get();
+ nodeList->setSendDomainServerCheckInEnabled(false);
+ nodeList->reset(true);
+ clearDomainOctreeDetails();
+}
+
void Application::enterBackground() {
QMetaObject::invokeMethod(DependencyManager::get().data(),
"stop", Qt::BlockingQueuedConnection);
@@ -8298,6 +8316,8 @@ void Application::enterForeground() {
if (!getActiveDisplayPlugin() || getActiveDisplayPlugin()->isActive() || !getActiveDisplayPlugin()->activate()) {
qWarning() << "Could not re-activate display plugin";
}
+ auto nodeList = DependencyManager::get();
+ nodeList->setSendDomainServerCheckInEnabled(true);
}
#endif
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 4a36cd5b41..fb8edf3b86 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -320,6 +320,7 @@ public:
Q_INVOKABLE void copyToClipboard(const QString& text);
#if defined(Q_OS_ANDROID)
+ void beforeEnterBackground();
void enterBackground();
void enterForeground();
#endif
diff --git a/interface/src/CrashHandler.h b/interface/src/CrashHandler.h
index 4a6483c700..6f8e9c3bf6 100644
--- a/interface/src/CrashHandler.h
+++ b/interface/src/CrashHandler.h
@@ -14,8 +14,7 @@
#include
-bool startCrashHandler();
+bool startCrashHandler(std::string appPath);
void setCrashAnnotation(std::string name, std::string value);
-
-#endif
\ No newline at end of file
+#endif // hifi_CrashHandler_h
diff --git a/interface/src/CrashHandler_Breakpad.cpp b/interface/src/CrashHandler_Breakpad.cpp
index f2a174b6ea..c21bfa95e0 100644
--- a/interface/src/CrashHandler_Breakpad.cpp
+++ b/interface/src/CrashHandler_Breakpad.cpp
@@ -9,10 +9,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
-#include "CrashHandler.h"
-
#if HAS_BREAKPAD
+#include "CrashHandler.h"
+
#include
#include
@@ -23,8 +23,10 @@
#include
#include
-#include
#include
+#include
+#include
+#include
google_breakpad::ExceptionHandler* gBreakpadHandler;
@@ -55,11 +57,14 @@ void flushAnnotations() {
settings.sync();
}
-bool startCrashHandler() {
+bool startCrashHandler(std::string appPath) {
annotations["version"] = BuildInfo::VERSION;
annotations["build_number"] = BuildInfo::BUILD_NUMBER;
annotations["build_type"] = BuildInfo::BUILD_TYPE_STRING;
+ auto machineFingerPrint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint());
+ annotations["machine_fingerprint"] = machineFingerPrint;
+
flushAnnotations();
gBreakpadHandler = new google_breakpad::ExceptionHandler(
diff --git a/interface/src/CrashHandler_Crashpad.cpp b/interface/src/CrashHandler_Crashpad.cpp
index 76d4a8e2e1..d1b5103990 100644
--- a/interface/src/CrashHandler_Crashpad.cpp
+++ b/interface/src/CrashHandler_Crashpad.cpp
@@ -9,21 +9,24 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+#if HAS_CRASHPAD
+
#include "CrashHandler.h"
#include
-#include
-
-#if HAS_CRASHPAD
-
#include
#include
-#include
+#include
#include
+#include
-#include
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++14-extensions"
+#endif
#include
#include
@@ -31,19 +34,32 @@
#include
#include
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
#include
+#include
+#include
using namespace crashpad;
static const std::string BACKTRACE_URL { CMAKE_BACKTRACE_URL };
static const std::string BACKTRACE_TOKEN { CMAKE_BACKTRACE_TOKEN };
-extern QString qAppFileName();
-
CrashpadClient* client { nullptr };
std::mutex annotationMutex;
crashpad::SimpleStringDictionary* crashpadAnnotations { nullptr };
+#if defined(Q_OS_WIN)
+static const QString CRASHPAD_HANDLER_NAME { "crashpad_handler.exe" };
+#else
+static const QString CRASHPAD_HANDLER_NAME { "crashpad_handler" };
+#endif
+
+#ifdef Q_OS_WIN
+#include
+
LONG WINAPI vectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) {
if (!client) {
return EXCEPTION_CONTINUE_SEARCH;
@@ -56,8 +72,9 @@ LONG WINAPI vectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) {
return EXCEPTION_CONTINUE_SEARCH;
}
+#endif
-bool startCrashHandler() {
+bool startCrashHandler(std::string appPath) {
if (BACKTRACE_URL.empty() || BACKTRACE_TOKEN.empty()) {
return false;
}
@@ -73,6 +90,10 @@ bool startCrashHandler() {
annotations["build_number"] = BuildInfo::BUILD_NUMBER.toStdString();
annotations["build_type"] = BuildInfo::BUILD_TYPE_STRING.toStdString();
+ auto machineFingerPrint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint());
+ annotations["machine_fingerprint"] = machineFingerPrint.toStdString();
+
+
arguments.push_back("--no-rate-limit");
// Setup Crashpad DB directory
@@ -82,7 +103,10 @@ bool startCrashHandler() {
const auto crashpadDbPath = crashpadDbDir.toStdString() + "/" + crashpadDbName;
// Locate Crashpad handler
- const std::string CRASHPAD_HANDLER_PATH = QFileInfo(qAppFileName()).absolutePath().toStdString() + "/crashpad_handler.exe";
+ const QFileInfo interfaceBinary { QString::fromStdString(appPath) };
+ const QDir interfaceDir = interfaceBinary.dir();
+ assert(interfaceDir.exists(CRASHPAD_HANDLER_NAME));
+ const std::string CRASHPAD_HANDLER_PATH = interfaceDir.filePath(CRASHPAD_HANDLER_NAME).toStdString();
// Setup different file paths
base::FilePath::StringType dbPath;
@@ -101,20 +125,24 @@ bool startCrashHandler() {
// Enable automated uploads.
database->GetSettings()->SetUploadsEnabled(true);
+#ifdef Q_OS_WIN
AddVectoredExceptionHandler(0, vectoredExceptionHandler);
+#endif
return client->StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true);
}
void setCrashAnnotation(std::string name, std::string value) {
- std::lock_guard guard(annotationMutex);
- if (!crashpadAnnotations) {
- crashpadAnnotations = new crashpad::SimpleStringDictionary(); // don't free this, let it leak
- crashpad::CrashpadInfo* crashpad_info = crashpad::CrashpadInfo::GetCrashpadInfo();
- crashpad_info->set_simple_annotations(crashpadAnnotations);
+ if (client) {
+ std::lock_guard guard(annotationMutex);
+ if (!crashpadAnnotations) {
+ crashpadAnnotations = new crashpad::SimpleStringDictionary(); // don't free this, let it leak
+ crashpad::CrashpadInfo* crashpad_info = crashpad::CrashpadInfo::GetCrashpadInfo();
+ crashpad_info->set_simple_annotations(crashpadAnnotations);
+ }
+ std::replace(value.begin(), value.end(), ',', ';');
+ crashpadAnnotations->SetKeyValue(name, value);
}
- std::replace(value.begin(), value.end(), ',', ';');
- crashpadAnnotations->SetKeyValue(name, value);
}
#endif
diff --git a/interface/src/CrashHandler_None.cpp b/interface/src/CrashHandler_None.cpp
index cba585f7b7..77b8ab332e 100644
--- a/interface/src/CrashHandler_None.cpp
+++ b/interface/src/CrashHandler_None.cpp
@@ -9,14 +9,15 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+#if !defined(HAS_CRASHPAD) && !defined(HAS_BREAKPAD)
+
#include "CrashHandler.h"
#include
+
#include
-#if !defined(HAS_CRASHPAD) && !defined(HAS_BREAKPAD)
-
-bool startCrashHandler() {
+bool startCrashHandler(std::string appPath) {
qDebug() << "No crash handler available.";
return false;
}
diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp
index b960c0b703..1f44343bdc 100644
--- a/interface/src/commerce/QmlCommerce.cpp
+++ b/interface/src/commerce/QmlCommerce.cpp
@@ -208,7 +208,7 @@ void QmlCommerce::alreadyOwned(const QString& marketplaceId) {
ledger->alreadyOwned(marketplaceId);
}
-QString QmlCommerce::getInstalledApps() {
+QString QmlCommerce::getInstalledApps(const QString& justInstalledAppID) {
QString installedAppsFromMarketplace;
QStringList runningScripts = DependencyManager::get()->getRunningScripts();
@@ -217,6 +217,18 @@ QString QmlCommerce::getInstalledApps() {
foreach(QString appFileName, apps) {
installedAppsFromMarketplace += appFileName;
installedAppsFromMarketplace += ",";
+
+ // If we were supplied a "justInstalledAppID" argument, that means we're entering this function
+ // to get the new list of installed apps immediately after installing an app.
+ // In that case, the app we installed may not yet have its associated script running -
+ // that task is asynchronous and takes a nonzero amount of time. This is especially true
+ // for apps that are not in Interface's script cache.
+ // Thus, we protect against deleting the .app.json from the user's disk (below)
+ // by skipping that check for the app we just installed.
+ if ((justInstalledAppID != "") && ((justInstalledAppID + ".app.json") == appFileName)) {
+ continue;
+ }
+
QFile appFile(_appsPath + appFileName);
if (appFile.open(QIODevice::ReadOnly)) {
QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll());
@@ -291,7 +303,8 @@ bool QmlCommerce::installApp(const QString& itemHref) {
return false;
}
- emit appInstalled(itemHref);
+ QFileInfo appFileInfo(appFile);
+ emit appInstalled(appFileInfo.baseName());
return true;
});
request->send();
@@ -321,7 +334,8 @@ bool QmlCommerce::uninstallApp(const QString& itemHref) {
qCWarning(commerce) << "Couldn't delete local .app.json file during app uninstall. Continuing anyway. App filename is:" << appHref.fileName();
}
- emit appUninstalled(itemHref);
+ QFileInfo appFileInfo(appFile);
+ emit appUninstalled(appFileInfo.baseName());
return true;
}
diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h
index a0c6916799..79d8e82e71 100644
--- a/interface/src/commerce/QmlCommerce.h
+++ b/interface/src/commerce/QmlCommerce.h
@@ -53,8 +53,8 @@ signals:
void contentSetChanged(const QString& contentSetHref);
- void appInstalled(const QString& appHref);
- void appUninstalled(const QString& appHref);
+ void appInstalled(const QString& appID);
+ void appUninstalled(const QString& appID);
protected:
Q_INVOKABLE void getWalletStatus();
@@ -86,7 +86,7 @@ protected:
Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID);
- Q_INVOKABLE QString getInstalledApps();
+ Q_INVOKABLE QString getInstalledApps(const QString& justInstalledAppID = "");
Q_INVOKABLE bool installApp(const QString& appHref);
Q_INVOKABLE bool uninstallApp(const QString& appHref);
Q_INVOKABLE bool openApp(const QString& appHref);
diff --git a/interface/src/graphics/GraphicsEngine.cpp b/interface/src/graphics/GraphicsEngine.cpp
index f256b0dfb5..21c9a9b22d 100644
--- a/interface/src/graphics/GraphicsEngine.cpp
+++ b/interface/src/graphics/GraphicsEngine.cpp
@@ -237,7 +237,7 @@ void GraphicsEngine::render_performFrame() {
PerformanceTimer perfTimer("renderOverlay");
// NOTE: There is no batch associated with this renderArgs
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
- renderArgs._viewport = glm::ivec4(0, 0, qApp->getDeviceSize() * qApp->getRenderResolutionScale());
+ renderArgs._viewport = glm::ivec4(0, 0, qApp->getDeviceSize());
qApp->getApplicationOverlay().renderOverlay(&renderArgs);
}
diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index d6665f1036..85a83d88d1 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -91,7 +91,7 @@ int main(int argc, const char* argv[]) {
qDebug() << "UserActivityLogger is enabled:" << ual.isEnabled();
if (ual.isEnabled()) {
- auto crashHandlerStarted = startCrashHandler();
+ auto crashHandlerStarted = startCrashHandler(argv[0]);
qDebug() << "Crash handler started:" << crashHandlerStarted;
}
diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp
index afbf7f4035..ba86925581 100644
--- a/interface/src/scripting/WindowScriptingInterface.cpp
+++ b/interface/src/scripting/WindowScriptingInterface.cpp
@@ -86,10 +86,6 @@ void WindowScriptingInterface::raise() {
});
}
-void WindowScriptingInterface::raiseMainWindow() {
- raise();
-}
-
/// Display an alert box
/// \param const QString& message message to display
/// \return QScriptValue::UndefinedValue
diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h
index dc868e6fcd..77895e0e76 100644
--- a/interface/src/scripting/WindowScriptingInterface.h
+++ b/interface/src/scripting/WindowScriptingInterface.h
@@ -80,13 +80,6 @@ public slots:
*/
void raise();
- /**jsdoc
- * Raise the Interface window if it is minimized. If raised, the window gains focus.
- * @function Window.raiseMainWindow
- * @deprecated Use {@link Window.raise|raise} instead.
- */
- void raiseMainWindow();
-
/**jsdoc
* Display a dialog with the specified message and an "OK" button. The dialog is non-modal; the script continues without
* waiting for a user response.
diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp
index a0b4f856a1..f1f64ec98d 100644
--- a/interface/src/ui/ApplicationOverlay.cpp
+++ b/interface/src/ui/ApplicationOverlay.cpp
@@ -179,7 +179,7 @@ static const auto DEPTH_FORMAT = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPT
void ApplicationOverlay::buildFramebufferObject() {
PROFILE_RANGE(app, __FUNCTION__);
- auto uiSize = glm::uvec2(glm::vec2(qApp->getUiSize()) * qApp->getRenderResolutionScale());
+ auto uiSize = glm::uvec2(qApp->getUiSize());
if (!_overlayFramebuffer || uiSize != _overlayFramebuffer->getSize()) {
_overlayFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ApplicationOverlay"));
}
diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp
index c7ee868855..6bb615948c 100644
--- a/interface/src/ui/Stats.cpp
+++ b/interface/src/ui/Stats.cpp
@@ -333,7 +333,13 @@ void Stats::updateStats(bool force) {
}
auto gpuContext = qApp->getGPUContext();
-
+ auto displayPlugin = qApp->getActiveDisplayPlugin();
+ if (displayPlugin) {
+ QVector2D dims(displayPlugin->getRecommendedRenderSize().x, displayPlugin->getRecommendedRenderSize().y);
+ dims *= displayPlugin->getRenderResolutionScale();
+ STAT_UPDATE(gpuFrameSize, dims);
+ STAT_UPDATE(gpuFrameTimePerPixel, (float)(gpuContext->getFrameTimerGPUAverage()*1000000.0 / double(dims.x()*dims.y())));
+ }
// Update Frame timing (in ms)
STAT_UPDATE(gpuFrameTime, (float)gpuContext->getFrameTimerGPUAverage());
STAT_UPDATE(batchFrameTime, (float)gpuContext->getFrameTimerBatchAverage());
diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h
index 36e923261d..f4181f9788 100644
--- a/interface/src/ui/Stats.h
+++ b/interface/src/ui/Stats.h
@@ -276,7 +276,9 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, gpuTextureExternalMemory, 0)
STATS_PROPERTY(QString, gpuTextureMemoryPressureState, QString())
STATS_PROPERTY(int, gpuFreeMemory, 0)
+ STATS_PROPERTY(QVector2D, gpuFrameSize, QVector2D(0,0))
STATS_PROPERTY(float, gpuFrameTime, 0)
+ STATS_PROPERTY(float, gpuFrameTimePerPixel, 0)
STATS_PROPERTY(float, batchFrameTime, 0)
STATS_PROPERTY(float, engineFrameTime, 0)
STATS_PROPERTY(float, avatarSimulationTime, 0)
@@ -962,6 +964,20 @@ signals:
*/
void gpuFrameTimeChanged();
+ /**jsdoc
+ * Triggered when the value of the gpuFrameTime
property changes.
+ * @function Stats.gpuFrameTimeChanged
+ * @returns {Signal}
+ */
+ void gpuFrameSizeChanged();
+
+ /**jsdoc
+ * Triggered when the value of the gpuFrameTime
property changes.
+ * @function Stats.gpuFrameTimeChanged
+ * @returns {Signal}
+ */
+ void gpuFrameTimePerPixelChanged();
+
/**jsdoc
* Triggered when the value of the batchFrameTime
property changes.
* @function Stats.batchFrameTimeChanged
diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp
index aca186a589..c6323614c5 100644
--- a/interface/src/ui/overlays/ContextOverlayInterface.cpp
+++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp
@@ -97,6 +97,10 @@ static const float CONTEXT_OVERLAY_UNHOVERED_COLORPULSE = 1.0f;
void ContextOverlayInterface::setEnabled(bool enabled) {
_enabled = enabled;
+ if (!enabled) {
+ // Destroy any potentially-active ContextOverlays when disabling the interface
+ createOrDestroyContextOverlay(EntityItemID(), PointerEvent());
+ }
}
void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) {
diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp
index 4f2a8e6fa4..5a576c6d78 100644
--- a/interface/src/ui/overlays/Overlays.cpp
+++ b/interface/src/ui/overlays/Overlays.cpp
@@ -116,7 +116,7 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
auto geometryCache = DependencyManager::get();
auto textureCache = DependencyManager::get();
- auto size = glm::uvec2(glm::vec2(qApp->getUiSize()) * qApp->getRenderResolutionScale());
+ auto size = glm::uvec2(qApp->getUiSize());
int width = size.x;
int height = size.y;
mat4 legacyProjection = glm::ortho(0, width, height, 0, -1000, 1000);
diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp
index b78f00fa0e..efa4859b42 100644
--- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp
+++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp
@@ -275,7 +275,7 @@ bool CompositorHelper::getReticleOverDesktop() const {
// as being over the desktop.
if (isHMD()) {
QMutexLocker locker(&_reticleLock);
- glm::vec2 maxOverlayPosition = glm::vec2(_currentDisplayPlugin->getRecommendedUiSize()) * _currentDisplayPlugin->getRenderResolutionScale();
+ glm::vec2 maxOverlayPosition = glm::vec2(_currentDisplayPlugin->getRecommendedUiSize());
static const glm::vec2 minOverlayPosition;
if (glm::any(glm::lessThan(_reticlePositionInHMD, minOverlayPosition)) ||
glm::any(glm::greaterThan(_reticlePositionInHMD, maxOverlayPosition))) {
@@ -317,7 +317,7 @@ void CompositorHelper::sendFakeMouseEvent() {
void CompositorHelper::setReticlePosition(const glm::vec2& position, bool sendFakeEvent) {
if (isHMD()) {
- glm::vec2 maxOverlayPosition = glm::vec2(_currentDisplayPlugin->getRecommendedUiSize()) * _currentDisplayPlugin->getRenderResolutionScale();
+ glm::vec2 maxOverlayPosition = glm::vec2(_currentDisplayPlugin->getRecommendedUiSize());
// FIXME don't allow negative mouseExtra
glm::vec2 mouseExtra = (MOUSE_EXTENTS_PIXELS - maxOverlayPosition) / 2.0f;
glm::vec2 minMouse = vec2(0) - mouseExtra;
diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
index 0d556544bb..9200843cf8 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
@@ -888,7 +888,7 @@ OpenGLDisplayPlugin::~OpenGLDisplayPlugin() {
}
void OpenGLDisplayPlugin::updateCompositeFramebuffer() {
- auto renderSize = glm::uvec2(glm::vec2(getRecommendedRenderSize()) * getRenderResolutionScale());
+ auto renderSize = glm::uvec2(getRecommendedRenderSize());
if (!_compositeFramebuffer || _compositeFramebuffer->getSize() != renderSize) {
_compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y));
}
diff --git a/libraries/entities/src/AnimationPropertyGroup.cpp b/libraries/entities/src/AnimationPropertyGroup.cpp
index 2db85eb7ac..95bdae43b9 100644
--- a/libraries/entities/src/AnimationPropertyGroup.cpp
+++ b/libraries/entities/src/AnimationPropertyGroup.cpp
@@ -22,13 +22,14 @@ const float AnimationPropertyGroup::MAXIMUM_POSSIBLE_FRAME = 100000.0f;
bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
return
-
(a._currentFrame == b._currentFrame) &&
(a._running == b._running) &&
(a._loop == b._loop) &&
(a._hold == b._hold) &&
(a._firstFrame == b._firstFrame) &&
(a._lastFrame == b._lastFrame) &&
+ (a._fps == b._fps) &&
+ (a._allowTranslation == b._allowTranslation) &&
(a._url == b._url);
}
@@ -40,6 +41,8 @@ bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b
(a._hold != b._hold) ||
(a._firstFrame != b._firstFrame) ||
(a._lastFrame != b._lastFrame) ||
+ (a._fps != b._fps) ||
+ (a._allowTranslation != b._allowTranslation) ||
(a._url != b._url);
}
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 31ec189cf9..8e382fabd4 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -2414,11 +2414,7 @@ bool EntityItem::shouldSuppressLocationEdits() const {
}
// if any of the ancestors are MyAvatar, suppress
- if (isChildOfMyAvatar()) {
- return true;
- }
-
- return false;
+ return isChildOfMyAvatar();
}
QList EntityItem::getActionsOfType(EntityDynamicType typeToGet) const {
diff --git a/libraries/gpu/src/gpu/Buffer.cpp b/libraries/gpu/src/gpu/Buffer.cpp
index ebb768e597..d085b4df76 100644
--- a/libraries/gpu/src/gpu/Buffer.cpp
+++ b/libraries/gpu/src/gpu/Buffer.cpp
@@ -163,6 +163,31 @@ Buffer::Size Buffer::getSize() const {
const Element BufferView::DEFAULT_ELEMENT = Element( gpu::SCALAR, gpu::UINT8, gpu::RAW );
+
+BufferPointer _buffer;
+Size _offset{ 0 };
+Size _size{ 0 };
+Element _element{ DEFAULT_ELEMENT };
+uint16 _stride{ 0 };
+
+BufferView::BufferView(const BufferView& view) :
+ _buffer(view._buffer),
+ _offset(view._offset),
+ _size(view._size),
+ _element(view._element),
+ _stride(view._stride)
+{}
+
+BufferView& BufferView::operator=(const BufferView& view) {
+ _buffer = (view._buffer);
+ _offset = (view._offset);
+ _size = (view._size);
+ _element = (view._element);
+ _stride = (view._stride);
+
+ return (*this);
+}
+
BufferView::BufferView() :
BufferView(DEFAULT_ELEMENT) {}
diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h
index 01cc652fd1..e486e2392a 100644
--- a/libraries/gpu/src/gpu/Buffer.h
+++ b/libraries/gpu/src/gpu/Buffer.h
@@ -183,8 +183,8 @@ public:
Element _element { DEFAULT_ELEMENT };
uint16 _stride { 0 };
- BufferView(const BufferView& view) = default;
- BufferView& operator=(const BufferView& view) = default;
+ BufferView(const BufferView& view);
+ BufferView& operator=(const BufferView& view);
BufferView();
BufferView(const Element& element);
diff --git a/libraries/graphics/src/graphics/Haze.cpp b/libraries/graphics/src/graphics/Haze.cpp
index d5a060b90b..ded48429ba 100644
--- a/libraries/graphics/src/graphics/Haze.cpp
+++ b/libraries/graphics/src/graphics/Haze.cpp
@@ -177,9 +177,9 @@ void Haze::setHazeBaseReference(const float hazeBaseReference) {
void Haze::setHazeBackgroundBlend(const float hazeBackgroundBlend) {
auto& params = _hazeParametersBuffer.get();
-
- if (params.hazeBackgroundBlend != hazeBackgroundBlend) {
- _hazeParametersBuffer.edit().hazeBackgroundBlend = hazeBackgroundBlend;
+ auto newBlend = 1.0f - hazeBackgroundBlend;
+ if (params.hazeBackgroundBlend != newBlend) {
+ _hazeParametersBuffer.edit().hazeBackgroundBlend = newBlend;
}
}
diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp
index d9d5c21e5d..2ce734dd26 100644
--- a/libraries/networking/src/NodeList.cpp
+++ b/libraries/networking/src/NodeList.cpp
@@ -289,6 +289,12 @@ void NodeList::addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes)
}
void NodeList::sendDomainServerCheckIn() {
+
+ if (!_sendDomainServerCheckInEnabled) {
+ qCDebug(networking) << "Refusing to send a domain-server check in while it is disabled.";
+ return;
+ }
+
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "sendDomainServerCheckIn", Qt::QueuedConnection);
return;
diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h
index c5cf5e9524..78d3fad696 100644
--- a/libraries/networking/src/NodeList.h
+++ b/libraries/networking/src/NodeList.h
@@ -90,6 +90,9 @@ public:
bool getRequestsDomainListData() { return _requestsDomainListData; }
void setRequestsDomainListData(bool isRequesting);
+ bool getSendDomainServerCheckInEnabled() { return _sendDomainServerCheckInEnabled; }
+ void setSendDomainServerCheckInEnabled(bool enabled) { _sendDomainServerCheckInEnabled = enabled; }
+
void removeFromIgnoreMuteSets(const QUuid& nodeID);
virtual bool isDomainServer() const override { return false; }
@@ -169,6 +172,8 @@ private:
QTimer _keepAlivePingTimer;
bool _requestsDomainListData { false };
+ bool _sendDomainServerCheckInEnabled { true };
+
mutable QReadWriteLock _ignoredSetLock;
tbb::concurrent_unordered_set _ignoredNodeIDs;
mutable QReadWriteLock _personalMutedSetLock;
diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp
index 9089f02aaf..a610a6f2a6 100644
--- a/libraries/physics/src/EntityMotionState.cpp
+++ b/libraries/physics/src/EntityMotionState.cpp
@@ -234,7 +234,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
return;
}
assert(entityTreeIsLocked());
- if (_motionType == MOTION_TYPE_KINEMATIC && !_entity->hasAncestorOfType(NestableType::Avatar)) {
+ if (_motionType == MOTION_TYPE_KINEMATIC) {
BT_PROFILE("kinematicIntegration");
// This is physical kinematic motion which steps strictly by the subframe count
// of the physics simulation and uses full gravity for acceleration.
@@ -327,13 +327,6 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
return true;
}
- bool parentTransformSuccess;
- Transform localToWorld = _entity->getParentTransform(parentTransformSuccess);
- Transform worldToLocal;
- if (parentTransformSuccess) {
- localToWorld.evalInverse(worldToLocal);
- }
-
int numSteps = simulationStep - _lastStep;
float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP;
@@ -361,6 +354,10 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
return true;
}
+ if (_body->isStaticOrKinematicObject()) {
+ return false;
+ }
+
_lastStep = simulationStep;
if (glm::length2(_serverVelocity) > 0.0f) {
// the entity-server doesn't know where avatars are, so it doesn't do simple extrapolation for children of
@@ -388,6 +385,12 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
// TODO: compensate for _worldOffset offset here
// compute position error
+ bool parentTransformSuccess;
+ Transform localToWorld = _entity->getParentTransform(parentTransformSuccess);
+ Transform worldToLocal;
+ if (parentTransformSuccess) {
+ localToWorld.evalInverse(worldToLocal);
+ }
btTransform worldTrans = _body->getWorldTransform();
glm::vec3 position = worldToLocal.transform(bulletToGLM(worldTrans.getOrigin()));
@@ -407,20 +410,23 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
if (glm::length2(_serverAngularVelocity) > 0.0f) {
// compute rotation error
- float attenuation = powf(1.0f - _body->getAngularDamping(), dt);
- _serverAngularVelocity *= attenuation;
+ //
// Bullet caps the effective rotation velocity inside its rotation integration step, therefore
// we must integrate with the same algorithm and timestep in order achieve similar results.
- for (int i = 0; i < numSteps; ++i) {
- _serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity,
- PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation);
+ float attenuation = powf(1.0f - _body->getAngularDamping(), PHYSICS_ENGINE_FIXED_SUBSTEP);
+ _serverAngularVelocity *= attenuation;
+ glm::quat rotation = computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP);
+ for (int i = 1; i < numSteps; ++i) {
+ _serverAngularVelocity *= attenuation;
+ rotation = computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * rotation;
}
+ _serverRotation = glm::normalize(rotation * _serverRotation);
+ const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation
+ glm::quat actualRotation = worldToLocal.getRotation() * bulletToGLM(worldTrans.getRotation());
+ return (fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT);
}
- const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation
- glm::quat actualRotation = worldToLocal.getRotation() * bulletToGLM(worldTrans.getRotation());
-
- return (fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT);
+ return false;
}
bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp
index b990d3612b..5666e75aa1 100644
--- a/libraries/physics/src/PhysicalEntitySimulation.cpp
+++ b/libraries/physics/src/PhysicalEntitySimulation.cpp
@@ -59,7 +59,10 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {
_entitiesToAddToPhysics.insert(entity);
}
} else if (canBeKinematic && entity->isMovingRelativeToParent()) {
- _simpleKinematicEntities.insert(entity);
+ SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+ if (itr == _simpleKinematicEntities.end()) {
+ _simpleKinematicEntities.insert(entity);
+ }
}
}
@@ -150,7 +153,10 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
removeOwnershipData(motionState);
_entitiesToRemoveFromPhysics.insert(entity);
if (canBeKinematic && entity->isMovingRelativeToParent()) {
- _simpleKinematicEntities.insert(entity);
+ SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+ if (itr == _simpleKinematicEntities.end()) {
+ _simpleKinematicEntities.insert(entity);
+ }
}
} else {
_incomingChanges.insert(motionState);
@@ -160,11 +166,20 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
// The intent is for this object to be in the PhysicsEngine, but it has no MotionState yet.
// Perhaps it's shape has changed and it can now be added?
_entitiesToAddToPhysics.insert(entity);
- _simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic
+ SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+ if (itr != _simpleKinematicEntities.end()) {
+ _simpleKinematicEntities.erase(itr);
+ }
} else if (canBeKinematic && entity->isMovingRelativeToParent()) {
- _simpleKinematicEntities.insert(entity);
+ SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+ if (itr == _simpleKinematicEntities.end()) {
+ _simpleKinematicEntities.insert(entity);
+ }
} else {
- _simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic
+ SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+ if (itr != _simpleKinematicEntities.end()) {
+ _simpleKinematicEntities.erase(itr);
+ }
}
}
@@ -212,7 +227,6 @@ const VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemoveFromPhys
assert(motionState);
// TODO CLEan this, just a n extra check to avoid the crash that shouldn;t happen
if (motionState) {
-
_entitiesToAddToPhysics.remove(entity);
if (entity->isDead() && entity->getElement()) {
_deadEntities.insert(entity);
@@ -255,7 +269,10 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re
// this entity should no longer be on the internal _entitiesToAddToPhysics
entityItr = _entitiesToAddToPhysics.erase(entityItr);
if (entity->isMovingRelativeToParent()) {
- _simpleKinematicEntities.insert(entity);
+ SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+ if (itr == _simpleKinematicEntities.end()) {
+ _simpleKinematicEntities.insert(entity);
+ }
}
} else if (entity->isReadyToComputeShape()) {
ShapeInfo shapeInfo;
@@ -375,19 +392,21 @@ void PhysicalEntitySimulation::handleChangedMotionStates(const VectorOfMotionSta
}
void PhysicalEntitySimulation::addOwnershipBid(EntityMotionState* motionState) {
- if (!getEntityTree()->isServerlessMode()) {
- motionState->initForBid();
- motionState->sendBid(_entityPacketSender, _physicsEngine->getNumSubsteps());
- _bids.push_back(motionState);
- _nextBidExpiry = glm::min(_nextBidExpiry, motionState->getNextBidExpiry());
+ if (getEntityTree()->isServerlessMode()) {
+ return;
}
+ motionState->initForBid();
+ motionState->sendBid(_entityPacketSender, _physicsEngine->getNumSubsteps());
+ _bids.push_back(motionState);
+ _nextBidExpiry = glm::min(_nextBidExpiry, motionState->getNextBidExpiry());
}
void PhysicalEntitySimulation::addOwnership(EntityMotionState* motionState) {
- if (!getEntityTree()->isServerlessMode()) {
- motionState->initForOwned();
- _owned.push_back(motionState);
+ if (getEntityTree()->isServerlessMode()) {
+ return;
}
+ motionState->initForOwned();
+ _owned.push_back(motionState);
}
void PhysicalEntitySimulation::sendOwnershipBids(uint32_t numSubsteps) {
@@ -426,7 +445,9 @@ void PhysicalEntitySimulation::sendOwnershipBids(uint32_t numSubsteps) {
}
void PhysicalEntitySimulation::sendOwnedUpdates(uint32_t numSubsteps) {
- bool serverlessMode = getEntityTree()->isServerlessMode();
+ if (getEntityTree()->isServerlessMode()) {
+ return;
+ }
PROFILE_RANGE_EX(simulation_physics, "Update", 0x00000000, (uint64_t)_owned.size());
uint32_t i = 0;
while (i < _owned.size()) {
@@ -438,7 +459,7 @@ void PhysicalEntitySimulation::sendOwnedUpdates(uint32_t numSubsteps) {
}
_owned.remove(i);
} else {
- if (!serverlessMode && _owned[i]->shouldSendUpdate(numSubsteps)) {
+ if (_owned[i]->shouldSendUpdate(numSubsteps)) {
_owned[i]->sendUpdate(_entityPacketSender, numSubsteps);
}
++i;
diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp
index 2ac8e77898..5be05da505 100644
--- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp
+++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp
@@ -176,7 +176,7 @@ AmbientOcclusionEffect::AmbientOcclusionEffect() {
}
void AmbientOcclusionEffect::configure(const Config& config) {
- DependencyManager::get()->setAmbientOcclusionEnabled(config.enabled);
+ DependencyManager::get()->setAmbientOcclusionEnabled(config.isEnabled());
bool shouldUpdateGaussian = false;
diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h
index b3a93ab1de..69b229d39f 100644
--- a/libraries/render-utils/src/AmbientOcclusionEffect.h
+++ b/libraries/render-utils/src/AmbientOcclusionEffect.h
@@ -56,7 +56,6 @@ using AmbientOcclusionFramebufferPointer = std::shared_ptr
+ // Trigger Scribe include
+ // <@endif@>
+//
diff --git a/libraries/render-utils/src/BloomApply.slf b/libraries/render-utils/src/BloomApply.slf
index 961438888e..28415643a0 100644
--- a/libraries/render-utils/src/BloomApply.slf
+++ b/libraries/render-utils/src/BloomApply.slf
@@ -9,11 +9,15 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+<@include BloomApply.shared.slh@>
uniform sampler2D blurMap0;
uniform sampler2D blurMap1;
uniform sampler2D blurMap2;
-uniform vec3 intensity;
+
+layout(std140) uniform parametersBuffer {
+ Parameters parameters;
+};
in vec2 varTexCoord0;
out vec4 outFragColor;
@@ -23,5 +27,5 @@ void main(void) {
vec4 blur1 = texture(blurMap1, varTexCoord0);
vec4 blur2 = texture(blurMap2, varTexCoord0);
- outFragColor = vec4(blur0.rgb*intensity.x + blur1.rgb*intensity.y + blur2.rgb*intensity.z, 1.0f);
+ outFragColor = vec4(blur0.rgb*parameters._intensities.x + blur1.rgb*parameters._intensities.y + blur2.rgb*parameters._intensities.z, 1.0f);
}
diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp
index b198442b15..93d2b5177b 100644
--- a/libraries/render-utils/src/BloomEffect.cpp
+++ b/libraries/render-utils/src/BloomEffect.cpp
@@ -21,13 +21,15 @@
#define BLOOM_BLUR_LEVEL_COUNT 3
-BloomThreshold::BloomThreshold(unsigned int downsamplingFactor) :
- _downsamplingFactor(downsamplingFactor) {
+BloomThreshold::BloomThreshold(unsigned int downsamplingFactor) {
assert(downsamplingFactor > 0);
+ _parameters.edit()._sampleCount = downsamplingFactor;
}
void BloomThreshold::configure(const Config& config) {
- _threshold = config.threshold;
+ if (_parameters.get()._threshold != config.threshold) {
+ _parameters.edit()._threshold = config.threshold;
+ }
}
void BloomThreshold::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
@@ -43,10 +45,11 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
auto inputBuffer = inputFrameBuffer->getRenderBuffer(0);
auto bufferSize = gpu::Vec2u(inputBuffer->getDimensions());
+ const auto downSamplingFactor = _parameters.get()._sampleCount;
// Downsample resolution
- bufferSize.x /= _downsamplingFactor;
- bufferSize.y /= _downsamplingFactor;
+ bufferSize.x /= downSamplingFactor;
+ bufferSize.y /= downSamplingFactor;
if (!_outputBuffer || _outputBuffer->getSize() != bufferSize) {
auto colorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(inputBuffer->getTexelFormat(), bufferSize.x, bufferSize.y,
@@ -54,10 +57,12 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
_outputBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomThreshold"));
_outputBuffer->setRenderBuffer(0, colorTexture);
+
+ _parameters.edit()._deltaUV = { 1.0f / bufferSize.x, 1.0f / bufferSize.y };
}
static const int COLOR_MAP_SLOT = 0;
- static const int THRESHOLD_SLOT = 1;
+ static const int PARAMETERS_SLOT = 1;
if (!_pipeline) {
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
@@ -66,7 +71,7 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding("colorMap", COLOR_MAP_SLOT));
- slotBindings.insert(gpu::Shader::Binding("threshold", THRESHOLD_SLOT));
+ slotBindings.insert(gpu::Shader::Binding("parametersBuffer", PARAMETERS_SLOT));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
@@ -86,21 +91,26 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
batch.setFramebuffer(_outputBuffer);
batch.setResourceTexture(COLOR_MAP_SLOT, inputBuffer);
- batch._glUniform1f(THRESHOLD_SLOT, _threshold);
+ batch.setUniformBuffer(PARAMETERS_SLOT, _parameters);
batch.draw(gpu::TRIANGLE_STRIP, 4);
});
outputs = _outputBuffer;
}
-BloomApply::BloomApply() : _intensities{ 1.0f, 1.0f, 1.0f } {
+BloomApply::BloomApply() {
}
void BloomApply::configure(const Config& config) {
- _intensities.x = config.intensity / 3.0f;
- _intensities.y = _intensities.x;
- _intensities.z = _intensities.x;
+ const auto newIntensity = config.intensity / 3.0f;
+
+ if (_parameters.get()._intensities.x != newIntensity) {
+ auto& parameters = _parameters.edit();
+ parameters._intensities.x = newIntensity;
+ parameters._intensities.y = newIntensity;
+ parameters._intensities.z = newIntensity;
+ }
}
void BloomApply::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
@@ -111,7 +121,7 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In
static const auto BLUR0_SLOT = 0;
static const auto BLUR1_SLOT = 1;
static const auto BLUR2_SLOT = 2;
- static const auto INTENSITY_SLOT = 3;
+ static const auto PARAMETERS_SLOT = 0;
if (!_pipeline) {
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
@@ -122,7 +132,7 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In
slotBindings.insert(gpu::Shader::Binding("blurMap0", BLUR0_SLOT));
slotBindings.insert(gpu::Shader::Binding("blurMap1", BLUR1_SLOT));
slotBindings.insert(gpu::Shader::Binding("blurMap2", BLUR2_SLOT));
- slotBindings.insert(gpu::Shader::Binding("intensity", INTENSITY_SLOT));
+ slotBindings.insert(gpu::Shader::Binding("parametersBuffer", PARAMETERS_SLOT));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
@@ -151,7 +161,7 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In
batch.setResourceTexture(BLUR0_SLOT, blur0FB->getRenderBuffer(0));
batch.setResourceTexture(BLUR1_SLOT, blur1FB->getRenderBuffer(0));
batch.setResourceTexture(BLUR2_SLOT, blur2FB->getRenderBuffer(0));
- batch._glUniform3f(INTENSITY_SLOT, _intensities.x, _intensities.y, _intensities.z);
+ batch.setUniformBuffer(PARAMETERS_SLOT, _parameters);
batch.draw(gpu::TRIANGLE_STRIP, 4);
});
}
diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h
index 2ff6bc35a7..04cb4a9474 100644
--- a/libraries/render-utils/src/BloomEffect.h
+++ b/libraries/render-utils/src/BloomEffect.h
@@ -61,10 +61,11 @@ public:
private:
+#include "BloomThreshold.shared.slh"
+
gpu::FramebufferPointer _outputBuffer;
gpu::PipelinePointer _pipeline;
- float _threshold;
- unsigned int _downsamplingFactor;
+ gpu::StructBuffer _parameters;
};
@@ -95,8 +96,10 @@ public:
private:
+#include "BloomApply.shared.slh"
+
gpu::PipelinePointer _pipeline;
- glm::vec3 _intensities;
+ gpu::StructBuffer _parameters;
};
class BloomDraw {
diff --git a/libraries/render-utils/src/BloomThreshold.shared.slh b/libraries/render-utils/src/BloomThreshold.shared.slh
new file mode 100644
index 0000000000..8aaf8ec311
--- /dev/null
+++ b/libraries/render-utils/src/BloomThreshold.shared.slh
@@ -0,0 +1,18 @@
+// glsl / C++ compatible source as interface for BloomThreshold
+#ifdef __cplusplus
+# define BT_VEC2 glm::vec2
+#else
+# define BT_VEC2 vec2
+#endif
+
+struct Parameters
+{
+ BT_VEC2 _deltaUV;
+ float _threshold;
+ int _sampleCount;
+};
+
+ // <@if 1@>
+ // Trigger Scribe include
+ // <@endif@>
+//
diff --git a/libraries/render-utils/src/BloomThreshold.slf b/libraries/render-utils/src/BloomThreshold.slf
index e4b96618df..6eb75fba6e 100644
--- a/libraries/render-utils/src/BloomThreshold.slf
+++ b/libraries/render-utils/src/BloomThreshold.slf
@@ -9,37 +9,35 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+<@include BloomThreshold.shared.slh@>
uniform sampler2D colorMap;
-uniform float threshold;
+layout(std140) uniform parametersBuffer {
+ Parameters parameters;
+};
in vec2 varTexCoord0;
out vec4 outFragColor;
-#define DOWNSAMPLING_FACTOR 4
-#define SAMPLE_COUNT (DOWNSAMPLING_FACTOR/2)
-
void main(void) {
- vec2 deltaX = dFdx(varTexCoord0) / SAMPLE_COUNT;
- vec2 deltaY = dFdy(varTexCoord0) / SAMPLE_COUNT;
vec2 startUv = varTexCoord0;
vec4 maskedColor = vec4(0,0,0,0);
- for (int y=0 ; y 0.0) && (hazeParams.hazeMode & HAZE_MODE_IS_ACTIVE) == HAZE_MODE_IS_ACTIVE) {
- vec4 colorV4 = computeHazeColor(
- vec4(color, 1.0), // fragment original color
+ vec4 hazeColor = computeHazeColor(
positionES, // fragment position in eye coordinates
fragPositionWS, // fragment position in world coordinates
invViewMat[3].xyz, // eye position in world coordinates
lightDirection // keylight direction vector in world coordinates
);
- color = colorV4.rgb;
+ color = mix(color.rgb, hazeColor.rgb, hazeColor.a);
}
return color;
@@ -273,15 +272,14 @@ vec3 evalGlobalLightingAlphaBlendedWithHaze(
// Haze
if ((isHazeEnabled() > 0.0) && (hazeParams.hazeMode & HAZE_MODE_IS_ACTIVE) == HAZE_MODE_IS_ACTIVE) {
- vec4 colorV4 = computeHazeColor(
- vec4(color, 1.0), // fragment original color
+ vec4 hazeColor = computeHazeColor(
positionES, // fragment position in eye coordinates
positionWS, // fragment position in world coordinates
invViewMat[3].xyz, // eye position in world coordinates
lightDirection // keylight direction vector
);
- color = colorV4.rgb;
+ color = mix(color.rgb, hazeColor.rgb, hazeColor.a);
}
return color;
diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp
index 136bc2dabf..48ddfbf5cd 100644
--- a/libraries/render-utils/src/DeferredLightingEffect.cpp
+++ b/libraries/render-utils/src/DeferredLightingEffect.cpp
@@ -393,34 +393,42 @@ graphics::MeshPointer DeferredLightingEffect::getSpotLightMesh() {
return _spotLightMesh;
}
-void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer) {
+gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) {
+ gpu::FramebufferPointer framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(name));
+ auto colorFormat = gpu::Element::COLOR_SRGBA_32;
+
+ auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR);
+ auto primaryColorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler);
+
+ framebuffer->setRenderBuffer(0, primaryColorTexture);
+
+ auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
+ auto primaryDepthTexture = gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler);
+
+ framebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat);
+
+ return framebuffer;
+}
+
+void PreparePrimaryFramebuffer::configure(const Config& config) {
+ _resolutionScale = config.resolutionScale;
+}
+
+void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, Output& primaryFramebuffer) {
glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w);
+ glm::uvec2 scaledFrameSize(glm::vec2(frameSize) * _resolutionScale);
// Resizing framebuffers instead of re-building them seems to cause issues with threaded
// rendering
- if (_primaryFramebuffer && _primaryFramebuffer->getSize() != frameSize) {
- _primaryFramebuffer.reset();
+ if (!_primaryFramebuffer || _primaryFramebuffer->getSize() != scaledFrameSize) {
+ _primaryFramebuffer = createFramebuffer("deferredPrimary", scaledFrameSize);
}
- if (!_primaryFramebuffer) {
- _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("deferredPrimary"));
- auto colorFormat = gpu::Element::COLOR_SRGBA_32;
-
- auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
- auto primaryColorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler);
-
-
- _primaryFramebuffer->setRenderBuffer(0, primaryColorTexture);
-
-
- auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
- auto primaryDepthTexture = gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler);
-
- _primaryFramebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat);
- }
-
-
primaryFramebuffer = _primaryFramebuffer;
+
+ // Set viewport for the rest of the scaled passes
+ renderContext->args->_viewport.z = scaledFrameSize.x;
+ renderContext->args->_viewport.w = scaledFrameSize.y;
}
void PrepareDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h
index 96d3f42958..fc4abb28c4 100644
--- a/libraries/render-utils/src/DeferredLightingEffect.h
+++ b/libraries/render-utils/src/DeferredLightingEffect.h
@@ -93,13 +93,34 @@ private:
friend class RenderDeferredCleanup;
};
+class PreparePrimaryFramebufferConfig : public render::Job::Config {
+ Q_OBJECT
+ Q_PROPERTY(float resolutionScale MEMBER resolutionScale NOTIFY dirty)
+public:
+
+ float resolutionScale{ 1.0f };
+
+signals:
+ void dirty();
+};
+
class PreparePrimaryFramebuffer {
public:
- using JobModel = render::Job::ModelO;
- void run(const render::RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer);
+ using Output = gpu::FramebufferPointer;
+ using Config = PreparePrimaryFramebufferConfig;
+ using JobModel = render::Job::ModelO;
+
+ PreparePrimaryFramebuffer(float resolutionScale = 1.0f) : _resolutionScale{resolutionScale} {}
+ void configure(const Config& config);
+ void run(const render::RenderContextPointer& renderContext, Output& primaryFramebuffer);
gpu::FramebufferPointer _primaryFramebuffer;
+ float _resolutionScale{ 1.0f };
+
+private:
+
+ static gpu::FramebufferPointer createFramebuffer(const char* name, const glm::uvec2& size);
};
class PrepareDeferred {
diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp
index e6337d7099..94bac4e3ac 100644
--- a/libraries/render-utils/src/DrawHaze.cpp
+++ b/libraries/render-utils/src/DrawHaze.cpp
@@ -107,11 +107,11 @@ void MakeHaze::run(const render::RenderContextPointer& renderContext, graphics::
haze = _haze;
}
+// Buffer slots
const int HazeEffect_ParamsSlot = 0;
const int HazeEffect_TransformBufferSlot = 1;
-const int HazeEffect_ColorMapSlot = 2;
-const int HazeEffect_LinearDepthMapSlot = 3;
-const int HazeEffect_LightingMapSlot = 4;
+// Texture slots
+const int HazeEffect_LinearDepthMapSlot = 0;
void DrawHaze::configure(const Config& config) {
}
@@ -122,11 +122,10 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
return;
}
- const auto inputBuffer = inputs.get1()->getRenderBuffer(0);
+ const auto outputBuffer = inputs.get1();
const auto framebuffer = inputs.get2();
const auto transformBuffer = inputs.get3();
-
- auto outputBuffer = inputs.get4();
+ const auto lightingModel = inputs.get4();
auto depthBuffer = framebuffer->getLinearDepthTexture();
@@ -139,6 +138,10 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
+ state->setBlendFunction(true,
+ gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
+ gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
+
// Mask out haze on the tablet
PrepareStencil::testMask(*state);
@@ -148,15 +151,15 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), HazeEffect_ParamsSlot));
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), HazeEffect_TransformBufferSlot));
- slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), HazeEffect_ColorMapSlot));
+ slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), render::ShapePipeline::Slot::LIGHTING_MODEL));
slotBindings.insert(gpu::Shader::Binding(std::string("linearDepthMap"), HazeEffect_LinearDepthMapSlot));
- slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), HazeEffect_LightingMapSlot));
+ slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), render::ShapePipeline::Slot::KEY_LIGHT));
gpu::Shader::makeProgram(*program, slotBindings);
});
});
}
- auto sourceFramebufferSize = glm::ivec2(inputBuffer->getDimensions());
+ auto outputFramebufferSize = glm::ivec2(outputBuffer->getSize());
gpu::doInBatch("DrawHaze::run", args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false);
@@ -165,7 +168,7 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
batch.setViewportTransform(args->_viewport);
batch.setProjectionTransform(glm::mat4());
batch.resetViewTransform();
- batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(sourceFramebufferSize, args->_viewport));
+ batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(outputFramebufferSize, args->_viewport));
batch.setPipeline(_hazePipeline);
@@ -181,17 +184,17 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
}
batch.setUniformBuffer(HazeEffect_TransformBufferSlot, transformBuffer->getFrameTransformBuffer());
+ batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer());
auto lightStage = args->_scene->getStage();
if (lightStage) {
graphics::LightPointer keyLight;
keyLight = lightStage->getCurrentKeyLight();
if (keyLight) {
- batch.setUniformBuffer(HazeEffect_LightingMapSlot, keyLight->getLightSchemaBuffer());
+ batch.setUniformBuffer(render::ShapePipeline::Slot::KEY_LIGHT, keyLight->getLightSchemaBuffer());
}
}
- batch.setResourceTexture(HazeEffect_ColorMapSlot, inputBuffer);
batch.setResourceTexture(HazeEffect_LinearDepthMapSlot, depthBuffer);
batch.draw(gpu::TRIANGLE_STRIP, 4);
diff --git a/libraries/render-utils/src/DrawHaze.h b/libraries/render-utils/src/DrawHaze.h
index e7d4e15d77..e30ce26dd4 100644
--- a/libraries/render-utils/src/DrawHaze.h
+++ b/libraries/render-utils/src/DrawHaze.h
@@ -22,6 +22,7 @@
#include
#include "SurfaceGeometryPass.h"
+#include "LightingModel.h"
using LinearDepthFramebufferPointer = std::shared_ptr;
@@ -159,7 +160,7 @@ public:
class DrawHaze {
public:
- using Inputs = render::VaryingSet5;
+ using Inputs = render::VaryingSet5;
using Config = HazeConfig;
using JobModel = render::Job::ModelI;
diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh
index a06c8c869e..a4e8fdf1f4 100644
--- a/libraries/render-utils/src/Fade.slh
+++ b/libraries/render-utils/src/Fade.slh
@@ -15,19 +15,20 @@
#define CATEGORY_COUNT 5
<@include Fade_shared.slh@>
+<@include FadeObjectParams.shared.slh@>
layout(std140) uniform fadeParametersBuffer {
FadeParameters fadeParameters[CATEGORY_COUNT];
};
uniform sampler2D fadeMaskMap;
-struct FadeObjectParams {
- int category;
- float threshold;
- vec3 noiseOffset;
- vec3 baseOffset;
- vec3 baseInvSize;
-};
+vec3 getNoiseInverseSize(int category) {
+ return fadeParameters[category]._noiseInvSizeAndLevel.xyz;
+}
+
+float getNoiseLevel(int category) {
+ return fadeParameters[category]._noiseInvSizeAndLevel.w;
+}
vec2 hash2D(vec3 position) {
return position.xy* vec2(0.1677, 0.221765) + position.z*0.561;
@@ -40,7 +41,7 @@ float noise3D(vec3 position) {
float evalFadeNoiseGradient(FadeObjectParams params, vec3 position) {
// Do tri-linear interpolation
- vec3 noisePosition = position * fadeParameters[params.category]._noiseInvSizeAndLevel.xyz + params.noiseOffset;
+ vec3 noisePosition = position * getNoiseInverseSize(params.category) + params.noiseOffset.xyz;
vec3 noisePositionFloored = floor(noisePosition);
vec3 noisePositionFraction = fract(noisePosition);
@@ -61,11 +62,11 @@ float evalFadeNoiseGradient(FadeObjectParams params, vec3 position) {
float noise = mix(maskY.x, maskY.y, noisePositionFraction.y);
noise -= 0.5; // Center on value 0
- return noise * fadeParameters[params.category]._noiseInvSizeAndLevel.w;
+ return noise * getNoiseLevel(params.category);
}
float evalFadeBaseGradient(FadeObjectParams params, vec3 position) {
- float gradient = length((position - params.baseOffset) * params.baseInvSize.xyz);
+ float gradient = length((position - params.baseOffset.xyz) * params.baseInvSize.xyz);
gradient = gradient-0.5; // Center on value 0.5
gradient *= fadeParameters[params.category]._baseLevel;
return gradient;
@@ -112,20 +113,14 @@ void applyFade(FadeObjectParams params, vec3 position, out vec3 emissive) {
<@func declareFadeFragmentUniform()@>
-uniform int fadeCategory;
-uniform vec3 fadeNoiseOffset;
-uniform vec3 fadeBaseOffset;
-uniform vec3 fadeBaseInvSize;
-uniform float fadeThreshold;
+layout(std140) uniform fadeObjectParametersBuffer {
+ FadeObjectParams fadeObjectParams;
+};
<@endfunc@>
<@func fetchFadeObjectParams(fadeParams)@>
- <$fadeParams$>.category = fadeCategory;
- <$fadeParams$>.threshold = fadeThreshold;
- <$fadeParams$>.noiseOffset = fadeNoiseOffset;
- <$fadeParams$>.baseOffset = fadeBaseOffset;
- <$fadeParams$>.baseInvSize = fadeBaseInvSize;
+ <$fadeParams$> = fadeObjectParams;
<@endfunc@>
<@func declareFadeFragmentVertexInput()@>
@@ -139,9 +134,9 @@ in vec4 _fadeData3;
<@func fetchFadeObjectParamsInstanced(fadeParams)@>
<$fadeParams$>.category = int(_fadeData1.w);
<$fadeParams$>.threshold = _fadeData2.w;
- <$fadeParams$>.noiseOffset = _fadeData1.xyz;
- <$fadeParams$>.baseOffset = _fadeData2.xyz;
- <$fadeParams$>.baseInvSize = _fadeData3.xyz;
+ <$fadeParams$>.noiseOffset = _fadeData1;
+ <$fadeParams$>.baseOffset = _fadeData2;
+ <$fadeParams$>.baseInvSize = _fadeData3;
<@endfunc@>
<@func declareFadeFragment()@>
diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp
index c09aa99988..12531d4c9d 100644
--- a/libraries/render-utils/src/FadeEffect.cpp
+++ b/libraries/render-utils/src/FadeEffect.cpp
@@ -13,6 +13,8 @@
#include "render/TransitionStage.h"
+#include "FadeObjectParams.shared.slh"
+
#include
FadeEffect::FadeEffect() {
@@ -31,15 +33,8 @@ void FadeEffect::build(render::Task::TaskConcept& task, const task::Varying& edi
render::ShapePipeline::BatchSetter FadeEffect::getBatchSetter() const {
return [this](const render::ShapePipeline& shapePipeline, gpu::Batch& batch, render::Args*) {
- auto program = shapePipeline.pipeline->getProgram();
- auto maskMapLocation = program->getTextures().findLocation("fadeMaskMap");
- auto bufferLocation = program->getUniformBuffers().findLocation("fadeParametersBuffer");
- if (maskMapLocation != -1) {
- batch.setResourceTexture(maskMapLocation, _maskMap);
- }
- if (bufferLocation != -1) {
- batch.setUniformBuffer(bufferLocation, _configurations);
- }
+ batch.setResourceTexture(render::ShapePipeline::Slot::FADE_MASK, _maskMap);
+ batch.setUniformBuffer(render::ShapePipeline::Slot::FADE_PARAMETERS, _configurations);
};
}
@@ -50,23 +45,29 @@ render::ShapePipeline::ItemSetter FadeEffect::getItemUniformSetter() const {
auto batch = args->_batch;
auto transitionStage = scene->getStage(render::TransitionStage::getName());
auto& transitionState = transitionStage->getTransition(item.getTransitionId());
- auto program = shapePipeline.pipeline->getProgram();
- auto& uniforms = program->getUniforms();
- auto fadeNoiseOffsetLocation = uniforms.findLocation("fadeNoiseOffset");
- auto fadeBaseOffsetLocation = uniforms.findLocation("fadeBaseOffset");
- auto fadeBaseInvSizeLocation = uniforms.findLocation("fadeBaseInvSize");
- auto fadeThresholdLocation = uniforms.findLocation("fadeThreshold");
- auto fadeCategoryLocation = uniforms.findLocation("fadeCategory");
- if (fadeNoiseOffsetLocation >= 0 || fadeBaseInvSizeLocation >= 0 || fadeBaseOffsetLocation >= 0 || fadeThresholdLocation >= 0 || fadeCategoryLocation >= 0) {
- const auto fadeCategory = FadeJob::transitionToCategory[transitionState.eventType];
-
- batch->_glUniform1i(fadeCategoryLocation, fadeCategory);
- batch->_glUniform1f(fadeThresholdLocation, transitionState.threshold);
- batch->_glUniform3f(fadeNoiseOffsetLocation, transitionState.noiseOffset.x, transitionState.noiseOffset.y, transitionState.noiseOffset.z);
- batch->_glUniform3f(fadeBaseOffsetLocation, transitionState.baseOffset.x, transitionState.baseOffset.y, transitionState.baseOffset.z);
- batch->_glUniform3f(fadeBaseInvSizeLocation, transitionState.baseInvSize.x, transitionState.baseInvSize.y, transitionState.baseInvSize.z);
+ if (transitionState.paramsBuffer._size != sizeof(gpu::StructBuffer)) {
+ static_assert(sizeof(transitionState.paramsBuffer) == sizeof(gpu::StructBuffer), "Assuming gpu::StructBuffer is a helper class for gpu::BufferView");
+ transitionState.paramsBuffer = gpu::StructBuffer();
}
+
+ const auto fadeCategory = FadeJob::transitionToCategory[transitionState.eventType];
+ auto& paramsConst = static_cast&>(transitionState.paramsBuffer).get();
+
+ if (paramsConst.category != fadeCategory
+ || paramsConst.threshold != transitionState.threshold
+ || glm::vec3(paramsConst.baseOffset) != transitionState.baseOffset
+ || glm::vec3(paramsConst.noiseOffset) != transitionState.noiseOffset
+ || glm::vec3(paramsConst.baseInvSize) != transitionState.baseInvSize) {
+ auto& params = static_cast&>(transitionState.paramsBuffer).edit();
+
+ params.category = fadeCategory;
+ params.threshold = transitionState.threshold;
+ params.baseInvSize = glm::vec4(transitionState.baseInvSize, 0.0f);
+ params.noiseOffset = glm::vec4(transitionState.noiseOffset, 0.0f);
+ params.baseOffset = glm::vec4(transitionState.baseOffset, 0.0f);
+ }
+ batch->setUniformBuffer(render::ShapePipeline::Slot::FADE_OBJECT_PARAMETERS, transitionState.paramsBuffer);
}
};
}
diff --git a/libraries/render-utils/src/FadeObjectParams.shared.slh b/libraries/render-utils/src/FadeObjectParams.shared.slh
new file mode 100644
index 0000000000..e97acaf0b0
--- /dev/null
+++ b/libraries/render-utils/src/FadeObjectParams.shared.slh
@@ -0,0 +1,25 @@
+// glsl / C++ compatible source as interface for FadeObjectParams
+#ifdef __cplusplus
+# define FOP_VEC4 glm::vec4
+# define FOP_VEC2 glm::vec2
+# define FOP_FLOAT32 glm::float32
+# define FOP_INT32 glm::int32
+#else
+# define FOP_VEC4 vec4
+# define FOP_VEC2 vec2
+# define FOP_FLOAT32 float
+# define FOP_INT32 int
+#endif
+
+struct FadeObjectParams {
+ FOP_VEC4 noiseOffset;
+ FOP_VEC4 baseOffset;
+ FOP_VEC4 baseInvSize;
+ FOP_INT32 category;
+ FOP_FLOAT32 threshold;
+};
+
+ // <@if 1@>
+ // Trigger Scribe include
+ // <@endif@>
+//
diff --git a/libraries/render-utils/src/ForwardGlobalLight.slh b/libraries/render-utils/src/ForwardGlobalLight.slh
index eccc44186c..cf5f070c55 100644
--- a/libraries/render-utils/src/ForwardGlobalLight.slh
+++ b/libraries/render-utils/src/ForwardGlobalLight.slh
@@ -228,15 +228,14 @@ vec3 evalGlobalLightingAlphaBlendedWithHaze(
// Haze
// FIXME - temporarily removed until we support it for forward...
/* if ((hazeParams.hazeMode & HAZE_MODE_IS_ACTIVE) == HAZE_MODE_IS_ACTIVE) {
- vec4 colorV4 = computeHazeColor(
- vec4(color, 1.0), // fragment original color
+ vec4 hazeColor = computeHazeColor(
positionES, // fragment position in eye coordinates
fragPositionWS, // fragment position in world coordinates
invViewMat[3].xyz, // eye position in world coordinates
lightDirection // keylight direction vector
);
- color = colorV4.rgb;
+ color = mix(color.rgb, hazeColor.rgb, hazeColor.a);
}*/
return color;
diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf
index 6b45a72768..93b66d99ed 100644
--- a/libraries/render-utils/src/Haze.slf
+++ b/libraries/render-utils/src/Haze.slf
@@ -22,7 +22,6 @@
<@include Haze.slh@>
-uniform sampler2D colorMap;
uniform sampler2D linearDepthMap;
vec4 unpackPositionFromZeye(vec2 texcoord) {
@@ -46,7 +45,6 @@ void main(void) {
discard;
}
- vec4 fragColor = texture(colorMap, varTexCoord0);
vec4 fragPositionES = unpackPositionFromZeye(varTexCoord0);
mat4 viewInverse = getViewInverse();
@@ -56,5 +54,8 @@ void main(void) {
Light light = getKeyLight();
vec3 lightDirectionWS = getLightDirection(light);
- outFragColor = computeHazeColor(fragColor, fragPositionES.xyz, fragPositionWS.xyz, eyePositionWS.xyz, lightDirectionWS);
+ outFragColor = computeHazeColor(fragPositionES.xyz, fragPositionWS.xyz, eyePositionWS.xyz, lightDirectionWS);
+ if (outFragColor.a < 1e-4) {
+ discard;
+ }
}
diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh
index ab973ba752..7854ad08ca 100644
--- a/libraries/render-utils/src/Haze.slh
+++ b/libraries/render-utils/src/Haze.slh
@@ -92,22 +92,21 @@ vec3 computeHazeColorKeyLightAttenuation(vec3 color, vec3 lightDirectionWS, vec3
}
// Input:
-// fragColor - fragment original color
// fragPositionES - fragment position in eye coordinates
// fragPositionWS - fragment position in world coordinates
// eyePositionWS - eye position in world coordinates
// Output:
-// fragment colour after haze effect
+// haze colour and alpha contains haze blend factor
//
// General algorithm taken from http://www.iquilezles.org/www/articles/fog/fog.htm, with permission
//
-vec4 computeHazeColor(vec4 fragColor, vec3 fragPositionES, vec3 fragPositionWS, vec3 eyePositionWS, vec3 lightDirectionWS) {
+vec4 computeHazeColor(vec3 fragPositionES, vec3 fragPositionWS, vec3 eyePositionWS, vec3 lightDirectionWS) {
// Distance to fragment
float distance = length(fragPositionES);
float eyeWorldHeight = eyePositionWS.y;
// Convert haze colour from uniform into a vec4
- vec4 hazeColor = vec4(hazeParams.hazeColor, 1.0);
+ vec4 hazeColor = vec4(hazeParams.hazeColor, 1.0);
// Use the haze colour for the glare colour, if blend is not enabled
vec4 blendedHazeColor;
@@ -149,13 +148,13 @@ vec4 computeHazeColor(vec4 fragColor, vec3 fragPositionES, vec3 fragPositionWS,
vec3 hazeAmount = 1.0 - exp(-hazeIntegral);
// Compute color after haze effect
- potentialFragColor = mix(fragColor, vec4(1.0, 1.0, 1.0, 1.0), vec4(hazeAmount, 1.0));
+ potentialFragColor = vec4(1.0, 1.0, 1.0, hazeAmount);
} else if ((hazeParams.hazeMode & HAZE_MODE_IS_ALTITUDE_BASED) != HAZE_MODE_IS_ALTITUDE_BASED) {
// Haze is based only on range
float hazeAmount = 1.0 - exp(-distance * hazeParams.hazeRangeFactor);
// Compute color after haze effect
- potentialFragColor = mix(fragColor, blendedHazeColor, hazeAmount);
+ potentialFragColor = vec4(blendedHazeColor.rgb, hazeAmount);
} else {
// Haze is based on both range and altitude
// Taken from www.crytek.com/download/GDC2007_RealtimeAtmoFxInGamesRev.ppt
@@ -181,16 +180,14 @@ vec4 computeHazeColor(vec4 fragColor, vec3 fragPositionES, vec3 fragPositionWS,
float hazeAmount = 1.0 - exp(-hazeIntegral);
// Compute color after haze effect
- potentialFragColor = mix(fragColor, blendedHazeColor, hazeAmount);
+ potentialFragColor = vec4(blendedHazeColor.rgb, hazeAmount);
}
// Mix with background at far range
const float BLEND_DISTANCE = 27000.0f;
- vec4 outFragColor;
+ vec4 outFragColor = potentialFragColor;
if (distance > BLEND_DISTANCE) {
- outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlend);
- } else {
- outFragColor = potentialFragColor;
+ outFragColor.a *= hazeParams.backgroundBlend;
}
return outFragColor;
diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp
index 20d0cc39be..6c8a90da81 100644
--- a/libraries/render-utils/src/HighlightEffect.cpp
+++ b/libraries/render-utils/src/HighlightEffect.cpp
@@ -117,6 +117,9 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
assert(renderContext->args->hasViewFrustum());
auto& inShapes = inputs.get0();
+ const int BOUNDS_SLOT = 0;
+ const int PARAMETERS_SLOT = 1;
+
if (!_stencilMaskPipeline || !_stencilMaskFillPipeline) {
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(true, false, gpu::LESS_EQUAL);
@@ -135,6 +138,8 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
+ slotBindings.insert(gpu::Shader::Binding(std::string("ssbo0Buffer"), BOUNDS_SLOT));
+ slotBindings.insert(gpu::Shader::Binding(std::string("parametersBuffer"), PARAMETERS_SLOT));
gpu::Shader::makeProgram(*program, slotBindings);
_stencilMaskPipeline = gpu::Pipeline::create(program, state);
@@ -214,6 +219,15 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
_boundsBuffer->setData(itemBounds.size() * sizeof(render::ItemBound), (const gpu::Byte*) itemBounds.data());
+ const auto securityMargin = 2.0f;
+ const float blurPixelWidth = 2.0f * securityMargin * HighlightSharedParameters::getBlurPixelWidth(highlight._style, args->_viewport.w);
+ const auto framebufferSize = ressources->getSourceFrameSize();
+ const glm::vec2 highlightWidth = { blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y };
+
+ if (highlightWidth != _outlineWidth.get()) {
+ _outlineWidth.edit() = highlightWidth;
+ }
+
gpu::doInBatch("DrawHighlightMask::run::end", args->_context, [&](gpu::Batch& batch) {
// Setup camera, projection and viewport for all items
batch.setViewportTransform(args->_viewport);
@@ -221,15 +235,10 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
batch.setViewTransform(viewMat);
// Draw stencil mask with object bounding boxes
- const auto highlightWidthLoc = _stencilMaskPipeline->getProgram()->getUniforms().findLocation("outlineWidth");
- const auto securityMargin = 2.0f;
- const float blurPixelWidth = 2.0f * securityMargin * HighlightSharedParameters::getBlurPixelWidth(highlight._style, args->_viewport.w);
- const auto framebufferSize = ressources->getSourceFrameSize();
-
auto stencilPipeline = highlight._style.isFilled() ? _stencilMaskFillPipeline : _stencilMaskPipeline;
batch.setPipeline(stencilPipeline);
- batch.setResourceBuffer(0, _boundsBuffer);
- batch._glUniform2f(highlightWidthLoc, blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y);
+ batch.setResourceBuffer(BOUNDS_SLOT, _boundsBuffer);
+ batch.setUniformBuffer(PARAMETERS_SLOT, _outlineWidth);
static const int NUM_VERTICES_PER_CUBE = 36;
batch.draw(gpu::TRIANGLES, NUM_VERTICES_PER_CUBE * (gpu::uint32) itemBounds.size(), 0);
});
diff --git a/libraries/render-utils/src/HighlightEffect.h b/libraries/render-utils/src/HighlightEffect.h
index 8af11da237..eee1c29cb7 100644
--- a/libraries/render-utils/src/HighlightEffect.h
+++ b/libraries/render-utils/src/HighlightEffect.h
@@ -127,6 +127,7 @@ protected:
render::ShapePlumberPointer _shapePlumber;
HighlightSharedParametersPointer _sharedParameters;
gpu::BufferPointer _boundsBuffer;
+ gpu::StructBuffer _outlineWidth;
static gpu::PipelinePointer _stencilMaskPipeline;
static gpu::PipelinePointer _stencilMaskFillPipeline;
diff --git a/libraries/render-utils/src/Highlight_aabox.slv b/libraries/render-utils/src/Highlight_aabox.slv
index 4927db9610..2a87e00f94 100644
--- a/libraries/render-utils/src/Highlight_aabox.slv
+++ b/libraries/render-utils/src/Highlight_aabox.slv
@@ -40,7 +40,9 @@ ItemBound getItemBound(int i) {
}
#endif
-uniform vec2 outlineWidth;
+uniform parametersBuffer {
+ vec2 outlineWidth;
+};
void main(void) {
const vec3 UNIT_BOX_VERTICES[8] = vec3[8](
diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp
index 24715f0afb..c2181b7613 100644
--- a/libraries/render-utils/src/RenderCommonTask.cpp
+++ b/libraries/render-utils/src/RenderCommonTask.cpp
@@ -51,19 +51,19 @@ void DrawOverlay3D::run(const RenderContextPointer& renderContext, const Inputs&
config->setNumDrawn((int)inItems.size());
emit config->numDrawnChanged();
+ RenderArgs* args = renderContext->args;
+
+ // Clear the framebuffer without stereo
+ // Needs to be distinct from the other batch because using the clear call
+ // while stereo is enabled triggers a warning
+ if (_opaquePass) {
+ gpu::doInBatch("DrawOverlay3D::run::clear", args->_context, [&](gpu::Batch& batch) {
+ batch.enableStereo(false);
+ batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0, false);
+ });
+ }
+
if (!inItems.empty()) {
- RenderArgs* args = renderContext->args;
-
- // Clear the framebuffer without stereo
- // Needs to be distinct from the other batch because using the clear call
- // while stereo is enabled triggers a warning
- if (_opaquePass) {
- gpu::doInBatch("DrawOverlay3D::run::clear", args->_context, [&](gpu::Batch& batch){
- batch.enableStereo(false);
- batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0, false);
- });
- }
-
// Render the items
gpu::doInBatch("DrawOverlay3D::main", args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp
index 32bdad280c..0b05977265 100644
--- a/libraries/render-utils/src/RenderDeferredTask.cpp
+++ b/libraries/render-utils/src/RenderDeferredTask.cpp
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#include "RenderHifi.h"
#include "RenderCommonTask.h"
@@ -59,8 +60,14 @@ RenderDeferredTask::RenderDeferredTask()
{
}
-void RenderDeferredTask::configure(const Config& config)
-{
+void RenderDeferredTask::configure(const Config& config) {
+ // Propagate resolution scale to sub jobs who need it
+ auto preparePrimaryBufferConfig = config.getConfig("PreparePrimaryBuffer");
+ auto upsamplePrimaryBufferConfig = config.getConfig("PrimaryBufferUpscale");
+ assert(preparePrimaryBufferConfig);
+ assert(upsamplePrimaryBufferConfig);
+ preparePrimaryBufferConfig->setProperty("resolutionScale", config.resolutionScale);
+ upsamplePrimaryBufferConfig->setProperty("factor", 1.0f / config.resolutionScale);
}
const render::Varying RenderDeferredTask::addSelectItemJobs(JobModel& task, const char* selectionName,
@@ -97,23 +104,22 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto jitter = task.addJob("JitterCam");
- // Prepare deferred, generate the shared Deferred Frame Transform
+ // GPU jobs: Start preparing the primary, deferred and lighting buffer
+ const auto scaledPrimaryFramebuffer = task.addJob("PreparePrimaryBuffer");
+
+ // Prepare deferred, generate the shared Deferred Frame Transform. Only valid with the scaled frame buffer
const auto deferredFrameTransform = task.addJob("DeferredFrameTransform", jitter);
const auto lightingModel = task.addJob("LightingModel");
-
-
- // GPU jobs: Start preparing the primary, deferred and lighting buffer
- const auto primaryFramebuffer = task.addJob("PreparePrimaryBuffer");
const auto opaqueRangeTimer = task.addJob("BeginOpaqueRangeTimer", "DrawOpaques");
- const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).asVarying();
+ const auto prepareDeferredInputs = PrepareDeferred::Inputs(scaledPrimaryFramebuffer, lightingModel).asVarying();
const auto prepareDeferredOutputs = task.addJob("PrepareDeferred", prepareDeferredInputs);
const auto deferredFramebuffer = prepareDeferredOutputs.getN(0);
const auto lightingFramebuffer = prepareDeferredOutputs.getN(1);
// draw a stencil mask in hidden regions of the framebuffer.
- task.addJob("PrepareStencil", primaryFramebuffer);
+ task.addJob("PrepareStencil", scaledPrimaryFramebuffer);
// Render opaque objects in DeferredBuffer
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel, jitter).asVarying();
@@ -174,7 +180,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
// Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job
task.addJob("DrawBackgroundDeferred", lightingModel);
- const auto drawHazeInputs = render::Varying(DrawHaze::Inputs(hazeModel, lightingFramebuffer, linearDepthTarget, deferredFrameTransform, lightingFramebuffer));
+ const auto drawHazeInputs = render::Varying(DrawHaze::Inputs(hazeModel, lightingFramebuffer, linearDepthTarget, deferredFrameTransform, lightingModel));
task.addJob("DrawHazeDeferred", drawHazeInputs);
// Render transparent objects forward in LightingBuffer
@@ -223,7 +229,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob("Bloom", bloomInputs);
// Lighting Buffer ready for tone mapping
- const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer).asVarying();
+ const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, scaledPrimaryFramebuffer).asVarying();
task.addJob("ToneMapping", toneMappingInputs);
{ // Debug the bounds of the rendered items, still look at the zbuffer
@@ -284,6 +290,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob("DrawZoneStack", deferredFrameTransform);
}
+ // Upscale to finale resolution
+ const auto primaryFramebuffer = task.addJob("PrimaryBufferUpscale", scaledPrimaryFramebuffer);
+
// Composite the HUD and HUD overlays
task.addJob("HUD");
diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h
index ab6ab177d2..1ce1682cf1 100644
--- a/libraries/render-utils/src/RenderDeferredTask.h
+++ b/libraries/render-utils/src/RenderDeferredTask.h
@@ -105,11 +105,13 @@ class RenderDeferredTaskConfig : public render::Task::Config {
Q_OBJECT
Q_PROPERTY(float fadeScale MEMBER fadeScale NOTIFY dirty)
Q_PROPERTY(float fadeDuration MEMBER fadeDuration NOTIFY dirty)
+ Q_PROPERTY(float resolutionScale MEMBER resolutionScale NOTIFY dirty)
Q_PROPERTY(bool debugFade MEMBER debugFade NOTIFY dirty)
Q_PROPERTY(float debugFadePercent MEMBER debugFadePercent NOTIFY dirty)
public:
float fadeScale{ 0.5f };
float fadeDuration{ 3.0f };
+ float resolutionScale{ 1.f };
float debugFadePercent{ 0.f };
bool debugFade{ false };
diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h
index 19ffcb4234..1c6291b1e0 100644
--- a/libraries/render-utils/src/RenderShadowTask.h
+++ b/libraries/render-utils/src/RenderShadowTask.h
@@ -36,7 +36,6 @@ protected:
class RenderShadowTaskConfig : public render::Task::Config::Persistent {
Q_OBJECT
- Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
public:
RenderShadowTaskConfig() : render::Task::Config::Persistent(QStringList() << "Render" << "Engine" << "Shadows", true) {}
diff --git a/libraries/render-utils/src/ToneMappingEffect.h b/libraries/render-utils/src/ToneMappingEffect.h
index 046e7606b3..69694b13f5 100644
--- a/libraries/render-utils/src/ToneMappingEffect.h
+++ b/libraries/render-utils/src/ToneMappingEffect.h
@@ -64,7 +64,6 @@ private:
class ToneMappingConfig : public render::Job::Config {
Q_OBJECT
- Q_PROPERTY(bool enabled MEMBER enabled)
Q_PROPERTY(float exposure MEMBER exposure WRITE setExposure);
Q_PROPERTY(int curve MEMBER curve WRITE setCurve);
public:
diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp
index 07f7367582..008234b437 100644
--- a/libraries/render/src/render/ResampleTask.cpp
+++ b/libraries/render/src/render/ResampleTask.cpp
@@ -81,3 +81,69 @@ void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::F
batch.draw(gpu::TRIANGLE_STRIP, 4);
});
}
+
+gpu::PipelinePointer Upsample::_pipeline;
+
+void Upsample::configure(const Config& config) {
+ _factor = config.factor;
+}
+
+gpu::FramebufferPointer Upsample::getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer) {
+ if (_factor == 1.0f) {
+ return sourceFramebuffer;
+ }
+
+ auto resampledFramebufferSize = glm::uvec2(glm::vec2(sourceFramebuffer->getSize()) * _factor);
+
+ if (!_destinationFrameBuffer || resampledFramebufferSize != _destinationFrameBuffer->getSize()) {
+ _destinationFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("UpsampledOutput"));
+
+ auto sampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR);
+ auto target = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), resampledFramebufferSize.x, resampledFramebufferSize.y, gpu::Texture::SINGLE_MIP, sampler);
+ _destinationFrameBuffer->setRenderBuffer(0, target);
+ }
+ return _destinationFrameBuffer;
+}
+
+void Upsample::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& resampledFrameBuffer) {
+ assert(renderContext->args);
+ assert(renderContext->args->hasViewFrustum());
+ RenderArgs* args = renderContext->args;
+
+ resampledFrameBuffer = getResampledFrameBuffer(sourceFramebuffer);
+ if (resampledFrameBuffer != sourceFramebuffer) {
+ if (!_pipeline) {
+ auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
+ auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS();
+ gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
+
+ gpu::Shader::BindingSet slotBindings;
+ gpu::Shader::makeProgram(*program, slotBindings);
+
+ gpu::StatePointer state = gpu::StatePointer(new gpu::State());
+ state->setDepthTest(gpu::State::DepthTest(false, false));
+ _pipeline = gpu::Pipeline::create(program, state);
+ }
+
+ const auto bufferSize = resampledFrameBuffer->getSize();
+ glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y };
+
+ gpu::doInBatch("Upsample::run", args->_context, [&](gpu::Batch& batch) {
+ batch.enableStereo(false);
+
+ batch.setFramebuffer(resampledFrameBuffer);
+
+ batch.setViewportTransform(viewport);
+ batch.setProjectionTransform(glm::mat4());
+ batch.resetViewTransform();
+ batch.setPipeline(_pipeline);
+
+ batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport));
+ batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0));
+ batch.draw(gpu::TRIANGLE_STRIP, 4);
+ });
+
+ // Set full final viewport
+ args->_viewport = viewport;
+ }
+}
diff --git a/libraries/render/src/render/ResampleTask.h b/libraries/render/src/render/ResampleTask.h
index da2b7b3537..25f9c6a3e9 100644
--- a/libraries/render/src/render/ResampleTask.h
+++ b/libraries/render/src/render/ResampleTask.h
@@ -36,6 +36,37 @@ namespace render {
gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer);
};
+
+ class UpsampleConfig : public render::Job::Config {
+ Q_OBJECT
+ Q_PROPERTY(float factor MEMBER factor NOTIFY dirty)
+ public:
+
+ float factor{ 1.0f };
+
+ signals:
+ void dirty();
+ };
+
+ class Upsample {
+ public:
+ using Config = UpsampleConfig;
+ using JobModel = Job::ModelIO;
+
+ Upsample(float factor = 2.0f) : _factor{ factor } {}
+
+ void configure(const Config& config);
+ void run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& resampledFrameBuffer);
+
+ protected:
+
+ static gpu::PipelinePointer _pipeline;
+
+ gpu::FramebufferPointer _destinationFrameBuffer;
+ float _factor{ 2.0f };
+
+ gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer);
+ };
}
#endif // hifi_render_ResampleTask_h
diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp
index 1ce58c49ae..8cd04f8067 100644
--- a/libraries/render/src/render/ShapePipeline.cpp
+++ b/libraries/render/src/render/ShapePipeline.cpp
@@ -95,6 +95,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT_MAP));
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK));
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
+ slotBindings.insert(gpu::Shader::Binding(std::string("fadeObjectParametersBuffer"), Slot::BUFFER::FADE_OBJECT_PARAMETERS));
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), Slot::BUFFER::HAZE_MODEL));
if (key.isTranslucent()) {
@@ -124,6 +125,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap");
locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap");
locations->fadeParameterBufferUnit = program->getUniformBuffers().findLocation("fadeParametersBuffer");
+ locations->fadeObjectParameterBufferUnit = program->getUniformBuffers().findLocation("fadeObjectParametersBuffer");
locations->hazeParameterBufferUnit = program->getUniformBuffers().findLocation("hazeBuffer");
if (key.isTranslucent()) {
locations->lightClusterGridBufferUnit = program->getUniformBuffers().findLocation("clusterGridBuffer");
diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h
index 7d87d98deb..10f1b757cc 100644
--- a/libraries/render/src/render/ShapePipeline.h
+++ b/libraries/render/src/render/ShapePipeline.h
@@ -240,6 +240,7 @@ public:
LIGHT_AMBIENT_BUFFER,
HAZE_MODEL,
FADE_PARAMETERS,
+ FADE_OBJECT_PARAMETERS,
LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT,
LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT,
LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT,
@@ -254,9 +255,9 @@ public:
ROUGHNESS,
OCCLUSION,
SCATTERING,
- FADE_MASK,
LIGHT_AMBIENT_MAP = 10,
+ FADE_MASK,
};
};
@@ -278,6 +279,7 @@ public:
int lightAmbientMapUnit;
int fadeMaskTextureUnit;
int fadeParameterBufferUnit;
+ int fadeObjectParameterBufferUnit;
int hazeParameterBufferUnit;
int lightClusterGridBufferUnit;
int lightClusterContentBufferUnit;
diff --git a/libraries/render/src/render/Transition.h b/libraries/render/src/render/Transition.h
index 622e6f69ce..30bda8aa2a 100644
--- a/libraries/render/src/render/Transition.h
+++ b/libraries/render/src/render/Transition.h
@@ -42,6 +42,8 @@ namespace render {
glm::vec3 baseInvSize{ 1.f, 1.f, 1.f };
float threshold{ 0.f };
uint8_t isFinished{ 0 };
+
+ mutable gpu::BufferView paramsBuffer;
};
typedef std::shared_ptr TransitionPointer;
diff --git a/libraries/shared/src/PhysicsHelpers.cpp b/libraries/shared/src/PhysicsHelpers.cpp
index b43d55020e..988af98c46 100644
--- a/libraries/shared/src/PhysicsHelpers.cpp
+++ b/libraries/shared/src/PhysicsHelpers.cpp
@@ -42,22 +42,27 @@ glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float time
// Exponential map
// google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia
- float speed = glm::length(angularVelocity);
+ glm::vec3 axis = angularVelocity;
+ float angle = glm::length(axis) * timeStep;
// limit the angular motion because the exponential approximation fails for large steps
const float ANGULAR_MOTION_THRESHOLD = 0.5f * PI_OVER_TWO;
- if (speed * timeStep > ANGULAR_MOTION_THRESHOLD) {
- speed = ANGULAR_MOTION_THRESHOLD / timeStep;
+ if (angle > ANGULAR_MOTION_THRESHOLD) {
+ angle = ANGULAR_MOTION_THRESHOLD;
}
- glm::vec3 axis = angularVelocity;
- if (speed < 0.001f) {
- // use Taylor's expansions of sync function
- axis *= (0.5f * timeStep - (timeStep * timeStep * timeStep) * (0.020833333333f * speed * speed));
+ const float MIN_ANGLE = 0.001f;
+ if (angle < MIN_ANGLE) {
+ // for small angles use Taylor's expansion of sin(x):
+ // sin(x) = x - (x^3)/(3!) + ...
+ // where: x = angle/2
+ // sin(angle/2) = angle/2 - (angle*angle*angle)/48
+ // but (angle = speed * timeStep) and we want to normalize the axis by dividing by speed
+ // which gives us:
+ axis *= timeStep * (0.5f - 0.020833333333f * angle * angle);
} else {
- // sync(speed) = sin(c * speed)/t
- axis *= (sinf(0.5f * speed * timeStep) / speed );
+ axis *= (sinf(0.5f * angle) * timeStep / angle);
}
- return glm::quat(cosf(0.5f * speed * timeStep), axis.x, axis.y, axis.z);
+ return glm::quat(cosf(0.5f * angle), axis.x, axis.y, axis.z);
}
/* end Bullet code derivation*/
diff --git a/scripts/developer/utilities/render/engineProfiler.js b/scripts/developer/utilities/render/engineProfiler.js
index 1baeb84dee..418cab8622 100644
--- a/scripts/developer/utilities/render/engineProfiler.js
+++ b/scripts/developer/utilities/render/engineProfiler.js
@@ -34,11 +34,11 @@
function createWindow() {
var qml = Script.resolvePath(QMLAPP_URL);
- window = new OverlayWindow({
+ window = Desktop.createWindow(Script.resolvePath(QMLAPP_URL), {
title: 'Render Engine Profiler',
- source: qml,
- width: 500,
- height: 100
+ flags: Desktop.ALWAYS_ON_TOP,
+ presentationMode: Desktop.PresentationMode.NATIVE,
+ size: {x: 500, y: 100}
});
window.setPosition(200, 50);
window.closed.connect(killWindow);
diff --git a/scripts/system/pal.js b/scripts/system/pal.js
index 7175685b4f..e967ee6469 100644
--- a/scripts/system/pal.js
+++ b/scripts/system/pal.js
@@ -670,12 +670,13 @@ triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Cont
triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand));
function tabletVisibilityChanged() {
- if (!tablet.tabletShown) {
+ if (!tablet.tabletShown && onPalScreen) {
ContextOverlay.enabled = true;
tablet.gotoHomeScreen();
}
}
+var wasOnPalScreen = false;
var onPalScreen = false;
var PAL_QML_SOURCE = "hifi/Pal.qml";
function onTabletButtonClicked() {
@@ -706,6 +707,7 @@ function wireEventBridge(on) {
}
function onTabletScreenChanged(type, url) {
+ wasOnPalScreen = onPalScreen;
onPalScreen = (type === "QML" && url === PAL_QML_SOURCE);
wireEventBridge(onPalScreen);
// for toolbar mode: change button to active when window is first openend, false otherwise.
@@ -729,7 +731,9 @@ function onTabletScreenChanged(type, url) {
populateNearbyUserList();
} else {
off();
- ContextOverlay.enabled = true;
+ if (wasOnPalScreen) {
+ ContextOverlay.enabled = true;
+ }
}
}
diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js
index c4fcb70792..3ddbeb997d 100644
--- a/scripts/system/snapshot.js
+++ b/scripts/system/snapshot.js
@@ -285,7 +285,7 @@ function printToPolaroid(image_url) {
var polaroid_url = image_url;
var model_pos = Vec3.sum(MyAvatar.position, Vec3.multiply(1.25, Quat.getForward(MyAvatar.orientation)));
- model_pos.y += 0.2; // Print a bit closer to the head
+ model_pos.y += 0.39; // Print a bit closer to the head
var model_q1 = MyAvatar.orientation;
var model_q2 = Quat.angleAxis(90, Quat.getRight(model_q1));
@@ -307,10 +307,8 @@ function printToPolaroid(image_url) {
"density": 200,
"restitution": 0.15,
- "gravity": { "x": 0, "y": -2.5, "z": 0 },
-
- "velocity": { "x": 0, "y": 1.95, "z": 0 },
- "angularVelocity": Vec3.multiplyQbyV(MyAvatar.orientation, { "x": -1.0, "y": 0, "z": -1.3 }),
+ "gravity": { "x": 0, "y": -2.0, "z": 0 },
+ "damping": 0.45,
"dynamic": true,
"collisionsWillMove": true,
diff --git a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml
index e0c836fb1c..033039b87d 100644
--- a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml
+++ b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml
@@ -60,7 +60,7 @@ Rectangle {
// "Spectator" text
HifiStylesUit.RalewaySemiBold {
id: titleBarText;
- text: "Spectator Camera 2.2";
+ text: "Spectator Camera 2.3";
// Anchors
anchors.left: parent.left;
anchors.leftMargin: 30;
diff --git a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js
index 3e749e38a2..4c39c5fb95 100644
--- a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js
+++ b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js
@@ -74,6 +74,7 @@
"collisionMask": 7,
"dynamic": false,
"modelURL": Script.resolvePath("spectator-camera.fbx"),
+ "name": "Spectator Camera",
"registrationPoint": {
"x": 0.56,
"y": 0.545,
@@ -102,6 +103,18 @@
position: cameraPosition,
localOnly: true
});
+
+ // Remove the existing camera model from the domain if one exists.
+ // It's easy for this to happen if the user crashes while the Spectator Camera is on.
+ // We do this down here (after the new one is rezzed) so that we don't accidentally delete
+ // the newly-rezzed model.
+ var entityIDs = Entities.findEntitiesByName("Spectator Camera", MyAvatar.position, 100, false);
+ entityIDs.forEach(function (currentEntityID) {
+ var currentEntityOwner = Entities.getEntityProperties(currentEntityID, ['owningAvatarID']).owningAvatarID;
+ if (currentEntityOwner === MyAvatar.sessionUUID && currentEntityID !== camera) {
+ Entities.deleteEntity(currentEntityID);
+ }
+ });
}
// Function Name: spectatorCameraOff()