mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #10729 from druiz17/hand-pucks
Hand pucks and Calibration UI
This commit is contained in:
commit
c70365d04a
22 changed files with 1888 additions and 189 deletions
BIN
interface/resources/images/loader-calibrate-blue.png
Normal file
BIN
interface/resources/images/loader-calibrate-blue.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.7 KiB |
BIN
interface/resources/images/loader-calibrate-white.png
Normal file
BIN
interface/resources/images/loader-calibrate-white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
|
@ -22,8 +22,8 @@ Original.CheckBox {
|
|||
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
|
||||
property bool isRedCheck: false
|
||||
property int boxSize: 14
|
||||
property int boxRadius: 3
|
||||
property bool wrap: true;
|
||||
readonly property int boxRadius: 3
|
||||
readonly property int checkSize: Math.max(boxSize - 8, 10)
|
||||
readonly property int checkRadius: 2
|
||||
activeFocusOnPress: true
|
||||
|
|
|
@ -20,6 +20,7 @@ FocusScope {
|
|||
HifiConstants { id: hifi }
|
||||
|
||||
property alias model: comboBox.model;
|
||||
property alias editable: comboBox.editable
|
||||
property alias comboBox: comboBox
|
||||
readonly property alias currentText: comboBox.currentText;
|
||||
property alias currentIndex: comboBox.currentIndex;
|
||||
|
|
213
interface/resources/qml/hifi/tablet/CalibratingScreen.qml
Normal file
213
interface/resources/qml/hifi/tablet/CalibratingScreen.qml
Normal file
|
@ -0,0 +1,213 @@
|
|||
//
|
||||
// Created by Dante Ruiz on 6/1/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
import QtQuick 2.5
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "../../styles-uit"
|
||||
import "../../controls"
|
||||
import "../../controls-uit" as HifiControls
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: info
|
||||
|
||||
|
||||
signal canceled()
|
||||
signal restart()
|
||||
|
||||
property int count: 3
|
||||
property string calibratingText: "CALIBRATING..."
|
||||
property string calibratingCountText: "CALIBRATION STARTING IN"
|
||||
property string calibrationSuccess: "CALIBRATION COMPLETED"
|
||||
property string calibrationFailed: "CALIBRATION FAILED"
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
visible: true
|
||||
color: hifi.colors.baseGray
|
||||
|
||||
property string whiteIndicator: "../../../images/loader-calibrate-white.png"
|
||||
property string blueIndicator: "../../../images/loader-calibrate-blue.png"
|
||||
|
||||
Image {
|
||||
id: busyIndicator
|
||||
width: 350
|
||||
height: 350
|
||||
|
||||
property bool running: true
|
||||
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.top
|
||||
topMargin: 60
|
||||
}
|
||||
visible: busyIndicator.running
|
||||
source: blueIndicator
|
||||
NumberAnimation on rotation {
|
||||
id: busyRotation
|
||||
running: busyIndicator.running
|
||||
loops: Animation.Infinite
|
||||
duration: 1000
|
||||
from: 0 ; to: 360
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: image
|
||||
text: hifi.glyphs.avatar1
|
||||
size: 190
|
||||
color: hifi.colors.white
|
||||
|
||||
anchors {
|
||||
top: busyIndicator.top
|
||||
topMargin: 40
|
||||
horizontalCenter: busyIndicator.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
id: statusText
|
||||
text: info.calibratingCountText
|
||||
size: 16
|
||||
color: hifi.colors.blueHighlight
|
||||
|
||||
anchors {
|
||||
top: image.bottom
|
||||
topMargin: 15
|
||||
horizontalCenter: image.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RalewayBold {
|
||||
id: countDown
|
||||
text: info.count
|
||||
color: hifi.colors.blueHighlight
|
||||
|
||||
anchors {
|
||||
top: statusText.bottom
|
||||
topMargin: 12
|
||||
horizontalCenter: statusText.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RalewayBold {
|
||||
id: directions
|
||||
|
||||
anchors {
|
||||
top: busyIndicator.bottom
|
||||
topMargin: 100
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
color: hifi.colors.white
|
||||
size: hifi.fontSizes.rootMenuDisclosure
|
||||
text: "Please stand in a T-Pose during calibration"
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: numberAnimation
|
||||
target: info
|
||||
property: "count"
|
||||
to: 0
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
|
||||
repeat: false
|
||||
interval: 3000
|
||||
onTriggered: {
|
||||
info.calibrating();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: closeWindow
|
||||
repeat: false
|
||||
interval: 3000
|
||||
onTriggered: stack.pop();
|
||||
}
|
||||
|
||||
Row {
|
||||
|
||||
spacing: 20
|
||||
anchors {
|
||||
top: directions.bottom
|
||||
topMargin: 30
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
|
||||
HifiControls.Button {
|
||||
width: 120
|
||||
height: 30
|
||||
color: hifi.buttons.red
|
||||
text: "RESTART"
|
||||
|
||||
onClicked: {
|
||||
restart();
|
||||
numberAnimation.stop();
|
||||
info.count = (timer.interval / 1000);
|
||||
numberAnimation.start();
|
||||
timer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
width: 120
|
||||
height: 30
|
||||
color: hifi.buttons.black
|
||||
text: "CANCEL"
|
||||
|
||||
onClicked: {
|
||||
canceled();
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function start(interval, countNumber) {
|
||||
countDown.visible = true;
|
||||
statusText.color = hifi.colors.blueHighlight;
|
||||
numberAnimation.duration = interval
|
||||
info.count = countNumber;
|
||||
timer.interval = interval;
|
||||
numberAnimation.start();
|
||||
timer.start();
|
||||
}
|
||||
|
||||
function calibrating() {
|
||||
countDown.visible = false;
|
||||
busyIndicator.source = whiteIndicator;
|
||||
busyRotation.from = 360
|
||||
busyRotation.to = 0
|
||||
statusText.text = info.calibratingText;
|
||||
statusText.color = hifi.colors.white
|
||||
}
|
||||
|
||||
function success() {
|
||||
busyIndicator.running = false;
|
||||
statusText.text = info.calibrationSuccess
|
||||
statusText.color = hifi.colors.greenHighlight
|
||||
closeWindow.start();
|
||||
}
|
||||
|
||||
function failure() {
|
||||
busyIndicator.running = false;
|
||||
statusText.text = info.calibrationFailed
|
||||
statusText.color = hifi.colors.redHighlight
|
||||
closeWindow.start();
|
||||
}
|
||||
}
|
218
interface/resources/qml/hifi/tablet/ControllerSettings.qml
Normal file
218
interface/resources/qml/hifi/tablet/ControllerSettings.qml
Normal file
|
@ -0,0 +1,218 @@
|
|||
//
|
||||
// Created by Dante Ruiz on 6/1/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
import "../../styles-uit"
|
||||
import "../../controls"
|
||||
import "../../controls-uit" as HifiControls
|
||||
|
||||
StackView {
|
||||
id: stack
|
||||
initialItem: inputConfiguration
|
||||
Rectangle {
|
||||
id: inputConfiguration
|
||||
anchors.fill: parent
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
color: hifi.colors.baseGray
|
||||
|
||||
property var pluginSettings: null
|
||||
|
||||
Rectangle {
|
||||
width: inputConfiguration.width
|
||||
height: 1
|
||||
color: hifi.colors.baseGrayShadow
|
||||
x: -hifi.dimensions.contentMargin.x
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: header
|
||||
text: "Controller Settings"
|
||||
size: 22
|
||||
color: "white"
|
||||
|
||||
anchors.top: inputConfiguration.top
|
||||
anchors.left: inputConfiguration.left
|
||||
anchors.leftMargin: 20
|
||||
anchors.topMargin: 20
|
||||
}
|
||||
|
||||
|
||||
Separator {
|
||||
id: headerSeparator
|
||||
width: inputConfiguration.width
|
||||
anchors.top: header.bottom
|
||||
anchors.topMargin: 10
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
id: sourceGlyph
|
||||
text: hifi.glyphs.source
|
||||
size: 36
|
||||
color: hifi.colors.blueHighlight
|
||||
|
||||
anchors.top: headerSeparator.bottom
|
||||
anchors.left: inputConfiguration.left
|
||||
anchors.leftMargin: 40
|
||||
anchors.topMargin: 20
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: configuration
|
||||
text: "SELECT DEVICE"
|
||||
size: 15
|
||||
color: hifi.colors.lightGrayText
|
||||
|
||||
|
||||
anchors.top: headerSeparator.bottom
|
||||
anchors.left: sourceGlyph.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.topMargin: 30
|
||||
}
|
||||
|
||||
Row {
|
||||
id: configRow
|
||||
z: 999
|
||||
anchors.top: sourceGlyph.bottom
|
||||
anchors.topMargin: 20
|
||||
anchors.left: sourceGlyph.left
|
||||
anchors.leftMargin: 40
|
||||
spacing: 10
|
||||
HifiControls.ComboBox {
|
||||
id: box
|
||||
width: 160
|
||||
z: 999
|
||||
editable: true
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
model: inputPlugins()
|
||||
label: ""
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
changeSource();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: checkBox
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
text: "show all input devices"
|
||||
|
||||
onClicked: {
|
||||
inputPlugins();
|
||||
changeSource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Separator {
|
||||
id: configurationSeparator
|
||||
z: 0
|
||||
width: inputConfiguration.width
|
||||
anchors.top: configRow.bottom
|
||||
anchors.topMargin: 10
|
||||
}
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: sliderGlyph
|
||||
text: hifi.glyphs.sliders
|
||||
size: 36
|
||||
color: hifi.colors.blueHighlight
|
||||
|
||||
anchors.top: configurationSeparator.bottom
|
||||
anchors.left: inputConfiguration.left
|
||||
anchors.leftMargin: 40
|
||||
anchors.topMargin: 20
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: configurationHeader
|
||||
text: "CONFIGURATION"
|
||||
size: 15
|
||||
color: hifi.colors.lightGrayText
|
||||
|
||||
|
||||
anchors.top: configurationSeparator.bottom
|
||||
anchors.left: sliderGlyph.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.topMargin: 30
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
asynchronous: false
|
||||
|
||||
width: inputConfiguration.width
|
||||
anchors.left: inputConfiguration.left
|
||||
anchors.right: inputConfiguration.right
|
||||
anchors.top: configurationHeader.bottom
|
||||
anchors.topMargin: 10
|
||||
anchors.bottom: inputConfiguration.bottom
|
||||
|
||||
source: InputConfiguration.configurationLayout(box.currentText);
|
||||
onLoaded: {
|
||||
if (loader.item.hasOwnProperty("pluginName")) {
|
||||
if (box.currentText === "Vive") {
|
||||
loader.item.pluginName = "OpenVR";
|
||||
} else {
|
||||
loader.item.pluginName = box.currentText;
|
||||
}
|
||||
}
|
||||
|
||||
if (loader.item.hasOwnProperty("displayInformation")) {
|
||||
loader.item.displayConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function inputPlugins() {
|
||||
if (checkBox.checked) {
|
||||
return InputConfiguration.inputPlugins();
|
||||
} else {
|
||||
return InputConfiguration.activeInputPlugins();
|
||||
}
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
changeSource();
|
||||
}
|
||||
|
||||
function changeSource() {
|
||||
loader.source = "";
|
||||
var source = "";
|
||||
if (box.currentText == "Vive") {
|
||||
source = InputConfiguration.configurationLayout("OpenVR");
|
||||
} else {
|
||||
source = InputConfiguration.configurationLayout(box.currentText);
|
||||
}
|
||||
|
||||
loader.source = source;
|
||||
if (source === "") {
|
||||
box.label = "(not configurable)";
|
||||
} else {
|
||||
box.label = "";
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
repeat: false
|
||||
interval: 300
|
||||
onTriggered: initialize()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
timer.start();
|
||||
}
|
||||
}
|
879
interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml
Normal file
879
interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml
Normal file
|
@ -0,0 +1,879 @@
|
|||
//
|
||||
// Created by Dante Ruiz on 6/5/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Controls 1.4 as Original
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "../../styles-uit"
|
||||
import "../../controls"
|
||||
import "../../controls-uit" as HifiControls
|
||||
import "."
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: openVrConfiguration
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.fill: parent
|
||||
|
||||
property int leftMargin: 75
|
||||
property int countDown: 0
|
||||
property string pluginName: ""
|
||||
property var displayInformation: null
|
||||
|
||||
readonly property bool feetChecked: feetBox.checked
|
||||
readonly property bool hipsChecked: hipBox.checked
|
||||
readonly property bool chestChecked: chestBox.checked
|
||||
readonly property bool shouldersChecked: shoulderBox.checked
|
||||
readonly property bool hmdHead: headBox.checked
|
||||
readonly property bool headPuck: headPuckBox.checked
|
||||
readonly property bool handController: handBox.checked
|
||||
readonly property bool handPuck: handPuckBox.checked
|
||||
|
||||
property int state: buttonState.disabled
|
||||
property var lastConfiguration: null
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
Component { id: screen; CalibratingScreen {} }
|
||||
QtObject {
|
||||
id: buttonState
|
||||
readonly property int disabled: 0
|
||||
readonly property int apply: 1
|
||||
readonly property int applyAndCalibrate: 2
|
||||
readonly property int calibrate: 3
|
||||
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
propagateComposedEvents: true
|
||||
onPressed: {
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
color: hifi.colors.baseGray
|
||||
|
||||
RalewayBold {
|
||||
id: head
|
||||
|
||||
text: "Head:"
|
||||
size: 12
|
||||
|
||||
color: "white"
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: leftMargin
|
||||
}
|
||||
|
||||
Row {
|
||||
id: headConfig
|
||||
anchors.top: head.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.left: openVrConfiguration.left
|
||||
anchors.leftMargin: leftMargin + 10
|
||||
spacing: 10
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: headBox
|
||||
width: 15
|
||||
height: 15
|
||||
boxRadius: 7
|
||||
|
||||
onClicked: {
|
||||
if (checked) {
|
||||
headPuckBox.checked = false;
|
||||
} else {
|
||||
checked = true;
|
||||
}
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
size: 12
|
||||
text: "Vive HMD"
|
||||
color: hifi.colors.lightGrayText
|
||||
}
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: headPuckBox
|
||||
width: 15
|
||||
height: 15
|
||||
boxRadius: 7
|
||||
|
||||
onClicked: {
|
||||
if (checked) {
|
||||
headBox.checked = false;
|
||||
} else {
|
||||
checked = true;
|
||||
}
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
size: 12
|
||||
text: "Tracker"
|
||||
color: hifi.colors.lightGrayText
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: headOffsets
|
||||
anchors.top: headConfig.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.left: openVrConfiguration.left
|
||||
anchors.leftMargin: leftMargin + 10
|
||||
spacing: 10
|
||||
visible: headPuckBox.checked
|
||||
HifiControls.SpinBox {
|
||||
id: headYOffset
|
||||
decimals: 4
|
||||
width: 112
|
||||
label: "Y: offset"
|
||||
minimumValue: -10
|
||||
stepSize: 0.0254
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
|
||||
onEditingFinished: {
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HifiControls.SpinBox {
|
||||
id: headZOffset
|
||||
width: 112
|
||||
label: "Z: offset"
|
||||
minimumValue: -10
|
||||
stepSize: 0.0254
|
||||
decimals: 4
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
|
||||
onEditingFinished: {
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RalewayBold {
|
||||
id: hands
|
||||
|
||||
text: "Hands:"
|
||||
size: 12
|
||||
|
||||
color: "white"
|
||||
|
||||
anchors.top: (headOffsets.visible ? headOffsets.bottom : headConfig.bottom)
|
||||
anchors.topMargin: (headOffsets.visible ? 22 : 10)
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: leftMargin
|
||||
}
|
||||
|
||||
Row {
|
||||
id: handConfig
|
||||
anchors.top: hands.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.left: openVrConfiguration.left
|
||||
anchors.leftMargin: leftMargin + 10
|
||||
spacing: 10
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: handBox
|
||||
width: 15
|
||||
height: 15
|
||||
boxRadius: 7
|
||||
|
||||
onClicked: {
|
||||
if (checked) {
|
||||
handPuckBox.checked = false;
|
||||
} else {
|
||||
checked = true;
|
||||
}
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
size: 12
|
||||
text: "Controllers"
|
||||
color: hifi.colors.lightGrayText
|
||||
}
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: handPuckBox
|
||||
width: 12
|
||||
height: 15
|
||||
boxRadius: 7
|
||||
|
||||
onClicked: {
|
||||
if (checked) {
|
||||
handBox.checked = false;
|
||||
} else {
|
||||
checked = true;
|
||||
}
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
size: 12
|
||||
text: "Trackers"
|
||||
color: hifi.colors.lightGrayText
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: handOffset
|
||||
visible: handPuckBox.checked
|
||||
anchors.top: handConfig.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.left: openVrConfiguration.left
|
||||
anchors.leftMargin: leftMargin + 10
|
||||
spacing: 10
|
||||
|
||||
HifiControls.SpinBox {
|
||||
id: handYOffset
|
||||
decimals: 4
|
||||
width: 112
|
||||
label: "Y: offset"
|
||||
minimumValue: -10
|
||||
stepSize: 0.0254
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
|
||||
onEditingFinished: {
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HifiControls.SpinBox {
|
||||
id: handZOffset
|
||||
width: 112
|
||||
label: "Z: offset"
|
||||
minimumValue: -10
|
||||
stepSize: 0.0254
|
||||
decimals: 4
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
|
||||
onEditingFinished: {
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
id: additional
|
||||
|
||||
text: "Additional Trackers"
|
||||
size: 12
|
||||
|
||||
color: hifi.colors.white
|
||||
|
||||
anchors.top: (handOffset.visible ? handOffset.bottom : handConfig.bottom)
|
||||
anchors.topMargin: (handOffset.visible ? 22 : 10)
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: leftMargin
|
||||
}
|
||||
|
||||
Row {
|
||||
id: feetConfig
|
||||
anchors.top: additional.bottom
|
||||
anchors.topMargin: 15
|
||||
anchors.left: openVrConfiguration.left
|
||||
anchors.leftMargin: leftMargin + 10
|
||||
spacing: 10
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: feetBox
|
||||
width: 15
|
||||
height: 15
|
||||
boxRadius: 7
|
||||
|
||||
onClicked: {
|
||||
if (!checked) {
|
||||
shoulderBox.checked = false;
|
||||
chestBox.checked = false;
|
||||
hipBox.checked = false;
|
||||
}
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
size: 12
|
||||
text: "Feet"
|
||||
color: hifi.colors.lightGrayText
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: hipConfig
|
||||
anchors.top: feetConfig.bottom
|
||||
anchors.topMargin: 15
|
||||
anchors.left: openVrConfiguration.left
|
||||
anchors.leftMargin: leftMargin + 10
|
||||
spacing: 10
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: hipBox
|
||||
width: 15
|
||||
height: 15
|
||||
boxRadius: 7
|
||||
|
||||
onClicked: {
|
||||
if (checked) {
|
||||
feetBox.checked = true;
|
||||
}
|
||||
|
||||
if (chestChecked) {
|
||||
checked = true;
|
||||
}
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
size: 12
|
||||
text: "Hips"
|
||||
color: hifi.colors.lightGrayText
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
size: 12
|
||||
text: "requires feet"
|
||||
color: hifi.colors.lightGray
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Row {
|
||||
id: chestConfig
|
||||
anchors.top: hipConfig.bottom
|
||||
anchors.topMargin: 15
|
||||
anchors.left: openVrConfiguration.left
|
||||
anchors.leftMargin: leftMargin + 10
|
||||
spacing: 10
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: chestBox
|
||||
width: 15
|
||||
height: 15
|
||||
boxRadius: 7
|
||||
|
||||
onClicked: {
|
||||
if (checked) {
|
||||
hipBox.checked = true;
|
||||
feetBox.checked = true;
|
||||
}
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
size: 12
|
||||
text: "Chest"
|
||||
color: hifi.colors.lightGrayText
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
size: 12
|
||||
text: "requires hips"
|
||||
color: hifi.colors.lightGray
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Row {
|
||||
id: shoulderConfig
|
||||
anchors.top: chestConfig.bottom
|
||||
anchors.topMargin: 15
|
||||
anchors.left: openVrConfiguration.left
|
||||
anchors.leftMargin: leftMargin + 10
|
||||
spacing: 10
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: shoulderBox
|
||||
width: 15
|
||||
height: 15
|
||||
boxRadius: 7
|
||||
|
||||
onClicked: {
|
||||
if (checked) {
|
||||
hipBox.checked = true;
|
||||
feetBox.checked = true;
|
||||
}
|
||||
sendConfigurationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
size: 12
|
||||
text: "Shoulders"
|
||||
color: hifi.colors.lightGrayText
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
size: 12
|
||||
text: "requires hips"
|
||||
color: hifi.colors.lightGray
|
||||
}
|
||||
}
|
||||
|
||||
Separator {
|
||||
id: bottomSeperator
|
||||
width: parent.width
|
||||
anchors.top: shoulderConfig.bottom
|
||||
anchors.topMargin: 10
|
||||
}
|
||||
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: calibrationButton
|
||||
property int color: hifi.buttons.blue
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
property string glyph: hifi.glyphs.avatar1
|
||||
property bool enabled: false
|
||||
property bool pressed: false
|
||||
property bool hovered: false
|
||||
property int size: 32
|
||||
property string text: "apply"
|
||||
property int padding: 12
|
||||
|
||||
width: glyphButton.width + calibrationText.width + padding
|
||||
height: hifi.dimensions.controlLineHeight
|
||||
anchors.top: bottomSeperator.bottom
|
||||
anchors.topMargin: 10
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: leftMargin
|
||||
|
||||
radius: hifi.buttons.radius
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.2
|
||||
color: {
|
||||
if (!calibrationButton.enabled) {
|
||||
hifi.buttons.disabledColorStart[calibrationButton.colorScheme]
|
||||
} else if (calibrationButton.pressed) {
|
||||
hifi.buttons.pressedColor[calibrationButton.color]
|
||||
} else if (calibrationButton.hovered) {
|
||||
hifi.buttons.hoveredColor[calibrationButton.color]
|
||||
} else {
|
||||
hifi.buttons.colorStart[calibrationButton.color]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: {
|
||||
if (!calibrationButton.enabled) {
|
||||
hifi.buttons.disabledColorFinish[calibrationButton.colorScheme]
|
||||
} else if (calibrationButton.pressed) {
|
||||
hifi.buttons.pressedColor[calibrationButton.color]
|
||||
} else if (calibrationButton.hovered) {
|
||||
hifi.buttons.hoveredColor[calibrationButton.color]
|
||||
} else {
|
||||
hifi.buttons.colorFinish[calibrationButton.color]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: glyphButton
|
||||
color: enabled ? hifi.buttons.textColor[calibrationButton.color]
|
||||
: hifi.buttons.disabledTextColor[calibrationButton.colorScheme]
|
||||
text: calibrationButton.glyph
|
||||
size: calibrationButton.size
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 1
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
id: calibrationText
|
||||
font.capitalization: Font.AllUppercase
|
||||
color: enabled ? hifi.buttons.textColor[calibrationButton.color]
|
||||
: hifi.buttons.disabledTextColor[calibrationButton.colorScheme]
|
||||
size: hifi.fontSizes.buttonLabel
|
||||
text: calibrationButton.text
|
||||
|
||||
anchors {
|
||||
left: glyphButton.right
|
||||
top: parent.top
|
||||
topMargin: 7
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
if (calibrationButton.enabled) {
|
||||
if (openVrConfiguration.state === buttonState.apply) {
|
||||
InputConfiguration.uncalibratePlugin(pluginName);
|
||||
updateCalibrationButton();
|
||||
} else {
|
||||
calibrationTimer.interval = timeToCalibrate.value * 1000
|
||||
openVrConfiguration.countDown = timeToCalibrate.value;
|
||||
var calibratingScreen = screen.createObject();
|
||||
stack.push(calibratingScreen);
|
||||
calibratingScreen.canceled.connect(cancelCalibration);
|
||||
calibratingScreen.restart.connect(restartCalibration);
|
||||
calibratingScreen.start(calibrationTimer.interval, timeToCalibrate.value);
|
||||
calibrationTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
calibrationButton.pressed = true;
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
calibrationButton.pressed = false;
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
calibrationButton.hovered = true;
|
||||
}
|
||||
|
||||
onExited: {
|
||||
calibrationButton.hovered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: calibrationTimer
|
||||
repeat: false
|
||||
interval: 20
|
||||
onTriggered: {
|
||||
InputConfiguration.calibratePlugin(pluginName)
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: displayTimer
|
||||
repeat: false
|
||||
interval: 3000
|
||||
onTriggered: {
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
InputConfiguration.calibrationStatus.connect(calibrationStatusInfo);
|
||||
lastConfiguration = composeConfigurationSettings();
|
||||
}
|
||||
|
||||
HifiControls.SpinBox {
|
||||
id: timeToCalibrate
|
||||
width: 70
|
||||
anchors.top: calibrationButton.bottom
|
||||
anchors.topMargin: 40
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: leftMargin
|
||||
|
||||
minimumValue: 3
|
||||
value: 3
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
|
||||
onEditingFinished: {
|
||||
calibrationTimer.interval = value * 1000;
|
||||
openVrConfiguration.countDown = value;
|
||||
numberAnimation.duration = calibrationTimer.interval;
|
||||
}
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
id: delayTextInfo
|
||||
size: 10
|
||||
text: "Delay Before Calibration Starts"
|
||||
color: hifi.colors.white
|
||||
|
||||
anchors {
|
||||
left: timeToCalibrate.right
|
||||
leftMargin: 20
|
||||
verticalCenter: timeToCalibrate.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
size: 12
|
||||
text: "sec"
|
||||
color: hifi.colors.lightGray
|
||||
|
||||
anchors {
|
||||
left: delayTextInfo.right
|
||||
leftMargin: 10
|
||||
verticalCenter: delayTextInfo.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: numberAnimation
|
||||
target: openVrConfiguration
|
||||
property: "countDown"
|
||||
to: 0
|
||||
}
|
||||
|
||||
function calibrationStatusInfo(status) {
|
||||
var calibrationScreen = stack.currentItem;
|
||||
if (status["calibrated"]) {
|
||||
calibrationScreen.success();
|
||||
} else if (!status["calibrated"]) {
|
||||
var uncalibrated = status["success"];
|
||||
if (!uncalibrated) {
|
||||
calibrationScreen.failure();
|
||||
}
|
||||
}
|
||||
|
||||
updateCalibrationButton();
|
||||
}
|
||||
|
||||
|
||||
function trackersForConfiguration() {
|
||||
var pucksNeeded = 0;
|
||||
|
||||
if (headPuckBox.checked) {
|
||||
pucksNeeded++;
|
||||
}
|
||||
|
||||
if (feetBox.checked) {
|
||||
pucksNeeded++;
|
||||
}
|
||||
|
||||
if (hipBox.checked) {
|
||||
pucksNeeded++;
|
||||
}
|
||||
|
||||
if (chestBox.checked) {
|
||||
pucksNeeded++;
|
||||
}
|
||||
|
||||
if (shoulderBox.checked) {
|
||||
pucksNeeded++;
|
||||
}
|
||||
|
||||
return pucksNeeded;
|
||||
}
|
||||
|
||||
function cancelCalibration() {
|
||||
calibrationTimer.stop();
|
||||
}
|
||||
|
||||
function restartCalibration() {
|
||||
calibrationTimer.restart();
|
||||
}
|
||||
|
||||
function displayConfiguration() {
|
||||
var settings = InputConfiguration.configurationSettings(pluginName);
|
||||
var configurationType = settings["trackerConfiguration"];
|
||||
displayTrackerConfiguration(configurationType);
|
||||
|
||||
|
||||
var HmdHead = settings["HMDHead"];
|
||||
var viveController = settings["handController"];
|
||||
|
||||
if (HmdHead) {
|
||||
headBox.checked = true;
|
||||
headPuckBox.checked = false;
|
||||
} else {
|
||||
headPuckBox.checked = true;
|
||||
headBox.checked = false;
|
||||
}
|
||||
|
||||
if (viveController) {
|
||||
handBox.checked = true;
|
||||
handPuckBox.checked = false;
|
||||
} else {
|
||||
handPuckBox.checked = true;
|
||||
handBox.checked = false;
|
||||
}
|
||||
|
||||
initializeButtonState();
|
||||
updateCalibrationText();
|
||||
}
|
||||
|
||||
function displayTrackerConfiguration(type) {
|
||||
if (type === "Feet") {
|
||||
feetBox.checked = true;
|
||||
} else if (type === "FeetAndHips") {
|
||||
feetBox.checked = true;
|
||||
hipBox.checked = true;
|
||||
} else if (type === "FeetHipsChest") {
|
||||
feetBox.checked = true;
|
||||
hipBox.checked = true;
|
||||
chestBox.checked = true;
|
||||
} else if (type === "FeetHipsAndShoulders") {
|
||||
feetBox.checked = true;
|
||||
hipBox.checked = true;
|
||||
shoulderBox.checked = true;
|
||||
} else if (type === "FeetHipsChestAndShoulders") {
|
||||
feetBox.checked = true;
|
||||
hipBox.checked = true;
|
||||
chestBox.checked = true;
|
||||
shoulderBox.checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
function updateButtonState() {
|
||||
var settings = composeConfigurationSettings();
|
||||
var bodySetting = settings["bodyConfiguration"];
|
||||
var headSetting = settings["headConfiguration"];
|
||||
var headOverride = headSetting["override"];
|
||||
var handSetting = settings["handConfiguration"];
|
||||
var handOverride = handSetting["override"];
|
||||
|
||||
var settingsChanged = false;
|
||||
|
||||
if (lastConfiguration["bodyConfiguration"] !== bodySetting) {
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
var lastHead = lastConfiguration["headConfiguration"];
|
||||
if (lastHead["override"] !== headOverride) {
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
var lastHand = lastConfiguration["handConfiguration"];
|
||||
if (lastHand["override"] !== handOverride) {
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (settingsChanged) {
|
||||
if ((!handOverride) && (!headOverride) && (bodySetting === "None")) {
|
||||
state = buttonState.apply;
|
||||
} else {
|
||||
state = buttonState.applyAndCalibrate;
|
||||
}
|
||||
} else {
|
||||
if (state == buttonState.apply) {
|
||||
state = buttonState.disabled;
|
||||
} else if (state == buttonState.applyAndCalibrate) {
|
||||
state = buttonState.calibrate;
|
||||
}
|
||||
}
|
||||
|
||||
lastConfiguration = settings;
|
||||
}
|
||||
|
||||
function initializeButtonState() {
|
||||
var settings = composeConfigurationSettings();
|
||||
var bodySetting = settings["bodyConfiguration"];
|
||||
var headSetting = settings["headConfiguration"];
|
||||
var headOverride = headSetting["override"];
|
||||
var handSetting = settings["handConfiguration"];
|
||||
var handOverride = handSetting["override"];
|
||||
|
||||
|
||||
if ((!handOverride) && (!headOverride) && (bodySetting === "None")) {
|
||||
state = buttonState.disabled;
|
||||
} else {
|
||||
state = buttonState.calibrate;
|
||||
}
|
||||
}
|
||||
|
||||
function updateCalibrationButton() {
|
||||
updateButtonState();
|
||||
updateCalibrationText();
|
||||
}
|
||||
|
||||
function updateCalibrationText() {
|
||||
if (buttonState.disabled == state) {
|
||||
calibrationButton.enabled = false;
|
||||
calibrationButton.text = "Apply";
|
||||
} else if (buttonState.apply == state) {
|
||||
calibrationButton.enabled = true;
|
||||
calibrationButton.text = "Apply";
|
||||
} else if (buttonState.applyAndCalibrate == state) {
|
||||
calibrationButton.enabled = true;
|
||||
calibrationButton.text = "Apply And Calibrate";
|
||||
} else if (buttonState.calibrate == state) {
|
||||
calibrationButton.enabled = true;
|
||||
calibrationButton.text = "Calibrate";
|
||||
}
|
||||
}
|
||||
|
||||
function composeConfigurationSettings() {
|
||||
var trackerConfiguration = "";
|
||||
var overrideHead = false;
|
||||
var overrideHandController = false;
|
||||
|
||||
if (shouldersChecked && chestChecked) {
|
||||
trackerConfiguration = "FeetHipsChestAndShoulders";
|
||||
} else if (shouldersChecked) {
|
||||
trackerConfiguration = "FeetHipsAndShoulders";
|
||||
} else if (chestChecked) {
|
||||
trackerConfiguration = "FeetHipsAndChest";
|
||||
} else if (hipsChecked) {
|
||||
trackerConfiguration = "FeetAndHips";
|
||||
} else if (feetChecked) {
|
||||
trackerConfiguration = "Feet";
|
||||
} else {
|
||||
trackerConfiguration = "None";
|
||||
}
|
||||
|
||||
if (headPuck) {
|
||||
overrideHead = true;
|
||||
} else if (hmdHead) {
|
||||
overrideHead = false;
|
||||
}
|
||||
|
||||
if (handController) {
|
||||
overrideHandController = false;
|
||||
} else if (handPuck) {
|
||||
overrideHandController = true;
|
||||
}
|
||||
|
||||
var headObject = {
|
||||
"override": overrideHead,
|
||||
"Y": headYOffset.value,
|
||||
"Z": headZOffset.value
|
||||
}
|
||||
|
||||
var handObject = {
|
||||
"override": overrideHandController,
|
||||
"Y": handYOffset.value,
|
||||
"Z": handZOffset.value
|
||||
}
|
||||
|
||||
var settingsObject = {
|
||||
"bodyConfiguration": trackerConfiguration,
|
||||
"headConfiguration": headObject,
|
||||
"handConfiguration": handObject
|
||||
}
|
||||
|
||||
return settingsObject;
|
||||
}
|
||||
|
||||
function sendConfigurationSettings() {
|
||||
var settings = composeConfigurationSettings();
|
||||
InputConfiguration.setConfigurationSettings(settings, pluginName);
|
||||
updateCalibrationButton();
|
||||
}
|
||||
}
|
|
@ -333,6 +333,7 @@ Item {
|
|||
readonly property string vol_x_2: "\ue015"
|
||||
readonly property string vol_x_3: "\ue016"
|
||||
readonly property string vol_x_4: "\ue017"
|
||||
readonly property string source: "\ue01c"
|
||||
readonly property string playback_play: "\ue01d"
|
||||
readonly property string stop_square: "\ue01e"
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@
|
|||
#include <plugins/PluginManager.h>
|
||||
#include <plugins/PluginUtils.h>
|
||||
#include <plugins/SteamClientPlugin.h>
|
||||
#include <plugins/InputConfiguration.h>
|
||||
#include <RecordingScriptingInterface.h>
|
||||
#include <RenderableWebEntityItem.h>
|
||||
#include <RenderShadowTask.h>
|
||||
|
@ -539,6 +540,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
DependencyManager::set<HMDScriptingInterface>();
|
||||
DependencyManager::set<ResourceScriptingInterface>();
|
||||
DependencyManager::set<TabletScriptingInterface>();
|
||||
DependencyManager::set<InputConfiguration>();
|
||||
DependencyManager::set<ToolbarScriptingInterface>();
|
||||
DependencyManager::set<UserActivityLoggerScriptingInterface>();
|
||||
DependencyManager::set<AssetMappingsScriptingInterface>();
|
||||
|
@ -2025,6 +2027,7 @@ void Application::initializeUi() {
|
|||
surfaceContext->setContextProperty("TextureCache", DependencyManager::get<TextureCache>().data());
|
||||
surfaceContext->setContextProperty("ModelCache", DependencyManager::get<ModelCache>().data());
|
||||
surfaceContext->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
|
||||
|
||||
surfaceContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <AudioClient.h>
|
||||
#include <CrashHelpers.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <TabletScriptingInterface.h>
|
||||
#include <display-plugins/DisplayPlugin.h>
|
||||
#include <PathUtils.h>
|
||||
#include <SettingHandle.h>
|
||||
|
@ -37,6 +38,7 @@
|
|||
#include "MainWindow.h"
|
||||
#include "render/DrawStatus.h"
|
||||
#include "scripting/MenuScriptingInterface.h"
|
||||
#include "scripting/HMDScriptingInterface.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
#include "ui/StandAloneJSConsole.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
@ -309,6 +311,17 @@ Menu::Menu() {
|
|||
QString("../../hifi/tablet/TabletLodPreferences.qml"), "LodPreferencesDialog");
|
||||
});
|
||||
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Controller Settings");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||
tablet->loadQMLSource("ControllerSettings.qml");
|
||||
|
||||
if (!hmd->getShouldShowTablet()) {
|
||||
hmd->toggleShouldShowTablet();
|
||||
}
|
||||
});
|
||||
|
||||
// Settings > Control with Speech [advanced]
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
auto speechRecognizer = DependencyManager::get<SpeechRecognizer>();
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "ui/AvatarInputs.h"
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "scripting/GlobalServicesScriptingInterface.h"
|
||||
#include <plugins/InputConfiguration.h>
|
||||
#include "ui/Snapshot.h"
|
||||
#include "SoundCache.h"
|
||||
|
||||
|
@ -182,6 +183,7 @@ void Web3DOverlay::loadSourceURL() {
|
|||
if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
auto flags = tabletScriptingInterface->getFlags();
|
||||
|
||||
_webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags);
|
||||
_webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountScriptingInterface::getInstance());
|
||||
|
@ -200,6 +202,7 @@ void Web3DOverlay::loadSourceURL() {
|
|||
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
|
||||
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
|
||||
|
|
143
libraries/plugins/src/plugins/InputConfiguration.cpp
Normal file
143
libraries/plugins/src/plugins/InputConfiguration.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
//
|
||||
// Created by Dante Ruiz on 6/1/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include "InputConfiguration.h"
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#include "DisplayPlugin.h"
|
||||
#include "InputPlugin.h"
|
||||
#include "PluginManager.h"
|
||||
|
||||
InputConfiguration::InputConfiguration() {
|
||||
}
|
||||
|
||||
QStringList InputConfiguration::inputPlugins() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QStringList result;
|
||||
QMetaObject::invokeMethod(this, "inputPlugins", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QStringList, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList inputPlugins;
|
||||
for (auto plugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
QString pluginName = plugin->getName();
|
||||
if (pluginName == QString("OpenVR")) {
|
||||
inputPlugins << QString("Vive");
|
||||
} else {
|
||||
inputPlugins << pluginName;
|
||||
}
|
||||
}
|
||||
return inputPlugins;
|
||||
}
|
||||
|
||||
|
||||
QStringList InputConfiguration::activeInputPlugins() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QStringList result;
|
||||
QMetaObject::invokeMethod(this, "activeInputPlugins", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QStringList, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList activePlugins;
|
||||
for (auto plugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (plugin->configurable()) {
|
||||
QString pluginName = plugin->getName();
|
||||
if (pluginName == QString("OpenVR")) {
|
||||
activePlugins << QString("Vive");
|
||||
} else {
|
||||
activePlugins << pluginName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return activePlugins;
|
||||
}
|
||||
|
||||
QString InputConfiguration::configurationLayout(QString pluginName) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QString result;
|
||||
QMetaObject::invokeMethod(this, "configurationLayout", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QString, result),
|
||||
Q_ARG(QString, pluginName));
|
||||
return result;
|
||||
}
|
||||
|
||||
QString sourcePath;
|
||||
for (auto plugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (plugin->getName() == pluginName) {
|
||||
return plugin->configurationLayout();
|
||||
}
|
||||
}
|
||||
return sourcePath;
|
||||
}
|
||||
|
||||
void InputConfiguration::setConfigurationSettings(QJsonObject configurationSettings, QString pluginName) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setConfigurationSettings", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QJsonObject, configurationSettings),
|
||||
Q_ARG(QString, pluginName));
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto plugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (plugin->getName() == pluginName) {
|
||||
plugin->setConfigurationSettings(configurationSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject InputConfiguration::configurationSettings(QString pluginName) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QJsonObject result;
|
||||
QMetaObject::invokeMethod(this, "configurationSettings", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QJsonObject, result),
|
||||
Q_ARG(QString, pluginName));
|
||||
return result;
|
||||
}
|
||||
|
||||
for (auto plugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (plugin->getName() == pluginName) {
|
||||
return plugin->configurationSettings();
|
||||
}
|
||||
}
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
void InputConfiguration::calibratePlugin(QString pluginName) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "calibratePlugin", Qt::BlockingQueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto plugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (plugin->getName() == pluginName) {
|
||||
plugin->calibrate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool InputConfiguration::uncalibratePlugin(QString pluginName) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
bool result;
|
||||
QMetaObject::invokeMethod(this, "uncalibratePlugin", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(bool, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
for (auto plugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (plugin->getName() == pluginName) {
|
||||
return plugin->uncalibrate();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
37
libraries/plugins/src/plugins/InputConfiguration.h
Normal file
37
libraries/plugins/src/plugins/InputConfiguration.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// Created by Dante Ruiz on 6/1/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_InputConfiguration_h
|
||||
#define hifi_InputConfiguration_h
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QJsonObject>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
class InputConfiguration : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
public:
|
||||
InputConfiguration();
|
||||
|
||||
Q_INVOKABLE QStringList inputPlugins();
|
||||
Q_INVOKABLE QStringList activeInputPlugins();
|
||||
Q_INVOKABLE QString configurationLayout(QString pluginName);
|
||||
Q_INVOKABLE void setConfigurationSettings(QJsonObject configurationSettings, QString pluginName);
|
||||
Q_INVOKABLE void calibratePlugin(QString pluginName);
|
||||
Q_INVOKABLE QJsonObject configurationSettings(QString pluginName);
|
||||
Q_INVOKABLE bool uncalibratePlugin(QString pluginName);
|
||||
|
||||
signals:
|
||||
void calibrationStatus(const QJsonObject& status);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -11,6 +11,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Plugin.h"
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace controller {
|
||||
struct InputCalibrationData;
|
||||
|
@ -24,7 +25,12 @@ public:
|
|||
// Some input plugins are comprised of multiple subdevices (SDL2, for instance).
|
||||
// If an input plugin is only a single device, it will only return it's primary name.
|
||||
virtual QStringList getSubdeviceNames() { return { getName() }; };
|
||||
virtual void setConfigurationSettings(const QJsonObject configurationSettings) { }
|
||||
virtual QJsonObject configurationSettings() { return QJsonObject(); }
|
||||
virtual QString configurationLayout() { return QString(); }
|
||||
virtual void calibrate() {}
|
||||
virtual bool uncalibrate() { return false; }
|
||||
virtual bool configurable() { return false; }
|
||||
virtual bool isHandController() const { return false; }
|
||||
virtual bool isHeadController() const { return false; }
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
set(TARGET_NAME hifiCodec)
|
||||
setup_hifi_client_server_plugin()
|
||||
link_hifi_libraries(audio plugins)
|
||||
link_hifi_libraries(audio plugins input-plugins display-plugins)
|
||||
add_dependency_external_projects(hifiAudioCodec)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAUDIOCODEC_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${HIFIAUDIOCODEC_LIBRARIES})
|
||||
|
|
|
@ -11,7 +11,7 @@ if (WIN32)
|
|||
if (KINECT_FOUND)
|
||||
set(TARGET_NAME hifiKinect)
|
||||
setup_hifi_plugin(Script Qml Widgets)
|
||||
link_hifi_libraries(shared controllers ui plugins input-plugins)
|
||||
link_hifi_libraries(shared controllers ui plugins input-plugins display-plugins)
|
||||
|
||||
# need to setup appropriate externals...
|
||||
target_kinect()
|
||||
|
|
|
@ -10,7 +10,7 @@ if (APPLE OR WIN32)
|
|||
|
||||
set(TARGET_NAME hifiNeuron)
|
||||
setup_hifi_plugin(Script Qml Widgets)
|
||||
link_hifi_libraries(shared controllers ui plugins input-plugins)
|
||||
link_hifi_libraries(shared controllers ui plugins input-plugins display-plugins)
|
||||
target_neuron()
|
||||
|
||||
endif()
|
||||
|
|
|
@ -8,5 +8,5 @@
|
|||
|
||||
set(TARGET_NAME hifiSdl2)
|
||||
setup_hifi_plugin(Script Qml Widgets)
|
||||
link_hifi_libraries(shared controllers ui plugins input-plugins script-engine)
|
||||
link_hifi_libraries(shared controllers ui plugins input-plugins script-engine display-plugins)
|
||||
target_sdl2()
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
if (NOT ANDROID)
|
||||
set(TARGET_NAME hifiSixense)
|
||||
setup_hifi_plugin(Script Qml Widgets)
|
||||
link_hifi_libraries(shared controllers ui plugins ui-plugins input-plugins)
|
||||
link_hifi_libraries(shared controllers ui plugins ui-plugins input-plugins display-plugins)
|
||||
target_sixense()
|
||||
endif ()
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <controllers/UserInputMapper.h>
|
||||
|
||||
#include <Plugins/InputConfiguration.h>
|
||||
#include <controllers/StandardControls.h>
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ extern PoseData _nextSimPoseData;
|
|||
vr::IVRSystem* acquireOpenVrSystem();
|
||||
void releaseOpenVrSystem();
|
||||
|
||||
|
||||
static const QString OPENVR_LAYOUT = QString("OpenVrConfiguration.qml");
|
||||
static const char* CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
|
||||
const quint64 CALIBRATION_TIMELAPSE = 1 * USECS_PER_SECOND;
|
||||
|
||||
|
@ -47,18 +47,23 @@ static const char* MENU_PARENT = "Avatar";
|
|||
static const char* MENU_NAME = "Vive Controllers";
|
||||
static const char* MENU_PATH = "Avatar" ">" "Vive Controllers";
|
||||
static const char* RENDER_CONTROLLERS = "Render Hand Controllers";
|
||||
|
||||
static const int MIN_HEAD = 1;
|
||||
static const int MIN_PUCK_COUNT = 2;
|
||||
static const int MIN_FEET_AND_HIPS = 3;
|
||||
static const int MIN_FEET_HIPS_CHEST = 4;
|
||||
static const int MIN_FEET_HIPS_HEAD = 4;
|
||||
static const int MIN_FEET_HIPS_SHOULDERS = 5;
|
||||
static const int MIN_FEET_HIPS_CHEST_HEAD = 5;
|
||||
static const int MIN_FEET_HIPS_CHEST_SHOULDERS = 6;
|
||||
|
||||
static const int FIRST_FOOT = 0;
|
||||
static const int SECOND_FOOT = 1;
|
||||
static const int HIP = 2;
|
||||
static const int CHEST = 3;
|
||||
|
||||
static float HEAD_PUCK_Y_OFFSET = -0.0254f;
|
||||
static float HEAD_PUCK_Z_OFFSET = -0.152f;
|
||||
static float HAND_PUCK_Y_OFFSET = -0.0508f;
|
||||
static float HAND_PUCK_Z_OFFSET = 0.0254f;
|
||||
|
||||
const char* ViveControllerManager::NAME { "OpenVR" };
|
||||
|
||||
|
@ -84,7 +89,7 @@ static bool sortPucksXPosition(PuckPosePair firstPuck, PuckPosePair secondPuck)
|
|||
return (firstPuck.second.translation.x < secondPuck.second.translation.x);
|
||||
}
|
||||
|
||||
static bool determineFeetOrdering(const controller::Pose& poseA, const controller::Pose& poseB, glm::vec3 axis, glm::vec3 axisOrigin) {
|
||||
static bool determineLimbOrdering(const controller::Pose& poseA, const controller::Pose& poseB, glm::vec3 axis, glm::vec3 axisOrigin) {
|
||||
glm::vec3 poseAPosition = poseA.getTranslation();
|
||||
glm::vec3 poseBPosition = poseB.getTranslation();
|
||||
|
||||
|
@ -116,10 +121,42 @@ static QString deviceTrackingResultToString(vr::ETrackingResult trackingResult)
|
|||
return result;
|
||||
}
|
||||
|
||||
void ViveControllerManager::calibrate() {
|
||||
if (isSupported()) {
|
||||
_inputDevice->calibrateNextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
bool ViveControllerManager::uncalibrate() {
|
||||
if (isSupported()) {
|
||||
_inputDevice->uncalibrate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ViveControllerManager::isSupported() const {
|
||||
return openVrSupported();
|
||||
}
|
||||
|
||||
void ViveControllerManager::setConfigurationSettings(const QJsonObject configurationSettings) {
|
||||
if (isSupported()) {
|
||||
_inputDevice->configureCalibrationSettings(configurationSettings);
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject ViveControllerManager::configurationSettings() {
|
||||
if (isSupported()) {
|
||||
return _inputDevice->configurationSettings();
|
||||
}
|
||||
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
QString ViveControllerManager::configurationLayout() {
|
||||
return OPENVR_LAYOUT;
|
||||
}
|
||||
|
||||
bool ViveControllerManager::activate() {
|
||||
InputPlugin::activate();
|
||||
|
||||
|
@ -207,17 +244,11 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu
|
|||
|
||||
ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system) {
|
||||
|
||||
_configStringMap[Config::Auto] = QString("Auto");
|
||||
_configStringMap[Config::Feet] = QString("Feet");
|
||||
_configStringMap[Config::FeetAndHips] = QString("FeetAndHips");
|
||||
_configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest");
|
||||
_configStringMap[Config::None] = QString("None");
|
||||
_configStringMap[Config::Feet] = QString("Feet");
|
||||
_configStringMap[Config::FeetAndHips] = QString("FeetAndHips");
|
||||
_configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest");
|
||||
_configStringMap[Config::FeetHipsAndShoulders] = QString("FeetHipsAndShoulders");
|
||||
_configStringMap[Config::FeetHipsChestAndHead] = QString("FeetHipsChestAndHead");
|
||||
_configStringMap[Config::FeetHipsAndHead] = QString("FeetHipsAndHead");
|
||||
|
||||
if (openVrSupported()) {
|
||||
createPreferences();
|
||||
}
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
|
||||
|
@ -265,6 +296,14 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle
|
|||
}
|
||||
_trackedControllers = numTrackedControllers;
|
||||
|
||||
calibrateFromHandController(inputCalibrationData);
|
||||
calibrateFromUI(inputCalibrationData);
|
||||
|
||||
updateCalibratedLimbs();
|
||||
_lastSimPoseData = _nextSimPoseData;
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData) {
|
||||
if (checkForCalibrationEvent()) {
|
||||
quint64 currentTime = usecTimestampNow();
|
||||
if (!_timeTilCalibrationSet) {
|
||||
|
@ -280,9 +319,82 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle
|
|||
_triggersPressedHandled = false;
|
||||
_timeTilCalibrationSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
updateCalibratedLimbs();
|
||||
_lastSimPoseData = _nextSimPoseData;
|
||||
void ViveControllerManager::InputDevice::calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData) {
|
||||
if (_calibrate) {
|
||||
uncalibrate();
|
||||
calibrate(inputCalibrationData);
|
||||
_calibrate = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJsonObject configurationSettings) {
|
||||
Locker locker(_lock);
|
||||
if (!configurationSettings.empty()) {
|
||||
auto iter = configurationSettings.begin();
|
||||
auto end = configurationSettings.end();
|
||||
while (iter != end) {
|
||||
if (iter.key() == "bodyConfiguration") {
|
||||
setConfigFromString(iter.value().toString());
|
||||
} else if (iter.key() == "headConfiguration") {
|
||||
QJsonObject headObject = iter.value().toObject();
|
||||
bool overrideHead = headObject["override"].toBool();
|
||||
if (overrideHead) {
|
||||
_headConfig = HeadConfig::Puck;
|
||||
HEAD_PUCK_Y_OFFSET = headObject["Y"].toDouble();
|
||||
HEAD_PUCK_Z_OFFSET = headObject["Z"].toDouble();
|
||||
} else {
|
||||
_headConfig = HeadConfig::HMD;
|
||||
}
|
||||
} else if (iter.key() == "handConfiguration") {
|
||||
QJsonObject handsObject = iter.value().toObject();
|
||||
bool overrideHands = handsObject["override"].toBool();
|
||||
if (overrideHands) {
|
||||
_handConfig = HandConfig::Pucks;
|
||||
HAND_PUCK_Y_OFFSET = handsObject["Y"].toDouble();
|
||||
HAND_PUCK_Z_OFFSET = handsObject["Z"].toDouble();
|
||||
} else {
|
||||
_handConfig = HandConfig::HandController;
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::calibrateNextFrame() {
|
||||
Locker locker(_lock);
|
||||
_calibrate = true;
|
||||
}
|
||||
|
||||
QJsonObject ViveControllerManager::InputDevice::configurationSettings() {
|
||||
Locker locker(_lock);
|
||||
QJsonObject configurationSettings;
|
||||
configurationSettings["trackerConfiguration"] = configToString(_preferedConfig);
|
||||
configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD) ? true : false;
|
||||
configurationSettings["handController"] = (_handConfig == HandConfig::HandController) ? true : false;
|
||||
return configurationSettings;
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::emitCalibrationStatus(const bool success) {
|
||||
auto inputConfiguration = DependencyManager::get<InputConfiguration>();
|
||||
QJsonObject status = QJsonObject();
|
||||
|
||||
if (_calibrated && success) {
|
||||
status["calibrated"] = _calibrated;
|
||||
status["configuration"] = configToString(_preferedConfig);
|
||||
} else if (!_calibrated && !success) {
|
||||
status["calibrated"] = _calibrated;
|
||||
status["success"] = success;
|
||||
} else if (!_calibrated && success) {
|
||||
status["calibrated"] = _calibrated;
|
||||
status["success"] = success;
|
||||
status["configuration"] = configToString(_preferedConfig);
|
||||
status["puckCount"] = (int)_validTrackedObjects.size();
|
||||
}
|
||||
|
||||
emit inputConfiguration->calibrationStatus(status); //inputConfiguration->calibrated(status);
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) {
|
||||
|
@ -330,102 +442,142 @@ void ViveControllerManager::InputDevice::calibrateOrUncalibrate(const controller
|
|||
calibrate(inputCalibration);
|
||||
} else {
|
||||
uncalibrate();
|
||||
emitCalibrationStatus(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibrationData& inputCalibration) {
|
||||
qDebug() << "Puck Calibration: Starting...";
|
||||
// convert the hmd head from sensor space to avatar space
|
||||
glm::mat4 hmdSensorFlippedMat = inputCalibration.hmdSensorMat * Matrices::Y_180;
|
||||
glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat;
|
||||
glm::mat4 hmdAvatarMat = sensorToAvatarMat * hmdSensorFlippedMat;
|
||||
|
||||
// cancel the roll and pitch for the hmd head
|
||||
glm::quat hmdRotation = cancelOutRollAndPitch(glmExtractRotation(hmdAvatarMat));
|
||||
glm::vec3 hmdTranslation = extractTranslation(hmdAvatarMat);
|
||||
glm::mat4 currentHmd = createMatFromQuatAndPos(hmdRotation, hmdTranslation);
|
||||
|
||||
// calculate the offset from the centerOfEye to defaultHeadMat
|
||||
glm::mat4 defaultHeadOffset = glm::inverse(inputCalibration.defaultCenterEyeMat) * inputCalibration.defaultHeadMat;
|
||||
|
||||
glm::mat4 currentHead = currentHmd * defaultHeadOffset;
|
||||
|
||||
// calculate the defaultToRefrenceXform
|
||||
glm::mat4 defaultToReferenceMat = currentHead * glm::inverse(inputCalibration.defaultHeadMat);
|
||||
|
||||
int puckCount = (int)_validTrackedObjects.size();
|
||||
qDebug() << "Puck Calibration: " << puckCount << " pucks found for calibration";
|
||||
_config = _preferedConfig;
|
||||
if (_config != Config::Auto && puckCount < MIN_PUCK_COUNT) {
|
||||
qDebug() << "Puck Calibration: Failed: Could not meet the minimal # of pucks";
|
||||
|
||||
if (puckCount == 0) {
|
||||
uncalibrate();
|
||||
emitCalibrationStatus(false);
|
||||
return;
|
||||
} else if (_config == Config::Auto){
|
||||
if (puckCount == MIN_PUCK_COUNT) {
|
||||
_config = Config::Feet;
|
||||
qDebug() << "Puck Calibration: Auto Config: " << configToString(_config) << " configuration";
|
||||
} else if (puckCount == MIN_FEET_AND_HIPS) {
|
||||
_config = Config::FeetAndHips;
|
||||
qDebug() << "Puck Calibration: Auto Config: " << configToString(_config) << " configuration";
|
||||
} else if (puckCount >= MIN_FEET_HIPS_CHEST) {
|
||||
_config = Config::FeetHipsAndChest;
|
||||
qDebug() << "Puck Calibration: Auto Config: " << configToString(_config) << " configuration";
|
||||
} else {
|
||||
qDebug() << "Puck Calibration: Auto Config Failed: Could not meet the minimal # of pucks";
|
||||
uncalibrate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition);
|
||||
glm::mat4 defaultToReferenceMat = glm::mat4();
|
||||
if (_headConfig == HeadConfig::HMD) {
|
||||
defaultToReferenceMat = calculateDefaultToReferenceForHmd(inputCalibration);
|
||||
} else if (_headConfig == HeadConfig::Puck) {
|
||||
defaultToReferenceMat = calculateDefaultToReferenceForHeadPuck(inputCalibration);
|
||||
}
|
||||
|
||||
_config = _preferedConfig;
|
||||
|
||||
bool headConfigured = configureHead(defaultToReferenceMat, inputCalibration);
|
||||
bool handsConfigured = configureHands(defaultToReferenceMat, inputCalibration);
|
||||
bool bodyConfigured = configureBody(defaultToReferenceMat, inputCalibration);
|
||||
|
||||
if (_config == Config::Feet) {
|
||||
if (!headConfigured || !handsConfigured || !bodyConfigured) {
|
||||
uncalibrate();
|
||||
emitCalibrationStatus(false);
|
||||
} else {
|
||||
_calibrated = true;
|
||||
emitCalibrationStatus(true);
|
||||
qDebug() << "PuckCalibration: " << configToString(_config) << " Configuration Successful";
|
||||
}
|
||||
}
|
||||
|
||||
bool ViveControllerManager::InputDevice::configureHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksXPosition);
|
||||
int puckCount = (int)_validTrackedObjects.size();
|
||||
if (_handConfig == HandConfig::Pucks && puckCount >= MIN_PUCK_COUNT) {
|
||||
glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||
glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||
size_t FIRST_INDEX = 0;
|
||||
size_t LAST_INDEX = _validTrackedObjects.size() -1;
|
||||
auto& firstHand = _validTrackedObjects[FIRST_INDEX];
|
||||
auto& secondHand = _validTrackedObjects[LAST_INDEX];
|
||||
controller::Pose& firstHandPose = firstHand.second;
|
||||
controller::Pose& secondHandPose = secondHand.second;
|
||||
|
||||
if (determineLimbOrdering(firstHandPose, secondHandPose, headXAxis, headPosition)) {
|
||||
calibrateLeftHand(defaultToReferenceMat, inputCalibration, firstHand);
|
||||
calibrateRightHand(defaultToReferenceMat, inputCalibration, secondHand);
|
||||
_validTrackedObjects.erase(_validTrackedObjects.begin());
|
||||
_validTrackedObjects.erase(_validTrackedObjects.end() - 1);
|
||||
_overrideHands = true;
|
||||
return true;
|
||||
} else {
|
||||
calibrateLeftHand(defaultToReferenceMat, inputCalibration, secondHand);
|
||||
calibrateRightHand(defaultToReferenceMat, inputCalibration, firstHand);
|
||||
_validTrackedObjects.erase(_validTrackedObjects.begin());
|
||||
_validTrackedObjects.erase(_validTrackedObjects.end() - 1);
|
||||
_overrideHands = true;
|
||||
return true;
|
||||
}
|
||||
} else if (_handConfig == HandConfig::HandController) {
|
||||
_overrideHands = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ViveControllerManager::InputDevice::configureHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition);
|
||||
int puckCount = (int)_validTrackedObjects.size();
|
||||
if (_headConfig == HeadConfig::Puck && puckCount >= MIN_HEAD) {
|
||||
calibrateHead(defaultToReferenceMat, inputCalibration);
|
||||
_validTrackedObjects.erase(_validTrackedObjects.end() - 1);
|
||||
_overrideHead = true;
|
||||
return true;
|
||||
} else if (_headConfig == HeadConfig::HMD) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ViveControllerManager::InputDevice::configureBody(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition);
|
||||
int puckCount = (int)_validTrackedObjects.size();
|
||||
glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||
glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||
if (_config == Config::None) {
|
||||
return true;
|
||||
} else if (_config == Config::Feet && puckCount >= MIN_PUCK_COUNT) {
|
||||
calibrateFeet(defaultToReferenceMat, inputCalibration);
|
||||
return true;
|
||||
} else if (_config == Config::FeetAndHips && puckCount >= MIN_FEET_AND_HIPS) {
|
||||
calibrateFeet(defaultToReferenceMat, inputCalibration);
|
||||
calibrateHips(defaultToReferenceMat, inputCalibration);
|
||||
return true;
|
||||
} else if (_config == Config::FeetHipsAndChest && puckCount >= MIN_FEET_HIPS_CHEST) {
|
||||
calibrateFeet(defaultToReferenceMat, inputCalibration);
|
||||
calibrateHips(defaultToReferenceMat, inputCalibration);
|
||||
calibrateChest(defaultToReferenceMat, inputCalibration);
|
||||
return true;
|
||||
} else if (_config == Config::FeetHipsAndShoulders && puckCount >= MIN_FEET_HIPS_SHOULDERS) {
|
||||
calibrateFeet(defaultToReferenceMat, inputCalibration);
|
||||
calibrateHips(defaultToReferenceMat, inputCalibration);
|
||||
int firstShoulderIndex = 3;
|
||||
int secondShoulderIndex = 4;
|
||||
calibrateShoulders(defaultToReferenceMat, inputCalibration, firstShoulderIndex, secondShoulderIndex);
|
||||
} else if (_config == Config::FeetHipsAndHead && puckCount == MIN_FEET_HIPS_HEAD) {
|
||||
glm::mat4 headPuckDefaultToReferenceMat = recalculateDefaultToReferenceForHeadPuck(inputCalibration);
|
||||
glm::vec3 headXAxis = getReferenceHeadXAxis(headPuckDefaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||
glm::vec3 headPosition = getReferenceHeadPosition(headPuckDefaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||
calibrateFeet(headPuckDefaultToReferenceMat, inputCalibration, headXAxis, headPosition);
|
||||
calibrateHips(headPuckDefaultToReferenceMat, inputCalibration);
|
||||
calibrateHead(headPuckDefaultToReferenceMat, inputCalibration);
|
||||
_overrideHead = true;
|
||||
} else if (_config == Config::FeetHipsChestAndHead && puckCount == MIN_FEET_HIPS_CHEST_HEAD) {
|
||||
glm::mat4 headPuckDefaultToReferenceMat = recalculateDefaultToReferenceForHeadPuck(inputCalibration);
|
||||
glm::vec3 headXAxis = getReferenceHeadXAxis(headPuckDefaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||
glm::vec3 headPosition = getReferenceHeadPosition(headPuckDefaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||
calibrateFeet(headPuckDefaultToReferenceMat, inputCalibration, headXAxis, headPosition);
|
||||
calibrateHips(headPuckDefaultToReferenceMat, inputCalibration);
|
||||
calibrateChest(headPuckDefaultToReferenceMat, inputCalibration);
|
||||
calibrateHead(headPuckDefaultToReferenceMat, inputCalibration);
|
||||
_overrideHead = true;
|
||||
} else {
|
||||
qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks";
|
||||
uncalibrate();
|
||||
return;
|
||||
return true;
|
||||
} else if (_config == Config::FeetHipsChestAndShoulders && puckCount >= MIN_FEET_HIPS_CHEST_SHOULDERS) {
|
||||
calibrateFeet(defaultToReferenceMat, inputCalibration);
|
||||
calibrateHips(defaultToReferenceMat, inputCalibration);
|
||||
calibrateChest(defaultToReferenceMat, inputCalibration);
|
||||
int firstShoulderIndex = 4;
|
||||
int secondShoulderIndex = 5;
|
||||
calibrateShoulders(defaultToReferenceMat, inputCalibration, firstShoulderIndex, secondShoulderIndex);
|
||||
return true;
|
||||
}
|
||||
_calibrated = true;
|
||||
qDebug() << "PuckCalibration: " << configToString(_config) << " Configuration Successful";
|
||||
qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks";
|
||||
uncalibrate();
|
||||
emitCalibrationStatus(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::uncalibrate() {
|
||||
_config = Config::Auto;
|
||||
_config = Config::None;
|
||||
_pucksOffset.clear();
|
||||
_jointToPuckMap.clear();
|
||||
_calibrated = false;
|
||||
_overrideHead = false;
|
||||
_overrideHands = false;
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::updateCalibratedLimbs() {
|
||||
|
@ -439,6 +591,11 @@ void ViveControllerManager::InputDevice::updateCalibratedLimbs() {
|
|||
if (_overrideHead) {
|
||||
_poseStateMap[controller::HEAD] = addOffsetToPuckPose(controller::HEAD);
|
||||
}
|
||||
|
||||
if (_overrideHands) {
|
||||
_poseStateMap[controller::LEFT_HAND] = addOffsetToPuckPose(controller::LEFT_HAND);
|
||||
_poseStateMap[controller::RIGHT_HAND] = addOffsetToPuckPose(controller::RIGHT_HAND);
|
||||
}
|
||||
}
|
||||
|
||||
controller::Pose ViveControllerManager::InputDevice::addOffsetToPuckPose(int joint) const {
|
||||
|
@ -503,8 +660,29 @@ void ViveControllerManager::InputDevice::handleHandController(float deltaTime, u
|
|||
}
|
||||
}
|
||||
}
|
||||
glm::mat4 ViveControllerManager::InputDevice::calculateDefaultToReferenceForHmd(const controller::InputCalibrationData& inputCalibration) {
|
||||
// convert the hmd head from sensor space to avatar space
|
||||
glm::mat4 hmdSensorFlippedMat = inputCalibration.hmdSensorMat * Matrices::Y_180;
|
||||
glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat;
|
||||
glm::mat4 hmdAvatarMat = sensorToAvatarMat * hmdSensorFlippedMat;
|
||||
|
||||
glm::mat4 ViveControllerManager::InputDevice::recalculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration) {
|
||||
// cancel the roll and pitch for the hmd head
|
||||
glm::quat hmdRotation = cancelOutRollAndPitch(glmExtractRotation(hmdAvatarMat));
|
||||
glm::vec3 hmdTranslation = extractTranslation(hmdAvatarMat);
|
||||
glm::mat4 currentHmd = createMatFromQuatAndPos(hmdRotation, hmdTranslation);
|
||||
|
||||
// calculate the offset from the centerOfEye to defaultHeadMat
|
||||
glm::mat4 defaultHeadOffset = glm::inverse(inputCalibration.defaultCenterEyeMat) * inputCalibration.defaultHeadMat;
|
||||
|
||||
glm::mat4 currentHead = currentHmd * defaultHeadOffset;
|
||||
|
||||
// calculate the defaultToRefrenceXform
|
||||
glm::mat4 defaultToReferenceMat = currentHead * glm::inverse(inputCalibration.defaultHeadMat);
|
||||
|
||||
return defaultToReferenceMat;
|
||||
}
|
||||
|
||||
glm::mat4 ViveControllerManager::InputDevice::calculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration) {
|
||||
glm::mat4 avatarToSensorMat = glm::inverse(inputCalibration.sensorToWorldMat) * inputCalibration.avatarMat;
|
||||
glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat;
|
||||
size_t headPuckIndex = _validTrackedObjects.size() - 1;
|
||||
|
@ -709,33 +887,78 @@ void ViveControllerManager::InputDevice::hapticsHelper(float deltaTime, bool lef
|
|||
}
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||
auto& firstFoot = _validTrackedObjects[FIRST_FOOT];
|
||||
auto& secondFoot = _validTrackedObjects[SECOND_FOOT];
|
||||
controller::Pose& firstFootPose = firstFoot.second;
|
||||
controller::Pose& secondFootPose = secondFoot.second;
|
||||
|
||||
if (firstFootPose.translation.x < secondFootPose.translation.x) {
|
||||
_jointToPuckMap[controller::LEFT_FOOT] = firstFoot.first;
|
||||
_pucksOffset[firstFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftFoot, firstFootPose);
|
||||
_jointToPuckMap[controller::RIGHT_FOOT] = secondFoot.first;
|
||||
_pucksOffset[secondFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightFoot, secondFootPose);
|
||||
} else {
|
||||
_jointToPuckMap[controller::LEFT_FOOT] = secondFoot.first;
|
||||
_pucksOffset[secondFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftFoot, secondFootPose);
|
||||
_jointToPuckMap[controller::RIGHT_FOOT] = firstFoot.first;
|
||||
_pucksOffset[firstFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightFoot, firstFootPose);
|
||||
void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) {
|
||||
controller::Pose& handPose = handPair.second;
|
||||
glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation());
|
||||
glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat);
|
||||
glm::vec3 handPoseZAxis = glmExtractRotation(handPoseAvatarMat) * glm::vec3(0.0f, 0.0f, 1.0f);
|
||||
glm::vec3 avatarHandYAxis = transformVectorFast(inputCalibration.defaultLeftHand, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
const float EPSILON = 1.0e-4f;
|
||||
if (fabsf(fabsf(glm::dot(glm::normalize(avatarHandYAxis), glm::normalize(handPoseZAxis))) - 1.0f) < EPSILON) {
|
||||
handPoseZAxis = glm::vec3(0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
glm::vec3 zPrime = handPoseZAxis;
|
||||
glm::vec3 xPrime = glm::normalize(glm::cross(avatarHandYAxis, handPoseZAxis));
|
||||
glm::vec3 yPrime = glm::normalize(glm::cross(zPrime, xPrime));
|
||||
|
||||
glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f),
|
||||
glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
|
||||
glm::vec3 translationOffset = glm::vec3(0.0f, HAND_PUCK_Y_OFFSET, HAND_PUCK_Z_OFFSET);
|
||||
glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat);
|
||||
glm::quat finalRotation = glmExtractRotation(newHandMat);
|
||||
|
||||
glm::quat rotationOffset = glm::inverse(initialRotation) * finalRotation;
|
||||
|
||||
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
|
||||
|
||||
_jointToPuckMap[controller::LEFT_HAND] = handPair.first;
|
||||
_pucksOffset[handPair.first] = offsetMat;
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) {
|
||||
controller::Pose& handPose = handPair.second;
|
||||
glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation());
|
||||
glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat);
|
||||
glm::vec3 handPoseZAxis = glmExtractRotation(handPoseAvatarMat) * glm::vec3(0.0f, 0.0f, 1.0f);
|
||||
glm::vec3 avatarHandYAxis = transformVectorFast(inputCalibration.defaultRightHand, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
const float EPSILON = 1.0e-4f;
|
||||
if (fabsf(fabsf(glm::dot(glm::normalize(avatarHandYAxis), glm::normalize(handPoseZAxis))) - 1.0f) < EPSILON) {
|
||||
handPoseZAxis = glm::vec3(0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
glm::vec3 zPrime = handPoseZAxis;
|
||||
glm::vec3 xPrime = glm::normalize(glm::cross(avatarHandYAxis, handPoseZAxis));
|
||||
glm::vec3 yPrime = glm::normalize(glm::cross(zPrime, xPrime));
|
||||
glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f),
|
||||
glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
|
||||
|
||||
glm::vec3 translationOffset = glm::vec3(0.0f, HAND_PUCK_Y_OFFSET, HAND_PUCK_Z_OFFSET);
|
||||
glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat);
|
||||
glm::quat finalRotation = glmExtractRotation(newHandMat);
|
||||
|
||||
glm::quat rotationOffset = glm::inverse(initialRotation) * finalRotation;
|
||||
|
||||
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
|
||||
|
||||
_jointToPuckMap[controller::RIGHT_HAND] = handPair.first;
|
||||
_pucksOffset[handPair.first] = offsetMat;
|
||||
}
|
||||
|
||||
|
||||
void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, glm::vec3 headXAxis, glm::vec3 headPosition) {
|
||||
void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||
glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||
glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||
auto& firstFoot = _validTrackedObjects[FIRST_FOOT];
|
||||
auto& secondFoot = _validTrackedObjects[SECOND_FOOT];
|
||||
controller::Pose& firstFootPose = firstFoot.second;
|
||||
controller::Pose& secondFootPose = secondFoot.second;
|
||||
|
||||
if (determineFeetOrdering(firstFootPose, secondFootPose, headXAxis, headPosition)) {
|
||||
if (determineLimbOrdering(firstFootPose, secondFootPose, headXAxis, headPosition)) {
|
||||
_jointToPuckMap[controller::LEFT_FOOT] = firstFoot.first;
|
||||
_pucksOffset[firstFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftFoot, firstFootPose);
|
||||
_jointToPuckMap[controller::RIGHT_FOOT] = secondFoot.first;
|
||||
|
@ -790,32 +1013,13 @@ void ViveControllerManager::InputDevice::calibrateHead(glm::mat4& defaultToRefer
|
|||
_pucksOffset[head.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHeadMat, newHead);
|
||||
}
|
||||
|
||||
|
||||
void ViveControllerManager::InputDevice::loadSettings() {
|
||||
Settings settings;
|
||||
settings.beginGroup("PUCK_CONFIG");
|
||||
{
|
||||
_preferedConfig = (Config)settings.value("configuration", QVariant((int)Config::Auto)).toInt();
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::saveSettings() const {
|
||||
Settings settings;
|
||||
settings.beginGroup("PUCK_CONFIG");
|
||||
{
|
||||
settings.setValue(QString("configuration"), (int)_preferedConfig);
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
QString ViveControllerManager::InputDevice::configToString(Config config) {
|
||||
return _configStringMap[config];
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::setConfigFromString(const QString& value) {
|
||||
if (value == "Auto") {
|
||||
_preferedConfig = Config::Auto;
|
||||
if (value == "None") {
|
||||
_preferedConfig = Config::None;
|
||||
} else if (value == "Feet") {
|
||||
_preferedConfig = Config::Feet;
|
||||
} else if (value == "FeetAndHips") {
|
||||
|
@ -824,58 +1028,8 @@ void ViveControllerManager::InputDevice::setConfigFromString(const QString& valu
|
|||
_preferedConfig = Config::FeetHipsAndChest;
|
||||
} else if (value == "FeetHipsAndShoulders") {
|
||||
_preferedConfig = Config::FeetHipsAndShoulders;
|
||||
} else if (value == "FeetHipsChestAndHead") {
|
||||
_preferedConfig = Config::FeetHipsChestAndHead;
|
||||
} else if (value == "FeetHipsAndHead") {
|
||||
_preferedConfig = Config::FeetHipsAndHead;
|
||||
}
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::createPreferences() {
|
||||
loadSettings();
|
||||
auto preferences = DependencyManager::get<Preferences>();
|
||||
static const QString VIVE_PUCKS_CONFIG = "Vive Pucks Configuration";
|
||||
|
||||
{
|
||||
static const float MIN_VALUE = -3.0f;
|
||||
static const float MAX_VALUE = 3.0f;
|
||||
static const float STEP = 0.01f;
|
||||
|
||||
auto getter = [this]()->float { return HEAD_PUCK_Y_OFFSET; };
|
||||
auto setter = [this](const float& value) { HEAD_PUCK_Y_OFFSET = value; };
|
||||
|
||||
auto preference = new SpinnerPreference(VIVE_PUCKS_CONFIG, "HeadPuckYOffset", getter, setter);
|
||||
preference->setMin(MIN_VALUE);
|
||||
preference->setMax(MAX_VALUE);
|
||||
preference->setDecimals(3);
|
||||
preference->setStep(STEP);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
static const float MIN_VALUE = -3.0f;
|
||||
static const float MAX_VALUE = 3.0f;
|
||||
static const float STEP = 0.01f;
|
||||
|
||||
auto getter = [this]()->float { return HEAD_PUCK_Z_OFFSET; };
|
||||
auto setter = [this](const float& value) { HEAD_PUCK_Z_OFFSET = value; };
|
||||
|
||||
auto preference = new SpinnerPreference(VIVE_PUCKS_CONFIG, "HeadPuckXOffset", getter, setter);
|
||||
preference->setMin(MIN_VALUE);
|
||||
preference->setMax(MAX_VALUE);
|
||||
preference->setStep(STEP);
|
||||
preference->setDecimals(3);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = [this]()->QString { return _configStringMap[_preferedConfig]; };
|
||||
auto setter = [this](const QString& value) { setConfigFromString(value); saveSettings(); };
|
||||
auto preference = new ComboBoxPreference(VIVE_PUCKS_CONFIG, "Configuration", getter, setter);
|
||||
QStringList list = {"Auto", "Feet", "FeetAndHips", "FeetHipsAndChest", "FeetHipsAndShoulders", "FeetHipsAndHead"};
|
||||
preference->setItems(list);
|
||||
preferences->addPreference(preference);
|
||||
|
||||
} else if (value == "FeetHipsChestAndShoulders") {
|
||||
_preferedConfig = Config::FeetHipsChestAndShoulders;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,13 @@ public:
|
|||
const QString getName() const override { return NAME; }
|
||||
|
||||
bool isHandController() const override { return true; }
|
||||
bool configurable() override { return true; }
|
||||
|
||||
QString configurationLayout() override;
|
||||
void setConfigurationSettings(const QJsonObject configurationSettings) override;
|
||||
QJsonObject configurationSettings() override;
|
||||
void calibrate() override;
|
||||
bool uncalibrate() override;
|
||||
bool isHeadController() const override { return true; }
|
||||
bool isHeadControllerMounted() const;
|
||||
|
||||
|
@ -61,14 +68,16 @@ private:
|
|||
QString getDefaultMappingConfig() const override;
|
||||
void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
|
||||
void focusOutEvent() override;
|
||||
void createPreferences();
|
||||
bool triggerHapticPulse(float strength, float duration, controller::Hand hand) override;
|
||||
void hapticsHelper(float deltaTime, bool leftHand);
|
||||
void calibrateOrUncalibrate(const controller::InputCalibrationData& inputCalibration);
|
||||
void calibrate(const controller::InputCalibrationData& inputCalibration);
|
||||
void uncalibrate();
|
||||
void configureCalibrationSettings(const QJsonObject configurationSettings);
|
||||
QJsonObject configurationSettings();
|
||||
controller::Pose addOffsetToPuckPose(int joint) const;
|
||||
glm::mat4 recalculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration);
|
||||
glm::mat4 calculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration);
|
||||
glm::mat4 calculateDefaultToReferenceForHmd(const controller::InputCalibrationData& inputCalibration);
|
||||
void updateCalibratedLimbs();
|
||||
bool checkForCalibrationEvent();
|
||||
void handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand);
|
||||
|
@ -83,16 +92,21 @@ private:
|
|||
void partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPsuedoButton, int xPseudoButton, int yPseudoButton);
|
||||
void printDeviceTrackingResultChange(uint32_t deviceIndex);
|
||||
void setConfigFromString(const QString& value);
|
||||
void loadSettings();
|
||||
void saveSettings() const;
|
||||
bool configureHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||
bool configureHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||
bool configureBody(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||
void calibrateLeftHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair);
|
||||
void calibrateRightHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair);
|
||||
void calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||
void calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, glm::vec3 headXAxis, glm::vec3 headPosition);
|
||||
void calibrateHips(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||
void calibrateChest(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||
|
||||
void calibrateShoulders(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration,
|
||||
int firstShoulderIndex, int secondShoulderIndex);
|
||||
void calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||
void calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData);
|
||||
void calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData);
|
||||
void emitCalibrationStatus(const bool success);
|
||||
void calibrateNextFrame();
|
||||
|
||||
|
||||
class FilteredStick {
|
||||
|
@ -119,16 +133,28 @@ private:
|
|||
glm::vec2 _stick { 0.0f, 0.0f };
|
||||
};
|
||||
enum class Config {
|
||||
Auto,
|
||||
None,
|
||||
Feet,
|
||||
FeetAndHips,
|
||||
FeetHipsAndChest,
|
||||
FeetHipsAndShoulders,
|
||||
FeetHipsChestAndHead,
|
||||
FeetHipsAndHead
|
||||
FeetHipsChestAndShoulders,
|
||||
};
|
||||
Config _config { Config::Auto };
|
||||
Config _preferedConfig { Config::Auto };
|
||||
|
||||
enum class HeadConfig {
|
||||
HMD,
|
||||
Puck
|
||||
};
|
||||
|
||||
enum class HandConfig {
|
||||
HandController,
|
||||
Pucks
|
||||
};
|
||||
|
||||
Config _config { Config::None };
|
||||
Config _preferedConfig { Config::None };
|
||||
HeadConfig _headConfig { HeadConfig::HMD };
|
||||
HandConfig _handConfig { HandConfig::HandController };
|
||||
FilteredStick _filteredLeftStick;
|
||||
FilteredStick _filteredRightStick;
|
||||
|
||||
|
@ -152,7 +178,9 @@ private:
|
|||
bool _triggersPressedHandled { false };
|
||||
bool _calibrated { false };
|
||||
bool _timeTilCalibrationSet { false };
|
||||
bool _calibrate { false };
|
||||
bool _overrideHead { false };
|
||||
bool _overrideHands { false };
|
||||
mutable std::recursive_mutex _lock;
|
||||
|
||||
QString configToString(Config config);
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
|
||||
set(TARGET_NAME pcmCodec)
|
||||
setup_hifi_client_server_plugin()
|
||||
link_hifi_libraries(shared plugins)
|
||||
link_hifi_libraries(shared plugins input-plugins display-plugins)
|
||||
install_beside_console()
|
||||
|
||||
|
|
Loading…
Reference in a new issue