mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 09:08:47 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into atp
This commit is contained in:
commit
9a2b2b4c16
48 changed files with 1329 additions and 591 deletions
0
examples/VR-VJ/cartridgesSpawner.js
Normal file
0
examples/VR-VJ/cartridgesSpawner.js
Normal file
|
@ -13,11 +13,11 @@
|
||||||
{ "from": "Hydra.RB", "to": "Standard.RB" },
|
{ "from": "Hydra.RB", "to": "Standard.RB" },
|
||||||
{ "from": "Hydra.RS", "to": "Standard.RS" },
|
{ "from": "Hydra.RS", "to": "Standard.RS" },
|
||||||
|
|
||||||
{ "from": [ "Hydra.L1", "Hydra.L2", "Hydra.L3", "Hydra.L4" ], "to": "Standard.LeftPrimaryThumb" },
|
{ "from": "Hydra.L0", "to": "Standard.Back" },
|
||||||
{ "from": [ "Hydra.L0" ], "to": "Standard.LeftSecondaryThumb" },
|
{ "from": "Hydra.R0", "to": "Standard.Start" },
|
||||||
|
|
||||||
|
{ "from": [ "Hydra.L1", "Hydra.L2", "Hydra.L3", "Hydra.L4" ], "to": "Standard.LeftPrimaryThumb" },
|
||||||
{ "from": [ "Hydra.R1", "Hydra.R2", "Hydra.R3", "Hydra.R4" ], "to": "Standard.RightPrimaryThumb" },
|
{ "from": [ "Hydra.R1", "Hydra.R2", "Hydra.R3", "Hydra.R4" ], "to": "Standard.RightPrimaryThumb" },
|
||||||
{ "from": [ "Hydra.R0" ], "to": "Standard.RightSecondaryThumb" },
|
|
||||||
|
|
||||||
{ "from": "Hydra.LeftHand", "to": "Standard.LeftHand" },
|
{ "from": "Hydra.LeftHand", "to": "Standard.LeftHand" },
|
||||||
{ "from": "Hydra.RightHand", "to": "Standard.RightHand" }
|
{ "from": "Hydra.RightHand", "to": "Standard.RightHand" }
|
||||||
|
|
|
@ -27,14 +27,11 @@
|
||||||
|
|
||||||
{ "from": "Standard.RY", "to": "Actions.Up", "filters": "invert"},
|
{ "from": "Standard.RY", "to": "Actions.Up", "filters": "invert"},
|
||||||
|
|
||||||
|
{ "from": "Standard.Back", "to": "Actions.CycleCamera" },
|
||||||
|
{ "from": "Standard.Start", "to": "Actions.ContextMenu" },
|
||||||
|
|
||||||
{ "from": [ "Standard.DU", "Standard.DL", "Standard.DR", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
|
{ "from": [ "Standard.DU", "Standard.DL", "Standard.DR", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
|
||||||
{ "from": "Standard.Back", "to": "Standard.LeftSecondaryThumb" },
|
|
||||||
|
|
||||||
{ "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" },
|
{ "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" },
|
||||||
{ "from": "Standard.Start", "to": "Standard.RightSecondaryThumb" },
|
|
||||||
|
|
||||||
{ "from": "Standard.LeftSecondaryThumb", "to": "Actions.CycleCamera" },
|
|
||||||
{ "from": "Standard.RightSecondaryThumb", "to": "Actions.ContextMenu" },
|
|
||||||
|
|
||||||
{ "from": "Standard.LT", "to": "Actions.LeftHandClick" },
|
{ "from": "Standard.LT", "to": "Actions.LeftHandClick" },
|
||||||
{ "from": "Standard.RT", "to": "Actions.RightHandClick" },
|
{ "from": "Standard.RT", "to": "Actions.RightHandClick" },
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
{ "from": "Standard.LB", "to": "Actions.UiNavGroup","filters": "invert" },
|
{ "from": "Standard.LB", "to": "Actions.UiNavGroup","filters": "invert" },
|
||||||
{ "from": "Standard.RB", "to": "Actions.UiNavGroup" },
|
{ "from": "Standard.RB", "to": "Actions.UiNavGroup" },
|
||||||
{ "from": [ "Standard.A", "Standard.X" ], "to": "Actions.UiNavSelect" },
|
{ "from": [ "Standard.A", "Standard.X" ], "to": "Actions.UiNavSelect" },
|
||||||
{ "from": [ "Standard.B", "Standard.Y", "Standard.RightPrimaryThumb", "Standard.LeftPrimaryThumb" ], "to": "Actions.UiNavBack" },
|
{ "from": [ "Standard.B", "Standard.Y" ], "to": "Actions.UiNavBack" },
|
||||||
{
|
{
|
||||||
"from": [ "Standard.RT", "Standard.LT" ],
|
"from": [ "Standard.RT", "Standard.LT" ],
|
||||||
"to": "Actions.UiNavSelect",
|
"to": "Actions.UiNavSelect",
|
||||||
|
|
|
@ -15,10 +15,8 @@
|
||||||
{ "from": "Vive.RB", "to": "Standard.RB" },
|
{ "from": "Vive.RB", "to": "Standard.RB" },
|
||||||
{ "from": "Vive.RS", "to": "Standard.RS" },
|
{ "from": "Vive.RS", "to": "Standard.RS" },
|
||||||
|
|
||||||
{ "from": "Vive.LeftPrimaryThumb", "to": "Standard.LeftPrimaryThumb" },
|
{ "from": "Vive.LeftApplicationMenu", "to": "Standard.Back" },
|
||||||
{ "from": "Vive.RightPrimaryThumb", "to": "Standard.RightPrimaryThumb" },
|
{ "from": "Vive.RightApplicationMenu", "to": "Standard.Start" },
|
||||||
{ "from": "Vive.LeftSecondaryThumb", "to": "Standard.LeftSecondaryThumb" },
|
|
||||||
{ "from": "Vive.RightSecondaryThumb", "to": "Standard.RightSecondaryThumb" },
|
|
||||||
|
|
||||||
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand" },
|
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand" },
|
||||||
{ "from": "Vive.RightHand", "to": "Standard.RightHand" }
|
{ "from": "Vive.RightHand", "to": "Standard.RightHand" }
|
||||||
|
|
|
@ -160,6 +160,7 @@ FocusScope {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
id: scrollView
|
id: scrollView
|
||||||
height: 480
|
height: 480
|
||||||
|
width: root.width + 4
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
|
@ -12,7 +12,7 @@ import QtQuick 2.5
|
||||||
|
|
||||||
import "../styles-uit"
|
import "../styles-uit"
|
||||||
|
|
||||||
RalewaySemibold {
|
RalewaySemiBold {
|
||||||
property int colorScheme: hifi.colorSchemes.light
|
property int colorScheme: hifi.colorSchemes.light
|
||||||
|
|
||||||
size: hifi.fontSizes.inputLabel
|
size: hifi.fontSizes.inputLabel
|
||||||
|
|
|
@ -17,8 +17,8 @@ TextEdit {
|
||||||
|
|
||||||
property real size: 32
|
property real size: 32
|
||||||
|
|
||||||
FontLoader { id: ralewaySemibold; source: "../../fonts/Raleway-Semibold.ttf"; }
|
FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; }
|
||||||
font.family: ralewaySemibold.name
|
font.family: ralewaySemiBold.name
|
||||||
font.pointSize: size
|
font.pointSize: size
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//
|
//
|
||||||
// Desktop.qml
|
// MessageDialog.qml
|
||||||
//
|
//
|
||||||
// Created by Bradley Austin Davis on 25 Apr 2015
|
// Created by Bradley Austin Davis on 15 Jan 2016
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
@ -42,10 +42,11 @@ ModalWindow {
|
||||||
property alias detailedText: detailedText.text
|
property alias detailedText: detailedText.text
|
||||||
property alias text: mainTextContainer.text
|
property alias text: mainTextContainer.text
|
||||||
property alias informativeText: informativeTextContainer.text
|
property alias informativeText: informativeTextContainer.text
|
||||||
onIconChanged: updateIcon();
|
|
||||||
property int buttons: OriginalDialogs.StandardButton.Ok
|
property int buttons: OriginalDialogs.StandardButton.Ok
|
||||||
property int icon: OriginalDialogs.StandardIcon.NoIcon
|
property int icon: OriginalDialogs.StandardIcon.NoIcon
|
||||||
property string iconText: ""
|
property string iconText: ""
|
||||||
|
property int iconSize: 50
|
||||||
|
onIconChanged: updateIcon();
|
||||||
property int defaultButton: OriginalDialogs.StandardButton.NoButton;
|
property int defaultButton: OriginalDialogs.StandardButton.NoButton;
|
||||||
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
|
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
|
||||||
focus: defaultButton === OriginalDialogs.StandardButton.NoButton
|
focus: defaultButton === OriginalDialogs.StandardButton.NoButton
|
||||||
|
@ -54,22 +55,7 @@ ModalWindow {
|
||||||
if (!root) {
|
if (!root) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (root.icon) {
|
iconText = hifi.glyphForIcon(root.icon);
|
||||||
case OriginalDialogs.StandardIcon.Information:
|
|
||||||
iconText = "\uF05A";
|
|
||||||
break;
|
|
||||||
case OriginalDialogs.StandardIcon.Question:
|
|
||||||
iconText = "\uF059"
|
|
||||||
break;
|
|
||||||
case OriginalDialogs.StandardIcon.Warning:
|
|
||||||
iconText = "\uF071"
|
|
||||||
break;
|
|
||||||
case OriginalDialogs.StandardIcon.Critical:
|
|
||||||
iconText = "\uF057"
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
iconText = ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -80,8 +66,6 @@ ModalWindow {
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
readonly property real spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
readonly property real outerSpacing: hifi.dimensions.contentSpacing.y
|
|
||||||
readonly property int minWidth: 480
|
readonly property int minWidth: 480
|
||||||
readonly property int maxWdith: 1280
|
readonly property int maxWdith: 1280
|
||||||
readonly property int minHeight: 120
|
readonly property int minHeight: 120
|
||||||
|
@ -98,9 +82,9 @@ ModalWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RalewaySemibold {
|
RalewaySemiBold {
|
||||||
id: mainTextContainer
|
id: mainTextContainer
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onTextChanged: d.resize();
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
size: hifi.fontSizes.menuItem
|
size: hifi.fontSizes.menuItem
|
||||||
color: hifi.colors.baseGrayHighlight
|
color: hifi.colors.baseGrayHighlight
|
||||||
|
@ -114,9 +98,9 @@ ModalWindow {
|
||||||
lineHeightMode: Text.ProportionalHeight
|
lineHeightMode: Text.ProportionalHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
RalewaySemibold {
|
RalewaySemiBold {
|
||||||
id: informativeTextContainer
|
id: informativeTextContainer
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onTextChanged: d.resize();
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
size: hifi.fontSizes.menuItem
|
size: hifi.fontSizes.menuItem
|
||||||
color: hifi.colors.baseGrayHighlight
|
color: hifi.colors.baseGrayHighlight
|
||||||
|
@ -132,7 +116,7 @@ ModalWindow {
|
||||||
Flow {
|
Flow {
|
||||||
id: buttons
|
id: buttons
|
||||||
focus: true
|
focus: true
|
||||||
spacing: d.spacing
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
layoutDirection: Qt.RightToLeft
|
layoutDirection: Qt.RightToLeft
|
||||||
anchors {
|
anchors {
|
||||||
|
@ -186,8 +170,8 @@ ModalWindow {
|
||||||
id: flickable
|
id: flickable
|
||||||
contentHeight: detailedText.height
|
contentHeight: detailedText.height
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.topMargin: root.spacing
|
anchors.topMargin: hifi.dimensions.contentSpacing.x
|
||||||
anchors.bottomMargin: root.outerSpacing
|
anchors.bottomMargin: hifi.dimensions.contentSpacing.y
|
||||||
TextEdit {
|
TextEdit {
|
||||||
id: detailedText
|
id: detailedText
|
||||||
size: hifi.fontSizes.menuItem
|
size: hifi.fontSizes.menuItem
|
||||||
|
@ -210,7 +194,10 @@ ModalWindow {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
Component.onCompleted: updateIcon();
|
Component.onCompleted: {
|
||||||
|
updateIcon();
|
||||||
|
d.resize();
|
||||||
|
}
|
||||||
onStateChanged: d.resize()
|
onStateChanged: d.resize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
|
//
|
||||||
|
// 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.5
|
import QtQuick 2.5
|
||||||
import QtQuick.Controls 1.2
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||||
|
|
||||||
import "../controls" as VrControls
|
import "../controls-uit"
|
||||||
import "../styles"
|
import "../styles-uit"
|
||||||
import "../windows"
|
import "../windows-uit"
|
||||||
|
|
||||||
ModalWindow {
|
ModalWindow {
|
||||||
id: root
|
id: root
|
||||||
|
@ -16,8 +26,13 @@ ModalWindow {
|
||||||
signal selected(var result);
|
signal selected(var result);
|
||||||
signal canceled();
|
signal canceled();
|
||||||
|
|
||||||
|
property int icon: hifi.icons.none
|
||||||
|
property string iconText: ""
|
||||||
|
property int iconSize: 35
|
||||||
|
onIconChanged: updateIcon();
|
||||||
|
|
||||||
property var items;
|
property var items;
|
||||||
property alias label: mainTextContainer.text
|
property string label
|
||||||
property var result;
|
property var result;
|
||||||
// FIXME not current honored
|
// FIXME not current honored
|
||||||
property var current;
|
property var current;
|
||||||
|
@ -28,66 +43,85 @@ ModalWindow {
|
||||||
// For combo boxes
|
// For combo boxes
|
||||||
property bool editable: true;
|
property bool editable: true;
|
||||||
|
|
||||||
Rectangle {
|
function updateIcon() {
|
||||||
|
if (!root) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iconText = hifi.glyphForIcon(root.icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
clip: true
|
clip: true
|
||||||
anchors.fill: parent
|
width: pane.width
|
||||||
radius: 4
|
height: pane.height
|
||||||
color: "white"
|
anchors.margins: 0
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
readonly property real spacing: hifi.layout.spacing
|
|
||||||
readonly property real outerSpacing: hifi.layout.spacing * 2
|
|
||||||
readonly property int minWidth: 480
|
readonly property int minWidth: 480
|
||||||
readonly property int maxWdith: 1280
|
readonly property int maxWdith: 1280
|
||||||
readonly property int minHeight: 120
|
readonly property int minHeight: 120
|
||||||
readonly property int maxHeight: 720
|
readonly property int maxHeight: 720
|
||||||
|
|
||||||
function resize() {
|
function resize() {
|
||||||
var targetWidth = mainTextContainer.width + d.spacing * 6
|
var targetWidth = pane.width
|
||||||
var targetHeight = mainTextContainer.implicitHeight + textResult.height + d.spacing + buttons.height
|
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.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)
|
root.height = (targetHeight < d.minHeight) ? d.minHeight: ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
|
||||||
id: mainTextContainer
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
font { pointSize: 14; weight: Font.Bold }
|
|
||||||
anchors { left: parent.left; top: parent.top; margins: d.spacing }
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors { top: mainTextContainer.bottom; bottom: buttons.top; left: parent.left; right: parent.right; margins: d.spacing }
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
bottom: buttons.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
|
// FIXME make a text field type that can be bound to a history for autocompletion
|
||||||
VrControls.TextField {
|
TextField {
|
||||||
id: textResult
|
id: textResult
|
||||||
|
label: root.label
|
||||||
focus: items ? false : true
|
focus: items ? false : true
|
||||||
visible: items ? false : true
|
visible: items ? false : true
|
||||||
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
|
anchors {
|
||||||
|
left: parent.left;
|
||||||
|
right: parent.right;
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VrControls.ComboBox {
|
ComboBox {
|
||||||
id: comboBox
|
id: comboBox
|
||||||
|
label: root.label
|
||||||
focus: true
|
focus: true
|
||||||
visible: items ? true : false
|
visible: items ? true : false
|
||||||
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
model: items ? items : []
|
model: items ? items : []
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Flow {
|
Flow {
|
||||||
id: buttons
|
id: buttons
|
||||||
focus: true
|
focus: true
|
||||||
spacing: d.spacing
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
layoutDirection: Qt.RightToLeft
|
layoutDirection: Qt.RightToLeft
|
||||||
anchors { bottom: parent.bottom; right: parent.right; margins: d.spacing; }
|
anchors {
|
||||||
Button { action: acceptAction }
|
bottom: parent.bottom
|
||||||
|
right: parent.right
|
||||||
|
margins: 0
|
||||||
|
bottomMargin: hifi.dimensions.contentSpacing.y
|
||||||
|
}
|
||||||
Button { action: cancelAction }
|
Button { action: cancelAction }
|
||||||
|
Button { action: acceptAction }
|
||||||
}
|
}
|
||||||
|
|
||||||
Action {
|
Action {
|
||||||
|
@ -130,4 +164,10 @@ ModalWindow {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
updateIcon();
|
||||||
|
d.resize();
|
||||||
|
textResult.forceActiveFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,35 @@ Item {
|
||||||
readonly property alias dimensions: dimensions
|
readonly property alias dimensions: dimensions
|
||||||
readonly property alias fontSizes: fontSizes
|
readonly property alias fontSizes: fontSizes
|
||||||
readonly property alias glyphs: glyphs
|
readonly property alias glyphs: glyphs
|
||||||
|
readonly property alias icons: icons
|
||||||
readonly property alias buttons: buttons
|
readonly property alias buttons: buttons
|
||||||
readonly property alias effects: effects
|
readonly property alias effects: effects
|
||||||
|
|
||||||
|
function glyphForIcon(icon) {
|
||||||
|
// Translates icon enum to glyph char.
|
||||||
|
var glyph;
|
||||||
|
switch (icon) {
|
||||||
|
case hifi.icons.information:
|
||||||
|
glyph = hifi.glyphs.info;
|
||||||
|
break;
|
||||||
|
case hifi.icons.question:
|
||||||
|
glyph = hifi.glyphs.question;
|
||||||
|
break;
|
||||||
|
case hifi.icons.warning:
|
||||||
|
glyph = hifi.glyphs.alert;
|
||||||
|
break;
|
||||||
|
case hifi.icons.critical:
|
||||||
|
glyph = hifi.glyphs.critical;
|
||||||
|
break;
|
||||||
|
case hifi.icons.placemark:
|
||||||
|
glyph = hifi.glyphs.placemark;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
glyph = hifi.glyphs.noIcon;
|
||||||
|
}
|
||||||
|
return glyph;
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: colors
|
id: colors
|
||||||
|
|
||||||
|
@ -135,6 +161,7 @@ Item {
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: glyphs
|
id: glyphs
|
||||||
|
readonly property string alert: "+"
|
||||||
readonly property string backward: "E"
|
readonly property string backward: "E"
|
||||||
readonly property string caratDn: "5"
|
readonly property string caratDn: "5"
|
||||||
readonly property string caratR: "3"
|
readonly property string caratR: "3"
|
||||||
|
@ -142,13 +169,18 @@ Item {
|
||||||
readonly property string close: "w"
|
readonly property string close: "w"
|
||||||
readonly property string closeInverted: "x"
|
readonly property string closeInverted: "x"
|
||||||
readonly property string closeSmall: "C"
|
readonly property string closeSmall: "C"
|
||||||
|
readonly property string critical: "="
|
||||||
readonly property string disclosureButtonCollapse: "M"
|
readonly property string disclosureButtonCollapse: "M"
|
||||||
readonly property string disclosureButtonExpand: "L"
|
readonly property string disclosureButtonExpand: "L"
|
||||||
readonly property string disclosureCollapse: "Z"
|
readonly property string disclosureCollapse: "Z"
|
||||||
readonly property string disclosureExpand: "B"
|
readonly property string disclosureExpand: "B"
|
||||||
readonly property string forward: "D"
|
readonly property string forward: "D"
|
||||||
|
readonly property string info: "["
|
||||||
|
readonly property string noIcon: ""
|
||||||
readonly property string pin: "y"
|
readonly property string pin: "y"
|
||||||
readonly property string pinInverted: "z"
|
readonly property string pinInverted: "z"
|
||||||
|
readonly property string placemark: "U"
|
||||||
|
readonly property string question: "]"
|
||||||
readonly property string reloadSmall: "a"
|
readonly property string reloadSmall: "a"
|
||||||
readonly property string resizeHandle: "A"
|
readonly property string resizeHandle: "A"
|
||||||
readonly property string upload: "j"
|
readonly property string upload: "j"
|
||||||
|
@ -157,6 +189,17 @@ Item {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: icons
|
||||||
|
// Values per OffscreenUi::Icon
|
||||||
|
readonly property int none: 0
|
||||||
|
readonly property int question: 1
|
||||||
|
readonly property int information: 2
|
||||||
|
readonly property int warning: 3
|
||||||
|
readonly property int critical: 4
|
||||||
|
readonly property int placemark: 5
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: buttons
|
id: buttons
|
||||||
readonly property int white: 0
|
readonly property int white: 0
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// RalewaySemibold.qml
|
// RalewaySemiBold.qml
|
||||||
//
|
//
|
||||||
// Created by David Rowe on 12 Feb 2016
|
// Created by David Rowe on 12 Feb 2016
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
@ -14,10 +14,10 @@ import QtQuick.Controls.Styles 1.4
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: root
|
id: root
|
||||||
FontLoader { id: ralewaySemibold; source: "../../fonts/Raleway-Semibold.ttf"; }
|
FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; }
|
||||||
property real size: 32
|
property real size: 32
|
||||||
font.pixelSize: size
|
font.pixelSize: size
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
font.family: ralewaySemibold.name
|
font.family: ralewaySemiBold.name
|
||||||
}
|
}
|
|
@ -47,16 +47,16 @@ Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: title.width + (window.iconText !== "" ? icon.width + hifi.dimensions.contentSpacing.x : 0)
|
width: title.width + (icon.text !== "" ? icon.width + hifi.dimensions.contentSpacing.x : 0)
|
||||||
x: (parent.width - width) / 2
|
x: (parent.width - width) / 2
|
||||||
|
|
||||||
FontAwesome {
|
HiFiGlyphs {
|
||||||
id: icon
|
id: icon
|
||||||
text: window.iconText
|
text: window.iconText ? window.iconText : ""
|
||||||
size: 30
|
size: window.iconSize ? window.iconSize : 30
|
||||||
color: hifi.colors.lightGrayText
|
color: hifi.colors.lightGray
|
||||||
visible: text != ""
|
visible: text != ""
|
||||||
y: -hifi.dimensions.modalDialogTitleHeight - 5
|
anchors.verticalCenter: title.verticalCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
}
|
}
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
|
|
|
@ -235,6 +235,44 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi
|
||||||
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }
|
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DeadlockWatchdogThread : public QThread {
|
||||||
|
public:
|
||||||
|
static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1;
|
||||||
|
static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1;
|
||||||
|
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 10 * USECS_PER_SECOND;
|
||||||
|
|
||||||
|
// Set the heartbeat on launch
|
||||||
|
DeadlockWatchdogThread() {
|
||||||
|
QTimer* heartbeatTimer = new QTimer();
|
||||||
|
// Give the heartbeat an initial value
|
||||||
|
_heartbeat = usecTimestampNow();
|
||||||
|
connect(heartbeatTimer, &QTimer::timeout, [this] {
|
||||||
|
_heartbeat = usecTimestampNow();
|
||||||
|
});
|
||||||
|
heartbeatTimer->start(HEARTBEAT_UPDATE_INTERVAL_SECS * MSECS_PER_SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deadlockDetectionCrash() {
|
||||||
|
uint32_t* crashTrigger = nullptr;
|
||||||
|
*crashTrigger = 0xDEAD10CC;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override {
|
||||||
|
while (!qApp->isAboutToQuit()) {
|
||||||
|
QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
auto lastHeartbeatAge = now - _heartbeat;
|
||||||
|
if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) {
|
||||||
|
deadlockDetectionCrash();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::atomic<uint64_t> _heartbeat;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
class MyNativeEventFilter : public QAbstractNativeEventFilter {
|
class MyNativeEventFilter : public QAbstractNativeEventFilter {
|
||||||
public:
|
public:
|
||||||
|
@ -457,6 +495,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
// Set up a watchdog thread to intentionally crash the application on deadlocks
|
||||||
|
(new DeadlockWatchdogThread())->start();
|
||||||
|
|
||||||
qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
||||||
|
|
||||||
_bookmarks = new Bookmarks(); // Before setting up the menu
|
_bookmarks = new Bookmarks(); // Before setting up the menu
|
||||||
|
@ -4966,6 +5007,15 @@ void Application::crashApplication() {
|
||||||
Q_UNUSED(value);
|
Q_UNUSED(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::deadlockApplication() {
|
||||||
|
qCDebug(interfaceapp) << "Intentionally deadlocked Interface";
|
||||||
|
// Using a loop that will *technically* eventually exit (in ~600 billion years)
|
||||||
|
// to avoid compiler warnings about a loop that will never exit
|
||||||
|
for (uint64_t i = 1; i != 0; ++i) {
|
||||||
|
QThread::sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::setActiveDisplayPlugin(const QString& pluginName) {
|
void Application::setActiveDisplayPlugin(const QString& pluginName) {
|
||||||
auto menu = Menu::getInstance();
|
auto menu = Menu::getInstance();
|
||||||
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
|
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
|
||||||
|
|
|
@ -277,6 +277,7 @@ public slots:
|
||||||
void reloadResourceCaches();
|
void reloadResourceCaches();
|
||||||
|
|
||||||
void crashApplication();
|
void crashApplication();
|
||||||
|
void deadlockApplication();
|
||||||
|
|
||||||
void rotationModeChanged();
|
void rotationModeChanged();
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ void Bookmarks::setupMenus(Menu* menubar, MenuWrapper* menu) {
|
||||||
|
|
||||||
void Bookmarks::bookmarkLocation() {
|
void Bookmarks::bookmarkLocation() {
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
auto bookmarkName = OffscreenUi::getText(nullptr, "Bookmark Location", "Name:", QLineEdit::Normal, QString(), &ok);
|
auto bookmarkName = OffscreenUi::getText(OffscreenUi::ICON_PLACEMARK, "Bookmark Location", "Name", QString(), &ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ void Bookmarks::bookmarkLocation() {
|
||||||
Menu* menubar = Menu::getInstance();
|
Menu* menubar = Menu::getInstance();
|
||||||
if (contains(bookmarkName)) {
|
if (contains(bookmarkName)) {
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
auto duplicateBookmarkMessage = offscreenUi->createMessageBox(QMessageBox::Warning, "Duplicate Bookmark",
|
auto duplicateBookmarkMessage = offscreenUi->createMessageBox(OffscreenUi::ICON_WARNING, "Duplicate Bookmark",
|
||||||
"The bookmark name you entered already exists in your list.",
|
"The bookmark name you entered already exists in your list.",
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
duplicateBookmarkMessage->setProperty("informativeText", "Would you like to overwrite it?");
|
duplicateBookmarkMessage->setProperty("informativeText", "Would you like to overwrite it?");
|
||||||
|
@ -156,7 +156,7 @@ void Bookmarks::deleteBookmark() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
auto bookmarkName = OffscreenUi::getItem(nullptr, "Delete Bookmark", "Select the bookmark to delete", bookmarkList, 0, false, &ok);
|
auto bookmarkName = OffscreenUi::getItem(OffscreenUi::ICON_PLACEMARK, "Delete Bookmark", "Select the bookmark to delete", bookmarkList, 0, false, &ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -594,6 +594,8 @@ Menu::Menu() {
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisplayCrashOptions, 0, true);
|
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisplayCrashOptions, 0, true);
|
||||||
// Developer > Crash Application
|
// Developer > Crash Application
|
||||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::CrashInterface, 0, qApp, SLOT(crashApplication()));
|
addActionToQMenuAndActionHash(developerMenu, MenuOption::CrashInterface, 0, qApp, SLOT(crashApplication()));
|
||||||
|
// Developer > Deadlock Application
|
||||||
|
addActionToQMenuAndActionHash(developerMenu, MenuOption::DeadlockInterface, 0, qApp, SLOT(deadlockApplication()));
|
||||||
|
|
||||||
// Developer > Log...
|
// Developer > Log...
|
||||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
||||||
|
|
|
@ -67,6 +67,7 @@ namespace MenuOption {
|
||||||
const QString CopyPath = "Copy Path to Clipboard";
|
const QString CopyPath = "Copy Path to Clipboard";
|
||||||
const QString CoupleEyelids = "Couple Eyelids";
|
const QString CoupleEyelids = "Couple Eyelids";
|
||||||
const QString CrashInterface = "Crash Interface";
|
const QString CrashInterface = "Crash Interface";
|
||||||
|
const QString DeadlockInterface = "Deadlock Interface";
|
||||||
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
||||||
const QString DeleteBookmark = "Delete Bookmark...";
|
const QString DeleteBookmark = "Delete Bookmark...";
|
||||||
const QString DisableActivityLogger = "Disable Activity Logger";
|
const QString DisableActivityLogger = "Disable Activity Logger";
|
||||||
|
|
|
@ -231,23 +231,19 @@ bool Overlays::editOverlay(unsigned int id, const QVariant& properties) {
|
||||||
|
|
||||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
if (thisOverlay) {
|
if (thisOverlay) {
|
||||||
|
thisOverlay->setProperties(properties.toMap());
|
||||||
|
|
||||||
if (thisOverlay->is3D()) {
|
if (thisOverlay->is3D()) {
|
||||||
render::ItemKey oldItemKey = render::payloadGetKey(thisOverlay);
|
auto itemID = thisOverlay->getRenderItemID();
|
||||||
|
if (render::Item::isValidID(itemID)) {
|
||||||
thisOverlay->setProperties(properties.toMap());
|
render::ScenePointer scene = qApp->getMain3DScene();
|
||||||
|
const render::Item& item = scene->getItem(itemID);
|
||||||
render::ItemKey itemKey = render::payloadGetKey(thisOverlay);
|
if (item.getKey() != render::payloadGetKey(thisOverlay)) {
|
||||||
if (itemKey != oldItemKey) {
|
|
||||||
auto itemID = thisOverlay->getRenderItemID();
|
|
||||||
if (render::Item::isValidID(itemID)) {
|
|
||||||
render::ScenePointer scene = qApp->getMain3DScene();
|
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
pendingChanges.resortItem(itemID, oldItemKey, itemKey);
|
pendingChanges.updateItem(itemID);
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
thisOverlay->setProperties(properties.toMap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -601,4 +597,4 @@ float Overlays::width() const {
|
||||||
float Overlays::height() const {
|
float Overlays::height() const {
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
return offscreenUi->getWindow()->size().height();
|
return offscreenUi->getWindow()->size().height();
|
||||||
}
|
}
|
||||||
|
|
|
@ -867,11 +867,10 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
}
|
}
|
||||||
} else if (object.name == "Material") {
|
} else if (object.name == "Material") {
|
||||||
FBXMaterial material;
|
FBXMaterial material;
|
||||||
if (object.properties.at(1).toByteArray().contains("StingrayPBS")) {
|
material.name = (object.properties.at(1).toString());
|
||||||
material.isPBSMaterial = true;
|
|
||||||
}
|
|
||||||
foreach (const FBXNode& subobject, object.children) {
|
foreach (const FBXNode& subobject, object.children) {
|
||||||
bool properties = false;
|
bool properties = false;
|
||||||
|
|
||||||
QByteArray propertyName;
|
QByteArray propertyName;
|
||||||
int index;
|
int index;
|
||||||
if (subobject.name == "Properties60") {
|
if (subobject.name == "Properties60") {
|
||||||
|
@ -884,25 +883,36 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
propertyName = "P";
|
propertyName = "P";
|
||||||
index = 4;
|
index = 4;
|
||||||
}
|
}
|
||||||
if (!material.isPBSMaterial && properties) {
|
if (properties) {
|
||||||
foreach (const FBXNode& property, subobject.children) {
|
std::vector<std::string> unknowns;
|
||||||
|
foreach(const FBXNode& property, subobject.children) {
|
||||||
if (property.name == propertyName) {
|
if (property.name == propertyName) {
|
||||||
if (property.properties.at(0) == "DiffuseColor") {
|
if (property.properties.at(0) == "DiffuseColor") {
|
||||||
material.diffuseColor = getVec3(property.properties, index);
|
material.diffuseColor = getVec3(property.properties, index);
|
||||||
} else if (property.properties.at(0) == "Diffuse") {
|
|
||||||
material.diffuseColor = getVec3(property.properties, index);
|
|
||||||
} else if (property.properties.at(0) == "DiffuseFactor") {
|
} else if (property.properties.at(0) == "DiffuseFactor") {
|
||||||
material.diffuseFactor = property.properties.at(index).value<double>();
|
material.diffuseFactor = property.properties.at(index).value<double>();
|
||||||
|
} else if (property.properties.at(0) == "Diffuse") {
|
||||||
|
// NOTE: this is uneeded but keep it for now for debug
|
||||||
|
// material.diffuseColor = getVec3(property.properties, index);
|
||||||
|
// material.diffuseFactor = 1.0;
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "SpecularColor") {
|
} else if (property.properties.at(0) == "SpecularColor") {
|
||||||
material.specularColor = getVec3(property.properties, index);
|
material.specularColor = getVec3(property.properties, index);
|
||||||
} else if (property.properties.at(0) == "Specular") {
|
|
||||||
material.specularColor = getVec3(property.properties, index);
|
|
||||||
} else if (property.properties.at(0) == "SpecularFactor") {
|
} else if (property.properties.at(0) == "SpecularFactor") {
|
||||||
material.specularFactor = property.properties.at(index).value<double>();
|
material.specularFactor = property.properties.at(index).value<double>();
|
||||||
|
} else if (property.properties.at(0) == "Specular") {
|
||||||
|
// NOTE: this is uneeded but keep it for now for debug
|
||||||
|
// material.specularColor = getVec3(property.properties, index);
|
||||||
|
// material.specularFactor = 1.0;
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Emissive") {
|
} else if (property.properties.at(0) == "EmissiveColor") {
|
||||||
material.emissiveColor = getVec3(property.properties, index);
|
material.emissiveColor = getVec3(property.properties, index);
|
||||||
|
} else if (property.properties.at(0) == "EmissiveFactor") {
|
||||||
|
material.emissiveFactor = property.properties.at(index).value<double>();
|
||||||
|
} else if (property.properties.at(0) == "Emissive") {
|
||||||
|
// NOTE: this is uneeded but keep it for now for debug
|
||||||
|
// material.emissiveColor = getVec3(property.properties, index);
|
||||||
|
// material.emissiveFactor = 1.0;
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Shininess") {
|
} else if (property.properties.at(0) == "Shininess") {
|
||||||
material.shininess = property.properties.at(index).value<double>();
|
material.shininess = property.properties.at(index).value<double>();
|
||||||
|
@ -910,45 +920,50 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
} else if (property.properties.at(0) == "Opacity") {
|
} else if (property.properties.at(0) == "Opacity") {
|
||||||
material.opacity = property.properties.at(index).value<double>();
|
material.opacity = property.properties.at(index).value<double>();
|
||||||
}
|
}
|
||||||
#if defined(DEBUG_FBXREADER)
|
|
||||||
else {
|
// Sting Ray Material Properties!!!!
|
||||||
const QString propname = property.properties.at(0).toString();
|
else if (property.properties.at(0) == "Maya|use_normal_map") {
|
||||||
if (propname == "EmissiveFactor") {
|
material.isPBSMaterial = true;
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (material.isPBSMaterial && properties) {
|
|
||||||
std::vector<std::string> unknowns;
|
|
||||||
foreach(const FBXNode& property, subobject.children) {
|
|
||||||
if (property.name == propertyName) {
|
|
||||||
if (property.properties.at(0) == "Maya|use_normal_map") {
|
|
||||||
material.useNormalMap = (bool)property.properties.at(index).value<double>();
|
material.useNormalMap = (bool)property.properties.at(index).value<double>();
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Maya|base_color") {
|
} else if (property.properties.at(0) == "Maya|base_color") {
|
||||||
|
material.isPBSMaterial = true;
|
||||||
material.diffuseColor = getVec3(property.properties, index);
|
material.diffuseColor = getVec3(property.properties, index);
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Maya|use_color_map") {
|
} else if (property.properties.at(0) == "Maya|use_color_map") {
|
||||||
|
material.isPBSMaterial = true;
|
||||||
material.useAlbedoMap = (bool) property.properties.at(index).value<double>();
|
material.useAlbedoMap = (bool) property.properties.at(index).value<double>();
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Maya|roughness") {
|
} else if (property.properties.at(0) == "Maya|roughness") {
|
||||||
|
material.isPBSMaterial = true;
|
||||||
material.roughness = property.properties.at(index).value<double>();
|
material.roughness = property.properties.at(index).value<double>();
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Maya|use_roughness_map") {
|
} else if (property.properties.at(0) == "Maya|use_roughness_map") {
|
||||||
|
material.isPBSMaterial = true;
|
||||||
material.useRoughnessMap = (bool)property.properties.at(index).value<double>();
|
material.useRoughnessMap = (bool)property.properties.at(index).value<double>();
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Maya|metallic") {
|
} else if (property.properties.at(0) == "Maya|metallic") {
|
||||||
|
material.isPBSMaterial = true;
|
||||||
material.metallic = property.properties.at(index).value<double>();
|
material.metallic = property.properties.at(index).value<double>();
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Maya|use_metallic_map") {
|
} else if (property.properties.at(0) == "Maya|use_metallic_map") {
|
||||||
|
material.isPBSMaterial = true;
|
||||||
material.useMetallicMap = (bool)property.properties.at(index).value<double>();
|
material.useMetallicMap = (bool)property.properties.at(index).value<double>();
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Maya|emissive") {
|
} else if (property.properties.at(0) == "Maya|emissive") {
|
||||||
|
material.isPBSMaterial = true;
|
||||||
material.emissiveColor = getVec3(property.properties, index);
|
material.emissiveColor = getVec3(property.properties, index);
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Maya|emissive_intensity") {
|
} else if (property.properties.at(0) == "Maya|emissive_intensity") {
|
||||||
|
material.isPBSMaterial = true;
|
||||||
material.emissiveIntensity = property.properties.at(index).value<double>();
|
material.emissiveIntensity = property.properties.at(index).value<double>();
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Maya|use_emissive_map") {
|
} else if (property.properties.at(0) == "Maya|use_emissive_map") {
|
||||||
|
material.isPBSMaterial = true;
|
||||||
material.useEmissiveMap = (bool)property.properties.at(index).value<double>();
|
material.useEmissiveMap = (bool)property.properties.at(index).value<double>();
|
||||||
|
|
||||||
} else if (property.properties.at(0) == "Maya|use_ao_map") {
|
} else if (property.properties.at(0) == "Maya|use_ao_map") {
|
||||||
|
material.isPBSMaterial = true;
|
||||||
material.useOcclusionMap = (bool)property.properties.at(index).value<double>();
|
material.useOcclusionMap = (bool)property.properties.at(index).value<double>();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -1073,7 +1088,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
if (connection.properties.at(0) == "OP") {
|
if (connection.properties.at(0) == "OP") {
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
QByteArray type = connection.properties.at(3).toByteArray().toLower();
|
QByteArray type = connection.properties.at(3).toByteArray().toLower();
|
||||||
if ((type.contains("diffuse") && !type.contains("tex_global_diffuse"))) {
|
if (type.contains("DiffuseFactor")) {
|
||||||
|
diffuseFactorTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
} else if ((type.contains("diffuse") && !type.contains("tex_global_diffuse"))) {
|
||||||
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
} else if (type.contains("tex_color_map")) {
|
} else if (type.contains("tex_color_map")) {
|
||||||
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
|
|
@ -138,19 +138,22 @@ public:
|
||||||
opacity(opacity) {}
|
opacity(opacity) {}
|
||||||
|
|
||||||
glm::vec3 diffuseColor{ 1.0f };
|
glm::vec3 diffuseColor{ 1.0f };
|
||||||
float diffuseFactor = 1.0f;
|
float diffuseFactor{ 1.0f };
|
||||||
glm::vec3 specularColor{ 0.02f };
|
glm::vec3 specularColor{ 0.02f };
|
||||||
float specularFactor = 1.0f;
|
float specularFactor{ 1.0f };
|
||||||
|
|
||||||
glm::vec3 emissiveColor{ 0.0f };
|
glm::vec3 emissiveColor{ 0.0f };
|
||||||
float shininess = 23.0f;
|
float emissiveFactor{ 0.0f };
|
||||||
float opacity = 1.0f;
|
|
||||||
|
float shininess{ 23.0f };
|
||||||
|
float opacity{ 1.0f };
|
||||||
|
|
||||||
float metallic{ 0.0f };
|
float metallic{ 0.0f };
|
||||||
float roughness{ 1.0f };
|
float roughness{ 1.0f };
|
||||||
float emissiveIntensity{ 1.0f };
|
float emissiveIntensity{ 1.0f };
|
||||||
|
|
||||||
QString materialID;
|
QString materialID;
|
||||||
|
QString name;
|
||||||
model::MaterialPointer _material;
|
model::MaterialPointer _material;
|
||||||
|
|
||||||
FBXTexture normalTexture;
|
FBXTexture normalTexture;
|
||||||
|
@ -421,6 +424,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
QHash<QString, QString> diffuseTextures;
|
QHash<QString, QString> diffuseTextures;
|
||||||
|
QHash<QString, QString> diffuseFactorTextures;
|
||||||
QHash<QString, QString> transparentTextures;
|
QHash<QString, QString> transparentTextures;
|
||||||
QHash<QString, QString> bumpTextures;
|
QHash<QString, QString> bumpTextures;
|
||||||
QHash<QString, QString> normalTextures;
|
QHash<QString, QString> normalTextures;
|
||||||
|
|
|
@ -75,12 +75,24 @@ void FBXReader::consolidateFBXMaterials() {
|
||||||
// the pure material associated with this part
|
// the pure material associated with this part
|
||||||
bool detectDifferentUVs = false;
|
bool detectDifferentUVs = false;
|
||||||
FBXTexture diffuseTexture;
|
FBXTexture diffuseTexture;
|
||||||
|
FBXTexture diffuseFactorTexture;
|
||||||
QString diffuseTextureID = diffuseTextures.value(material.materialID);
|
QString diffuseTextureID = diffuseTextures.value(material.materialID);
|
||||||
if (!diffuseTextureID.isNull()) {
|
QString diffuseFactorTextureID = diffuseFactorTextures.value(material.materialID);
|
||||||
|
|
||||||
|
// If both factor and color textures are specified, the texture bound to DiffuseColor wins
|
||||||
|
if (!diffuseFactorTextureID.isNull() || !diffuseTextureID.isNull()) {
|
||||||
|
if (!diffuseFactorTextureID.isNull() && diffuseTextureID.isNull()) {
|
||||||
|
diffuseTextureID = diffuseFactorTextureID;
|
||||||
|
// If the diffuseTextureID comes from the Texture bound to DiffuseFactor, we know it s exported from maya
|
||||||
|
// And the DiffuseFactor is forced to 0.5 by Maya which is bad
|
||||||
|
// So we need to force it to 1.0
|
||||||
|
material.diffuseFactor = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
diffuseTexture = getTexture(diffuseTextureID);
|
diffuseTexture = getTexture(diffuseTextureID);
|
||||||
|
|
||||||
// FBX files generated by 3DSMax have an intermediate texture parent, apparently
|
// FBX files generated by 3DSMax have an intermediate texture parent, apparently
|
||||||
foreach (const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) {
|
foreach(const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) {
|
||||||
if (_textureFilenames.contains(childTextureID)) {
|
if (_textureFilenames.contains(childTextureID)) {
|
||||||
diffuseTexture = getTexture(diffuseTextureID);
|
diffuseTexture = getTexture(diffuseTextureID);
|
||||||
}
|
}
|
||||||
|
@ -180,11 +192,13 @@ void FBXReader::consolidateFBXMaterials() {
|
||||||
|
|
||||||
// Finally create the true material representation
|
// Finally create the true material representation
|
||||||
material._material = std::make_shared<model::Material>();
|
material._material = std::make_shared<model::Material>();
|
||||||
material._material->setEmissive(material.emissiveColor);
|
|
||||||
|
|
||||||
auto diffuse = material.diffuseColor;
|
// Emissive color is the mix of emissiveColor with emissiveFactor
|
||||||
// FIXME: Do not use the Diffuse Factor yet as some FBX models have it set to 0
|
auto emissive = material.emissiveColor * material.emissiveFactor;
|
||||||
// diffuse *= material.diffuseFactor;
|
material._material->setEmissive(emissive);
|
||||||
|
|
||||||
|
// Final diffuse color is the mix of diffuseColor with diffuseFactor
|
||||||
|
auto diffuse = material.diffuseColor * material.diffuseFactor;
|
||||||
material._material->setAlbedo(diffuse);
|
material._material->setAlbedo(diffuse);
|
||||||
|
|
||||||
if (material.isPBSMaterial) {
|
if (material.isPBSMaterial) {
|
||||||
|
|
|
@ -344,6 +344,7 @@ void NetworkTexture::setImage(const QImage& image, void* voidTexture, int origin
|
||||||
_width = _height = 0;
|
_width = _height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isCacheable = true;
|
||||||
finishedLoading(true);
|
finishedLoading(true);
|
||||||
|
|
||||||
emit networkTextureCreated(qWeakPointerCast<NetworkTexture, Resource> (_self));
|
emit networkTextureCreated(qWeakPointerCast<NetworkTexture, Resource> (_self));
|
||||||
|
|
|
@ -132,6 +132,8 @@ signals:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
virtual bool isCacheable() const override { return _isCacheable; }
|
||||||
|
|
||||||
virtual void downloadFinished(const QByteArray& data) override;
|
virtual void downloadFinished(const QByteArray& data) override;
|
||||||
|
|
||||||
Q_INVOKABLE void loadContent(const QByteArray& content);
|
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||||
|
@ -146,6 +148,7 @@ private:
|
||||||
int _originalHeight { 0 };
|
int _originalHeight { 0 };
|
||||||
int _width { 0 };
|
int _width { 0 };
|
||||||
int _height { 0 };
|
int _height { 0 };
|
||||||
|
bool _isCacheable { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_TextureCache_h
|
#endif // hifi_TextureCache_h
|
||||||
|
|
|
@ -278,20 +278,20 @@ void Resource::refresh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resource::allReferencesCleared() {
|
void Resource::allReferencesCleared() {
|
||||||
if (_cache) {
|
if (_cache && isCacheable()) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "allReferencesCleared");
|
QMetaObject::invokeMethod(this, "allReferencesCleared");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create and reinsert new shared pointer
|
// create and reinsert new shared pointer
|
||||||
QSharedPointer<Resource> self(this, &Resource::allReferencesCleared);
|
QSharedPointer<Resource> self(this, &Resource::allReferencesCleared);
|
||||||
setSelf(self);
|
setSelf(self);
|
||||||
reinsert();
|
reinsert();
|
||||||
|
|
||||||
// add to the unused list
|
// add to the unused list
|
||||||
_cache->addUnusedResource(self);
|
_cache->addUnusedResource(self);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,6 +192,9 @@ protected slots:
|
||||||
protected:
|
protected:
|
||||||
virtual void init();
|
virtual void init();
|
||||||
|
|
||||||
|
/// Checks whether the resource is cacheable.
|
||||||
|
virtual bool isCacheable() const { return true; }
|
||||||
|
|
||||||
/// Called when the download has finished
|
/// Called when the download has finished
|
||||||
virtual void downloadFinished(const QByteArray& data);
|
virtual void downloadFinished(const QByteArray& data);
|
||||||
|
|
||||||
|
|
|
@ -10,27 +10,30 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "RenderDeferredTask.h"
|
||||||
|
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
#include <RenderArgs.h>
|
#include <RenderArgs.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
#include <gpu/Context.h>
|
#include <gpu/Context.h>
|
||||||
|
|
||||||
|
#include <render/CullTask.h>
|
||||||
|
#include <render/SortTask.h>
|
||||||
|
#include <render/DrawTask.h>
|
||||||
|
#include <render/DrawStatus.h>
|
||||||
|
#include <render/DrawSceneOctree.h>
|
||||||
|
|
||||||
#include "DebugDeferredBuffer.h"
|
#include "DebugDeferredBuffer.h"
|
||||||
#include "DeferredLightingEffect.h"
|
#include "DeferredLightingEffect.h"
|
||||||
#include "FramebufferCache.h"
|
#include "FramebufferCache.h"
|
||||||
#include "HitEffect.h"
|
#include "HitEffect.h"
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
|
|
||||||
#include "render/DrawTask.h"
|
|
||||||
#include "render/DrawStatus.h"
|
|
||||||
#include "render/DrawSceneOctree.h"
|
|
||||||
#include "AmbientOcclusionEffect.h"
|
#include "AmbientOcclusionEffect.h"
|
||||||
#include "AntialiasingEffect.h"
|
#include "AntialiasingEffect.h"
|
||||||
#include "ToneMappingEffect.h"
|
#include "ToneMappingEffect.h"
|
||||||
|
|
||||||
#include "RenderDeferredTask.h"
|
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
extern void initStencilPipeline(gpu::PipelinePointer& pipeline);
|
extern void initStencilPipeline(gpu::PipelinePointer& pipeline);
|
||||||
|
@ -54,34 +57,42 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
|
||||||
|
|
||||||
// CPU jobs:
|
// CPU jobs:
|
||||||
// Fetch and cull the items from the scene
|
// Fetch and cull the items from the scene
|
||||||
auto sceneFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
|
auto spatialFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
|
||||||
const auto sceneSelection = addJob<FetchSpatialTree>("FetchSceneSelection", sceneFilter);
|
const auto spatialSelection = addJob<FetchSpatialTree>("FetchSceneSelection", spatialFilter);
|
||||||
const auto culledSceneSelection = addJob<CullSpatialSelection>("CullSceneSelection", sceneSelection, cullFunctor, RenderDetails::ITEM, sceneFilter);
|
const auto culledSpatialSelection = addJob<CullSpatialSelection>("CullSceneSelection", spatialSelection, cullFunctor, RenderDetails::ITEM, spatialFilter);
|
||||||
|
|
||||||
|
// Overlays are not culled
|
||||||
|
const auto nonspatialSelection = addJob<FetchNonspatialItems>("FetchOverlaySelection");
|
||||||
|
|
||||||
// Multi filter visible items into different buckets
|
// Multi filter visible items into different buckets
|
||||||
const int NUM_FILTERS = 3;
|
const int NUM_FILTERS = 3;
|
||||||
const int OPAQUE_SHAPE_BUCKET = 0;
|
const int OPAQUE_SHAPE_BUCKET = 0;
|
||||||
const int TRANSPARENT_SHAPE_BUCKET = 1;
|
const int TRANSPARENT_SHAPE_BUCKET = 1;
|
||||||
const int LIGHT_BUCKET = 2;
|
const int LIGHT_BUCKET = 2;
|
||||||
MultiFilterItem<NUM_FILTERS>::ItemFilterArray triageFilters = { {
|
const int BACKGROUND_BUCKET = 2;
|
||||||
|
MultiFilterItem<NUM_FILTERS>::ItemFilterArray spatialFilters = { {
|
||||||
ItemFilter::Builder::opaqueShape(),
|
ItemFilter::Builder::opaqueShape(),
|
||||||
ItemFilter::Builder::transparentShape(),
|
ItemFilter::Builder::transparentShape(),
|
||||||
ItemFilter::Builder::light()
|
ItemFilter::Builder::light()
|
||||||
} };
|
} };
|
||||||
const auto filteredItemsBuckets = addJob<MultiFilterItem<NUM_FILTERS>>("FilterSceneSelection", culledSceneSelection, triageFilters).get<MultiFilterItem<NUM_FILTERS>::ItemBoundsArray>();
|
MultiFilterItem<NUM_FILTERS>::ItemFilterArray nonspatialFilters = { {
|
||||||
|
ItemFilter::Builder::opaqueShape(),
|
||||||
|
ItemFilter::Builder::transparentShape(),
|
||||||
|
ItemFilter::Builder::background()
|
||||||
|
} };
|
||||||
|
const auto filteredSpatialBuckets = addJob<MultiFilterItem<NUM_FILTERS>>("FilterSceneSelection", culledSpatialSelection, spatialFilters).get<MultiFilterItem<NUM_FILTERS>::ItemBoundsArray>();
|
||||||
|
const auto filteredNonspatialBuckets = addJob<MultiFilterItem<NUM_FILTERS>>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters).get<MultiFilterItem<NUM_FILTERS>::ItemBoundsArray>();
|
||||||
|
|
||||||
// Extract / Sort opaques / Transparents / Lights / Overlays
|
// Extract / Sort opaques / Transparents / Lights / Overlays
|
||||||
const auto opaques = addJob<DepthSortItems>("DepthSortOpaque", filteredItemsBuckets[OPAQUE_SHAPE_BUCKET]);
|
const auto opaques = addJob<DepthSortItems>("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]);
|
||||||
const auto transparents = addJob<DepthSortItems>("DepthSortTransparent", filteredItemsBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
|
const auto transparents = addJob<DepthSortItems>("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
|
||||||
const auto lights = filteredItemsBuckets[LIGHT_BUCKET];
|
const auto lights = filteredSpatialBuckets[LIGHT_BUCKET];
|
||||||
|
|
||||||
// Overlays are not culled because we want to make sure they are seen
|
const auto overlayOpaques = addJob<DepthSortItems>("DepthSortOverlayOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]);
|
||||||
// Could be considered a bug in the current cullfunctor
|
const auto overlayTransparents = addJob<DepthSortItems>("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
|
||||||
const auto overlayOpaques = addJob<FetchItems>("FetchOverlayOpaque", ItemFilter::Builder::opaqueShapeLayered());
|
const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET];
|
||||||
const auto fetchedOverlayOpaques = addJob<FetchItems>("FetchOverlayTransparents", ItemFilter::Builder::transparentShapeLayered());
|
|
||||||
const auto overlayTransparents = addJob<DepthSortItems>("DepthSortTransparentOverlay", fetchedOverlayOpaques, DepthSortItems(false));
|
|
||||||
|
|
||||||
// GPU Jobs: Start preparing the deferred and lighting buffer
|
// GPU jobs: Start preparing the deferred and lighting buffer
|
||||||
addJob<PrepareDeferred>("PrepareDeferred");
|
addJob<PrepareDeferred>("PrepareDeferred");
|
||||||
|
|
||||||
// Render opaque objects in DeferredBuffer
|
// Render opaque objects in DeferredBuffer
|
||||||
|
@ -91,7 +102,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
|
||||||
addJob<DrawStencilDeferred>("DrawOpaqueStencil");
|
addJob<DrawStencilDeferred>("DrawOpaqueStencil");
|
||||||
|
|
||||||
// Use Stencil and start drawing background in Lighting buffer
|
// Use Stencil and start drawing background in Lighting buffer
|
||||||
addJob<DrawBackgroundDeferred>("DrawBackgroundDeferred");
|
addJob<DrawBackgroundDeferred>("DrawBackgroundDeferred", background);
|
||||||
|
|
||||||
// AO job
|
// AO job
|
||||||
addJob<AmbientOcclusionEffect>("AmbientOcclusion");
|
addJob<AmbientOcclusionEffect>("AmbientOcclusion");
|
||||||
|
@ -123,8 +134,8 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
|
||||||
|
|
||||||
// Scene Octree Debuging job
|
// Scene Octree Debuging job
|
||||||
{
|
{
|
||||||
addJob<DrawSceneOctree>("DrawSceneOctree", sceneSelection);
|
addJob<DrawSceneOctree>("DrawSceneOctree", spatialSelection);
|
||||||
addJob<DrawItemSelection>("DrawItemSelection", sceneSelection);
|
addJob<DrawItemSelection>("DrawItemSelection", spatialSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status icon rendering job
|
// Status icon rendering job
|
||||||
|
@ -170,9 +181,9 @@ void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderCont
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
|
args->_batch = &batch;
|
||||||
batch.setViewportTransform(args->_viewport);
|
batch.setViewportTransform(args->_viewport);
|
||||||
batch.setStateScissorRect(args->_viewport);
|
batch.setStateScissorRect(args->_viewport);
|
||||||
args->_batch = &batch;
|
|
||||||
|
|
||||||
config->setNumDrawn((int)inItems.size());
|
config->setNumDrawn((int)inItems.size());
|
||||||
emit config->numDrawnChanged();
|
emit config->numDrawnChanged();
|
||||||
|
@ -222,7 +233,8 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
|
||||||
// Render the items
|
// Render the items
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
args->_batch = &batch;
|
args->_batch = &batch;
|
||||||
args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture();
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
batch.setStateScissorRect(args->_viewport);
|
||||||
|
|
||||||
glm::mat4 projMat;
|
glm::mat4 projMat;
|
||||||
Transform viewMat;
|
Transform viewMat;
|
||||||
|
@ -231,14 +243,10 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
|
||||||
|
|
||||||
batch.setProjectionTransform(projMat);
|
batch.setProjectionTransform(projMat);
|
||||||
batch.setViewTransform(viewMat);
|
batch.setViewTransform(viewMat);
|
||||||
batch.setViewportTransform(args->_viewport);
|
|
||||||
batch.setStateScissorRect(args->_viewport);
|
|
||||||
batch.setResourceTexture(0, args->_whiteTexture);
|
|
||||||
|
|
||||||
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn);
|
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn);
|
||||||
|
args->_batch = nullptr;
|
||||||
});
|
});
|
||||||
args->_batch = nullptr;
|
|
||||||
args->_whiteTexture.reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,20 +284,10 @@ void DrawStencilDeferred::run(const SceneContextPointer& sceneContext, const Ren
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems) {
|
||||||
assert(renderContext->args);
|
assert(renderContext->args);
|
||||||
assert(renderContext->args->_viewFrustum);
|
assert(renderContext->args->_viewFrustum);
|
||||||
|
|
||||||
// render backgrounds
|
|
||||||
auto& scene = sceneContext->_scene;
|
|
||||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::background());
|
|
||||||
|
|
||||||
|
|
||||||
ItemBounds inItems;
|
|
||||||
inItems.reserve(items.size());
|
|
||||||
for (auto id : items) {
|
|
||||||
inItems.emplace_back(id);
|
|
||||||
}
|
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
doInBatch(args->_context, [&](gpu::Batch& batch) {
|
doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
args->_batch = &batch;
|
args->_batch = &batch;
|
||||||
|
|
|
@ -12,9 +12,8 @@
|
||||||
#ifndef hifi_RenderDeferredTask_h
|
#ifndef hifi_RenderDeferredTask_h
|
||||||
#define hifi_RenderDeferredTask_h
|
#define hifi_RenderDeferredTask_h
|
||||||
|
|
||||||
#include "gpu/Pipeline.h"
|
#include <gpu/Pipeline.h>
|
||||||
|
#include <render/CullTask.h>
|
||||||
#include "render/DrawTask.h"
|
|
||||||
|
|
||||||
class SetupDeferred {
|
class SetupDeferred {
|
||||||
public:
|
public:
|
||||||
|
@ -85,9 +84,9 @@ protected:
|
||||||
|
|
||||||
class DrawBackgroundDeferred {
|
class DrawBackgroundDeferred {
|
||||||
public:
|
public:
|
||||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemBounds& inItems);
|
||||||
|
|
||||||
using JobModel = render::Job::Model<DrawBackgroundDeferred>;
|
using JobModel = render::Job::ModelI<DrawBackgroundDeferred, render::ItemBounds>;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawOverlay3DConfig : public render::Job::Config {
|
class DrawOverlay3DConfig : public render::Job::Config {
|
||||||
|
|
|
@ -9,16 +9,20 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "RenderShadowTask.h"
|
||||||
|
|
||||||
#include <gpu/Context.h>
|
#include <gpu/Context.h>
|
||||||
|
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
|
|
||||||
#include "render/Context.h"
|
#include <render/Context.h>
|
||||||
|
#include <render/CullTask.h>
|
||||||
|
#include <render/SortTask.h>
|
||||||
|
#include <render/DrawTask.h>
|
||||||
|
|
||||||
#include "DeferredLightingEffect.h"
|
#include "DeferredLightingEffect.h"
|
||||||
#include "FramebufferCache.h"
|
#include "FramebufferCache.h"
|
||||||
|
|
||||||
#include "RenderShadowTask.h"
|
|
||||||
|
|
||||||
#include "model_shadow_vert.h"
|
#include "model_shadow_vert.h"
|
||||||
#include "skin_model_shadow_vert.h"
|
#include "skin_model_shadow_vert.h"
|
||||||
|
|
||||||
|
@ -28,7 +32,7 @@
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext,
|
void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext,
|
||||||
const render::ShapesIDsBounds& inShapes) {
|
const render::ShapeBounds& inShapes) {
|
||||||
assert(renderContext->args);
|
assert(renderContext->args);
|
||||||
assert(renderContext->args->_viewFrustum);
|
assert(renderContext->args->_viewFrustum);
|
||||||
|
|
||||||
|
@ -104,20 +108,18 @@ RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) : Task(std::make_sha
|
||||||
skinProgram, state);
|
skinProgram, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CPU: Fetch shadow-casting opaques
|
// CPU jobs:
|
||||||
const auto fetchedItems = addJob<FetchItems>("FetchShadowMap");
|
// Fetch and cull the items from the scene
|
||||||
|
auto shadowFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
||||||
|
const auto shadowSelection = addJob<FetchSpatialTree>("FetchShadowSelection", shadowFilter);
|
||||||
|
const auto culledShadowSelection = addJob<CullSpatialSelection>("CullShadowSelection", shadowSelection, cullFunctor, RenderDetails::SHADOW, shadowFilter);
|
||||||
|
|
||||||
// CPU: Cull against KeyLight frustum (nearby viewing camera)
|
// Sort
|
||||||
const auto culledItems = addJob<CullItems<RenderDetails::SHADOW>>("CullShadowMap", fetchedItems, cullFunctor);
|
const auto sortedPipelines = addJob<PipelineSortShapes>("PipelineSortShadowSort", culledShadowSelection);
|
||||||
|
const auto sortedShapes = addJob<DepthSortShapes>("DepthSortShadowMap", sortedPipelines);
|
||||||
|
|
||||||
// CPU: Sort by pipeline
|
// GPU jobs: Render to shadow map
|
||||||
const auto sortedShapes = addJob<PipelineSortShapes>("PipelineSortShadowSort", culledItems);
|
addJob<RenderShadowMap>("RenderShadowMap", sortedShapes, shapePlumber);
|
||||||
|
|
||||||
// CPU: Sort front to back
|
|
||||||
const auto shadowShapes = addJob<DepthSortShapes>("DepthSortShadowMap", sortedShapes);
|
|
||||||
|
|
||||||
// GPU: Render to shadow map
|
|
||||||
addJob<RenderShadowMap>("RenderShadowMap", shadowShapes, shapePlumber);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderShadowTask::configure(const Config& configuration) {
|
void RenderShadowTask::configure(const Config& configuration) {
|
||||||
|
|
|
@ -15,17 +15,17 @@
|
||||||
#include <gpu/Framebuffer.h>
|
#include <gpu/Framebuffer.h>
|
||||||
#include <gpu/Pipeline.h>
|
#include <gpu/Pipeline.h>
|
||||||
|
|
||||||
#include <render/DrawTask.h>
|
#include <render/CullTask.h>
|
||||||
|
|
||||||
class ViewFrustum;
|
class ViewFrustum;
|
||||||
|
|
||||||
class RenderShadowMap {
|
class RenderShadowMap {
|
||||||
public:
|
public:
|
||||||
using JobModel = render::Job::ModelI<RenderShadowMap, render::ShapesIDsBounds>;
|
using JobModel = render::Job::ModelI<RenderShadowMap, render::ShapeBounds>;
|
||||||
|
|
||||||
RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
|
RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
|
||||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext,
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext,
|
||||||
const render::ShapesIDsBounds& inShapes);
|
const render::ShapeBounds& inShapes);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
render::ShapePlumberPointer _shapePlumber;
|
render::ShapePlumberPointer _shapePlumber;
|
||||||
|
|
|
@ -62,99 +62,21 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc
|
||||||
details._rendered += (int)outItems.size();
|
details._rendered += (int)outItems.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ItemBoundSort {
|
void FetchNonspatialItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemBounds& outItems) {
|
||||||
float _centerDepth = 0.0f;
|
|
||||||
float _nearDepth = 0.0f;
|
|
||||||
float _farDepth = 0.0f;
|
|
||||||
ItemID _id = 0;
|
|
||||||
AABox _bounds;
|
|
||||||
|
|
||||||
ItemBoundSort() {}
|
|
||||||
ItemBoundSort(float centerDepth, float nearDepth, float farDepth, ItemID id, const AABox& bounds) : _centerDepth(centerDepth), _nearDepth(nearDepth), _farDepth(farDepth), _id(id), _bounds(bounds) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FrontToBackSort {
|
|
||||||
bool operator() (const ItemBoundSort& left, const ItemBoundSort& right) {
|
|
||||||
return (left._centerDepth < right._centerDepth);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BackToFrontSort {
|
|
||||||
bool operator() (const ItemBoundSort& left, const ItemBoundSort& right) {
|
|
||||||
return (left._centerDepth > right._centerDepth);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems) {
|
|
||||||
assert(renderContext->args);
|
|
||||||
assert(renderContext->args->_viewFrustum);
|
|
||||||
|
|
||||||
auto& scene = sceneContext->_scene;
|
|
||||||
RenderArgs* args = renderContext->args;
|
|
||||||
|
|
||||||
|
|
||||||
// Allocate and simply copy
|
|
||||||
outItems.clear();
|
|
||||||
outItems.reserve(inItems.size());
|
|
||||||
|
|
||||||
|
|
||||||
// Make a local dataset of the center distance and closest point distance
|
|
||||||
std::vector<ItemBoundSort> itemBoundSorts;
|
|
||||||
itemBoundSorts.reserve(outItems.size());
|
|
||||||
|
|
||||||
for (auto itemDetails : inItems) {
|
|
||||||
auto item = scene->getItem(itemDetails.id);
|
|
||||||
auto bound = itemDetails.bound; // item.getBound();
|
|
||||||
float distance = args->_viewFrustum->distanceToCamera(bound.calcCenter());
|
|
||||||
|
|
||||||
itemBoundSorts.emplace_back(ItemBoundSort(distance, distance, distance, itemDetails.id, bound));
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort against Z
|
|
||||||
if (frontToBack) {
|
|
||||||
FrontToBackSort frontToBackSort;
|
|
||||||
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), frontToBackSort);
|
|
||||||
} else {
|
|
||||||
BackToFrontSort backToFrontSort;
|
|
||||||
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), backToFrontSort);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FInally once sorted result to a list of itemID
|
|
||||||
for (auto& item : itemBoundSorts) {
|
|
||||||
outItems.emplace_back(ItemBound(item._id, item._bounds));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
|
||||||
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void FetchItems::configure(const Config& config) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemBounds& outItems) {
|
|
||||||
assert(renderContext->args);
|
assert(renderContext->args);
|
||||||
assert(renderContext->args->_viewFrustum);
|
assert(renderContext->args->_viewFrustum);
|
||||||
auto& scene = sceneContext->_scene;
|
auto& scene = sceneContext->_scene;
|
||||||
|
|
||||||
outItems.clear();
|
outItems.clear();
|
||||||
|
|
||||||
const auto& bucket = scene->getMasterBucket();
|
const auto& items = scene->getNonspatialSet();
|
||||||
const auto& items = bucket.find(_filter);
|
outItems.reserve(items.size());
|
||||||
if (items != bucket.end()) {
|
for (auto& id : items) {
|
||||||
outItems.reserve(items->second.size());
|
auto& item = scene->getItem(id);
|
||||||
for (auto& id : items->second) {
|
outItems.emplace_back(ItemBound(id, item.getBound()));
|
||||||
auto& item = scene->getItem(id);
|
|
||||||
outItems.emplace_back(ItemBound(id, item.getBound()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::static_pointer_cast<Config>(renderContext->jobConfig)->numItems = (int)outItems.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void FetchSpatialTree::configure(const Config& config) {
|
void FetchSpatialTree::configure(const Config& config) {
|
||||||
_justFrozeFrustum = _justFrozeFrustum || (config.freezeFrustum && !_freezeFrustum);
|
_justFrozeFrustum = _justFrozeFrustum || (config.freezeFrustum && !_freezeFrustum);
|
||||||
_freezeFrustum = config.freezeFrustum;
|
_freezeFrustum = config.freezeFrustum;
|
||||||
|
|
|
@ -21,52 +21,13 @@ namespace render {
|
||||||
|
|
||||||
void cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details,
|
void cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details,
|
||||||
const ItemBounds& inItems, ItemBounds& outItems);
|
const ItemBounds& inItems, ItemBounds& outItems);
|
||||||
void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems);
|
|
||||||
|
|
||||||
class FetchItemsConfig : public Job::Config {
|
class FetchNonspatialItems {
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(int numItems READ getNumItems)
|
|
||||||
public:
|
public:
|
||||||
int getNumItems() { return numItems; }
|
using JobModel = Job::ModelO<FetchNonspatialItems, ItemBounds>;
|
||||||
|
|
||||||
int numItems{ 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
class FetchItems {
|
|
||||||
public:
|
|
||||||
using Config = FetchItemsConfig;
|
|
||||||
using JobModel = Job::ModelO<FetchItems, ItemBounds, Config>;
|
|
||||||
|
|
||||||
FetchItems() {}
|
|
||||||
FetchItems(const ItemFilter& filter) : _filter(filter) {}
|
|
||||||
|
|
||||||
ItemFilter _filter{ ItemFilter::Builder::opaqueShape().withoutLayered() };
|
|
||||||
|
|
||||||
void configure(const Config& config);
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemBounds& outItems);
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemBounds& outItems);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<RenderDetails::Type T>
|
|
||||||
class CullItems {
|
|
||||||
public:
|
|
||||||
using JobModel = Job::ModelIO<CullItems<T>, ItemBounds, ItemBounds>;
|
|
||||||
|
|
||||||
CullItems(CullFunctor cullFunctor) : _cullFunctor{ cullFunctor } {}
|
|
||||||
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
|
||||||
const auto& args = renderContext->args;
|
|
||||||
auto& details = args->_details.edit(T);
|
|
||||||
outItems.clear();
|
|
||||||
outItems.reserve(inItems.size());
|
|
||||||
render::cullItems(renderContext, _cullFunctor, details, inItems, outItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
CullFunctor _cullFunctor;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class FetchSpatialTreeConfig : public Job::Config {
|
class FetchSpatialTreeConfig : public Job::Config {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(int numItems READ getNumItems)
|
Q_PROPERTY(int numItems READ getNumItems)
|
||||||
|
@ -209,28 +170,19 @@ namespace render {
|
||||||
outItems[i].template edit<ItemBounds>().clear();
|
outItems[i].template edit<ItemBounds>().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each item, filter it into the buckets
|
// For each item, filter it into one bucket
|
||||||
for (auto itemBound : inItems) {
|
for (auto itemBound : inItems) {
|
||||||
auto& item = scene->getItem(itemBound.id);
|
auto& item = scene->getItem(itemBound.id);
|
||||||
auto itemKey = item.getKey();
|
auto itemKey = item.getKey();
|
||||||
for (size_t i = 0; i < NUM_FILTERS; i++) {
|
for (size_t i = 0; i < NUM_FILTERS; i++) {
|
||||||
if (_filters[i].test(itemKey)) {
|
if (_filters[i].test(itemKey)) {
|
||||||
outItems[i].template edit<ItemBounds>().emplace_back(itemBound);
|
outItems[i].template edit<ItemBounds>().emplace_back(itemBound);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DepthSortItems {
|
|
||||||
public:
|
|
||||||
using JobModel = Job::ModelIO<DepthSortItems, ItemBounds, ItemBounds>;
|
|
||||||
|
|
||||||
bool _frontToBack;
|
|
||||||
DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {}
|
|
||||||
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // hifi_render_CullTask_h;
|
#endif // hifi_render_CullTask_h;
|
|
@ -73,38 +73,3 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipelineSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ShapesIDsBounds& outShapes) {
|
|
||||||
auto& scene = sceneContext->_scene;
|
|
||||||
outShapes.clear();
|
|
||||||
|
|
||||||
for (const auto& item : inItems) {
|
|
||||||
auto key = scene->getItem(item.id).getShapeKey();
|
|
||||||
auto outItems = outShapes.find(key);
|
|
||||||
if (outItems == outShapes.end()) {
|
|
||||||
outItems = outShapes.insert(std::make_pair(key, ItemBounds{})).first;
|
|
||||||
outItems->second.reserve(inItems.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
outItems->second.push_back(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& items : outShapes) {
|
|
||||||
items.second.shrink_to_fit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DepthSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapesIDsBounds& inShapes, ShapesIDsBounds& outShapes) {
|
|
||||||
outShapes.clear();
|
|
||||||
outShapes.reserve(inShapes.size());
|
|
||||||
|
|
||||||
for (auto& pipeline : inShapes) {
|
|
||||||
auto& inItems = pipeline.second;
|
|
||||||
auto outItems = outShapes.find(pipeline.first);
|
|
||||||
if (outItems == outShapes.end()) {
|
|
||||||
outItems = outShapes.insert(std::make_pair(pipeline.first, ItemBounds{})).first;
|
|
||||||
}
|
|
||||||
|
|
||||||
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,10 +13,6 @@
|
||||||
#define hifi_render_DrawTask_h
|
#define hifi_render_DrawTask_h
|
||||||
|
|
||||||
#include "Engine.h"
|
#include "Engine.h"
|
||||||
#include "CullTask.h"
|
|
||||||
#include "ShapePipeline.h"
|
|
||||||
#include "gpu/Batch.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
|
||||||
|
@ -31,22 +27,6 @@ public:
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
class PipelineSortShapes {
|
|
||||||
public:
|
|
||||||
using JobModel = Job::ModelIO<PipelineSortShapes, ItemBounds, ShapesIDsBounds>;
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ShapesIDsBounds& outShapes);
|
|
||||||
};
|
|
||||||
|
|
||||||
class DepthSortShapes {
|
|
||||||
public:
|
|
||||||
using JobModel = Job::ModelIO<DepthSortShapes, ShapesIDsBounds, ShapesIDsBounds>;
|
|
||||||
|
|
||||||
bool _frontToBack;
|
|
||||||
DepthSortShapes(bool frontToBack = true) : _frontToBack(frontToBack) {}
|
|
||||||
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapesIDsBounds& inShapes, ShapesIDsBounds& outShapes);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // hifi_render_DrawTask_h
|
#endif // hifi_render_DrawTask_h
|
||||||
|
|
|
@ -63,6 +63,13 @@ void Item::PayloadInterface::addStatusGetters(const Status::Getters& getters) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Item::update(const UpdateFunctorPointer& updateFunctor) {
|
||||||
|
if (updateFunctor) {
|
||||||
|
_payload->update(updateFunctor);
|
||||||
|
}
|
||||||
|
_key = _payload->getKey();
|
||||||
|
}
|
||||||
|
|
||||||
void Item::resetPayload(const PayloadPointer& payload) {
|
void Item::resetPayload(const PayloadPointer& payload) {
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
kill();
|
kill();
|
||||||
|
|
|
@ -112,6 +112,7 @@ public:
|
||||||
bool isPickable() const { return _flags[PICKABLE]; }
|
bool isPickable() const { return _flags[PICKABLE]; }
|
||||||
|
|
||||||
bool isLayered() const { return _flags[LAYERED]; }
|
bool isLayered() const { return _flags[LAYERED]; }
|
||||||
|
bool isSpatial() const { return !isLayered(); }
|
||||||
|
|
||||||
// Probably not public, flags used by the scene
|
// Probably not public, flags used by the scene
|
||||||
bool isSmall() const { return _flags[SMALLER]; }
|
bool isSmall() const { return _flags[SMALLER]; }
|
||||||
|
@ -312,11 +313,11 @@ public:
|
||||||
Item() {}
|
Item() {}
|
||||||
~Item() {}
|
~Item() {}
|
||||||
|
|
||||||
// Main scene / item managment interface Reset/Update/Kill
|
// Main scene / item managment interface reset/update/kill
|
||||||
void resetPayload(const PayloadPointer& payload);
|
void resetPayload(const PayloadPointer& payload);
|
||||||
void resetCell(ItemCell cell, bool _small) { _cell = cell; _key.setSmaller(_small); }
|
void resetCell(ItemCell cell = INVALID_CELL, bool _small = false) { _cell = cell; _key.setSmaller(_small); }
|
||||||
void update(const UpdateFunctorPointer& updateFunctor) { _payload->update(updateFunctor); } // Communicate update to the payload
|
void update(const UpdateFunctorPointer& updateFunctor); // communicate update to payload
|
||||||
void kill() { _payload.reset(); _key._flags.reset(); _cell = INVALID_CELL; } // Kill means forget the payload and key and cell
|
void kill() { _payload.reset(); resetCell(); _key._flags.reset(); } // forget the payload, key, cell
|
||||||
|
|
||||||
// Check heuristic key
|
// Check heuristic key
|
||||||
const ItemKey& getKey() const { return _key; }
|
const ItemKey& getKey() const { return _key; }
|
||||||
|
@ -464,7 +465,7 @@ public:
|
||||||
using ItemBounds = std::vector<ItemBound>;
|
using ItemBounds = std::vector<ItemBound>;
|
||||||
|
|
||||||
// A map of items by ShapeKey to optimize rendering pipeline assignments
|
// A map of items by ShapeKey to optimize rendering pipeline assignments
|
||||||
using ShapesIDsBounds = std::unordered_map<ShapeKey, ItemBounds, ShapeKey::Hash, ShapeKey::KeyEqual>;
|
using ShapeBounds = std::unordered_map<ShapeKey, ItemBounds, ShapeKey::Hash, ShapeKey::KeyEqual>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,59 +15,11 @@
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
void ItemBucketMap::insert(const ItemID& id, const ItemKey& key) {
|
|
||||||
// Insert the itemID in every bucket where it filters true
|
|
||||||
for (auto& bucket : (*this)) {
|
|
||||||
if (bucket.first.test(key)) {
|
|
||||||
bucket.second.insert(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void ItemBucketMap::erase(const ItemID& id, const ItemKey& key) {
|
|
||||||
// Remove the itemID in every bucket where it filters true
|
|
||||||
for (auto& bucket : (*this)) {
|
|
||||||
if (bucket.first.test(key)) {
|
|
||||||
bucket.second.erase(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ItemBucketMap::reset(const ItemID& id, const ItemKey& oldKey, const ItemKey& newKey) {
|
|
||||||
// Reset the itemID in every bucket,
|
|
||||||
// Remove from the buckets where oldKey filters true AND newKey filters false
|
|
||||||
// Insert into the buckets where newKey filters true
|
|
||||||
for (auto& bucket : (*this)) {
|
|
||||||
if (bucket.first.test(oldKey)) {
|
|
||||||
if (!bucket.first.test(newKey)) {
|
|
||||||
bucket.second.erase(id);
|
|
||||||
}
|
|
||||||
} else if (bucket.first.test(newKey)) {
|
|
||||||
bucket.second.insert(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ItemBucketMap::allocateStandardOpaqueTranparentBuckets() {
|
|
||||||
(*this)[ItemFilter::Builder::opaqueShape().withoutLayered()];
|
|
||||||
(*this)[ItemFilter::Builder::transparentShape().withoutLayered()];
|
|
||||||
(*this)[ItemFilter::Builder::light()];
|
|
||||||
(*this)[ItemFilter::Builder::background()];
|
|
||||||
(*this)[ItemFilter::Builder::opaqueShape().withLayered()];
|
|
||||||
(*this)[ItemFilter::Builder::transparentShape().withLayered()];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PendingChanges::resetItem(ItemID id, const PayloadPointer& payload) {
|
void PendingChanges::resetItem(ItemID id, const PayloadPointer& payload) {
|
||||||
_resetItems.push_back(id);
|
_resetItems.push_back(id);
|
||||||
_resetPayloads.push_back(payload);
|
_resetPayloads.push_back(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PendingChanges::resortItem(ItemID id, ItemKey oldKey, ItemKey newKey) {
|
|
||||||
_resortItems.push_back(id);
|
|
||||||
_resortOldKeys.push_back(oldKey);
|
|
||||||
_resortNewKeys.push_back(newKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PendingChanges::removeItem(ItemID id) {
|
void PendingChanges::removeItem(ItemID id) {
|
||||||
_removedItems.push_back(id);
|
_removedItems.push_back(id);
|
||||||
}
|
}
|
||||||
|
@ -80,9 +32,6 @@ void PendingChanges::updateItem(ItemID id, const UpdateFunctorPointer& functor)
|
||||||
void PendingChanges::merge(PendingChanges& changes) {
|
void PendingChanges::merge(PendingChanges& changes) {
|
||||||
_resetItems.insert(_resetItems.end(), changes._resetItems.begin(), changes._resetItems.end());
|
_resetItems.insert(_resetItems.end(), changes._resetItems.begin(), changes._resetItems.end());
|
||||||
_resetPayloads.insert(_resetPayloads.end(), changes._resetPayloads.begin(), changes._resetPayloads.end());
|
_resetPayloads.insert(_resetPayloads.end(), changes._resetPayloads.begin(), changes._resetPayloads.end());
|
||||||
_resortItems.insert(_resortItems.end(), changes._resortItems.begin(), changes._resortItems.end());
|
|
||||||
_resortOldKeys.insert(_resortOldKeys.end(), changes._resortOldKeys.begin(), changes._resortOldKeys.end());
|
|
||||||
_resortNewKeys.insert(_resortNewKeys.end(), changes._resortNewKeys.begin(), changes._resortNewKeys.end());
|
|
||||||
_removedItems.insert(_removedItems.end(), changes._removedItems.begin(), changes._removedItems.end());
|
_removedItems.insert(_removedItems.end(), changes._removedItems.begin(), changes._removedItems.end());
|
||||||
_updatedItems.insert(_updatedItems.end(), changes._updatedItems.begin(), changes._updatedItems.end());
|
_updatedItems.insert(_updatedItems.end(), changes._updatedItems.begin(), changes._updatedItems.end());
|
||||||
_updateFunctors.insert(_updateFunctors.end(), changes._updateFunctors.begin(), changes._updateFunctors.end());
|
_updateFunctors.insert(_updateFunctors.end(), changes._updateFunctors.begin(), changes._updateFunctors.end());
|
||||||
|
@ -92,7 +41,6 @@ Scene::Scene(glm::vec3 origin, float size) :
|
||||||
_masterSpatialTree(origin, size)
|
_masterSpatialTree(origin, size)
|
||||||
{
|
{
|
||||||
_items.push_back(Item()); // add the itemID #0 to nothing
|
_items.push_back(Item()); // add the itemID #0 to nothing
|
||||||
_masterBucketMap.allocateStandardOpaqueTranparentBuckets();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemID Scene::allocateID() {
|
ItemID Scene::allocateID() {
|
||||||
|
@ -133,7 +81,6 @@ void Scene::processPendingChangesQueue() {
|
||||||
// capture anything coming from the pendingChanges
|
// capture anything coming from the pendingChanges
|
||||||
resetItems(consolidatedPendingChanges._resetItems, consolidatedPendingChanges._resetPayloads);
|
resetItems(consolidatedPendingChanges._resetItems, consolidatedPendingChanges._resetPayloads);
|
||||||
updateItems(consolidatedPendingChanges._updatedItems, consolidatedPendingChanges._updateFunctors);
|
updateItems(consolidatedPendingChanges._updatedItems, consolidatedPendingChanges._updateFunctors);
|
||||||
resortItems(consolidatedPendingChanges._resortItems, consolidatedPendingChanges._resortOldKeys, consolidatedPendingChanges._resortNewKeys);
|
|
||||||
removeItems(consolidatedPendingChanges._removedItems);
|
removeItems(consolidatedPendingChanges._removedItems);
|
||||||
|
|
||||||
// ready to go back to rendering activities
|
// ready to go back to rendering activities
|
||||||
|
@ -141,7 +88,6 @@ void Scene::processPendingChangesQueue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) {
|
void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) {
|
||||||
|
|
||||||
auto resetPayload = payloads.begin();
|
auto resetPayload = payloads.begin();
|
||||||
for (auto resetID : ids) {
|
for (auto resetID : ids) {
|
||||||
// Access the true item
|
// Access the true item
|
||||||
|
@ -153,28 +99,20 @@ void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) {
|
||||||
item.resetPayload(*resetPayload);
|
item.resetPayload(*resetPayload);
|
||||||
auto newKey = item.getKey();
|
auto newKey = item.getKey();
|
||||||
|
|
||||||
|
// Update the item's container
|
||||||
// Reset the item in the Bucket map
|
assert((oldKey.isSpatial() == newKey.isSpatial()) || oldKey._flags.none());
|
||||||
_masterBucketMap.reset(resetID, oldKey, newKey);
|
if (newKey.isSpatial()) {
|
||||||
|
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), resetID, newKey);
|
||||||
// Reset the item in the spatial tree
|
item.resetCell(newCell, newKey.isSmall());
|
||||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), resetID, newKey);
|
} else {
|
||||||
item.resetCell(newCell, newKey.isSmall());
|
_masterNonspatialSet.insert(resetID);
|
||||||
|
}
|
||||||
|
|
||||||
// next loop
|
// next loop
|
||||||
resetPayload++;
|
resetPayload++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::resortItems(const ItemIDs& ids, ItemKeys& oldKeys, ItemKeys& newKeys) {
|
|
||||||
auto resortID = ids.begin();
|
|
||||||
auto oldKey = oldKeys.begin();
|
|
||||||
auto newKey = newKeys.begin();
|
|
||||||
for (; resortID != ids.end(); resortID++, oldKey++, newKey++) {
|
|
||||||
_masterBucketMap.reset(*resortID, *oldKey, *newKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scene::removeItems(const ItemIDs& ids) {
|
void Scene::removeItems(const ItemIDs& ids) {
|
||||||
for (auto removedID :ids) {
|
for (auto removedID :ids) {
|
||||||
// Access the true item
|
// Access the true item
|
||||||
|
@ -182,11 +120,12 @@ void Scene::removeItems(const ItemIDs& ids) {
|
||||||
auto oldCell = item.getCell();
|
auto oldCell = item.getCell();
|
||||||
auto oldKey = item.getKey();
|
auto oldKey = item.getKey();
|
||||||
|
|
||||||
// Remove from Bucket map
|
// Remove the item
|
||||||
_masterBucketMap.erase(removedID, item.getKey());
|
if (oldKey.isSpatial()) {
|
||||||
|
_masterSpatialTree.removeItem(oldCell, oldKey, removedID);
|
||||||
// Remove from spatial tree
|
} else {
|
||||||
_masterSpatialTree.removeItem(oldCell, oldKey, removedID);
|
_masterNonspatialSet.erase(removedID);
|
||||||
|
}
|
||||||
|
|
||||||
// Kill it
|
// Kill it
|
||||||
item.kill();
|
item.kill();
|
||||||
|
@ -202,14 +141,30 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) {
|
||||||
auto oldCell = item.getCell();
|
auto oldCell = item.getCell();
|
||||||
auto oldKey = item.getKey();
|
auto oldKey = item.getKey();
|
||||||
|
|
||||||
// Update it
|
// Update the item
|
||||||
_items[updateID].update((*updateFunctor));
|
item.update((*updateFunctor));
|
||||||
|
|
||||||
auto newKey = item.getKey();
|
auto newKey = item.getKey();
|
||||||
|
|
||||||
// Update the citem in the spatial tree if needed
|
// Update the item's container
|
||||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), updateID, newKey);
|
if (oldKey.isSpatial() == newKey.isSpatial()) {
|
||||||
item.resetCell(newCell, newKey.isSmall());
|
if (newKey.isSpatial()) {
|
||||||
|
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), updateID, newKey);
|
||||||
|
item.resetCell(newCell, newKey.isSmall());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (newKey.isSpatial()) {
|
||||||
|
_masterNonspatialSet.erase(updateID);
|
||||||
|
|
||||||
|
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), updateID, newKey);
|
||||||
|
item.resetCell(newCell, newKey.isSmall());
|
||||||
|
} else {
|
||||||
|
_masterSpatialTree.removeItem(oldCell, oldKey, updateID);
|
||||||
|
item.resetCell();
|
||||||
|
|
||||||
|
_masterNonspatialSet.insert(updateID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// next loop
|
// next loop
|
||||||
updateFunctor++;
|
updateFunctor++;
|
||||||
|
|
|
@ -17,21 +17,6 @@
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
|
||||||
// A map of ItemIDSets allowing to create bucket lists of items which are filtered according to their key
|
|
||||||
class ItemBucketMap : public std::map<ItemFilter, ItemIDSet, ItemFilter::Less> {
|
|
||||||
public:
|
|
||||||
|
|
||||||
ItemBucketMap() {}
|
|
||||||
|
|
||||||
void insert(const ItemID& id, const ItemKey& key);
|
|
||||||
void erase(const ItemID& id, const ItemKey& key);
|
|
||||||
void reset(const ItemID& id, const ItemKey& oldKey, const ItemKey& newKey);
|
|
||||||
|
|
||||||
// standard builders allocating the main buckets
|
|
||||||
void allocateStandardOpaqueTranparentBuckets();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class Engine;
|
class Engine;
|
||||||
|
|
||||||
class PendingChanges {
|
class PendingChanges {
|
||||||
|
@ -40,7 +25,6 @@ public:
|
||||||
~PendingChanges() {}
|
~PendingChanges() {}
|
||||||
|
|
||||||
void resetItem(ItemID id, const PayloadPointer& payload);
|
void resetItem(ItemID id, const PayloadPointer& payload);
|
||||||
void resortItem(ItemID id, ItemKey oldKey, ItemKey newKey);
|
|
||||||
void removeItem(ItemID id);
|
void removeItem(ItemID id);
|
||||||
|
|
||||||
template <class T> void updateItem(ItemID id, std::function<void(T&)> func) {
|
template <class T> void updateItem(ItemID id, std::function<void(T&)> func) {
|
||||||
|
@ -48,14 +32,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateItem(ItemID id, const UpdateFunctorPointer& functor);
|
void updateItem(ItemID id, const UpdateFunctorPointer& functor);
|
||||||
|
void updateItem(ItemID id) { updateItem(id, nullptr); }
|
||||||
|
|
||||||
void merge(PendingChanges& changes);
|
void merge(PendingChanges& changes);
|
||||||
|
|
||||||
ItemIDs _resetItems;
|
ItemIDs _resetItems;
|
||||||
Payloads _resetPayloads;
|
Payloads _resetPayloads;
|
||||||
ItemIDs _resortItems;
|
|
||||||
ItemKeys _resortOldKeys;
|
|
||||||
ItemKeys _resortNewKeys;
|
|
||||||
ItemIDs _removedItems;
|
ItemIDs _removedItems;
|
||||||
ItemIDs _updatedItems;
|
ItemIDs _updatedItems;
|
||||||
UpdateFunctors _updateFunctors;
|
UpdateFunctors _updateFunctors;
|
||||||
|
@ -75,27 +57,27 @@ public:
|
||||||
Scene(glm::vec3 origin, float size);
|
Scene(glm::vec3 origin, float size);
|
||||||
~Scene() {}
|
~Scene() {}
|
||||||
|
|
||||||
/// This call is thread safe, can be called from anywhere to allocate a new ID
|
// This call is thread safe, can be called from anywhere to allocate a new ID
|
||||||
ItemID allocateID();
|
ItemID allocateID();
|
||||||
|
|
||||||
/// Enqueue change batch to the scene
|
// Enqueue change batch to the scene
|
||||||
void enqueuePendingChanges(const PendingChanges& pendingChanges);
|
void enqueuePendingChanges(const PendingChanges& pendingChanges);
|
||||||
|
|
||||||
// Process the penging changes equeued
|
// Process the penging changes equeued
|
||||||
void processPendingChangesQueue();
|
void processPendingChangesQueue();
|
||||||
|
|
||||||
/// Access a particular item form its ID
|
// Access a particular item form its ID
|
||||||
/// WARNING, There is No check on the validity of the ID, so this could return a bad Item
|
// WARNING, There is No check on the validity of the ID, so this could return a bad Item
|
||||||
const Item& getItem(const ItemID& id) const { return _items[id]; }
|
const Item& getItem(const ItemID& id) const { return _items[id]; }
|
||||||
|
|
||||||
size_t getNumItems() const { return _items.size(); }
|
size_t getNumItems() const { return _items.size(); }
|
||||||
|
|
||||||
/// Access the main bucketmap of items
|
// Access the spatialized items
|
||||||
const ItemBucketMap& getMasterBucket() const { return _masterBucketMap; }
|
|
||||||
|
|
||||||
/// Access the item spatial tree
|
|
||||||
const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; }
|
const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; }
|
||||||
|
|
||||||
|
// Access non-spatialized items (overlays, backgrounds)
|
||||||
|
const ItemIDSet& getNonspatialSet() const { return _masterNonspatialSet; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Thread safe elements that can be accessed from anywhere
|
// Thread safe elements that can be accessed from anywhere
|
||||||
std::atomic<unsigned int> _IDAllocator{ 1 }; // first valid itemID will be One
|
std::atomic<unsigned int> _IDAllocator{ 1 }; // first valid itemID will be One
|
||||||
|
@ -106,12 +88,10 @@ protected:
|
||||||
// database of items is protected for editing by a mutex
|
// database of items is protected for editing by a mutex
|
||||||
std::mutex _itemsMutex;
|
std::mutex _itemsMutex;
|
||||||
Item::Vector _items;
|
Item::Vector _items;
|
||||||
ItemBucketMap _masterBucketMap;
|
|
||||||
ItemSpatialTree _masterSpatialTree;
|
ItemSpatialTree _masterSpatialTree;
|
||||||
|
ItemIDSet _masterNonspatialSet;
|
||||||
|
|
||||||
void resetItems(const ItemIDs& ids, Payloads& payloads);
|
void resetItems(const ItemIDs& ids, Payloads& payloads);
|
||||||
void resortItems(const ItemIDs& ids, ItemKeys& oldKeys, ItemKeys& newKeys);
|
|
||||||
void removeItems(const ItemIDs& ids);
|
void removeItems(const ItemIDs& ids);
|
||||||
void updateItems(const ItemIDs& ids, UpdateFunctors& functors);
|
void updateItems(const ItemIDs& ids, UpdateFunctors& functors);
|
||||||
|
|
||||||
|
|
120
libraries/render/src/render/SortTask.cpp
Normal file
120
libraries/render/src/render/SortTask.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
//
|
||||||
|
// CullTask.cpp
|
||||||
|
// render/src/render
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 2/2/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
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SortTask.h"
|
||||||
|
#include "ShapePipeline.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ViewFrustum.h>
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
|
||||||
|
struct ItemBoundSort {
|
||||||
|
float _centerDepth = 0.0f;
|
||||||
|
float _nearDepth = 0.0f;
|
||||||
|
float _farDepth = 0.0f;
|
||||||
|
ItemID _id = 0;
|
||||||
|
AABox _bounds;
|
||||||
|
|
||||||
|
ItemBoundSort() {}
|
||||||
|
ItemBoundSort(float centerDepth, float nearDepth, float farDepth, ItemID id, const AABox& bounds) : _centerDepth(centerDepth), _nearDepth(nearDepth), _farDepth(farDepth), _id(id), _bounds(bounds) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrontToBackSort {
|
||||||
|
bool operator() (const ItemBoundSort& left, const ItemBoundSort& right) {
|
||||||
|
return (left._centerDepth < right._centerDepth);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BackToFrontSort {
|
||||||
|
bool operator() (const ItemBoundSort& left, const ItemBoundSort& right) {
|
||||||
|
return (left._centerDepth > right._centerDepth);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems) {
|
||||||
|
assert(renderContext->args);
|
||||||
|
assert(renderContext->args->_viewFrustum);
|
||||||
|
|
||||||
|
auto& scene = sceneContext->_scene;
|
||||||
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
|
|
||||||
|
// Allocate and simply copy
|
||||||
|
outItems.clear();
|
||||||
|
outItems.reserve(inItems.size());
|
||||||
|
|
||||||
|
|
||||||
|
// Make a local dataset of the center distance and closest point distance
|
||||||
|
std::vector<ItemBoundSort> itemBoundSorts;
|
||||||
|
itemBoundSorts.reserve(outItems.size());
|
||||||
|
|
||||||
|
for (auto itemDetails : inItems) {
|
||||||
|
auto item = scene->getItem(itemDetails.id);
|
||||||
|
auto bound = itemDetails.bound; // item.getBound();
|
||||||
|
float distance = args->_viewFrustum->distanceToCamera(bound.calcCenter());
|
||||||
|
|
||||||
|
itemBoundSorts.emplace_back(ItemBoundSort(distance, distance, distance, itemDetails.id, bound));
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort against Z
|
||||||
|
if (frontToBack) {
|
||||||
|
FrontToBackSort frontToBackSort;
|
||||||
|
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), frontToBackSort);
|
||||||
|
} else {
|
||||||
|
BackToFrontSort backToFrontSort;
|
||||||
|
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), backToFrontSort);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally once sorted result to a list of itemID
|
||||||
|
for (auto& item : itemBoundSorts) {
|
||||||
|
outItems.emplace_back(ItemBound(item._id, item._bounds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PipelineSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ShapeBounds& outShapes) {
|
||||||
|
auto& scene = sceneContext->_scene;
|
||||||
|
outShapes.clear();
|
||||||
|
|
||||||
|
for (const auto& item : inItems) {
|
||||||
|
auto key = scene->getItem(item.id).getShapeKey();
|
||||||
|
auto outItems = outShapes.find(key);
|
||||||
|
if (outItems == outShapes.end()) {
|
||||||
|
outItems = outShapes.insert(std::make_pair(key, ItemBounds{})).first;
|
||||||
|
outItems->second.reserve(inItems.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
outItems->second.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& items : outShapes) {
|
||||||
|
items.second.shrink_to_fit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepthSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapeBounds& inShapes, ShapeBounds& outShapes) {
|
||||||
|
outShapes.clear();
|
||||||
|
outShapes.reserve(inShapes.size());
|
||||||
|
|
||||||
|
for (auto& pipeline : inShapes) {
|
||||||
|
auto& inItems = pipeline.second;
|
||||||
|
auto outItems = outShapes.find(pipeline.first);
|
||||||
|
if (outItems == outShapes.end()) {
|
||||||
|
outItems = outShapes.insert(std::make_pair(pipeline.first, ItemBounds{})).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
||||||
|
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems);
|
||||||
|
}
|
47
libraries/render/src/render/SortTask.h
Normal file
47
libraries/render/src/render/SortTask.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//
|
||||||
|
// SortTask.h
|
||||||
|
// render/src/render
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 2/26/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
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_render_SortTask_h
|
||||||
|
#define hifi_render_SortTask_h
|
||||||
|
|
||||||
|
#include "Engine.h"
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems);
|
||||||
|
|
||||||
|
class PipelineSortShapes {
|
||||||
|
public:
|
||||||
|
using JobModel = Job::ModelIO<PipelineSortShapes, ItemBounds, ShapeBounds>;
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ShapeBounds& outShapes);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DepthSortShapes {
|
||||||
|
public:
|
||||||
|
using JobModel = Job::ModelIO<DepthSortShapes, ShapeBounds, ShapeBounds>;
|
||||||
|
|
||||||
|
bool _frontToBack;
|
||||||
|
DepthSortShapes(bool frontToBack = true) : _frontToBack(frontToBack) {}
|
||||||
|
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapeBounds& inShapes, ShapeBounds& outShapes);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DepthSortItems {
|
||||||
|
public:
|
||||||
|
using JobModel = Job::ModelIO<DepthSortItems, ItemBounds, ItemBounds>;
|
||||||
|
|
||||||
|
bool _frontToBack;
|
||||||
|
DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {}
|
||||||
|
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // hifi_render_SortTask_h;
|
|
@ -204,7 +204,7 @@ private slots:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QQuickItem* OffscreenUi::createMessageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
QQuickItem* OffscreenUi::createMessageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||||
QVariantMap map;
|
QVariantMap map;
|
||||||
map.insert("title", title);
|
map.insert("title", title);
|
||||||
map.insert("text", text);
|
map.insert("text", text);
|
||||||
|
@ -232,12 +232,12 @@ int OffscreenUi::waitForMessageBoxResult(QQuickItem* messageBox) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
QMessageBox::StandardButton OffscreenUi::messageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton;
|
QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton;
|
||||||
QMetaObject::invokeMethod(this, "messageBox", Qt::BlockingQueuedConnection,
|
QMetaObject::invokeMethod(this, "messageBox", Qt::BlockingQueuedConnection,
|
||||||
Q_RETURN_ARG(QMessageBox::StandardButton, result),
|
Q_RETURN_ARG(QMessageBox::StandardButton, result),
|
||||||
Q_ARG(QMessageBox::Icon, icon),
|
Q_ARG(Icon, icon),
|
||||||
Q_ARG(QString, title),
|
Q_ARG(QString, title),
|
||||||
Q_ARG(QString, text),
|
Q_ARG(QString, text),
|
||||||
Q_ARG(QMessageBox::StandardButtons, buttons),
|
Q_ARG(QMessageBox::StandardButtons, buttons),
|
||||||
|
@ -250,19 +250,19 @@ QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, cons
|
||||||
|
|
||||||
QMessageBox::StandardButton OffscreenUi::critical(const QString& title, const QString& text,
|
QMessageBox::StandardButton OffscreenUi::critical(const QString& title, const QString& text,
|
||||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
|
return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_CRITICAL, title, text, buttons, defaultButton);
|
||||||
}
|
}
|
||||||
QMessageBox::StandardButton OffscreenUi::information(const QString& title, const QString& text,
|
QMessageBox::StandardButton OffscreenUi::information(const QString& title, const QString& text,
|
||||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Information, title, text, buttons, defaultButton);
|
return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_INFORMATION, title, text, buttons, defaultButton);
|
||||||
}
|
}
|
||||||
QMessageBox::StandardButton OffscreenUi::question(const QString& title, const QString& text,
|
QMessageBox::StandardButton OffscreenUi::question(const QString& title, const QString& text,
|
||||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Question, title, text, buttons, defaultButton);
|
return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_QUESTION, title, text, buttons, defaultButton);
|
||||||
}
|
}
|
||||||
QMessageBox::StandardButton OffscreenUi::warning(const QString& title, const QString& text,
|
QMessageBox::StandardButton OffscreenUi::warning(const QString& title, const QString& text,
|
||||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Warning, title, text, buttons, defaultButton);
|
return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_WARNING, title, text, buttons, defaultButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -286,24 +286,24 @@ private slots:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME many input parameters currently ignored
|
QString OffscreenUi::getText(const Icon icon, const QString& title, const QString& label, const QString& text, bool* ok) {
|
||||||
QString OffscreenUi::getText(void* ignored, const QString & title, const QString & label, QLineEdit::EchoMode mode, const QString & text, bool * ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints) {
|
|
||||||
if (ok) { *ok = false; }
|
if (ok) { *ok = false; }
|
||||||
QVariant result = DependencyManager::get<OffscreenUi>()->inputDialog(title, label, text).toString();
|
QVariant result = DependencyManager::get<OffscreenUi>()->inputDialog(icon, title, label, text).toString();
|
||||||
if (ok && result.isValid()) {
|
if (ok && result.isValid()) {
|
||||||
*ok = true;
|
*ok = true;
|
||||||
}
|
}
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME many input parameters currently ignored
|
QString OffscreenUi::getItem(const Icon icon, const QString& title, const QString& label, const QStringList& items,
|
||||||
QString OffscreenUi::getItem(void *ignored, const QString & title, const QString & label, const QStringList & items, int current, bool editable, bool * ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints) {
|
int current, bool editable, bool* ok) {
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
*ok = false;
|
*ok = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
auto inputDialog = offscreenUi->createInputDialog(title, label, current);
|
auto inputDialog = offscreenUi->createInputDialog(icon, title, label, current);
|
||||||
if (!inputDialog) {
|
if (!inputDialog) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
@ -321,24 +321,28 @@ QString OffscreenUi::getItem(void *ignored, const QString & title, const QString
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant OffscreenUi::inputDialog(const QString& title, const QString& label, const QVariant& current) {
|
QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const QString& label, const QVariant& current) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QVariant result;
|
QVariant result;
|
||||||
QMetaObject::invokeMethod(this, "inputDialog", Qt::BlockingQueuedConnection,
|
QMetaObject::invokeMethod(this, "inputDialog", Qt::BlockingQueuedConnection,
|
||||||
Q_RETURN_ARG(QVariant, result),
|
Q_RETURN_ARG(QVariant, result),
|
||||||
Q_ARG(QString, title),
|
Q_ARG(QString, title),
|
||||||
|
Q_ARG(Icon, icon),
|
||||||
Q_ARG(QString, label),
|
Q_ARG(QString, label),
|
||||||
Q_ARG(QVariant, current));
|
Q_ARG(QVariant, current));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return waitForInputDialogResult(createInputDialog(title, label, current));
|
return waitForInputDialogResult(createInputDialog(icon, title, label, current));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QQuickItem* OffscreenUi::createInputDialog(const QString& title, const QString& label, const QVariant& current) {
|
QQuickItem* OffscreenUi::createInputDialog(const Icon icon, const QString& title, const QString& label,
|
||||||
|
const QVariant& current) {
|
||||||
|
|
||||||
QVariantMap map;
|
QVariantMap map;
|
||||||
map.insert("title", title);
|
map.insert("title", title);
|
||||||
|
map.insert("icon", icon);
|
||||||
map.insert("label", label);
|
map.insert("label", label);
|
||||||
map.insert("current", current);
|
map.insert("current", current);
|
||||||
QVariant result;
|
QVariant result;
|
||||||
|
|
|
@ -41,11 +41,19 @@ public:
|
||||||
QQuickItem* getDesktop();
|
QQuickItem* getDesktop();
|
||||||
QQuickItem* getToolWindow();
|
QQuickItem* getToolWindow();
|
||||||
|
|
||||||
|
enum Icon {
|
||||||
|
ICON_NONE = 0,
|
||||||
|
ICON_QUESTION,
|
||||||
|
ICON_INFORMATION,
|
||||||
|
ICON_WARNING,
|
||||||
|
ICON_CRITICAL,
|
||||||
|
ICON_PLACEMARK
|
||||||
|
};
|
||||||
|
|
||||||
// Message box compatibility
|
// Message box compatibility
|
||||||
Q_INVOKABLE QMessageBox::StandardButton messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
|
Q_INVOKABLE QMessageBox::StandardButton messageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
|
||||||
// Must be called from the main thread
|
// Must be called from the main thread
|
||||||
QQuickItem* createMessageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
|
QQuickItem* createMessageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
|
||||||
// Must be called from the main thread
|
// Must be called from the main thread
|
||||||
Q_INVOKABLE int waitForMessageBoxResult(QQuickItem* messageBox);
|
Q_INVOKABLE int waitForMessageBoxResult(QQuickItem* messageBox);
|
||||||
|
|
||||||
|
@ -95,16 +103,25 @@ public:
|
||||||
// Compatibility with QFileDialog::getSaveFileName
|
// Compatibility with QFileDialog::getSaveFileName
|
||||||
static QString getSaveFileName(void* ignored, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);
|
static QString getSaveFileName(void* ignored, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);
|
||||||
|
|
||||||
|
Q_INVOKABLE QVariant inputDialog(const Icon icon, const QString& title, const QString& label = QString(), const QVariant& current = QVariant());
|
||||||
// input dialog compatibility
|
QQuickItem* createInputDialog(const Icon icon, const QString& title, const QString& label, const QVariant& current);
|
||||||
Q_INVOKABLE QVariant inputDialog(const QString& title, const QString& label = QString(), const QVariant& current = QVariant());
|
|
||||||
QQuickItem* createInputDialog(const QString& title, const QString& label, const QVariant& current);
|
|
||||||
QVariant waitForInputDialogResult(QQuickItem* inputDialog);
|
QVariant waitForInputDialogResult(QQuickItem* inputDialog);
|
||||||
|
|
||||||
// Compatibility with QInputDialog::getText
|
// Compatibility with QInputDialog::getText
|
||||||
static QString getText(void* ignored, const QString & title, const QString & label, QLineEdit::EchoMode mode = QLineEdit::Normal, const QString & text = QString(), bool * ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
|
static QString getText(void* ignored, const QString & title, const QString & label,
|
||||||
|
QLineEdit::EchoMode mode = QLineEdit::Normal, const QString & text = QString(), bool * ok = 0,
|
||||||
|
Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone) {
|
||||||
|
return getText(OffscreenUi::ICON_NONE, title, label, text, ok);
|
||||||
|
}
|
||||||
// Compatibility with QInputDialog::getItem
|
// Compatibility with QInputDialog::getItem
|
||||||
static QString getItem(void *ignored, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
|
static QString getItem(void *ignored, const QString & title, const QString & label, const QStringList & items,
|
||||||
|
int current = 0, bool editable = true, bool * ok = 0, Qt::WindowFlags flags = 0,
|
||||||
|
Qt::InputMethodHints inputMethodHints = Qt::ImhNone) {
|
||||||
|
return getItem(OffscreenUi::ICON_NONE, title, label, items, current, editable, ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString getText(const Icon icon, const QString & title, const QString & label, const QString & text = QString(), bool * ok = 0);
|
||||||
|
static QString getItem(const Icon icon, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void showDesktop();
|
void showDesktop();
|
||||||
|
|
|
@ -303,6 +303,13 @@ void ViveControllerManager::InputDevice::handleAxisEvent(float deltaTime, uint32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An enum for buttons which do not exist in the StandardControls enum
|
||||||
|
enum ViveButtonChannel {
|
||||||
|
LEFT_APP_MENU = controller::StandardButtonChannel::NUM_STANDARD_BUTTONS,
|
||||||
|
RIGHT_APP_MENU
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// These functions do translation from the Steam IDs to the standard controller IDs
|
// These functions do translation from the Steam IDs to the standard controller IDs
|
||||||
void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand) {
|
void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand) {
|
||||||
if (!pressed) {
|
if (!pressed) {
|
||||||
|
@ -311,7 +318,7 @@ void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint
|
||||||
|
|
||||||
using namespace controller;
|
using namespace controller;
|
||||||
if (button == vr::k_EButton_ApplicationMenu) {
|
if (button == vr::k_EButton_ApplicationMenu) {
|
||||||
_buttonPressedMap.insert(isLeftHand ? LEFT_PRIMARY_THUMB : RIGHT_PRIMARY_THUMB);
|
_buttonPressedMap.insert(isLeftHand ? LEFT_APP_MENU : RIGHT_APP_MENU);
|
||||||
} else if (button == vr::k_EButton_Grip) {
|
} else if (button == vr::k_EButton_Grip) {
|
||||||
_buttonPressedMap.insert(isLeftHand ? LB : RB);
|
_buttonPressedMap.insert(isLeftHand ? LB : RB);
|
||||||
} else if (button == vr::k_EButton_SteamVR_Trigger) {
|
} else if (button == vr::k_EButton_SteamVR_Trigger) {
|
||||||
|
@ -426,24 +433,10 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI
|
||||||
makePair(LEFT_HAND, "LeftHand"),
|
makePair(LEFT_HAND, "LeftHand"),
|
||||||
makePair(RIGHT_HAND, "RightHand"),
|
makePair(RIGHT_HAND, "RightHand"),
|
||||||
|
|
||||||
makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"),
|
Input::NamedPair(Input(_deviceID, LEFT_APP_MENU, ChannelType::BUTTON), "LeftApplicationMenu"),
|
||||||
makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"),
|
Input::NamedPair(Input(_deviceID, RIGHT_APP_MENU, ChannelType::BUTTON), "RightApplicationMenu"),
|
||||||
makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"),
|
|
||||||
makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 0), "Left Button A"));
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 0), "Left Grip Button"));
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 0), "Left Trackpad Button"));
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 0), "Left Trigger Button"));
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 0), "Left Back Trigger"));
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(RIGHT_HAND), "Right Hand"));
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 1), "Right Button A"));
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 1), "Right Grip Button"));
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 1), "Right Trackpad Button"));
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 1), "Right Trigger Button"));
|
|
||||||
//availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 1), "Right Back Trigger"));
|
|
||||||
|
|
||||||
return availableInputs;
|
return availableInputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,31 +444,3 @@ QString ViveControllerManager::InputDevice::getDefaultMappingConfig() const {
|
||||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json";
|
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json";
|
||||||
return MAPPING_JSON;
|
return MAPPING_JSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
//void ViveControllerManager::assignDefaultInputMapping(UserInputMapper& mapper) {
|
|
||||||
// const float JOYSTICK_MOVE_SPEED = 1.0f;
|
|
||||||
//
|
|
||||||
// // Left Trackpad: Movement, strafing
|
|
||||||
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(AXIS_Y_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
|
||||||
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(AXIS_Y_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
|
||||||
// mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(AXIS_X_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
|
||||||
// mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(AXIS_X_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED);
|
|
||||||
//
|
|
||||||
// // Right Trackpad: Vertical movement, zooming
|
|
||||||
// mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(AXIS_Y_POS, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED);
|
|
||||||
// mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(AXIS_Y_NEG, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED);
|
|
||||||
//
|
|
||||||
// // Buttons
|
|
||||||
// mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 0));
|
|
||||||
// mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 1));
|
|
||||||
//
|
|
||||||
// mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(GRIP_BUTTON, 0));
|
|
||||||
// mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(GRIP_BUTTON, 1));
|
|
||||||
//
|
|
||||||
// mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0));
|
|
||||||
// mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1));
|
|
||||||
//
|
|
||||||
// // Hands
|
|
||||||
// mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
|
|
||||||
// mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
|
|
||||||
//}
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import "../../../interface/resources/qml/windows-uit"
|
||||||
import "../../../interface/resources/qml/dialogs"
|
import "../../../interface/resources/qml/dialogs"
|
||||||
import "../../../interface/resources/qml/hifi"
|
import "../../../interface/resources/qml/hifi"
|
||||||
import "../../../interface/resources/qml/hifi/dialogs"
|
import "../../../interface/resources/qml/hifi/dialogs"
|
||||||
|
import "../../../interface/resources/qml/styles-uit"
|
||||||
|
|
||||||
ApplicationWindow {
|
ApplicationWindow {
|
||||||
id: appWindow
|
id: appWindow
|
||||||
|
@ -17,6 +18,8 @@ ApplicationWindow {
|
||||||
height: 800
|
height: 800
|
||||||
title: qsTr("Scratch App")
|
title: qsTr("Scratch App")
|
||||||
|
|
||||||
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
Desktop {
|
Desktop {
|
||||||
id: desktop
|
id: desktop
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
@ -99,11 +102,11 @@ ApplicationWindow {
|
||||||
var messageBox = desktop.messageBox({
|
var messageBox = desktop.messageBox({
|
||||||
title: "Set Avatar",
|
title: "Set Avatar",
|
||||||
text: "Would you like to use 'Albert' for your avatar?",
|
text: "Would you like to use 'Albert' for your avatar?",
|
||||||
icon: OriginalDialogs.StandardIcon.Question, // Test question icon
|
icon: hifi.icons.question, // Test question icon
|
||||||
//icon: OriginalDialogs.StandardIcon.Information, // Test informaton icon
|
//icon: hifi.icons.information, // Test informaton icon
|
||||||
//icon: OriginalDialogs.StandardIcon.Warning, // Test warning icon
|
//icon: hifi.icons.warning, // Test warning icon
|
||||||
//icon: OriginalDialogs.StandardIcon.Critical, // Test critical icon
|
//icon: hifi.icons.critical, // Test critical icon
|
||||||
//icon: OriginalDialogs.StandardIcon.NoIcon, // Test no icon
|
//icon: hifi.icons.none, // Test no icon
|
||||||
buttons: OriginalDialogs.StandardButton.Ok + OriginalDialogs.StandardButton.Cancel,
|
buttons: OriginalDialogs.StandardButton.Ok + OriginalDialogs.StandardButton.Cancel,
|
||||||
defaultButton: OriginalDialogs.StandardButton.Ok
|
defaultButton: OriginalDialogs.StandardButton.Ok
|
||||||
});
|
});
|
||||||
|
@ -118,7 +121,7 @@ ApplicationWindow {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var messageBox = desktop.messageBox({
|
var messageBox = desktop.messageBox({
|
||||||
text: "Diagnostic cycle will be complete in 30 seconds",
|
text: "Diagnostic cycle will be complete in 30 seconds",
|
||||||
icon: OriginalDialogs.StandardIcon.Critical,
|
icon: hifi.icons.critical,
|
||||||
});
|
});
|
||||||
messageBox.selected.connect(function(button) {
|
messageBox.selected.connect(function(button) {
|
||||||
console.log("You clicked " + button)
|
console.log("You clicked " + button)
|
||||||
|
@ -132,11 +135,45 @@ ApplicationWindow {
|
||||||
desktop.messageBox({
|
desktop.messageBox({
|
||||||
informativeText: "Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds ",
|
informativeText: "Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds ",
|
||||||
text: "Baloney",
|
text: "Baloney",
|
||||||
icon: OriginalDialogs.StandardIcon.Warning,
|
icon: hifi.icons.warning,
|
||||||
detailedText: "sakjd;laskj dksa;dl jka;lsd j;lkjas ;dlkaj s;dlakjd ;alkjda; slkjda; lkjda;lksjd ;alksjd; alksjd ;alksjd; alksjd; alksdjas;ldkjas;lkdja ;kj ;lkasjd; lkj as;dlka jsd;lka jsd;laksjd a"
|
detailedText: "sakjd;laskj dksa;dl jka;lsd j;lkjas ;dlkaj s;dlakjd ;alkjda; slkjda; lkjda;lksjd ;alksjd; alksjd ;alksjd; alksjd; alksdjas;ldkjas;lkdja ;kj ;lkasjd; lkj as;dlka jsd;lka jsd;laksjd a"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Button {
|
||||||
|
text: "Bookmark Location"
|
||||||
|
onClicked: {
|
||||||
|
desktop.inputDialog({
|
||||||
|
title: "Bookmark Location",
|
||||||
|
icon: hifi.icons.placemark,
|
||||||
|
label: "Name"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "Delete Bookmark"
|
||||||
|
onClicked: {
|
||||||
|
desktop.inputDialog({
|
||||||
|
title: "Delete Bookmark",
|
||||||
|
icon: hifi.icons.placemark,
|
||||||
|
label: "Select the bookmark to delete",
|
||||||
|
items: ["Bookmark A", "Bookmark B", "Bookmark C"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "Duplicate Bookmark"
|
||||||
|
onClicked: {
|
||||||
|
desktop.messageBox({
|
||||||
|
title: "Duplicate Bookmark",
|
||||||
|
icon: hifi.icons.warning,
|
||||||
|
text: "The bookmark name you entered alread exists in yoru list.",
|
||||||
|
informativeText: "Would you like to overwrite it?",
|
||||||
|
buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No,
|
||||||
|
defaultButton: OriginalDialogs.StandardButton.Yes
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
// There is no such desktop.queryBox() function; may need to update test to cover QueryDialog.qml?
|
// There is no such desktop.queryBox() function; may need to update test to cover QueryDialog.qml?
|
||||||
Button {
|
Button {
|
||||||
|
@ -145,7 +182,7 @@ ApplicationWindow {
|
||||||
var queryBox = desktop.queryBox({
|
var queryBox = desktop.queryBox({
|
||||||
text: "Have you stopped beating your wife?",
|
text: "Have you stopped beating your wife?",
|
||||||
placeholderText: "Are you sure?",
|
placeholderText: "Are you sure?",
|
||||||
// icon: OriginalDialogs.StandardIcon.Critical,
|
// icon: hifi.icons.critical,
|
||||||
});
|
});
|
||||||
queryBox.selected.connect(function(result) {
|
queryBox.selected.connect(function(result) {
|
||||||
console.log("User responded with " + result);
|
console.log("User responded with " + result);
|
||||||
|
|
94
unpublishedScripts/DomainContent/Home/plant/flower.fs
Normal file
94
unpublishedScripts/DomainContent/Home/plant/flower.fs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
//
|
||||||
|
// flowers.fs
|
||||||
|
// examples/homeContent/plant
|
||||||
|
//
|
||||||
|
// Created by Eric Levin on 3/7/16.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This fragment shader is designed to shader a sphere to create the effect of a blooming flower
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
|
||||||
|
#define TWO_PI 6.28318530718
|
||||||
|
|
||||||
|
uniform float iBloomPct = 0.2;
|
||||||
|
uniform vec3 iHSLColor = vec3(0.7, 0.5, 0.5);
|
||||||
|
|
||||||
|
|
||||||
|
float hue2rgb(float f1, float f2, float hue) {
|
||||||
|
if (hue < 0.0)
|
||||||
|
hue += 1.0;
|
||||||
|
else if (hue > 1.0)
|
||||||
|
hue -= 1.0;
|
||||||
|
float res;
|
||||||
|
if ((6.0 * hue) < 1.0)
|
||||||
|
res = f1 + (f2 - f1) * 6.0 * hue;
|
||||||
|
else if ((2.0 * hue) < 1.0)
|
||||||
|
res = f2;
|
||||||
|
else if ((3.0 * hue) < 2.0)
|
||||||
|
res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;
|
||||||
|
else
|
||||||
|
res = f1;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hsl2rgb(vec3 hsl) {
|
||||||
|
vec3 rgb;
|
||||||
|
|
||||||
|
if (hsl.y == 0.0) {
|
||||||
|
rgb = vec3(hsl.z); // Luminance
|
||||||
|
} else {
|
||||||
|
float f2;
|
||||||
|
|
||||||
|
if (hsl.z < 0.5)
|
||||||
|
f2 = hsl.z * (1.0 + hsl.y);
|
||||||
|
else
|
||||||
|
f2 = hsl.z + hsl.y - hsl.y * hsl.z;
|
||||||
|
|
||||||
|
float f1 = 2.0 * hsl.z - f2;
|
||||||
|
|
||||||
|
rgb.r = hue2rgb(f1, f2, hsl.x + (1.0/3.0));
|
||||||
|
rgb.g = hue2rgb(f1, f2, hsl.x);
|
||||||
|
rgb.b = hue2rgb(f1, f2, hsl.x - (1.0/3.0));
|
||||||
|
}
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hsl2rgb(float h, float s, float l) {
|
||||||
|
return hsl2rgb(vec3(h, s, l));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
|
||||||
|
vec2 st = fragCoord.xy/iWorldScale.xz;
|
||||||
|
vec3 color = vec3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
vec2 toCenter = vec2(0.5) - st;
|
||||||
|
float angle = atan(toCenter.y, toCenter.x);
|
||||||
|
float radius = length(toCenter) * 2.0;
|
||||||
|
|
||||||
|
// Second check is so we discard the top half of the sphere
|
||||||
|
if ( iBloomPct < radius || _position.y > 0) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulate ambient occlusion
|
||||||
|
float brightness = pow(radius, 0.8);
|
||||||
|
vec3 hslColor = iHSLColor + (abs(angle) * 0.02);
|
||||||
|
hslColor.z = 0.15 + pow(radius, 2.);
|
||||||
|
vec3 rgbColor = hsl2rgb(hslColor);
|
||||||
|
fragColor = vec4(rgbColor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec4 getProceduralColor() {
|
||||||
|
vec4 result;
|
||||||
|
vec2 position = _position.xz;
|
||||||
|
position += 0.5;
|
||||||
|
|
||||||
|
mainImage(result, position * iWorldScale.xz);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
//
|
||||||
|
// growingPlantEntityScript.js
|
||||||
|
// examples/homeContent/plant
|
||||||
|
//
|
||||||
|
// Created by Eric Levin on 2/10/16.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This entity script handles the logic for growing a plant when it has water poured on it
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
Script.include('../../../../libraries/utils.js');
|
||||||
|
|
||||||
|
var _this;
|
||||||
|
GrowingPlant = function() {
|
||||||
|
_this = this;
|
||||||
|
_this.flowers = [];
|
||||||
|
// _this.STARTING_FLOWER_DIMENSIONS = {x: 0.1, y: 0.001, z: 0.1}
|
||||||
|
_this.STARTING_FLOWER_DIMENSIONS = {
|
||||||
|
x: 0.001,
|
||||||
|
y: 0.001,
|
||||||
|
z: 0.001
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.MAX_FLOWERS = 50;
|
||||||
|
_this.MIN_FLOWER_TO_FLOWER_DISTANCE = 0.03;
|
||||||
|
|
||||||
|
_this.debounceRange = {
|
||||||
|
min: 500,
|
||||||
|
max: 1000
|
||||||
|
};
|
||||||
|
_this.canCreateFlower = true;
|
||||||
|
_this.SHADER_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/shaders/flower.fs";
|
||||||
|
// _this.SHADER_URL = "file:///C:/Users/Eric/hifi/unpublishedScripts/DomainContent/Home/plant/flower.fs";
|
||||||
|
|
||||||
|
_this.flowerHSLColors = [{
|
||||||
|
hue: 19 / 360,
|
||||||
|
saturation: 0.92,
|
||||||
|
light: 0.31
|
||||||
|
}, {
|
||||||
|
hue: 161 / 360,
|
||||||
|
saturation: 0.28,
|
||||||
|
light: 0.62
|
||||||
|
}];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
GrowingPlant.prototype = {
|
||||||
|
|
||||||
|
|
||||||
|
continueWatering: function(entityID, data) {
|
||||||
|
// we're being watered- every now and then spawn a new flower to add to our growing list
|
||||||
|
// If we don't have any flowers yet, immediately grow one
|
||||||
|
var data = JSON.parse(data[0]);
|
||||||
|
|
||||||
|
if (_this.canCreateFlower && _this.flowers.length < _this.MAX_FLOWERS) {
|
||||||
|
_this.createFlower(data.position, data.surfaceNormal);
|
||||||
|
_this.canCreateFlower = false;
|
||||||
|
Script.setTimeout(function() {
|
||||||
|
_this.canCreateFlower = true;
|
||||||
|
}, randFloat(_this.debounceRange.min, this.debounceRange.max));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.flowers.forEach(function(flower) {
|
||||||
|
flower.grow();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
createFlower: function(position, surfaceNormal) {
|
||||||
|
if (_this.previousFlowerPosition && Vec3.distance(position, _this.previousFlowerPosition) < _this.MIN_FLOWER_TO_FLOWER_DISTANCE) {
|
||||||
|
// Reduces flower overlap
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var xzGrowthRate = randFloat(0.00006, 0.00016);
|
||||||
|
var growthRate = {x: xzGrowthRate, y: randFloat(0.001, 0.003), z: xzGrowthRate};
|
||||||
|
|
||||||
|
var flower = {
|
||||||
|
dimensions: {
|
||||||
|
x: _this.STARTING_FLOWER_DIMENSIONS.x,
|
||||||
|
y: _this.STARTING_FLOWER_DIMENSIONS.y,
|
||||||
|
z: _this.STARTING_FLOWER_DIMENSIONS.z
|
||||||
|
},
|
||||||
|
startingPosition: position,
|
||||||
|
rotation: Quat.rotationBetween(Vec3.UNIT_Y, surfaceNormal),
|
||||||
|
maxYDimension: randFloat(0.4, 1.1),
|
||||||
|
// startingHSLColor: {
|
||||||
|
// hue: 80 / 360,
|
||||||
|
// saturation: 0.47,
|
||||||
|
// light: 0.48
|
||||||
|
// },
|
||||||
|
// endingHSLColor: {
|
||||||
|
// hue: 19 / 260,
|
||||||
|
// saturation: 0.92,
|
||||||
|
// light: 0.41
|
||||||
|
// },
|
||||||
|
hslColor: Math.random() < 0.5 ? _this.flowerHSLColors[0] : _this.flowerHSLColors[1],
|
||||||
|
growthRate: growthRate
|
||||||
|
};
|
||||||
|
flower.userData = {
|
||||||
|
ProceduralEntity: {
|
||||||
|
shaderUrl: _this.SHADER_URL,
|
||||||
|
uniforms: {
|
||||||
|
iBloomPct: randFloat(0.4, 0.8),
|
||||||
|
iHSLColor: [flower.hslColor.hue, flower.hslColor.saturation, flower.hslColor.light]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
flower.id = Entities.addEntity({
|
||||||
|
type: "Sphere",
|
||||||
|
name: "flower",
|
||||||
|
lifetime: 3600,
|
||||||
|
position: position,
|
||||||
|
collisionless: true,
|
||||||
|
rotation: flower.rotation,
|
||||||
|
dimensions: _this.STARTING_FLOWER_DIMENSIONS,
|
||||||
|
userData: JSON.stringify(flower.userData)
|
||||||
|
});
|
||||||
|
flower.grow = function() {
|
||||||
|
// grow flower a bit
|
||||||
|
if (flower.dimensions.y > flower.maxYDimension) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flower.dimensions = Vec3.sum(flower.dimensions, flower.growthRate);
|
||||||
|
flower.position = Vec3.sum(flower.startingPosition, Vec3.multiply(Quat.getUp(flower.rotation), flower.dimensions.y / 2));
|
||||||
|
//As we grow we must also move ourselves in direction we grow!
|
||||||
|
//TODO: Add this color changing back once we fix bug https://app.asana.com/0/inbox/31759584831096/96943843100173/98022172055918
|
||||||
|
// var newHue = map(flower.dimensions.y, _this.STARTING_FLOWER_DIMENSIONS.y, flower.maxYDimension, flower.startingHSLColor.hue, flower.endingHSLColor.hue);
|
||||||
|
// var newSaturation = map(flower.dimensions.y, _this.STARTING_FLOWER_DIMENSIONS.y, flower.maxYDimension, flower.startingHSLColor.saturation, flower.endingHSLColor.saturation);
|
||||||
|
// var newLight = map(flower.dimensions.y, _this.STARTING_FLOWER_DIMENSIONS.y, flower.maxYDimension, flower.startingHSLColor.light, flower.endingHSLColor.light);
|
||||||
|
// flower.userData.PrsoceduralEntity.uniforms.iHSLColor = [newHue, newSaturation, newLight];
|
||||||
|
Entities.editEntity(flower.id, {
|
||||||
|
dimensions: flower.dimensions,
|
||||||
|
position: flower.position,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_this.flowers.push(flower);
|
||||||
|
_this.previousFlowerPosition = position;
|
||||||
|
},
|
||||||
|
|
||||||
|
preload: function(entityID) {
|
||||||
|
_this.entityID = entityID;
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// entity scripts always need to return a newly constructed object of our type
|
||||||
|
return new GrowingPlant();
|
||||||
|
});
|
|
@ -0,0 +1,139 @@
|
||||||
|
//
|
||||||
|
// growingPlantSpawner.js
|
||||||
|
// examples/homeContent/plant
|
||||||
|
//
|
||||||
|
// Created by Eric Levin on 2/10/16.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This entity script handles the logic for growing a plant when it has water poured on it
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
|
||||||
|
var orientation = Camera.getOrientation();
|
||||||
|
orientation = Quat.safeEulerAngles(orientation);
|
||||||
|
orientation.x = 0;
|
||||||
|
orientation = Quat.fromVec3Degrees(orientation);
|
||||||
|
|
||||||
|
|
||||||
|
var bowlPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation)));
|
||||||
|
var BOWL_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Flowers--Bowl.fbx";
|
||||||
|
var bowlDimensions = {
|
||||||
|
x: 0.518,
|
||||||
|
y: 0.1938,
|
||||||
|
z: 0.5518
|
||||||
|
};
|
||||||
|
var bowl = Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
modelURL: BOWL_MODEL_URL,
|
||||||
|
dimensions: bowlDimensions,
|
||||||
|
name: "plant bowl",
|
||||||
|
position: bowlPosition
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var PLANT_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Flowers--Moss-Rock.fbx";
|
||||||
|
var PLANT_SCRIPT_URL = Script.resolvePath("growingPlantEntityScript.js?v1" + Math.random().toFixed(2));
|
||||||
|
var plantDimensions = {
|
||||||
|
x: 0.52,
|
||||||
|
y: 0.2600,
|
||||||
|
z: 0.52
|
||||||
|
};
|
||||||
|
var plantPosition = Vec3.sum(bowlPosition, {
|
||||||
|
x: 0,
|
||||||
|
y: plantDimensions.y / 2,
|
||||||
|
z: 0
|
||||||
|
});
|
||||||
|
var plant = Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
modelURL: PLANT_MODEL_URL,
|
||||||
|
name: "hifi-growable-plant",
|
||||||
|
dimensions: plantDimensions,
|
||||||
|
position: plantPosition,
|
||||||
|
script: PLANT_SCRIPT_URL,
|
||||||
|
parentID: bowl
|
||||||
|
});
|
||||||
|
|
||||||
|
var WATER_CAN_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/waterCan.fbx?v1" + Math.random();
|
||||||
|
var WATER_CAN_SCRIPT_URL = Script.resolvePath("waterCanEntityScript.js?v2" + Math.random().toFixed());
|
||||||
|
var waterCanPosition = Vec3.sum(plantPosition, Vec3.multiply(0.6, Quat.getRight(orientation)));
|
||||||
|
var waterCanRotation = orientation;
|
||||||
|
var waterCan = Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
shapeType: 'box',
|
||||||
|
name: "hifi-water-can",
|
||||||
|
modelURL: WATER_CAN_MODEL_URL,
|
||||||
|
script: WATER_CAN_SCRIPT_URL,
|
||||||
|
dimensions: {
|
||||||
|
x: 0.1859,
|
||||||
|
y: 0.2762,
|
||||||
|
z: 0.4115
|
||||||
|
},
|
||||||
|
position: waterCanPosition,
|
||||||
|
angularDamping: 1,
|
||||||
|
dynamic: true,
|
||||||
|
gravity: {
|
||||||
|
x: 0.0,
|
||||||
|
y: -2.0,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
rotation: waterCanRotation,
|
||||||
|
userData: JSON.stringify({
|
||||||
|
wearable: {
|
||||||
|
joints: {
|
||||||
|
RightHand: [{
|
||||||
|
x: 0.024,
|
||||||
|
y: 0.173,
|
||||||
|
z: 0.152
|
||||||
|
}, {
|
||||||
|
x: 0.374,
|
||||||
|
y: 0.636,
|
||||||
|
z: -0.638,
|
||||||
|
w: -0.215
|
||||||
|
}],
|
||||||
|
LeftHand: [{
|
||||||
|
x: -0.0348,
|
||||||
|
y: 0.201,
|
||||||
|
z: 0.166
|
||||||
|
}, {
|
||||||
|
x: 0.4095,
|
||||||
|
y: -0.625,
|
||||||
|
z: 0.616,
|
||||||
|
w: -0.247
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var waterSpoutPosition = Vec3.sum(waterCanPosition, Vec3.multiply(0.2, Quat.getFront(orientation)))
|
||||||
|
var waterSpoutRotation = Quat.multiply(waterCanRotation, Quat.fromPitchYawRollDegrees(10, 0, 0));
|
||||||
|
var waterSpout = Entities.addEntity({
|
||||||
|
type: "Box",
|
||||||
|
name: "hifi-water-spout",
|
||||||
|
dimensions: {
|
||||||
|
x: 0.02,
|
||||||
|
y: 0.02,
|
||||||
|
z: 0.07
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
red: 200,
|
||||||
|
green: 10,
|
||||||
|
blue: 200
|
||||||
|
},
|
||||||
|
position: waterSpoutPosition,
|
||||||
|
rotation: waterSpoutRotation,
|
||||||
|
parentID: waterCan,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
// Entities.deleteEntity(plant);
|
||||||
|
// Entities.deleteEntity(bowl);
|
||||||
|
// Entities.deleteEntity(waterCan);
|
||||||
|
// Entities.deleteEntity(waterSpout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(cleanup);
|
|
@ -0,0 +1,242 @@
|
||||||
|
//
|
||||||
|
// waterCanEntityScript.js
|
||||||
|
// examples/homeContent/plant
|
||||||
|
//
|
||||||
|
// Created by Eric Levin on 2/15/16.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This entity script handles the logic for pouring water when a user tilts the entity the script is attached too.
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
Script.include('../../../../libraries/utils.js');
|
||||||
|
|
||||||
|
var _this;
|
||||||
|
WaterSpout = function() {
|
||||||
|
_this = this;
|
||||||
|
_this.waterSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/eric/Sounds/shower.wav");
|
||||||
|
_this.POUR_ANGLE_THRESHOLD = 0;
|
||||||
|
_this.waterPouring = false;
|
||||||
|
_this.WATER_SPOUT_NAME = "hifi-water-spout";
|
||||||
|
_this.GROWABLE_ENTITIES_SEARCH_RANGE = 100;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
WaterSpout.prototype = {
|
||||||
|
|
||||||
|
startNearGrab: function() {
|
||||||
|
_this.startHold();
|
||||||
|
},
|
||||||
|
|
||||||
|
startEquip: function() {
|
||||||
|
_this.startHold();
|
||||||
|
},
|
||||||
|
|
||||||
|
startHold: function() {
|
||||||
|
_this.findGrowableEntities();
|
||||||
|
},
|
||||||
|
|
||||||
|
releaseEquip: function() {
|
||||||
|
_this.releaseHold();
|
||||||
|
},
|
||||||
|
|
||||||
|
releaseGrab: function() {
|
||||||
|
_this.releaseHold();
|
||||||
|
},
|
||||||
|
|
||||||
|
releaseHold: function() {
|
||||||
|
_this.stopPouring();
|
||||||
|
},
|
||||||
|
|
||||||
|
stopPouring: function() {
|
||||||
|
Entities.editEntity(_this.waterEffect, {
|
||||||
|
isEmitting: false
|
||||||
|
});
|
||||||
|
_this.waterPouring = false;
|
||||||
|
//water no longer pouring...
|
||||||
|
if (_this.waterInjector) {
|
||||||
|
_this.waterInjector.stop();
|
||||||
|
}
|
||||||
|
Entities.callEntityMethod(_this.mostRecentIntersectedGrowableEntity, 'stopWatering');
|
||||||
|
},
|
||||||
|
continueEquip: function() {
|
||||||
|
_this.continueHolding();
|
||||||
|
},
|
||||||
|
|
||||||
|
continueNearGrab: function() {
|
||||||
|
_this.continueHolding();
|
||||||
|
},
|
||||||
|
|
||||||
|
continueHolding: function() {
|
||||||
|
if (!_this.waterSpout) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check rotation of water can along it's z axis. If it's beyond a threshold, then start spraying water
|
||||||
|
_this.castRay();
|
||||||
|
var rotation = Entities.getEntityProperties(_this.entityID, "rotation").rotation;
|
||||||
|
var pitch = Quat.safeEulerAngles(rotation).x;
|
||||||
|
if (pitch < _this.POUR_ANGLE_THRESHOLD) {
|
||||||
|
// Water is pouring
|
||||||
|
var spoutProps = Entities.getEntityProperties(_this.waterSpout, ["rotation", "position"]);
|
||||||
|
if (!_this.waterPouring) {
|
||||||
|
Entities.editEntity(_this.waterEffect, {
|
||||||
|
isEmitting: true
|
||||||
|
});
|
||||||
|
_this.waterPouring = true;
|
||||||
|
if (!_this.waterInjector) {
|
||||||
|
_this.waterInjector = Audio.playSound(_this.waterSound, {
|
||||||
|
position: spoutProps.position,
|
||||||
|
loop: true
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_this.waterInjector.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_this.waterSpoutRotation = spoutProps.rotation;
|
||||||
|
var waterEmitOrientation = Quat.multiply(_this.waterSpoutRotation, Quat.fromPitchYawRollDegrees(0, 180, 0));
|
||||||
|
Entities.editEntity(_this.waterEffect, {
|
||||||
|
emitOrientation: waterEmitOrientation
|
||||||
|
});
|
||||||
|
} else if (pitch > _this.POUR_ANGLE_THRESHOLD && _this.waterPouring) {
|
||||||
|
_this.stopPouring();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
castRay: function() {
|
||||||
|
var spoutProps = Entities.getEntityProperties(_this.waterSpout, ["position, rotation"]);
|
||||||
|
var direction = Quat.getFront(spoutProps.rotation)
|
||||||
|
var end = Vec3.sum(spoutProps.position, Vec3.multiply(5, direction));
|
||||||
|
|
||||||
|
var pickRay = {
|
||||||
|
origin: spoutProps.position,
|
||||||
|
direction: direction
|
||||||
|
};
|
||||||
|
var intersection = Entities.findRayIntersection(pickRay, true, _this.growableEntities);
|
||||||
|
|
||||||
|
if (intersection.intersects) {
|
||||||
|
//We've intersected with a waterable object
|
||||||
|
var data = JSON.stringify({
|
||||||
|
position: intersection.intersection,
|
||||||
|
surfaceNormal: intersection.surfaceNormal
|
||||||
|
});
|
||||||
|
_this.mostRecentIntersectedGrowableEntity = intersection.entityID;
|
||||||
|
Entities.callEntityMethod(intersection.entityID, 'continueWatering', [data]);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
createWaterEffect: function() {
|
||||||
|
var waterEffectPosition = Vec3.sum(_this.waterSpoutPosition, Vec3.multiply(Quat.getFront(_this.waterSpoutRotation), -0.04));
|
||||||
|
_this.waterEffect = Entities.addEntity({
|
||||||
|
type: "ParticleEffect",
|
||||||
|
name: "water particle effect",
|
||||||
|
position: waterEffectPosition,
|
||||||
|
isEmitting: false,
|
||||||
|
parentID: _this.waterSpout,
|
||||||
|
colorStart: {
|
||||||
|
red: 90,
|
||||||
|
green: 90,
|
||||||
|
blue: 110
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
red: 70,
|
||||||
|
green: 70,
|
||||||
|
blue: 130
|
||||||
|
},
|
||||||
|
colorFinish: {
|
||||||
|
red: 23,
|
||||||
|
green: 195,
|
||||||
|
blue: 206
|
||||||
|
},
|
||||||
|
maxParticles: 20000,
|
||||||
|
lifespan: 2,
|
||||||
|
emitRate: 2000,
|
||||||
|
emitSpeed: .3,
|
||||||
|
speedSpread: 0.1,
|
||||||
|
emitDimensions: {
|
||||||
|
x: 0.0,
|
||||||
|
y: 0.0,
|
||||||
|
z: 0.0
|
||||||
|
},
|
||||||
|
emitAcceleration: {
|
||||||
|
x: 0.0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
polarStart: 0.0,
|
||||||
|
polarFinish: 0.1,
|
||||||
|
accelerationSpread: {
|
||||||
|
x: 0.01,
|
||||||
|
y: 0.0,
|
||||||
|
z: 0.01
|
||||||
|
},
|
||||||
|
emitOrientation: Quat.fromPitchYawRollDegrees(0, 0, 0),
|
||||||
|
radiusSpread: 0.0001,
|
||||||
|
radiusStart: 0.005,
|
||||||
|
particleRadius: 0.003,
|
||||||
|
radiusFinish: 0.001,
|
||||||
|
alphaSpread: 0,
|
||||||
|
alphaStart: 0.1,
|
||||||
|
alpha: 1.0,
|
||||||
|
alphaFinish: 1.0,
|
||||||
|
emitterShouldTrail: true,
|
||||||
|
textures: "https://s3-us-west-1.amazonaws.com/hifi-content/eric/images/raindrop.png",
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
findGrowableEntities: function() {
|
||||||
|
_this.growableEntities = [];
|
||||||
|
var entities = Entities.findEntities(_this.position, _this.GROWABLE_ENTITIES_SEARCH_RANGE);
|
||||||
|
entities.forEach(function(entity) {
|
||||||
|
var name = Entities.getEntityProperties(entity, "name").name;
|
||||||
|
if (name.length > 0 && name.indexOf("growable") !== -1) {
|
||||||
|
_this.growableEntities.push(entity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
preload: function(entityID) {
|
||||||
|
_this.entityID = entityID;
|
||||||
|
_this.position = Entities.getEntityProperties(_this.entityID, "position").position;
|
||||||
|
// Wait a a bit for spout to spawn for case where preload is initial spawn, then save it
|
||||||
|
Script.setTimeout(function() {
|
||||||
|
var entities = Entities.findEntities(_this.position, 1);
|
||||||
|
entities.forEach(function(entity) {
|
||||||
|
var name = Entities.getEntityProperties(entity, "name").name;
|
||||||
|
if (name === _this.WATER_SPOUT_NAME) {
|
||||||
|
_this.waterSpout = entity;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_this.waterSpout) {
|
||||||
|
_this.waterSpoutPosition = Entities.getEntityProperties(_this.waterSpout, "position").position;
|
||||||
|
_this.waterSpoutRotation = Entities.getEntityProperties(_this.waterSpout, "rotation").rotation;
|
||||||
|
_this.createWaterEffect();
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
unload: function() {
|
||||||
|
Entities.deleteEntity(_this.waterEffect);
|
||||||
|
if (_this.waterInjector) {
|
||||||
|
_this.waterInjector.stop();
|
||||||
|
delete _this.waterInjector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// entity scripts always need to return a newly constructed object of our type
|
||||||
|
return new WaterSpout();
|
||||||
|
});
|
Loading…
Reference in a new issue