Merge branch 'vive-ui' of https://github.com/highfidelity/hifi into vive-ui

This commit is contained in:
howard-stearns 2016-06-08 10:50:03 -07:00
commit bd24a07750
33 changed files with 616 additions and 267 deletions

View file

@ -9,6 +9,8 @@
"to": "Actions.StepYaw", "to": "Actions.StepYaw",
"filters": "filters":
[ [
{ "type": "deadZone", "min": 0.15 },
"constrainToInteger",
{ "type": "pulse", "interval": 0.5 }, { "type": "pulse", "interval": 0.5 },
{ "type": "scale", "scale": 22.5 } { "type": "scale", "scale": 22.5 }
] ]

View file

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.49;}
.st1{fill:#1E1E1E;}
.st2{opacity:0.5;}
.st3{fill:#EAEAEA;}
.st4{fill:#FFFFFF;}
</style>
<g class="st0">
<path class="st1" d="M50,146c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V146z"/>
</g>
<g class="st2">
<g>
<path class="st3" d="M25.1,109.5c-4.2,0-8,1.8-10.8,4.8c0,0-0.5,0.7,0.2,1.2c0.7,0.6,1.4-0.1,1.4-0.1c2.4-2.4,5.7-3.9,9.2-3.9
c3.6,0,6.9,1.5,9.3,4.1c0,0,0.7,0.8,1.5,0.3c0.7-0.4,0.2-1.2,0.2-1.3C33.3,111.4,29.4,109.5,25.1,109.5z"/>
<path class="st3" d="M35.4,116.3c-0.2,0-0.4,0-0.5-0.1c-0.2-0.1-0.5-0.3-0.6-0.4l0,0c-2.5-2.6-5.7-4-9.2-4c-3.4,0-6.6,1.4-9.1,3.9
l0,0c-0.1,0.1-0.3,0.2-0.4,0.3c-0.5,0.2-0.9,0.2-1.3-0.2c-0.6-0.5-0.4-1.1-0.3-1.4c0-0.1,0.1-0.1,0.1-0.2l0,0
c2.9-3.1,6.8-4.9,10.9-4.9c4.2,0,8.2,1.8,11.2,5.1c0.1,0.1,0.3,0.5,0.2,0.9c0,0.3-0.2,0.6-0.5,0.8
C35.9,116.2,35.6,116.3,35.4,116.3z M34.7,115.4c0.1,0.1,0.6,0.6,1.1,0.2c0.1-0.1,0.2-0.2,0.2-0.3c0-0.3-0.1-0.5-0.1-0.6
c-2.9-3.2-6.7-5-10.8-5c-4,0-7.7,1.7-10.6,4.7c-0.1,0.1-0.3,0.5,0.1,0.9c0.5,0.4,1,0,1.1-0.1c2.6-2.6,5.9-4,9.4-4
C28.7,111.2,32.1,112.7,34.7,115.4L34.7,115.4z M36,114.7C36,114.7,36,114.7,36,114.7L36,114.7z M35.9,114.7
C35.9,114.7,35.9,114.7,35.9,114.7L35.9,114.7z"/>
</g>
<path class="st3" d="M27.3,116l-1.5-0.9c-0.3-0.2-0.7-0.2-1,0l-1.5,0.9c-0.3,0.2-0.5,0.5-0.5,0.9l0,1.8c0,0.4,0.2,0.7,0.5,0.9
l1.5,0.9c0.2,0.1,0.3,0.1,0.5,0.1c0.2,0,0.4,0,0.5-0.1l1.5-0.9c0.3-0.2,0.5-0.5,0.5-0.9l0-1.8C27.8,116.5,27.6,116.2,27.3,116z"/>
<path class="st3" d="M31.2,125l-1.2-1.5c-0.2-0.3-0.5-0.4-0.8-0.4l-7.9,0c0,0,0,0,0,0c-0.3,0-0.6,0.1-0.8,0.4l-1.2,1.5
c-0.3,0.4-0.3,0.9,0,1.3l1.2,1.5c0.2,0.3,0.5,0.4,0.8,0.4l7.9,0c0,0,0,0,0,0c0.3,0,0.6-0.1,0.8-0.4l1.2-1.5
C31.5,126,31.5,125.4,31.2,125z"/>
</g>
<g class="st2">
<path class="st3" d="M19.2,135.5v6.4H18v-2.7h-2.9v2.7h-1.2v-6.4h1.2v2.6H18v-2.6H19.2z"/>
<path class="st3" d="M25.4,141c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.5-0.5c0.1-0.2,0.2-0.4,0.3-0.7c0.1-0.3,0.1-0.5,0.1-0.8
v-3.4h1.3v3.4c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.3,0.7-0.5,1c-0.2,0.3-0.5,0.5-0.9,0.7c-0.4,0.2-0.8,0.3-1.3,0.3
c-0.5,0-1-0.1-1.4-0.3c-0.4-0.2-0.7-0.4-0.9-0.7c-0.2-0.3-0.4-0.6-0.5-1c-0.1-0.4-0.2-0.8-0.2-1.2v-3.4h1.3v3.4
c0,0.3,0,0.5,0.1,0.8c0.1,0.3,0.1,0.5,0.3,0.7c0.1,0.2,0.3,0.4,0.5,0.5S25.1,141,25.4,141z"/>
<path class="st3" d="M31.7,141.9v-6.4H34c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.4,1,0.7c0.3,0.3,0.5,0.6,0.6,1
c0.1,0.4,0.2,0.8,0.2,1.2c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.4,0.7-0.6,1c-0.3,0.3-0.6,0.5-1,0.6c-0.4,0.2-0.8,0.2-1.3,0.2H31.7z
M35.9,138.7c0-0.3,0-0.6-0.1-0.8c-0.1-0.3-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.6-0.4c-0.2-0.1-0.5-0.2-0.8-0.2h-1.1v4.2H34
c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.6-0.4c0.2-0.2,0.3-0.4,0.4-0.7C35.8,139.3,35.9,139,35.9,138.7z"/>
</g>
<g>
<path class="st1" d="M50,96c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4V54c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V96z"/>
</g>
<g>
<g>
<path class="st3" d="M25.1,59.5c-4.2,0-8,1.8-10.8,4.8c0,0-0.5,0.7,0.2,1.2c0.7,0.6,1.4-0.1,1.4-0.1c2.4-2.4,5.7-3.9,9.2-3.9
c3.6,0,6.9,1.5,9.3,4.1c0,0,0.7,0.8,1.5,0.3c0.7-0.4,0.2-1.2,0.2-1.3C33.3,61.5,29.4,59.5,25.1,59.5z"/>
<path class="st3" d="M35.4,66.3c-0.2,0-0.4,0-0.5-0.1c-0.2-0.1-0.5-0.3-0.6-0.4l0,0c-2.5-2.6-5.7-4-9.2-4c-3.4,0-6.6,1.4-9.1,3.9
l0,0c-0.1,0.1-0.3,0.2-0.4,0.3c-0.5,0.2-0.9,0.2-1.3-0.2c-0.6-0.5-0.4-1.1-0.3-1.4c0-0.1,0.1-0.1,0.1-0.2l0,0
c2.9-3.1,6.8-4.9,10.9-4.9c4.2,0,8.2,1.8,11.2,5.1c0.1,0.1,0.3,0.5,0.2,0.9c0,0.3-0.2,0.6-0.5,0.8C35.9,66.2,35.6,66.3,35.4,66.3z
M34.7,65.5c0.1,0.1,0.6,0.6,1.1,0.2c0.1-0.1,0.2-0.2,0.2-0.3c0-0.3-0.1-0.5-0.1-0.6c-2.9-3.2-6.7-5-10.8-5c-4,0-7.7,1.7-10.6,4.7
c-0.1,0.1-0.3,0.5,0.1,0.9c0.5,0.4,1,0,1.1-0.1c2.6-2.6,5.9-4,9.4-4C28.7,61.3,32.1,62.7,34.7,65.5L34.7,65.5z M36,64.7
C36,64.7,36,64.7,36,64.7L36,64.7z M35.9,64.7C35.9,64.7,35.9,64.7,35.9,64.7L35.9,64.7z"/>
</g>
<path class="st3" d="M27.3,66l-1.5-0.9c-0.3-0.2-0.7-0.2-1,0L23.2,66c-0.3,0.2-0.5,0.5-0.5,0.9l0,1.8c0,0.4,0.2,0.7,0.5,0.9
l1.5,0.9c0.2,0.1,0.3,0.1,0.5,0.1c0.2,0,0.4,0,0.5-0.1l1.5-0.9c0.3-0.2,0.5-0.5,0.5-0.9l0-1.8C27.8,66.5,27.6,66.2,27.3,66z"/>
<path class="st3" d="M31.2,75.1L30,73.5c-0.2-0.3-0.5-0.4-0.8-0.4l-7.9,0c0,0,0,0,0,0c-0.3,0-0.6,0.1-0.8,0.4l-1.2,1.5
c-0.3,0.4-0.3,0.9,0,1.3l1.2,1.5c0.2,0.3,0.5,0.4,0.8,0.4l7.9,0c0,0,0,0,0,0c0.3,0,0.6-0.1,0.8-0.4l1.2-1.5
C31.5,76,31.5,75.5,31.2,75.1z"/>
</g>
<g>
<path class="st3" d="M19.2,85.5v6.4H18v-2.7h-2.9v2.7h-1.2v-6.4h1.2v2.6H18v-2.6H19.2z"/>
<path class="st3" d="M25.4,91c0.3,0,0.6-0.1,0.8-0.2s0.4-0.3,0.5-0.5c0.1-0.2,0.2-0.4,0.3-0.7s0.1-0.5,0.1-0.8v-3.4h1.3v3.4
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.3,0.7-0.5,1c-0.2,0.3-0.5,0.5-0.9,0.7c-0.4,0.2-0.8,0.3-1.3,0.3c-0.5,0-1-0.1-1.4-0.3
c-0.4-0.2-0.7-0.4-0.9-0.7c-0.2-0.3-0.4-0.6-0.5-1c-0.1-0.4-0.2-0.8-0.2-1.2v-3.4h1.3v3.4c0,0.3,0,0.5,0.1,0.8
c0.1,0.3,0.1,0.5,0.3,0.7c0.1,0.2,0.3,0.4,0.5,0.5S25.1,91,25.4,91z"/>
<path class="st3" d="M31.7,91.9v-6.4H34c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.4,1,0.7c0.3,0.3,0.5,0.6,0.6,1c0.1,0.4,0.2,0.8,0.2,1.2
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.4,0.7-0.6,1c-0.3,0.3-0.6,0.5-1,0.6c-0.4,0.2-0.8,0.2-1.3,0.2H31.7z M35.9,88.7
c0-0.3,0-0.6-0.1-0.8c-0.1-0.3-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.6-0.4c-0.2-0.1-0.5-0.2-0.8-0.2h-1.1v4.2H34
c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.6-0.4c0.2-0.2,0.3-0.4,0.4-0.7C35.8,89.3,35.9,89,35.9,88.7z"/>
</g>
<g>
<path class="st4" d="M50,46.1c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V46.1z"/>
</g>
<g>
<g>
<path d="M25.1,9.6c-4.2,0-8,1.8-10.8,4.8c0,0-0.5,0.7,0.2,1.2c0.7,0.6,1.4-0.1,1.4-0.1c2.4-2.4,5.7-3.9,9.2-3.9
c3.6,0,6.9,1.5,9.3,4.1c0,0,0.7,0.8,1.5,0.3c0.7-0.4,0.2-1.2,0.2-1.3C33.3,11.5,29.4,9.6,25.1,9.6z"/>
<path d="M35.4,16.3c-0.2,0-0.4,0-0.5-0.1c-0.2-0.1-0.5-0.3-0.6-0.4l0,0c-2.5-2.6-5.7-4-9.2-4c-3.4,0-6.6,1.4-9.1,3.9l0,0
c-0.1,0.1-0.3,0.2-0.4,0.3c-0.5,0.2-0.9,0.2-1.3-0.2c-0.6-0.5-0.4-1.1-0.3-1.4c0-0.1,0.1-0.1,0.1-0.2l0,0
c2.9-3.1,6.8-4.9,10.9-4.9c4.2,0,8.2,1.8,11.2,5.1c0.1,0.1,0.3,0.5,0.2,0.9c0,0.3-0.2,0.6-0.5,0.8C35.9,16.3,35.6,16.3,35.4,16.3z
M34.7,15.5c0.1,0.1,0.6,0.6,1.1,0.2c0.1-0.1,0.2-0.2,0.2-0.3c0-0.3-0.1-0.5-0.1-0.6c-2.9-3.2-6.7-5-10.8-5c-4,0-7.7,1.7-10.6,4.7
c-0.1,0.1-0.3,0.5,0.1,0.9c0.5,0.4,1,0,1.1-0.1c2.6-2.6,5.9-4,9.4-4C28.7,11.3,32.1,12.8,34.7,15.5L34.7,15.5z M36,14.8
C36,14.8,36,14.8,36,14.8L36,14.8z M35.9,14.8C35.9,14.8,35.9,14.8,35.9,14.8L35.9,14.8z"/>
</g>
<path d="M27.3,16l-1.5-0.9c-0.3-0.2-0.7-0.2-1,0L23.2,16c-0.3,0.2-0.5,0.5-0.5,0.9l0,1.8c0,0.4,0.2,0.7,0.5,0.9l1.5,0.9
c0.2,0.1,0.3,0.1,0.5,0.1c0.2,0,0.4,0,0.5-0.1l1.5-0.9c0.3-0.2,0.5-0.5,0.5-0.9l0-1.8C27.8,16.6,27.6,16.2,27.3,16z"/>
<path d="M31.2,25.1L30,23.6c-0.2-0.3-0.5-0.4-0.8-0.4l-7.9,0c0,0,0,0,0,0c-0.3,0-0.6,0.1-0.8,0.4l-1.2,1.5c-0.3,0.4-0.3,0.9,0,1.3
l1.2,1.5c0.2,0.3,0.5,0.4,0.8,0.4l7.9,0c0,0,0,0,0,0c0.3,0,0.6-0.1,0.8-0.4l1.2-1.5C31.5,26,31.5,25.5,31.2,25.1z"/>
</g>
<g>
<path d="M19.2,35.6V42H18v-2.7h-2.9V42h-1.2v-6.4h1.2v2.6H18v-2.6H19.2z"/>
<path d="M25.4,41c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.5-0.5c0.1-0.2,0.2-0.4,0.3-0.7c0.1-0.3,0.1-0.5,0.1-0.8v-3.4h1.3v3.4
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.3,0.7-0.5,1c-0.2,0.3-0.5,0.5-0.9,0.7c-0.4,0.2-0.8,0.3-1.3,0.3c-0.5,0-1-0.1-1.4-0.3
c-0.4-0.2-0.7-0.4-0.9-0.7c-0.2-0.3-0.4-0.6-0.5-1c-0.1-0.4-0.2-0.8-0.2-1.2v-3.4h1.3v3.4c0,0.3,0,0.5,0.1,0.8
c0.1,0.3,0.1,0.5,0.3,0.7c0.1,0.2,0.3,0.4,0.5,0.5C24.9,41,25.1,41,25.4,41z"/>
<path d="M31.7,42v-6.4H34c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.4,1,0.7c0.3,0.3,0.5,0.6,0.6,1c0.1,0.4,0.2,0.8,0.2,1.2
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.4,0.7-0.6,1c-0.3,0.3-0.6,0.5-1,0.6C34.9,41.9,34.5,42,34,42H31.7z M35.9,38.8
c0-0.3,0-0.6-0.1-0.8c-0.1-0.3-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.6-0.4c-0.2-0.1-0.5-0.2-0.8-0.2h-1.1v4.2H34
c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.6-0.4c0.2-0.2,0.3-0.4,0.4-0.7C35.8,39.3,35.9,39.1,35.9,38.8z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -299,7 +299,7 @@ FocusScope {
if (pinned) { if (pinned) {
// recalculate our non-pinned children // recalculate our non-pinned children
hiddenChildren = d.findMatchingChildren(desktop, function(child){ hiddenChildren = d.findMatchingChildren(desktop, function(child){
return !d.isTopLevelWindow(child) && child.visible; return !d.isTopLevelWindow(child) && child.visible && !child.pinned;
}); });
hiddenChildren.forEach(function(child){ hiddenChildren.forEach(function(child){

View file

@ -4,11 +4,13 @@ import QtWebEngine 1.1;
import "../desktop" import "../desktop"
import ".." import ".."
import "."
Desktop { Desktop {
id: desktop id: desktop
MouseArea { MouseArea {
id: hoverWatch
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
propagateComposedEvents: true propagateComposedEvents: true
@ -47,7 +49,12 @@ Desktop {
} }
} }
ToggleHudButton {
anchors.bottom: parent.bottom
anchors.bottomMargin: 32
anchors.horizontalCenter: parent.horizontalCenter
}
} }

View file

@ -0,0 +1,36 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import "../windows"
Window {
//frame: HiddenFrame {}
hideBackground: true
resizable: false
destroyOnCloseButton: false
destroyOnHidden: false
closable: false
shown: true
pinned: true
width: 50
height: 50
clip: true
visible: true
Item {
width: 50
height: 50
Image {
y: desktop.pinned ? -50 : 0
id: hudToggleImage
source: "../../icons/hud-01.svg"
}
MouseArea {
readonly property string overlayMenuItem: "Overlays"
anchors.fill: parent
onClicked: MenuInterface.setIsOptionChecked(overlayMenuItem, !MenuInterface.isOptionChecked(overlayMenuItem))
}
}
}

View file

@ -23,9 +23,9 @@ Window {
title: "Running Scripts" title: "Running Scripts"
resizable: true resizable: true
destroyOnHidden: true destroyOnHidden: true
implicitWidth: 400 implicitWidth: 424
implicitHeight: isHMD ? 695 : 728 implicitHeight: isHMD ? 695 : 728
minSize: Qt.vector2d(200, 300) minSize: Qt.vector2d(424, 300)
HifiConstants { id: hifi } HifiConstants { id: hifi }
@ -86,6 +86,11 @@ Window {
scripts.reloadAllScripts(); scripts.reloadAllScripts();
} }
function loadDefaults() {
console.log("Load default scripts");
scripts.loadOneScript(scripts.defaultScriptsPath + "/defaultScripts.js");
}
function stopAll() { function stopAll() {
console.log("Stop all scripts"); console.log("Stop all scripts");
scripts.stopAllScripts(); scripts.stopAllScripts();
@ -104,13 +109,13 @@ Window {
spacing: hifi.dimensions.contentSpacing.x spacing: hifi.dimensions.contentSpacing.x
HifiControls.Button { HifiControls.Button {
text: "Reload all" text: "Reload All"
color: hifi.buttons.black color: hifi.buttons.black
onClicked: reloadAll() onClicked: reloadAll()
} }
HifiControls.Button { HifiControls.Button {
text: "Stop all" text: "Remove All"
color: hifi.buttons.red color: hifi.buttons.red
onClicked: stopAll() onClicked: stopAll()
} }
@ -218,7 +223,6 @@ Window {
Row { Row {
spacing: hifi.dimensions.contentSpacing.x spacing: hifi.dimensions.contentSpacing.x
anchors.right: parent.right
HifiControls.Button { HifiControls.Button {
text: "from URL" text: "from URL"
@ -256,6 +260,12 @@ Window {
onTriggered: ApplicationInterface.loadDialog(); onTriggered: ApplicationInterface.loadDialog();
} }
} }
HifiControls.Button {
text: "Load Defaults"
color: hifi.buttons.black
onClicked: loadDefaults()
}
} }
HifiControls.VerticalSpacer {} HifiControls.VerticalSpacer {}

View file

@ -19,6 +19,7 @@
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <QtCore/QAbstractNativeEventFilter> #include <QtCore/QAbstractNativeEventFilter>
#include <QtCore/QCommandLineParser>
#include <QtCore/QMimeData> #include <QtCore/QMimeData>
#include <QtCore/QThreadPool> #include <QtCore/QThreadPool>
@ -197,7 +198,6 @@ static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check f
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
static const QString INPUT_DEVICE_MENU_PREFIX = "Device: ";
Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS);
const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions { const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {
@ -999,7 +999,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get()); RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get());
if (webEntity) { if (webEntity) {
webEntity->setProxyWindow(_window->windowHandle()); webEntity->setProxyWindow(_window->windowHandle());
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->pluginFocusOutEvent(); _keyboardMouseDevice->pluginFocusOutEvent();
} }
_keyboardFocusedItem = entityItemID; _keyboardFocusedItem = entityItemID;
@ -1152,9 +1152,7 @@ void Application::aboutToQuit() {
emit beforeAboutToQuit(); emit beforeAboutToQuit();
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); if (inputPlugin->isActive()) {
QAction* action = Menu::getInstance()->getActionForOption(name);
if (action->isChecked()) {
inputPlugin->deactivate(); inputPlugin->deactivate();
} }
} }
@ -1418,7 +1416,7 @@ void Application::initializeUi() {
rootContext->setContextProperty("Overlays", &_overlays); rootContext->setContextProperty("Overlays", &_overlays);
rootContext->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data()); rootContext->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
rootContext->setContextProperty("Menu", MenuScriptingInterface::getInstance()); rootContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
rootContext->setContextProperty("Stats", Stats::getInstance()); rootContext->setContextProperty("Stats", Stats::getInstance());
rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data()); rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
@ -1476,7 +1474,6 @@ void Application::initializeUi() {
} }
} }
_window->setMenuBar(new Menu()); _window->setMenuBar(new Menu());
updateInputModes();
auto compositorHelper = DependencyManager::get<CompositorHelper>(); auto compositorHelper = DependencyManager::get<CompositorHelper>();
connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, [=] { connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, [=] {
@ -2024,7 +2021,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
} }
if (hasFocus()) { if (hasFocus()) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->keyPressEvent(event); _keyboardMouseDevice->keyPressEvent(event);
} }
@ -2359,7 +2356,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->keyReleaseEvent(event); _keyboardMouseDevice->keyReleaseEvent(event);
} }
@ -2391,9 +2388,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
void Application::focusOutEvent(QFocusEvent* event) { void Application::focusOutEvent(QFocusEvent* event) {
auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
foreach(auto inputPlugin, inputPlugins) { foreach(auto inputPlugin, inputPlugins) {
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); if (inputPlugin->isActive()) {
QAction* action = Menu::getInstance()->getActionForOption(name);
if (action && action->isChecked()) {
inputPlugin->pluginFocusOutEvent(); inputPlugin->pluginFocusOutEvent();
} }
} }
@ -2478,7 +2473,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->mouseMoveEvent(event); _keyboardMouseDevice->mouseMoveEvent(event);
} }
@ -2515,7 +2510,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
if (hasFocus()) { if (hasFocus()) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->mousePressEvent(event); _keyboardMouseDevice->mousePressEvent(event);
} }
@ -2560,7 +2555,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
} }
if (hasFocus()) { if (hasFocus()) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->mouseReleaseEvent(event); _keyboardMouseDevice->mouseReleaseEvent(event);
} }
@ -2587,7 +2582,7 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->touchUpdateEvent(event); _keyboardMouseDevice->touchUpdateEvent(event);
} }
} }
@ -2605,7 +2600,7 @@ void Application::touchBeginEvent(QTouchEvent* event) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->touchBeginEvent(event); _keyboardMouseDevice->touchBeginEvent(event);
} }
@ -2622,7 +2617,7 @@ void Application::touchEndEvent(QTouchEvent* event) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->touchEndEvent(event); _keyboardMouseDevice->touchEndEvent(event);
} }
@ -2638,7 +2633,7 @@ void Application::wheelEvent(QWheelEvent* event) const {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->wheelEvent(event); _keyboardMouseDevice->wheelEvent(event);
} }
} }
@ -2771,9 +2766,7 @@ void Application::idle(float nsecsElapsed) {
getActiveDisplayPlugin()->idle(); getActiveDisplayPlugin()->idle();
auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
foreach(auto inputPlugin, inputPlugins) { foreach(auto inputPlugin, inputPlugins) {
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); if (inputPlugin->isActive()) {
QAction* action = Menu::getInstance()->getActionForOption(name);
if (action && action->isChecked()) {
inputPlugin->idle(); inputPlugin->idle();
} }
} }
@ -2957,6 +2950,27 @@ void Application::loadSettings() {
//DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false); //DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false);
Menu::getInstance()->loadSettings(); Menu::getInstance()->loadSettings();
// If there is a preferred plugin, we probably messed it up with the menu settings, so fix it.
auto pluginManager = PluginManager::getInstance();
auto plugins = pluginManager->getPreferredDisplayPlugins();
for (auto plugin : plugins) {
auto menu = Menu::getInstance();
if (auto action = menu->getActionForOption(plugin->getName())) {
action->setChecked(true);
action->trigger();
// Find and activated highest priority plugin, bail for the rest
break;
}
}
auto inputs = pluginManager->getInputPlugins();
for (auto plugin : inputs) {
if (!plugin->isActive()) {
plugin->activate();
}
}
getMyAvatar()->loadData(); getMyAvatar()->loadData();
_settingsLoaded = true; _settingsLoaded = true;
@ -4937,7 +4951,34 @@ void Application::postLambdaEvent(std::function<void()> f) {
} }
} }
void Application::initPlugins() { void Application::initPlugins(const QStringList& arguments) {
QCommandLineOption display("display", "Preferred displays", "displays");
QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "displays");
QCommandLineOption disableInputs("disable-inputs", "Inputs to disable", "inputs");
QCommandLineParser parser;
parser.addOption(display);
parser.addOption(disableDisplays);
parser.addOption(disableInputs);
parser.parse(arguments);
if (parser.isSet(display)) {
auto preferredDisplays = parser.value(display).split(',', QString::SkipEmptyParts);
qInfo() << "Setting prefered display plugins:" << preferredDisplays;
PluginManager::getInstance()->setPreferredDisplayPlugins(preferredDisplays);
}
if (parser.isSet(disableDisplays)) {
auto disabledDisplays = parser.value(disableDisplays).split(',', QString::SkipEmptyParts);
qInfo() << "Disabling following display plugins:" << disabledDisplays;
PluginManager::getInstance()->disableDisplays(disabledDisplays);
}
if (parser.isSet(disableInputs)) {
auto disabledInputs = parser.value(disableInputs).split(',', QString::SkipEmptyParts);
qInfo() << "Disabling following input plugins:" << disabledInputs;
PluginManager::getInstance()->disableInputs(disabledInputs);
}
} }
void Application::shutdownPlugins() { void Application::shutdownPlugins() {
@ -5207,81 +5248,6 @@ void Application::updateDisplayMode() {
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
} }
static void addInputPluginToMenu(InputPluginPointer inputPlugin) {
auto menu = Menu::getInstance();
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
Q_ASSERT(!menu->menuItemExists(MenuOption::InputMenu, name));
static QActionGroup* inputPluginGroup = nullptr;
if (!inputPluginGroup) {
inputPluginGroup = new QActionGroup(menu);
inputPluginGroup->setExclusive(false);
}
auto parent = menu->getMenu(MenuOption::InputMenu);
auto action = menu->addCheckableActionToQMenuAndActionHash(parent,
name, 0, true, qApp,
SLOT(updateInputModes()));
inputPluginGroup->addAction(action);
Q_ASSERT(menu->menuItemExists(MenuOption::InputMenu, name));
}
void Application::updateInputModes() {
auto menu = Menu::getInstance();
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
static std::once_flag once;
std::call_once(once, [&] {
foreach(auto inputPlugin, inputPlugins) {
addInputPluginToMenu(inputPlugin);
}
});
auto offscreenUi = DependencyManager::get<OffscreenUi>();
InputPluginList newInputPlugins;
InputPluginList removedInputPlugins;
foreach(auto inputPlugin, inputPlugins) {
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
QAction* action = menu->getActionForOption(name);
auto it = std::find(std::begin(_activeInputPlugins), std::end(_activeInputPlugins), inputPlugin);
if (action->isChecked() && it == std::end(_activeInputPlugins)) {
_activeInputPlugins.push_back(inputPlugin);
newInputPlugins.push_back(inputPlugin);
} else if (!action->isChecked() && it != std::end(_activeInputPlugins)) {
_activeInputPlugins.erase(it);
removedInputPlugins.push_back(inputPlugin);
}
}
// A plugin was checked
if (newInputPlugins.size() > 0) {
foreach(auto newInputPlugin, newInputPlugins) {
newInputPlugin->activate();
//newInputPlugin->installEventFilter(qApp);
//newInputPlugin->installEventFilter(offscreenUi.data());
}
}
if (removedInputPlugins.size() > 0) { // A plugin was unchecked
foreach(auto removedInputPlugin, removedInputPlugins) {
removedInputPlugin->deactivate();
//removedInputPlugin->removeEventFilter(qApp);
//removedInputPlugin->removeEventFilter(offscreenUi.data());
}
}
//if (newInputPlugins.size() > 0 || removedInputPlugins.size() > 0) {
// if (!_currentInputPluginActions.isEmpty()) {
// auto menu = Menu::getInstance();
// foreach(auto itemInfo, _currentInputPluginActions) {
// menu->removeMenuItem(itemInfo.first, itemInfo.second);
// }
// _currentInputPluginActions.clear();
// }
//}
}
mat4 Application::getEyeProjection(int eye) const { mat4 Application::getEyeProjection(int eye) const {
QMutexLocker viewLocker(&_viewMutex); QMutexLocker viewLocker(&_viewMutex);
if (isHMDMode()) { if (isHMDMode()) {

View file

@ -101,7 +101,7 @@ public:
}; };
// FIXME? Empty methods, do we still need them? // FIXME? Empty methods, do we still need them?
static void initPlugins(); static void initPlugins(const QStringList& arguments);
static void shutdownPlugins(); static void shutdownPlugins();
Application(int& argc, char** argv, QElapsedTimer& startup_time); Application(int& argc, char** argv, QElapsedTimer& startup_time);
@ -327,7 +327,6 @@ private slots:
void nodeKilled(SharedNodePointer node); void nodeKilled(SharedNodePointer node);
static void packetSent(quint64 length); static void packetSent(quint64 length);
void updateDisplayMode(); void updateDisplayMode();
void updateInputModes();
void domainConnectionRefused(const QString& reasonMessage, int reason); void domainConnectionRefused(const QString& reasonMessage, int reason);
private: private:

View file

@ -403,12 +403,6 @@ Menu::Menu() {
// Developer > Avatar >>> // Developer > Avatar >>>
MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar"); MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar");
// Settings > Input Devices
MenuWrapper* inputModeMenu = addMenu(MenuOption::InputMenu, "Advanced");
QActionGroup* inputModeGroup = new QActionGroup(inputModeMenu);
inputModeGroup->setExclusive(false);
// Developer > Avatar > Face Tracking // Developer > Avatar > Face Tracking
MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking"); MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking");
{ {

View file

@ -113,7 +113,6 @@ namespace MenuOption {
const QString Help = "Help..."; const QString Help = "Help...";
const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode"; const QString IndependentMode = "Independent Mode";
const QString InputMenu = "Developer>Avatar>Input Devices";
const QString ActionMotorControl = "Enable Default Motor Control"; const QString ActionMotorControl = "Enable Default Motor Control";
const QString LeapMotionOnHMD = "Leap Motion on HMD"; const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File..."; const QString LoadScript = "Open and Run Script File...";

View file

@ -46,6 +46,12 @@ int main(int argc, const char* argv[]) {
bool instanceMightBeRunning = true; bool instanceMightBeRunning = true;
QStringList arguments;
for (int i = 0; i < argc; ++i) {
arguments << argv[i];
}
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
// Try to create a shared memory block - if it can't be created, there is an instance of // Try to create a shared memory block - if it can't be created, there is an instance of
// interface already running. We only do this on Windows for now because of the potential // interface already running. We only do this on Windows for now because of the potential
@ -64,12 +70,6 @@ int main(int argc, const char* argv[]) {
// Try to connect - if we can't connect, interface has probably just gone down // Try to connect - if we can't connect, interface has probably just gone down
if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) { if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) {
QStringList arguments;
for (int i = 0; i < argc; ++i) {
arguments << argv[i];
}
QCommandLineParser parser; QCommandLineParser parser;
QCommandLineOption urlOption("url", "", "value"); QCommandLineOption urlOption("url", "", "value");
parser.addOption(urlOption); parser.addOption(urlOption);
@ -135,7 +135,7 @@ int main(int argc, const char* argv[]) {
// Oculus initialization MUST PRECEDE OpenGL context creation. // Oculus initialization MUST PRECEDE OpenGL context creation.
// The nature of the Application constructor means this has to be either here, // The nature of the Application constructor means this has to be either here,
// or in the main window ctor, before GL startup. // or in the main window ctor, before GL startup.
Application::initPlugins(); Application::initPlugins(arguments);
int exitCode; int exitCode;
{ {

View file

@ -14,6 +14,10 @@
ClipboardScriptingInterface::ClipboardScriptingInterface() { ClipboardScriptingInterface::ClipboardScriptingInterface() {
} }
glm::vec3 ClipboardScriptingInterface::getContentsDimensions() {
return qApp->getEntityClipboard()->getContentsDimensions();
}
float ClipboardScriptingInterface::getClipboardContentsLargestDimension() { float ClipboardScriptingInterface::getClipboardContentsLargestDimension() {
return qApp->getEntityClipboard()->getContentsLargestDimension(); return qApp->getEntityClipboard()->getContentsLargestDimension();
} }

View file

@ -22,6 +22,7 @@ signals:
void readyToImport(); void readyToImport();
public slots: public slots:
glm::vec3 getContentsDimensions(); /// returns the overall dimensions of everything on the blipboard
float getClipboardContentsLargestDimension(); /// returns the largest dimension of everything on the clipboard float getClipboardContentsLargestDimension(); /// returns the largest dimension of everything on the clipboard
bool importEntities(const QString& filename); bool importEntities(const QString& filename);
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs); bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs);

View file

@ -632,13 +632,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
#endif #endif
int numBytesRead = sourceBuffer - startPosition; int numBytesRead = sourceBuffer - startPosition;
if (numBytesRead != buffer.size()) {
if (shouldLogError(now)) {
qCWarning(avatars) << "AvatarData packet size mismatch: expected " << numBytesRead << " received " << buffer.size();
}
}
_averageBytesReceived.updateAverage(numBytesRead); _averageBytesReceived.updateAverage(numBytesRead);
return numBytesRead; return numBytesRead;
} }
@ -1270,6 +1263,10 @@ static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName");
static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments"); static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments");
static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities"); static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities");
static const QString JSON_AVATAR_SCALE = QStringLiteral("scale"); static const QString JSON_AVATAR_SCALE = QStringLiteral("scale");
static const QString JSON_AVATAR_VERSION = QStringLiteral("version");
static const int JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION = 0;
static const int JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION = 1;
QJsonValue toJsonValue(const JointData& joint) { QJsonValue toJsonValue(const JointData& joint) {
QJsonArray result; QJsonArray result;
@ -1293,6 +1290,8 @@ JointData jointDataFromJsonValue(const QJsonValue& json) {
QJsonObject AvatarData::toJson() const { QJsonObject AvatarData::toJson() const {
QJsonObject root; QJsonObject root;
root[JSON_AVATAR_VERSION] = JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION;
if (!getSkeletonModelURL().isEmpty()) { if (!getSkeletonModelURL().isEmpty()) {
root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString(); root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString();
} }
@ -1359,6 +1358,15 @@ QJsonObject AvatarData::toJson() const {
} }
void AvatarData::fromJson(const QJsonObject& json) { void AvatarData::fromJson(const QJsonObject& json) {
int version;
if (json.contains(JSON_AVATAR_VERSION)) {
version = json[JSON_AVATAR_VERSION].toInt();
} else {
// initial data did not have a version field.
version = JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION;
}
// The head setOrientation likes to overwrite the avatar orientation, // The head setOrientation likes to overwrite the avatar orientation,
// so lets do the head first // so lets do the head first
// Most head data is relative to the avatar, and needs no basis correction, // Most head data is relative to the avatar, and needs no basis correction,
@ -1424,8 +1432,15 @@ void AvatarData::fromJson(const QJsonObject& json) {
// } // }
// } // }
// Joint rotations are relative to the avatar, so they require no basis correction
if (json.contains(JSON_AVATAR_JOINT_ARRAY)) { if (json.contains(JSON_AVATAR_JOINT_ARRAY)) {
if (version == JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION) {
// because we don't have the full joint hierarchy skeleton of the model,
// we can't properly convert from relative rotations into absolute rotations.
quint64 now = usecTimestampNow();
if (shouldLogError(now)) {
qCWarning(avatars) << "Version 0 avatar recordings not supported. using default rotations";
}
} else {
QVector<JointData> jointArray; QVector<JointData> jointArray;
QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray(); QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray();
jointArray.reserve(jointArrayJson.size()); jointArray.reserve(jointArrayJson.size());
@ -1439,6 +1454,7 @@ void AvatarData::fromJson(const QJsonObject& json) {
} }
setRawJointData(jointArray); setRawJointData(jointArray);
} }
}
} }
// Every frame will store both a basis for the recording and a relative transform // Every frame will store both a basis for the recording and a relative transform

View file

@ -1121,6 +1121,27 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) {
return result; return result;
} }
QVector<QUuid> EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) {
QVector<QUuid> result;
if (!_entityTree) {
return result;
}
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID);
if (!entity) {
qDebug() << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID;
return result;
}
_entityTree->withReadLock([&] {
entity->forEachChild([&](SpatiallyNestablePointer child) {
result.push_back(child->getID());
});
});
return result;
}
QVector<QUuid> EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) { QVector<QUuid> EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) {
QVector<QUuid> result; QVector<QUuid> result;
if (!_entityTree) { if (!_entityTree) {

View file

@ -171,6 +171,7 @@ public slots:
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name); Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name);
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID); Q_INVOKABLE QStringList getJointNames(const QUuid& entityID);
Q_INVOKABLE QVector<QUuid> getChildrenIDs(const QUuid& parentID);
Q_INVOKABLE QVector<QUuid> getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex); Q_INVOKABLE QVector<QUuid> getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex);
signals: signals:

View file

@ -1284,6 +1284,7 @@ class ContentsDimensionOperator : public RecurseOctreeOperator {
public: public:
virtual bool preRecursion(OctreeElementPointer element); virtual bool preRecursion(OctreeElementPointer element);
virtual bool postRecursion(OctreeElementPointer element) { return true; } virtual bool postRecursion(OctreeElementPointer element) { return true; }
glm::vec3 getDimensions() const { return _contentExtents.size(); }
float getLargestDimension() const { return _contentExtents.largestDimension(); } float getLargestDimension() const { return _contentExtents.largestDimension(); }
private: private:
Extents _contentExtents; Extents _contentExtents;
@ -1295,6 +1296,12 @@ bool ContentsDimensionOperator::preRecursion(OctreeElementPointer element) {
return true; return true;
} }
glm::vec3 EntityTree::getContentsDimensions() {
ContentsDimensionOperator theOperator;
recurseTreeWithOperator(&theOperator);
return theOperator.getDimensions();
}
float EntityTree::getContentsLargestDimension() { float EntityTree::getContentsLargestDimension() {
ContentsDimensionOperator theOperator; ContentsDimensionOperator theOperator;
recurseTreeWithOperator(&theOperator); recurseTreeWithOperator(&theOperator);

View file

@ -207,6 +207,7 @@ public:
bool skipThoseWithBadParents) override; bool skipThoseWithBadParents) override;
virtual bool readFromMap(QVariantMap& entityDescription) override; virtual bool readFromMap(QVariantMap& entityDescription) override;
glm::vec3 getContentsDimensions();
float getContentsLargestDimension(); float getContentsLargestDimension();
virtual void resetEditStats() override { virtual void resetEditStats() override {

View file

@ -55,7 +55,7 @@ void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) cons
if (extraEncodeData->contains(this)) { if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
qCDebug(entities) << " encode data:" << entityTreeElementExtraEncodeData; qCDebug(entities) << " encode data:" << entityTreeElementExtraEncodeData;
} else { } else {
qCDebug(entities) << " encode data: MISSING!!"; qCDebug(entities) << " encode data: MISSING!!";
@ -97,7 +97,7 @@ bool EntityTreeElement::shouldIncludeChildData(int childIndex, EncodeBitstreamPa
if (extraEncodeData->contains(this)) { if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
bool childCompleted = entityTreeElementExtraEncodeData->childCompleted[childIndex]; bool childCompleted = entityTreeElementExtraEncodeData->childCompleted[childIndex];
@ -126,7 +126,7 @@ bool EntityTreeElement::alreadyFullyEncoded(EncodeBitstreamParams& params) const
if (extraEncodeData->contains(this)) { if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
// If we know that ALL subtrees below us have already been recursed, then we don't // If we know that ALL subtrees below us have already been recursed, then we don't
// need to recurse this child. // need to recurse this child.
@ -140,7 +140,7 @@ void EntityTreeElement::updateEncodedData(int childIndex, AppendState childAppen
assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes
if (extraEncodeData->contains(this)) { if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
if (childAppendState == OctreeElement::COMPLETED) { if (childAppendState == OctreeElement::COMPLETED) {
entityTreeElementExtraEncodeData->childCompleted[childIndex] = true; entityTreeElementExtraEncodeData->childCompleted[childIndex] = true;
@ -165,7 +165,7 @@ void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params) con
assert(extraEncodeData->contains(this)); assert(extraEncodeData->contains(this));
EntityTreeElementExtraEncodeData* thisExtraEncodeData EntityTreeElementExtraEncodeData* thisExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
// Note: this will be called when OUR element has finished running through encodeTreeBitstreamRecursion() // Note: this will be called when OUR element has finished running through encodeTreeBitstreamRecursion()
// which means, it's possible that our parent element hasn't finished encoding OUR data... so // which means, it's possible that our parent element hasn't finished encoding OUR data... so
@ -241,7 +241,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
bool hadElementExtraData = false; bool hadElementExtraData = false;
if (extraEncodeData && extraEncodeData->contains(this)) { if (extraEncodeData && extraEncodeData->contains(this)) {
entityTreeElementExtraEncodeData = entityTreeElementExtraEncodeData =
static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
hadElementExtraData = true; hadElementExtraData = true;
} else { } else {
// if there wasn't one already, then create one // if there wasn't one already, then create one
@ -268,7 +268,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
//assert(extraEncodeData); //assert(extraEncodeData);
//assert(extraEncodeData->contains(this)); //assert(extraEncodeData->contains(this));
//entityTreeElementExtraEncodeData = static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); //entityTreeElementExtraEncodeData = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
LevelDetails elementLevel = packetData->startLevel(); LevelDetails elementLevel = packetData->startLevel();

View file

@ -25,7 +25,6 @@ InputPluginList getInputPlugins() {
for (int i = 0; PLUGIN_POOL[i]; ++i) { for (int i = 0; PLUGIN_POOL[i]; ++i) {
InputPlugin* plugin = PLUGIN_POOL[i]; InputPlugin* plugin = PLUGIN_POOL[i];
if (plugin->isSupported()) { if (plugin->isSupported()) {
plugin->init();
result.push_back(InputPluginPointer(plugin)); result.push_back(InputPluginPointer(plugin));
} }
} }

View file

@ -25,6 +25,50 @@ PluginManager* PluginManager::getInstance() {
return &_manager; return &_manager;
} }
QString getPluginNameFromMetaData(QJsonObject object) {
static const char* METADATA_KEY = "MetaData";
static const char* NAME_KEY = "name";
if (!object.contains(METADATA_KEY) || !object[METADATA_KEY].isObject()) {
return QString();
}
auto metaDataObject = object[METADATA_KEY].toObject();
if (!metaDataObject.contains(NAME_KEY) || !metaDataObject[NAME_KEY].isString()) {
return QString();
}
return metaDataObject[NAME_KEY].toString();
}
QString getPluginIIDFromMetaData(QJsonObject object) {
static const char* IID_KEY = "IID";
if (!object.contains(IID_KEY) || !object[IID_KEY].isString()) {
return QString();
}
return object[IID_KEY].toString();
}
QStringList preferredDisplayPlugins;
QStringList disabledDisplays;
QStringList disabledInputs;
bool isDisabled(QJsonObject metaData) {
auto name = getPluginNameFromMetaData(metaData);
auto iid = getPluginIIDFromMetaData(metaData);
if (iid == DisplayProvider_iid) {
return disabledDisplays.contains(name);
} else if (iid == InputProvider_iid) {
return disabledInputs.contains(name);
}
return false;
}
using Loader = QSharedPointer<QPluginLoader>; using Loader = QSharedPointer<QPluginLoader>;
using LoaderList = QList<Loader>; using LoaderList = QList<Loader>;
@ -43,11 +87,21 @@ const LoaderList& getLoadedPlugins() {
qDebug() << "Loading runtime plugins from " << pluginPath; qDebug() << "Loading runtime plugins from " << pluginPath;
auto candidates = pluginDir.entryList(); auto candidates = pluginDir.entryList();
for (auto plugin : candidates) { for (auto plugin : candidates) {
qDebug() << "Attempting plugins " << plugin; qDebug() << "Attempting plugin" << qPrintable(plugin);
QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath + plugin)); QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath + plugin));
if (isDisabled(loader->metaData())) {
qWarning() << "Plugin" << qPrintable(plugin) << "is disabled";
// Skip this one, it's disabled
continue;
}
if (loader->load()) { if (loader->load()) {
qDebug() << "Plugins " << plugin << " success"; qDebug() << "Plugin" << qPrintable(plugin) << "loaded successfully";
loadedPlugins.push_back(loader); loadedPlugins.push_back(loader);
} else {
qDebug() << "Plugin" << qPrintable(plugin) << "failed to load:";
qDebug() << " " << qPrintable(loader->errorString());
} }
} }
} }
@ -110,10 +164,12 @@ const InputPluginList& PluginManager::getInputPlugins() {
InputProvider* inputProvider = qobject_cast<InputProvider*>(loader->instance()); InputProvider* inputProvider = qobject_cast<InputProvider*>(loader->instance());
if (inputProvider) { if (inputProvider) {
for (auto inputPlugin : inputProvider->getInputPlugins()) { for (auto inputPlugin : inputProvider->getInputPlugins()) {
if (inputPlugin->isSupported()) {
inputPlugins.push_back(inputPlugin); inputPlugins.push_back(inputPlugin);
} }
} }
} }
}
auto& container = PluginContainer::getInstance(); auto& container = PluginContainer::getInstance();
for (auto plugin : inputPlugins) { for (auto plugin : inputPlugins) {
@ -124,6 +180,40 @@ const InputPluginList& PluginManager::getInputPlugins() {
return inputPlugins; return inputPlugins;
} }
void PluginManager::setPreferredDisplayPlugins(const QStringList& displays) {
preferredDisplayPlugins = displays;
}
DisplayPluginList PluginManager::getPreferredDisplayPlugins() {
static DisplayPluginList displayPlugins;
static std::once_flag once;
std::call_once(once, [&] {
// Grab the built in plugins
auto plugins = getDisplayPlugins();
for (auto pluginName : preferredDisplayPlugins) {
auto it = std::find_if(plugins.begin(), plugins.end(), [&](DisplayPluginPointer plugin) {
return plugin->getName() == pluginName;
});
if (it != plugins.end()) {
displayPlugins.push_back(*it);
}
}
});
return displayPlugins;
}
void PluginManager::disableDisplays(const QStringList& displays) {
disabledDisplays << displays;
}
void PluginManager::disableInputs(const QStringList& inputs) {
disabledInputs << inputs;
}
void PluginManager::saveSettings() { void PluginManager::saveSettings() {
saveInputPluginSettings(getInputPlugins()); saveInputPluginSettings(getInputPlugins());
} }

View file

@ -17,7 +17,13 @@ public:
PluginManager(); PluginManager();
const DisplayPluginList& getDisplayPlugins(); const DisplayPluginList& getDisplayPlugins();
void disableDisplayPlugin(const QString& name);
const InputPluginList& getInputPlugins(); const InputPluginList& getInputPlugins();
DisplayPluginList getPreferredDisplayPlugins();
void setPreferredDisplayPlugins(const QStringList& displays);
void disableDisplayPlugin(const QString& name);
void disableDisplays(const QStringList& displays);
void disableInputs(const QStringList& inputs);
void saveSettings(); void saveSettings();
}; };

View file

@ -28,7 +28,9 @@ Settings::~Settings() {
} }
void Settings::remove(const QString& key) { void Settings::remove(const QString& key) {
if (key == "" || _manager->contains(key)) {
_manager->remove(key); _manager->remove(key);
}
} }
QStringList Settings::childGroups() const { QStringList Settings::childGroups() const {
@ -72,7 +74,9 @@ void Settings::endGroup() {
} }
void Settings::setValue(const QString& name, const QVariant& value) { void Settings::setValue(const QString& name, const QVariant& value) {
if (_manager->value(name) != value) {
_manager->setValue(name, value); _manager->setValue(name, value);
}
} }
QVariant Settings::value(const QString& name, const QVariant& defaultValue) const { QVariant Settings::value(const QString& name, const QVariant& defaultValue) const {

View file

@ -1 +1 @@
{} {"name":"Neuron"}

View file

@ -1 +1 @@
{} {"name":"SDL2"}

View file

@ -1 +1 @@
{} {"name":"Sixense"}

View file

@ -1 +1 @@
{} {"name":"Spacemouse"}

View file

@ -1 +1 @@
{} {"name":"Oculus Rift"}

View file

@ -31,7 +31,7 @@
using namespace oglplus; using namespace oglplus;
const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift (0.5) (Legacy)"); const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift");
OculusLegacyDisplayPlugin::OculusLegacyDisplayPlugin() { OculusLegacyDisplayPlugin::OculusLegacyDisplayPlugin() {
} }

View file

@ -1 +1 @@
{} {"name":"Oculus Rift"}

View file

@ -1 +1 @@
{} {"name":"OpenVR (Vive)"}

View file

@ -92,6 +92,7 @@ var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new posit
// other constants // other constants
// //
var HOTSPOT_DRAW_DISTANCE = 10;
var RIGHT_HAND = 1; var RIGHT_HAND = 1;
var LEFT_HAND = 0; var LEFT_HAND = 0;
@ -179,47 +180,85 @@ var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic";
var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC; var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC;
var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC; var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC;
function stateToName(state) { var CONTROLLER_STATE_MACHINE = {};
switch (state) {
case STATE_OFF:
return "off";
case STATE_SEARCHING:
return "searching";
case STATE_HOLD_SEARCHING:
return "hold_searching";
case STATE_DISTANCE_HOLDING:
return "distance_holding";
case STATE_CONTINUE_DISTANCE_HOLDING:
return "continue_distance_holding";
case STATE_NEAR_GRABBING:
return "near_grabbing";
case STATE_CONTINUE_NEAR_GRABBING:
return "continue_near_grabbing";
case STATE_NEAR_TRIGGER:
return "near_trigger";
case STATE_CONTINUE_NEAR_TRIGGER:
return "continue_near_trigger";
case STATE_FAR_TRIGGER:
return "far_trigger";
case STATE_CONTINUE_FAR_TRIGGER:
return "continue_far_trigger";
case STATE_RELEASE:
return "release";
case STATE_EQUIP:
return "equip";
case STATE_HOLD:
return "hold";
case STATE_CONTINUE_HOLD:
return "continue_hold";
case STATE_CONTINUE_EQUIP:
return "continue_equip";
case STATE_WAITING_FOR_EQUIP_THUMB_RELEASE:
return "waiting_for_equip_thumb_release";
case STATE_WAITING_FOR_RELEASE_THUMB_RELEASE:
return "waiting_for_release_thumb_release";
}
return "unknown"; CONTROLLER_STATE_MACHINE[STATE_OFF] = {
name: "off",
updateMethod: "off"
};
CONTROLLER_STATE_MACHINE[STATE_SEARCHING] = {
name: "searching",
updateMethod: "search",
enterMethod: "searchEnter",
exitMethod: "searchExit"
};
CONTROLLER_STATE_MACHINE[STATE_HOLD_SEARCHING] = {
name: "hold_searching",
updateMethod: "search"
};
CONTROLLER_STATE_MACHINE[STATE_DISTANCE_HOLDING] = {
name: "distance_holding",
updateMethod: "distanceHolding"
};
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_DISTANCE_HOLDING] = {
name: "continue_distance_holding",
updateMethod: "continueDistanceHolding"
};
CONTROLLER_STATE_MACHINE[STATE_NEAR_GRABBING] = {
name: "near_grabbing",
updateMethod: "nearGrabbing"
};
CONTROLLER_STATE_MACHINE[STATE_EQUIP] = {
name: "equip",
updateMethod: "nearGrabbing"
};
CONTROLLER_STATE_MACHINE[STATE_HOLD] = {
name: "hold",
updateMethod: "nearGrabbing"
};
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_NEAR_GRABBING] = {
name: "continue_near_grabbing",
updateMethod: "continueNearGrabbing"
};
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_HOLD] = {
name: "continue_hold",
updateMethod: "continueNearGrabbing"
};
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_EQUIP] = {
name: "continue_equip",
updateMethod: "continueNearGrabbing"
};
CONTROLLER_STATE_MACHINE[STATE_NEAR_TRIGGER] = {
name: "near_trigger",
updateMethod: "nearTrigger"
};
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_NEAR_TRIGGER] = {
name: "continue_near_trigger",
updateMethod: "continueNearTrigger"
};
CONTROLLER_STATE_MACHINE[STATE_FAR_TRIGGER] = {
name: "far_trigger",
updateMethod: "farTrigger"
};
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_FAR_TRIGGER] = {
name: "continue_far_trigger",
updateMethod: "continueFarTrigger"
};
CONTROLLER_STATE_MACHINE[STATE_RELEASE] = {
name: "release",
updateMethod: "release"
};
CONTROLLER_STATE_MACHINE[STATE_WAITING_FOR_EQUIP_THUMB_RELEASE] = {
name: "waiting_for_equip_thumb_release",
updateMethod: "waitingForEquipThumbRelease"
};
CONTROLLER_STATE_MACHINE[STATE_WAITING_FOR_RELEASE_THUMB_RELEASE] = {
name: "waiting_for_release_thumb_release",
updateMethod: "waitingForReleaseThumbRelease"
};
function stateToName(state) {
return CONTROLLER_STATE_MACHINE[state] ? CONTROLLER_STATE_MACHINE[state].name : "???";
} }
function getTag() { function getTag() {
@ -249,6 +288,14 @@ function entityIsGrabbedByOther(entityID) {
return false; return false;
} }
function propsArePhysical(props) {
if (!props.dynamic) {
return false;
}
var isPhysical = (props.shapeType && props.shapeType != 'none');
return isPhysical;
}
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here, // If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode. // and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true; var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
@ -314,55 +361,22 @@ function MyController(hand) {
this.update = function() { this.update = function() {
this.updateSmoothedTrigger(); this.updateSmoothedTrigger();
if (isIn2DMode()) { if (isIn2DMode()) {
_this.turnOffVisualizations(); _this.turnOffVisualizations();
return; return;
} }
switch (this.state) {
case STATE_OFF: if (CONTROLLER_STATE_MACHINE[this.state]) {
this.off(); var updateMethodName = CONTROLLER_STATE_MACHINE[this.state].updateMethod;
break; var updateMethod = this[updateMethodName];
case STATE_SEARCHING: if (updateMethod) {
case STATE_HOLD_SEARCHING: updateMethod.call(this);
this.search(); } else {
break; print("WARNING: could not find updateMethod for state " + stateToName(this.state));
case STATE_DISTANCE_HOLDING: }
this.distanceHolding(); } else {
break; print("WARNING: could not find state " + this.state + " in state machine");
case STATE_CONTINUE_DISTANCE_HOLDING:
this.continueDistanceHolding();
break;
case STATE_NEAR_GRABBING:
case STATE_EQUIP:
case STATE_HOLD:
this.nearGrabbing();
break;
case STATE_WAITING_FOR_EQUIP_THUMB_RELEASE:
this.waitingForEquipThumbRelease();
break;
case STATE_WAITING_FOR_RELEASE_THUMB_RELEASE:
this.waitingForReleaseThumbRelease();
break;
case STATE_CONTINUE_NEAR_GRABBING:
case STATE_CONTINUE_HOLD:
case STATE_CONTINUE_EQUIP:
this.continueNearGrabbing();
break;
case STATE_NEAR_TRIGGER:
this.nearTrigger();
break;
case STATE_CONTINUE_NEAR_TRIGGER:
this.continueNearTrigger();
break;
case STATE_FAR_TRIGGER:
this.farTrigger();
break;
case STATE_CONTINUE_FAR_TRIGGER:
this.continueFarTrigger();
break;
case STATE_RELEASE:
this.release();
break;
} }
}; };
@ -374,9 +388,33 @@ function MyController(hand) {
this.setState = function(newState) { this.setState = function(newState) {
this.grabSphereOff(); this.grabSphereOff();
if (WANT_DEBUG || WANT_DEBUG_STATE) { if (WANT_DEBUG || WANT_DEBUG_STATE) {
print("STATE (" + this.hand + "): " + stateToName(this.state) + " --> " + var oldStateName = stateToName(this.state);
stateToName(newState) + ", hand: " + this.hand); var newStateName = stateToName(newState);
print("STATE (" + this.hand + "): " + newStateName + " <-- " + oldStateName);
} }
// exit the old state
if (CONTROLLER_STATE_MACHINE[this.state]) {
var exitMethodName = CONTROLLER_STATE_MACHINE[this.state].exitMethod;
var exitMethod = this[exitMethodName];
if (exitMethod) {
exitMethod.call(this);
}
} else {
print("WARNING: could not find state " + this.state + " in state machine");
}
// enter the new state
if (CONTROLLER_STATE_MACHINE[newState]) {
var enterMethodName = CONTROLLER_STATE_MACHINE[newState].enterMethod;
var enterMethod = this[enterMethodName];
if (enterMethod) {
enterMethod.call(this);
}
} else {
print("WARNING: could not find newState " + newState + " in state machine");
}
this.state = newState; this.state = newState;
}; };
@ -759,14 +797,6 @@ function MyController(hand) {
} }
}; };
this.propsArePhysical = function(props) {
if (!props.dynamic) {
return false;
}
var isPhysical = (props.shapeType && props.shapeType != 'none');
return isPhysical;
}
this.turnOffVisualizations = function() { this.turnOffVisualizations = function() {
if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) {
this.lineOff(); this.lineOff();
@ -852,6 +882,56 @@ function MyController(hand) {
} }
}; };
this.searchEnter = function() {
this.equipHotspotOverlays = [];
// find entities near the avatar that might be equipable.
var entities = Entities.findEntities(MyAvatar.position, HOTSPOT_DRAW_DISTANCE);
var i, l = entities.length;
for (i = 0; i < l; i++) {
// is this entity equipable?
var grabData = getEntityCustomData(GRABBABLE_DATA_KEY, entities[i], undefined);
var grabProps = Entities.getEntityProperties(entities[i], GRABBABLE_PROPERTIES);
if (grabData) {
var hotspotPos = grabProps.position;
// does this entity have an attach point?
var wearableData = getEntityCustomData("wearable", entities[i], undefined);
if (wearableData) {
var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
if (wearableData[handJointName]) {
// draw the hotspot around the attach point.
hotspotPos = wearableData[handJointName][0];
}
}
// draw a hotspot!
this.equipHotspotOverlays.push(Overlays.addOverlay("sphere", {
position: hotspotPos,
size: 0.2,
color: { red: 90, green: 255, blue: 90 },
alpha: 0.7,
solid: true,
visible: true,
ignoreRayIntersection: false,
drawInFront: false
}));
}
}
};
this.searchExit = function() {
// delete all equip hotspots
var i, l = this.equipHotspotOverlays.length;
for (i = 0; i < l; i++) {
Overlays.deleteOverlay(this.equipHotspotOverlays[i]);
}
this.equipHotspotOverlays = [];
};
this.search = function() { this.search = function() {
this.grabbedEntity = null; this.grabbedEntity = null;
this.isInitialGrab = false; this.isInitialGrab = false;
@ -863,6 +943,7 @@ function MyController(hand) {
this.setState(STATE_RELEASE); this.setState(STATE_RELEASE);
return; return;
} }
if (this.state == STATE_HOLD_SEARCHING && this.bumperReleased()) { if (this.state == STATE_HOLD_SEARCHING && this.bumperReleased()) {
this.setState(STATE_RELEASE); this.setState(STATE_RELEASE);
return; return;
@ -951,7 +1032,7 @@ function MyController(hand) {
var propsForCandidate = Entities.getEntityProperties(candidateEntities[i], GRABBABLE_PROPERTIES); var propsForCandidate = Entities.getEntityProperties(candidateEntities[i], GRABBABLE_PROPERTIES);
var near = (nearPickedCandidateEntities.indexOf(candidateEntities[i]) >= 0); var near = (nearPickedCandidateEntities.indexOf(candidateEntities[i]) >= 0);
var isPhysical = this.propsArePhysical(propsForCandidate); var isPhysical = propsArePhysical(propsForCandidate);
var grabbable; var grabbable;
if (isPhysical) { if (isPhysical) {
// physical things default to grabbable // physical things default to grabbable
@ -1030,7 +1111,7 @@ function MyController(hand) {
if ((this.grabbedEntity !== null) && (this.triggerSmoothedGrab() || this.bumperSqueezed())) { if ((this.grabbedEntity !== null) && (this.triggerSmoothedGrab() || this.bumperSqueezed())) {
// We are squeezing enough to grab, and we've found an entity that we'll try to do something with. // We are squeezing enough to grab, and we've found an entity that we'll try to do something with.
var near = (nearPickedCandidateEntities.indexOf(this.grabbedEntity) >= 0) || minDistance <= NEAR_PICK_MAX_DISTANCE; var near = (nearPickedCandidateEntities.indexOf(this.grabbedEntity) >= 0) || minDistance <= NEAR_PICK_MAX_DISTANCE;
var isPhysical = this.propsArePhysical(props); var isPhysical = propsArePhysical(props);
// near or far trigger // near or far trigger
if (grabbableData.wantsTrigger) { if (grabbableData.wantsTrigger) {
@ -1462,7 +1543,7 @@ function MyController(hand) {
} }
} }
var isPhysical = this.propsArePhysical(grabbedProperties) || entityHasActions(this.grabbedEntity); var isPhysical = propsArePhysical(grabbedProperties) || entityHasActions(this.grabbedEntity);
if (isPhysical && this.state == STATE_NEAR_GRABBING) { if (isPhysical && this.state == STATE_NEAR_GRABBING) {
// grab entity via action // grab entity via action
if (!this.setupHoldAction()) { if (!this.setupHoldAction()) {
@ -1879,7 +1960,7 @@ function MyController(hand) {
var forceVelocity = false; var forceVelocity = false;
var doSetVelocity = false; var doSetVelocity = false;
if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && this.propsArePhysical(props)) { if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && propsArePhysical(props)) {
// TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up // TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up
// props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that // props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that
// is done, we use a measured velocity here so that things held via a bumper-grab / parenting-grab // is done, we use a measured velocity here so that things held via a bumper-grab / parenting-grab

View file

@ -51,7 +51,7 @@ ApplicationWindow {
Button { Button {
text: "toggle desktop" text: "toggle desktop"
onClicked: desktop.toggleVisible() onClicked: desktop.togglePinned()
} }
// Error alerts // Error alerts