mirror of
https://github.com/overte-org/overte.git
synced 2025-04-18 00:26:33 +02:00
Merge branch 'master' into feature/puck-attach
This commit is contained in:
commit
6e10a6fc60
72 changed files with 1744 additions and 832 deletions
|
@ -23,6 +23,7 @@
|
|||
#include <AvatarHashMap.h>
|
||||
#include <AudioInjectorManager.h>
|
||||
#include <AssetClient.h>
|
||||
#include <LocationScriptingInterface.h>
|
||||
#include <MessagesClient.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
|
@ -453,6 +454,9 @@ void Agent::executeScript() {
|
|||
|
||||
_scriptEngine->registerGlobalObject("EntityViewer", &_entityViewer);
|
||||
|
||||
_scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
LocationScriptingInterface::locationSetter);
|
||||
|
||||
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
||||
_scriptEngine->registerGlobalObject("Recording", recordingInterface.data());
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1,70 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="mic-mute-a.svg"><metadata
|
||||
id="metadata22"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs20" /><sodipodi:namedview
|
||||
pagecolor="#ff0000"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="852"
|
||||
inkscape:window-height="480"
|
||||
id="namedview18"
|
||||
showgrid="false"
|
||||
inkscape:zoom="4.72"
|
||||
inkscape:cx="25"
|
||||
inkscape:cy="25"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg2" /><style
|
||||
type="text/css"
|
||||
id="style4">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style><g
|
||||
id="Layer_2" /><g
|
||||
id="Layer_1"
|
||||
style="fill:#000000;fill-opacity:1"><path
|
||||
class="st0"
|
||||
d="M28.9,17.1v-0.5c0-2-1.7-3.6-3.7-3.6h0c-2,0-3.7,1.6-3.7,3.6v6.9L28.9,17.1z"
|
||||
id="path8"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M21.5,29.2v0.2c0,2,1.6,3.6,3.7,3.6h0c2,0,3.7-1.6,3.7-3.6v-6.6L21.5,29.2z"
|
||||
id="path10"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M39.1,16.8L13.6,39.1c-0.7,0.6-1.8,0.5-2.4-0.2l-0.2-0.2c-0.6-0.7-0.5-1.8,0.2-2.4l25.4-22.4 c0.7-0.6,1.8-0.5,2.4,0.2l0.2,0.2C39.8,15.1,39.7,16.1,39.1,16.8z"
|
||||
id="path12"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M23.4,40.2l0,3.4h-4.3c-1,0-1.8,0.8-1.8,1.8c0,1,0.8,1.8,1.8,1.8h12.3c1,0,1.8-0.8,1.8-1.8 c0-1-0.8-1.8-1.8-1.8h-4.4l0-3.4c5.2-0.8,9.2-5,9.2-10.1c0-0.1,0-5.1,0-5.3c0-1-0.9-1.7-1.8-1.7c-1,0-1.7,0.8-1.7,1.8 c0,0.3,0,4.8,0,5.2c0,3.7-3.4,6.7-7.5,6.7c-3.6,0-6.7-2.3-7.3-5.4L15,34C16.4,37.2,19.6,39.7,23.4,40.2z"
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M17.7,24.9c0-1-0.7-1.8-1.6-1.8c-1-0.1-1.8,0.7-1.9,1.6c0,0.2,0,4.2,0,5.3l3.5-3.1 C17.7,25.9,17.7,25,17.7,24.9z"
|
||||
id="path16"
|
||||
style="fill:#000000;fill-opacity:1" /></g></svg>
|
||||
<svg version="1.1"
|
||||
id="svg2" inkscape:version="0.91 r13725" sodipodi:docname="mic-mute-a.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#EA4C5F;}
|
||||
</style>
|
||||
<sodipodi:namedview bordercolor="#666666" borderopacity="1" gridtolerance="10" guidetolerance="10" id="namedview18" inkscape:current-layer="svg2" inkscape:cx="25" inkscape:cy="25" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="480" inkscape:window-maximized="0" inkscape:window-width="852" inkscape:window-x="0" inkscape:window-y="0" inkscape:zoom="4.72" objecttolerance="10" pagecolor="#ff0000" showgrid="false">
|
||||
</sodipodi:namedview>
|
||||
<g id="Layer_2">
|
||||
</g>
|
||||
<g id="Layer_1">
|
||||
<path id="path8" class="st0" d="M28.9,17.1v-0.5c0-2-1.7-3.6-3.7-3.6l0,0c-2,0-3.7,1.6-3.7,3.6v6.9L28.9,17.1z"/>
|
||||
<path id="path10" class="st0" d="M21.5,29.2v0.2c0,2,1.6,3.6,3.7,3.6l0,0c2,0,3.7-1.6,3.7-3.6v-6.6L21.5,29.2z"/>
|
||||
<path id="path12" class="st0" d="M39.1,16.8L13.6,39.1c-0.7,0.6-1.8,0.5-2.4-0.2L11,38.7c-0.6-0.7-0.5-1.8,0.2-2.4l25.4-22.4
|
||||
c0.7-0.6,1.8-0.5,2.4,0.2l0.2,0.2C39.8,15.1,39.7,16.1,39.1,16.8z"/>
|
||||
<path id="path14" class="st0" d="M23.4,40.2v3.4h-4.3c-1,0-1.8,0.8-1.8,1.8s0.8,1.8,1.8,1.8h12.3c1,0,1.8-0.8,1.8-1.8
|
||||
s-0.8-1.8-1.8-1.8H27v-3.4c5.2-0.8,9.2-5,9.2-10.1c0-0.1,0-5.1,0-5.3c0-1-0.9-1.7-1.8-1.7c-1,0-1.7,0.8-1.7,1.8c0,0.3,0,4.8,0,5.2
|
||||
c0,3.7-3.4,6.7-7.5,6.7c-3.6,0-6.7-2.3-7.3-5.4L15,34C16.4,37.2,19.6,39.7,23.4,40.2z"/>
|
||||
<path id="path16" class="st0" d="M17.7,24.9c0-1-0.7-1.8-1.6-1.8c-1-0.1-1.8,0.7-1.9,1.6c0,0.2,0,4.2,0,5.3l3.5-3.1
|
||||
C17.7,25.9,17.7,25,17.7,24.9z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.1 KiB |
|
@ -1,21 +1,25 @@
|
|||
<?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" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||
<svg version="1.1"
|
||||
id="svg2" inkscape:version="0.91 r13725" sodipodi:docname="mic-mute-a.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st0{fill:#EA4C5F;}
|
||||
</style>
|
||||
<sodipodi:namedview bordercolor="#666666" borderopacity="1" gridtolerance="10" guidetolerance="10" id="namedview18" inkscape:current-layer="svg2" inkscape:cx="25" inkscape:cy="25" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="480" inkscape:window-maximized="0" inkscape:window-width="852" inkscape:window-x="0" inkscape:window-y="0" inkscape:zoom="4.72" objecttolerance="10" pagecolor="#ff0000" showgrid="false">
|
||||
</sodipodi:namedview>
|
||||
<g id="Layer_2">
|
||||
</g>
|
||||
<g id="Layer_1">
|
||||
<path class="st0" d="M28.9,17.1v-0.5c0-2-1.7-3.6-3.7-3.6h0c-2,0-3.7,1.6-3.7,3.6v6.9L28.9,17.1z"/>
|
||||
<path class="st0" d="M21.5,29.2v0.2c0,2,1.6,3.6,3.7,3.6h0c2,0,3.7-1.6,3.7-3.6v-6.6L21.5,29.2z"/>
|
||||
<path class="st0" d="M39.1,16.8L13.6,39.1c-0.7,0.6-1.8,0.5-2.4-0.2l-0.2-0.2c-0.6-0.7-0.5-1.8,0.2-2.4l25.4-22.4
|
||||
<path id="path8" class="st0" d="M28.9,17.1v-0.5c0-2-1.7-3.6-3.7-3.6l0,0c-2,0-3.7,1.6-3.7,3.6v6.9L28.9,17.1z"/>
|
||||
<path id="path10" class="st0" d="M21.5,29.2v0.2c0,2,1.6,3.6,3.7,3.6l0,0c2,0,3.7-1.6,3.7-3.6v-6.6L21.5,29.2z"/>
|
||||
<path id="path12" class="st0" d="M39.1,16.8L13.6,39.1c-0.7,0.6-1.8,0.5-2.4-0.2L11,38.7c-0.6-0.7-0.5-1.8,0.2-2.4l25.4-22.4
|
||||
c0.7-0.6,1.8-0.5,2.4,0.2l0.2,0.2C39.8,15.1,39.7,16.1,39.1,16.8z"/>
|
||||
<path class="st0" d="M23.4,40.2l0,3.4h-4.3c-1,0-1.8,0.8-1.8,1.8c0,1,0.8,1.8,1.8,1.8h12.3c1,0,1.8-0.8,1.8-1.8
|
||||
c0-1-0.8-1.8-1.8-1.8h-4.4l0-3.4c5.2-0.8,9.2-5,9.2-10.1c0-0.1,0-5.1,0-5.3c0-1-0.9-1.7-1.8-1.7c-1,0-1.7,0.8-1.7,1.8
|
||||
c0,0.3,0,4.8,0,5.2c0,3.7-3.4,6.7-7.5,6.7c-3.6,0-6.7-2.3-7.3-5.4L15,34C16.4,37.2,19.6,39.7,23.4,40.2z"/>
|
||||
<path class="st0" d="M17.7,24.9c0-1-0.7-1.8-1.6-1.8c-1-0.1-1.8,0.7-1.9,1.6c0,0.2,0,4.2,0,5.3l3.5-3.1
|
||||
<path id="path14" class="st0" d="M23.4,40.2v3.4h-4.3c-1,0-1.8,0.8-1.8,1.8s0.8,1.8,1.8,1.8h12.3c1,0,1.8-0.8,1.8-1.8
|
||||
s-0.8-1.8-1.8-1.8H27v-3.4c5.2-0.8,9.2-5,9.2-10.1c0-0.1,0-5.1,0-5.3c0-1-0.9-1.7-1.8-1.7c-1,0-1.7,0.8-1.7,1.8c0,0.3,0,4.8,0,5.2
|
||||
c0,3.7-3.4,6.7-7.5,6.7c-3.6,0-6.7-2.3-7.3-5.4L15,34C16.4,37.2,19.6,39.7,23.4,40.2z"/>
|
||||
<path id="path16" class="st0" d="M17.7,24.9c0-1-0.7-1.8-1.6-1.8c-1-0.1-1.8,0.7-1.9,1.6c0,0.2,0,4.2,0,5.3l3.5-3.1
|
||||
C17.7,25.9,17.7,25,17.7,24.9z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.1 KiB |
|
@ -12,84 +12,21 @@ import QtQuick.Controls 1.3
|
|||
import QtGraphicalEffects 1.0
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "./hifi/audio" as HifiAudio
|
||||
|
||||
Hifi.AvatarInputs {
|
||||
id: root
|
||||
id: root;
|
||||
objectName: "AvatarInputs"
|
||||
width: rootWidth
|
||||
height: controls.height
|
||||
x: 10; y: 5
|
||||
width: audio.width;
|
||||
height: audio.height;
|
||||
x: 10; y: 5;
|
||||
|
||||
readonly property int rootWidth: 265
|
||||
readonly property int iconSize: 24
|
||||
readonly property int iconPadding: 5
|
||||
readonly property bool shouldReposition: true;
|
||||
|
||||
readonly property bool shouldReposition: true
|
||||
|
||||
Settings {
|
||||
category: "Overlay.AvatarInputs"
|
||||
property alias x: root.x
|
||||
property alias y: root.y
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: hover
|
||||
hoverEnabled: true
|
||||
drag.target: parent
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
Item {
|
||||
id: controls
|
||||
width: root.rootWidth
|
||||
height: 44
|
||||
visible: root.showAudioTools
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "#00000000"
|
||||
|
||||
Item {
|
||||
id: audioMeter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.iconPadding
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: root.iconPadding
|
||||
height: 8
|
||||
Rectangle {
|
||||
id: blueRect
|
||||
color: "blue"
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
width: parent.width / 4
|
||||
}
|
||||
Rectangle {
|
||||
id: greenRect
|
||||
color: "green"
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: blueRect.right
|
||||
anchors.right: redRect.left
|
||||
}
|
||||
Rectangle {
|
||||
id: redRect
|
||||
color: "red"
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: parent.width / 5
|
||||
}
|
||||
Rectangle {
|
||||
z: 100
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: (1.0 - root.audioLevel) * parent.width
|
||||
color: "black"
|
||||
}
|
||||
}
|
||||
}
|
||||
HifiAudio.MicBar {
|
||||
id: audio;
|
||||
visible: root.showAudioTools;
|
||||
standalone: true;
|
||||
dragTarget: parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,12 @@ Windows.Window {
|
|||
root.dynamicContent.fromScript(message);
|
||||
}
|
||||
}
|
||||
|
||||
function clearDebugWindow() {
|
||||
if (root.dynamicContent && root.dynamicContent.clearWindow) {
|
||||
root.dynamicContent.clearWindow();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle message traffic from our loaded QML to the script that launched us
|
||||
signal sendToScript(var message);
|
||||
|
|
|
@ -22,6 +22,7 @@ Original.CheckBox {
|
|||
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
|
||||
property bool isRedCheck: false
|
||||
property int boxSize: 14
|
||||
property bool wrap: true;
|
||||
readonly property int boxRadius: 3
|
||||
readonly property int checkSize: Math.max(boxSize - 8, 10)
|
||||
readonly property int checkRadius: 2
|
||||
|
@ -92,7 +93,8 @@ Original.CheckBox {
|
|||
text: control.text
|
||||
color: control.color
|
||||
x: 2
|
||||
wrapMode: Text.Wrap
|
||||
wrapMode: checkBox.wrap ? Text.Wrap : Text.NoWrap
|
||||
elide: checkBox.wrap ? Text.ElideNone : Text.ElideRight
|
||||
enabled: checkBox.enabled
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import QtQuick.Layouts 1.3
|
|||
import "../../styles-uit"
|
||||
import "../../controls-uit" as HifiControls
|
||||
import "../../windows"
|
||||
import "./" as Audio
|
||||
import "./" as AudioControls
|
||||
|
||||
Rectangle {
|
||||
id: root;
|
||||
|
@ -52,33 +52,40 @@ Rectangle {
|
|||
|
||||
Separator { visible: root.showTitle() }
|
||||
|
||||
Grid {
|
||||
columns: 2;
|
||||
ColumnLayout {
|
||||
x: 16; // padding does not work
|
||||
spacing: 16;
|
||||
|
||||
Audio.CheckBox {
|
||||
text: qsTr("Mute microphone");
|
||||
checked: Audio.muted;
|
||||
onClicked: {
|
||||
Audio.muted = checked;
|
||||
checked = Qt.binding(function() { return Audio.muted; }); // restore binding
|
||||
// mute is in its own row
|
||||
RowLayout {
|
||||
AudioControls.CheckBox {
|
||||
text: qsTr("Mute microphone");
|
||||
isRedCheck: true;
|
||||
checked: Audio.muted;
|
||||
onClicked: {
|
||||
Audio.muted = checked;
|
||||
checked = Qt.binding(function() { return Audio.muted; }); // restore binding
|
||||
}
|
||||
}
|
||||
}
|
||||
Audio.CheckBox {
|
||||
text: qsTr("Enable noise reduction");
|
||||
checked: Audio.noiseReduction;
|
||||
onClicked: {
|
||||
Audio.noiseReduction = checked;
|
||||
checked = Qt.binding(function() { return Audio.noiseReduction; }); // restore binding
|
||||
|
||||
RowLayout {
|
||||
spacing: 16;
|
||||
AudioControls.CheckBox {
|
||||
text: qsTr("Enable noise reduction");
|
||||
checked: Audio.noiseReduction;
|
||||
onClicked: {
|
||||
Audio.noiseReduction = checked;
|
||||
checked = Qt.binding(function() { return Audio.noiseReduction; }); // restore binding
|
||||
}
|
||||
}
|
||||
}
|
||||
Audio.CheckBox {
|
||||
text: qsTr("Show audio level meter");
|
||||
checked: AvatarInputs.showAudioTools;
|
||||
onClicked: {
|
||||
AvatarInputs.showAudioTools = checked;
|
||||
checked = Qt.binding(function() { return AvatarInputs.showAudioTools; }); // restore binding
|
||||
AudioControls.CheckBox {
|
||||
text: qsTr("Show audio level meter");
|
||||
checked: AvatarInputs.showAudioTools;
|
||||
onClicked: {
|
||||
AvatarInputs.showAudioTools = checked;
|
||||
checked = Qt.binding(function() { return AvatarInputs.showAudioTools; }); // restore binding
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,12 +117,25 @@ Rectangle {
|
|||
delegate: Item {
|
||||
width: parent.width;
|
||||
height: 36;
|
||||
Audio.CheckBox {
|
||||
text: display;
|
||||
checked: selected;
|
||||
onClicked: {
|
||||
selected = checked;
|
||||
checked = Qt.binding(function() { return selected; }); // restore binding
|
||||
|
||||
RowLayout {
|
||||
width: parent.width;
|
||||
|
||||
AudioControls.CheckBox {
|
||||
Layout.maximumWidth: parent.width - level.width - 40;
|
||||
text: display;
|
||||
wrap: false;
|
||||
checked: selected;
|
||||
onClicked: {
|
||||
selected = checked;
|
||||
checked = Qt.binding(function() { return selected; }); // restore binding
|
||||
}
|
||||
}
|
||||
InputLevel {
|
||||
id: level;
|
||||
Layout.alignment: Qt.AlignRight;
|
||||
Layout.rightMargin: 30;
|
||||
visible: selected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,17 +144,23 @@ Rectangle {
|
|||
Separator {}
|
||||
|
||||
RowLayout {
|
||||
HiFiGlyphs {
|
||||
text: hifi.glyphs.unmuted;
|
||||
color: hifi.colors.primaryHighlight;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
size: 36;
|
||||
}
|
||||
RalewayRegular {
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
size: 16;
|
||||
color: hifi.colors.lightGrayText;
|
||||
text: qsTr("CHOOSE OUTPUT DEVICE");
|
||||
Column {
|
||||
RowLayout {
|
||||
HiFiGlyphs {
|
||||
text: hifi.glyphs.unmuted;
|
||||
color: hifi.colors.primaryHighlight;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
size: 36;
|
||||
}
|
||||
RalewayRegular {
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
size: 16;
|
||||
color: hifi.colors.lightGrayText;
|
||||
text: qsTr("CHOOSE OUTPUT DEVICE");
|
||||
}
|
||||
}
|
||||
|
||||
PlaySampleSound { anchors { left: parent.left; leftMargin: 60 }}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,7 +174,7 @@ Rectangle {
|
|||
delegate: Item {
|
||||
width: parent.width;
|
||||
height: 36;
|
||||
Audio.CheckBox {
|
||||
AudioControls.CheckBox {
|
||||
text: display;
|
||||
checked: selected;
|
||||
onClicked: {
|
||||
|
|
105
interface/resources/qml/hifi/audio/InputLevel.qml
Normal file
105
interface/resources/qml/hifi/audio/InputLevel.qml
Normal file
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// InputLevel.qml
|
||||
// qml/hifi/audio
|
||||
//
|
||||
// Created by Zach Pomerantz on 6/20/2017
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
Rectangle {
|
||||
readonly property var level: Audio.inputLevel;
|
||||
|
||||
width: 70;
|
||||
height: 8;
|
||||
|
||||
color: "transparent";
|
||||
|
||||
Item {
|
||||
id: colors;
|
||||
|
||||
readonly property string muted: "#E2334D";
|
||||
readonly property string gutter: "#575757";
|
||||
readonly property string greenStart: "#39A38F";
|
||||
readonly property string greenEnd: "#1FC6A6";
|
||||
readonly property string red: colors.muted;
|
||||
}
|
||||
|
||||
Text {
|
||||
id: status;
|
||||
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter;
|
||||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
visible: Audio.muted;
|
||||
color: colors.muted;
|
||||
|
||||
text: "MUTED";
|
||||
font.pointSize: 10;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: bar;
|
||||
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
|
||||
anchors { fill: parent }
|
||||
|
||||
visible: !status.visible;
|
||||
|
||||
Rectangle { // base
|
||||
radius: 4;
|
||||
anchors { fill: parent }
|
||||
color: colors.gutter;
|
||||
}
|
||||
|
||||
Rectangle { // mask
|
||||
id: mask;
|
||||
width: parent.width * level;
|
||||
radius: 5;
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
bottomMargin: 0;
|
||||
top: parent.top;
|
||||
topMargin: 0;
|
||||
left: parent.left;
|
||||
leftMargin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
LinearGradient {
|
||||
anchors { fill: mask }
|
||||
source: mask
|
||||
start: Qt.point(0, 0);
|
||||
end: Qt.point(70, 0);
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0;
|
||||
color: colors.greenStart;
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.8;
|
||||
color: colors.greenEnd;
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.801;
|
||||
color: colors.red;
|
||||
}
|
||||
GradientStop {
|
||||
position: 1;
|
||||
color: colors.red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
223
interface/resources/qml/hifi/audio/MicBar.qml
Normal file
223
interface/resources/qml/hifi/audio/MicBar.qml
Normal file
|
@ -0,0 +1,223 @@
|
|||
//
|
||||
// MicBar.qml
|
||||
// qml/hifi/audio
|
||||
//
|
||||
// Created by Zach Pomerantz on 6/14/2017
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
Rectangle {
|
||||
readonly property var level: Audio.inputLevel;
|
||||
|
||||
property bool standalone: false;
|
||||
property var dragTarget: null;
|
||||
|
||||
width: 240;
|
||||
height: 50;
|
||||
|
||||
radius: 5;
|
||||
|
||||
color: "#00000000";
|
||||
border {
|
||||
width: (standalone || Audio.muted || mouseArea.containsMouse) ? 2 : 0;
|
||||
color: colors.border;
|
||||
}
|
||||
|
||||
// borders are painted over fill, so reduce the fill to fit inside the border
|
||||
Rectangle {
|
||||
color: standalone ? colors.fill : "#00000000";
|
||||
width: 236;
|
||||
height: 46;
|
||||
|
||||
radius: 5;
|
||||
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter;
|
||||
horizontalCenter: parent.horizontalCenter;
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea;
|
||||
|
||||
anchors {
|
||||
left: icon.left;
|
||||
right: bar.right;
|
||||
top: icon.top;
|
||||
bottom: icon.bottom;
|
||||
}
|
||||
|
||||
hoverEnabled: true;
|
||||
scrollGestureEnabled: false;
|
||||
onClicked: { Audio.muted = !Audio.muted; }
|
||||
drag.target: dragTarget;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: colors;
|
||||
|
||||
readonly property string unmuted: "#FFF";
|
||||
readonly property string muted: "#E2334D";
|
||||
readonly property string gutter: "#575757";
|
||||
readonly property string greenStart: "#39A38F";
|
||||
readonly property string greenEnd: "#1FC6A6";
|
||||
readonly property string red: colors.muted;
|
||||
readonly property string fill: "#55000000";
|
||||
readonly property string border: standalone ? "#80FFFFFF" : "#55FFFFFF";
|
||||
readonly property string icon: (Audio.muted && !mouseArea.containsMouse) ? muted : unmuted;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: icon;
|
||||
|
||||
anchors {
|
||||
left: parent.left;
|
||||
leftMargin: 5;
|
||||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
width: 40;
|
||||
height: 40;
|
||||
|
||||
Item {
|
||||
Image {
|
||||
readonly property string unmutedIcon: "../../../icons/tablet-icons/mic-unmute-i.svg";
|
||||
readonly property string mutedIcon: "../../../icons/tablet-icons/mic-mute-i.svg";
|
||||
|
||||
function exclusiveOr(a, b) { return (a || b) && !(a && b); }
|
||||
|
||||
id: image;
|
||||
source: exclusiveOr(Audio.muted, mouseArea.containsMouse) ? mutedIcon : unmutedIcon;
|
||||
|
||||
width: 30;
|
||||
height: 30;
|
||||
anchors {
|
||||
left: parent.left;
|
||||
leftMargin: 5;
|
||||
top: parent.top;
|
||||
topMargin: 5;
|
||||
}
|
||||
}
|
||||
|
||||
ColorOverlay {
|
||||
anchors { fill: image }
|
||||
source: image;
|
||||
color: colors.icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: status;
|
||||
|
||||
readonly property string color: (Audio.muted && !mouseArea.containsMouse) ? colors.muted : colors.unmuted;
|
||||
|
||||
visible: Audio.muted || mouseArea.containsMouse;
|
||||
|
||||
anchors {
|
||||
left: parent.left;
|
||||
leftMargin: 50;
|
||||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
width: 170;
|
||||
height: 8
|
||||
|
||||
Text {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter;
|
||||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
color: parent.color;
|
||||
|
||||
text: Audio.muted ? (mouseArea.containsMouse ? "UNMUTE" : "MUTED") : "MUTE";
|
||||
font.pointSize: 12;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left;
|
||||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
width: 50;
|
||||
height: 4;
|
||||
color: parent.color;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
right: parent.right;
|
||||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
width: 50;
|
||||
height: 4;
|
||||
color: parent.color;
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: bar;
|
||||
|
||||
visible: !status.visible;
|
||||
|
||||
anchors.fill: status;
|
||||
|
||||
width: status.width;
|
||||
|
||||
Rectangle { // base
|
||||
radius: 4;
|
||||
anchors { fill: parent }
|
||||
color: colors.gutter;
|
||||
}
|
||||
|
||||
Rectangle { // mask
|
||||
id: mask;
|
||||
width: parent.width * level;
|
||||
radius: 5;
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
bottomMargin: 0;
|
||||
top: parent.top;
|
||||
topMargin: 0;
|
||||
left: parent.left;
|
||||
leftMargin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
LinearGradient {
|
||||
anchors { fill: mask }
|
||||
source: mask
|
||||
start: Qt.point(0, 0);
|
||||
end: Qt.point(170, 0);
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0;
|
||||
color: colors.greenStart;
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.8;
|
||||
color: colors.greenEnd;
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.81;
|
||||
color: colors.red;
|
||||
}
|
||||
GradientStop {
|
||||
position: 1;
|
||||
color: colors.red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
86
interface/resources/qml/hifi/audio/PlaySampleSound.qml
Normal file
86
interface/resources/qml/hifi/audio/PlaySampleSound.qml
Normal file
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// PlaySampleSound.qml
|
||||
// qml/hifi/audio
|
||||
//
|
||||
// Created by Zach Pomerantz on 6/13/2017
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import "../../styles-uit"
|
||||
import "../../controls-uit" as HifiControls
|
||||
|
||||
RowLayout {
|
||||
property var sound: null;
|
||||
property var sample: null;
|
||||
property bool isPlaying: false;
|
||||
function createSampleSound() {
|
||||
var SOUND = Qt.resolvedUrl("../../../sounds/sample.wav");
|
||||
sound = SoundCache.getSound(SOUND);
|
||||
sample = null;
|
||||
}
|
||||
function playSound() {
|
||||
// FIXME: MyAvatar is not properly exposed to QML; MyAvatar.qmlPosition is a stopgap
|
||||
// FIXME: Audio.playSystemSound should not require position
|
||||
sample = Audio.playSystemSound(sound, MyAvatar.qmlPosition);
|
||||
isPlaying = true;
|
||||
sample.finished.connect(function() { isPlaying = false; sample = null; });
|
||||
}
|
||||
function stopSound() {
|
||||
sample && sample.stop();
|
||||
}
|
||||
|
||||
Component.onCompleted: createSampleSound();
|
||||
Component.onDestruction: stopSound();
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
stopSound();
|
||||
}
|
||||
}
|
||||
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
Button {
|
||||
style: ButtonStyle {
|
||||
background: Rectangle {
|
||||
implicitWidth: 20;
|
||||
implicitHeight: 20;
|
||||
radius: hifi.buttons.radius;
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.2;
|
||||
color: isPlaying ? hifi.buttons.colorStart[hifi.buttons.blue] : hifi.buttons.colorStart[hifi.buttons.black];
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0;
|
||||
color: isPlaying ? hifi.buttons.colorFinish[hifi.buttons.blue] : hifi.buttons.colorFinish[hifi.buttons.black];
|
||||
}
|
||||
}
|
||||
}
|
||||
label: HiFiGlyphs {
|
||||
// absolutely position due to asymmetry in glyph
|
||||
x: isPlaying ? 0 : 1;
|
||||
y: 1;
|
||||
size: 14;
|
||||
color: (control.pressed || control.hovered) ? (isPlaying ? "black" : hifi.colors.primaryHighlight) : "white";
|
||||
text: isPlaying ? hifi.glyphs.stop_square : hifi.glyphs.playback_play;
|
||||
}
|
||||
}
|
||||
onClicked: isPlaying ? stopSound() : playSound();
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
Layout.leftMargin: 2;
|
||||
size: 14;
|
||||
color: "white";
|
||||
text: isPlaying ? qsTr("Stop sample sound") : qsTr("Play sample sound");
|
||||
}
|
||||
|
||||
}
|
|
@ -51,7 +51,20 @@ ScrollingWindow {
|
|||
}
|
||||
|
||||
function updateRunningScripts() {
|
||||
function simplify(path) {
|
||||
// trim URI querystring/fragment
|
||||
path = (path+'').replace(/[#?].*$/,'');
|
||||
// normalize separators and grab last path segment (ie: just the filename)
|
||||
path = path.replace(/\\/g, '/').split('/').pop();
|
||||
// return lowercased because we want to sort mnemonically
|
||||
return path.toLowerCase();
|
||||
}
|
||||
var runningScripts = ScriptDiscoveryService.getRunning();
|
||||
runningScripts.sort(function(a,b) {
|
||||
a = simplify(a.path);
|
||||
b = simplify(b.path);
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
});
|
||||
runningScriptsModel.clear()
|
||||
for (var i = 0; i < runningScripts.length; ++i) {
|
||||
runningScriptsModel.append(runningScripts[i]);
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "../../styles-uit"
|
||||
import "../audio" as HifiAudio
|
||||
|
||||
Item {
|
||||
id: tablet
|
||||
objectName: "tablet"
|
||||
property double micLevel: 0.8
|
||||
property int rowIndex: 0
|
||||
property int columnIndex: 0
|
||||
property int count: (flowMain.children.length - 1)
|
||||
|
||||
// called by C++ code to keep audio bar updated
|
||||
function setMicLevel(newMicLevel) {
|
||||
tablet.micLevel = newMicLevel;
|
||||
}
|
||||
|
||||
// used to look up a button by its uuid
|
||||
function findButtonIndex(uuid) {
|
||||
if (!uuid) {
|
||||
|
@ -83,6 +79,16 @@ Item {
|
|||
Rectangle {
|
||||
id: bgTopBar
|
||||
height: 90
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: 0
|
||||
left: parent.left
|
||||
leftMargin: 0
|
||||
right: parent.right
|
||||
rightMargin: 0
|
||||
}
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0
|
||||
|
@ -94,108 +100,13 @@ Item {
|
|||
color: "#1e1e1e"
|
||||
}
|
||||
}
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.topMargin: 0
|
||||
anchors.top: parent.top
|
||||
|
||||
Item {
|
||||
id: audioIcon
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 5
|
||||
|
||||
Image {
|
||||
id: micIcon
|
||||
source: "../../../icons/tablet-icons/mic.svg"
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: (Audio.muted && !toggleMuteMouseArea.containsMouse)
|
||||
|| (!Audio.muted && toggleMuteMouseArea.containsMouse)
|
||||
|
||||
Image {
|
||||
id: muteIcon
|
||||
source: "../../../icons/tablet-icons/mic-mute.svg"
|
||||
}
|
||||
|
||||
ColorOverlay {
|
||||
anchors.fill: muteIcon
|
||||
source: muteIcon
|
||||
color: toggleMuteMouseArea.containsMouse ? "#a0a0a0" : "#ff0000"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: audioBar
|
||||
width: 170
|
||||
height: 10
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 50
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Rectangle {
|
||||
id: audioBarBase
|
||||
color: "#333333"
|
||||
radius: 5
|
||||
anchors.fill: parent
|
||||
}
|
||||
Rectangle {
|
||||
id: audioBarMask
|
||||
width: parent.width * tablet.micLevel
|
||||
color: "#333333"
|
||||
radius: 5
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
}
|
||||
LinearGradient {
|
||||
anchors.fill: audioBarMask
|
||||
source: audioBarMask
|
||||
start: Qt.point(0, 0)
|
||||
end: Qt.point(170, 0)
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0
|
||||
color: "#2c8e72"
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.8
|
||||
color: "#1fc6a6"
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.81
|
||||
color: "#ea4c5f"
|
||||
}
|
||||
GradientStop {
|
||||
position: 1
|
||||
color: "#ea4c5f"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: toggleMuteMouseArea
|
||||
HifiAudio.MicBar {
|
||||
anchors {
|
||||
left: audioIcon.left
|
||||
right: audioBar.right
|
||||
top: audioIcon.top
|
||||
bottom: audioIcon.bottom
|
||||
left: parent.left
|
||||
leftMargin: 30
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
hoverEnabled: true
|
||||
preventStealing: true
|
||||
propagateComposedEvents: false
|
||||
scrollGestureEnabled: false
|
||||
onClicked: { Audio.muted = !Audio.muted }
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
|
@ -254,27 +165,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "muted state"
|
||||
|
||||
PropertyChanges {
|
||||
target: muteText
|
||||
text: "UNMUTE"
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: muteIcon
|
||||
visible: !Audio.muted
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: tablet
|
||||
micLevel: 0
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
function setCurrentItemState(state) {
|
||||
var index = rowIndex + columnIndex;
|
||||
|
||||
|
|
|
@ -333,5 +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 playback_play: "\ue01d"
|
||||
readonly property string stop_square: "\ue01e"
|
||||
}
|
||||
}
|
||||
|
|
BIN
interface/resources/sounds/sample.wav
Normal file
BIN
interface/resources/sounds/sample.wav
Normal file
Binary file not shown.
|
@ -88,6 +88,7 @@
|
|||
#include <UserActivityLoggerScriptingInterface.h>
|
||||
#include <LogHandler.h>
|
||||
#include "LocationBookmarks.h"
|
||||
#include <LocationScriptingInterface.h>
|
||||
#include <MainWindow.h>
|
||||
#include <MappingRequest.h>
|
||||
#include <MessagesClient.h>
|
||||
|
@ -160,7 +161,6 @@
|
|||
#include "scripting/DesktopScriptingInterface.h"
|
||||
#include "scripting/GlobalServicesScriptingInterface.h"
|
||||
#include "scripting/HMDScriptingInterface.h"
|
||||
#include "scripting/LocationScriptingInterface.h"
|
||||
#include "scripting/MenuScriptingInterface.h"
|
||||
#include "scripting/SettingsScriptingInterface.h"
|
||||
#include "scripting/WindowScriptingInterface.h"
|
||||
|
@ -4120,7 +4120,7 @@ void Application::updateMyAvatarLookAtPosition() {
|
|||
lookAtSpot = transformPoint(worldHeadMat, glm::vec3(0.0f, 0.0f, TREE_SCALE));
|
||||
} else {
|
||||
lookAtSpot = myAvatar->getHead()->getEyePosition() +
|
||||
(myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE));
|
||||
(myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, TREE_SCALE));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5569,6 +5569,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
connect(scriptEngine, &ScriptEngine::errorMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onErrorMessage);
|
||||
connect(scriptEngine, &ScriptEngine::warningMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onWarningMessage);
|
||||
connect(scriptEngine, &ScriptEngine::infoMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onInfoMessage);
|
||||
connect(scriptEngine, &ScriptEngine::clearDebugWindow, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onClearDebugWindow);
|
||||
}
|
||||
|
||||
bool Application::canAcceptURL(const QString& urlString) const {
|
||||
|
|
|
@ -87,9 +87,10 @@ const float MyAvatar::ZOOM_MAX = 25.0f;
|
|||
const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
||||
|
||||
// default values, used when avatar is missing joints... (avatar space)
|
||||
// static const glm::quat DEFAULT_AVATAR_MIDDLE_EYE_ROT { Quaternions::Y_180 };
|
||||
static const glm::quat DEFAULT_AVATAR_MIDDLE_EYE_ROT { Quaternions::Y_180 };
|
||||
static const glm::vec3 DEFAULT_AVATAR_MIDDLE_EYE_POS { 0.0f, 0.6f, 0.0f };
|
||||
static const glm::vec3 DEFAULT_AVATAR_HEAD_POS { 0.0f, 0.53f, 0.0f };
|
||||
static const glm::quat DEFAULT_AVATAR_HEAD_ROT { Quaternions::Y_180 };
|
||||
static const glm::vec3 DEFAULT_AVATAR_RIGHTARM_POS { -0.134824f, 0.396348f, -0.0515777f };
|
||||
static const glm::quat DEFAULT_AVATAR_RIGHTARM_ROT { -0.536241f, 0.536241f, -0.460918f, -0.460918f };
|
||||
static const glm::vec3 DEFAULT_AVATAR_LEFTARM_POS { 0.134795f, 0.396349f, -0.0515881f };
|
||||
|
@ -100,7 +101,9 @@ static const glm::vec3 DEFAULT_AVATAR_LEFTHAND_POS { 0.727588f, 0.39635f, -0.051
|
|||
static const glm::quat DEFAULT_AVATAR_LEFTHAND_ROT { -0.479181f, -0.52001f, 0.52254f, -0.476369f };
|
||||
static const glm::vec3 DEFAULT_AVATAR_NECK_POS { 0.0f, 0.445f, 0.025f };
|
||||
static const glm::vec3 DEFAULT_AVATAR_SPINE2_POS { 0.0f, 0.32f, 0.02f };
|
||||
static const glm::quat DEFAULT_AVATAR_SPINE2_ROT { Quaternions::Y_180 };
|
||||
static const glm::vec3 DEFAULT_AVATAR_HIPS_POS { 0.0f, 0.0f, 0.0f };
|
||||
static const glm::quat DEFAULT_AVATAR_HIPS_ROT { Quaternions::Y_180 };
|
||||
static const glm::vec3 DEFAULT_AVATAR_LEFTFOOT_POS { -0.08f, -0.96f, 0.029f};
|
||||
static const glm::quat DEFAULT_AVATAR_LEFTFOOT_ROT { -0.40167322754859924f, 0.9154590368270874f, -0.005437685176730156f, -0.023744143545627594f };
|
||||
static const glm::vec3 DEFAULT_AVATAR_RIGHTFOOT_POS { 0.08f, -0.96f, 0.029f };
|
||||
|
@ -2764,7 +2767,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
|||
const glm::mat4& currentBodyMatrix, bool hasDriveInput) {
|
||||
|
||||
if (myAvatar.getHMDLeanRecenterEnabled()) {
|
||||
if (!isActive(Rotation) && shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix)) {
|
||||
if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||
activate(Rotation);
|
||||
}
|
||||
if (!isActive(Horizontal) && shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix)) {
|
||||
|
@ -2966,7 +2969,7 @@ glm::mat4 MyAvatar::getCenterEyeCalibrationMat() const {
|
|||
auto centerEyeRot = Quaternions::Y_180;
|
||||
return createMatFromQuatAndPos(centerEyeRot, centerEyePos);
|
||||
} else {
|
||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_MIDDLE_EYE_POS, DEFAULT_AVATAR_MIDDLE_EYE_POS);
|
||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_MIDDLE_EYE_ROT, DEFAULT_AVATAR_MIDDLE_EYE_POS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2978,7 +2981,7 @@ glm::mat4 MyAvatar::getHeadCalibrationMat() const {
|
|||
auto headRot = getAbsoluteDefaultJointRotationInObjectFrame(headIndex);
|
||||
return createMatFromQuatAndPos(headRot, headPos);
|
||||
} else {
|
||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_HEAD_POS, DEFAULT_AVATAR_HEAD_POS);
|
||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_HEAD_ROT, DEFAULT_AVATAR_HEAD_POS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2990,7 +2993,7 @@ glm::mat4 MyAvatar::getSpine2CalibrationMat() const {
|
|||
auto spine2Rot = getAbsoluteDefaultJointRotationInObjectFrame(spine2Index);
|
||||
return createMatFromQuatAndPos(spine2Rot, spine2Pos);
|
||||
} else {
|
||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_SPINE2_POS, DEFAULT_AVATAR_SPINE2_POS);
|
||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_SPINE2_ROT, DEFAULT_AVATAR_SPINE2_POS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3002,7 +3005,7 @@ glm::mat4 MyAvatar::getHipsCalibrationMat() const {
|
|||
auto hipsRot = getAbsoluteDefaultJointRotationInObjectFrame(hipsIndex);
|
||||
return createMatFromQuatAndPos(hipsRot, hipsPos);
|
||||
} else {
|
||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_HIPS_POS, DEFAULT_AVATAR_HIPS_POS);
|
||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_HIPS_ROT, DEFAULT_AVATAR_HIPS_POS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ class MyAvatar : public Avatar {
|
|||
*
|
||||
* @namespace MyAvatar
|
||||
* @augments Avatar
|
||||
* @property qmlPosition {Vec3} Used as a stopgap for position access by QML, as glm::vec3 is unavailable outside of scripts
|
||||
* @property shouldRenderLocally {bool} Set it to true if you would like to see MyAvatar in your local interface,
|
||||
* and false if you would not like to see MyAvatar in your local interface.
|
||||
* @property motorVelocity {Vec3} Can be used to move the avatar with this velocity.
|
||||
|
@ -101,6 +102,10 @@ class MyAvatar : public Avatar {
|
|||
* "scripts/system/controllers/toggleAdvancedMovementForHandControllers.js".
|
||||
*/
|
||||
|
||||
// FIXME: `glm::vec3 position` is not accessible from QML, so this exposes position in a QML-native type
|
||||
Q_PROPERTY(QVector3D qmlPosition READ getQmlPosition)
|
||||
QVector3D getQmlPosition() { auto p = getPosition(); return QVector3D(p.x, p.y, p.z); }
|
||||
|
||||
Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally)
|
||||
Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity)
|
||||
Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale)
|
||||
|
|
|
@ -23,9 +23,33 @@ QString Audio::HMD { "VR" };
|
|||
|
||||
Setting::Handle<bool> enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true };
|
||||
|
||||
float Audio::loudnessToLevel(float loudness) {
|
||||
const float LOG2 = log(2.0f);
|
||||
const float METER_LOUDNESS_SCALE = 2.8f / 5.0f;
|
||||
const float LOG2_LOUDNESS_FLOOR = 11.0f;
|
||||
|
||||
float level = 0.0f;
|
||||
|
||||
loudness += 1.0f;
|
||||
float log2loudness = logf(loudness) / LOG2;
|
||||
|
||||
if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
|
||||
level = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE;
|
||||
} else {
|
||||
level = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.0f)) * METER_LOUDNESS_SCALE;
|
||||
}
|
||||
|
||||
if (level > 1.0f) {
|
||||
level = 1.0;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
Audio::Audio() : _devices(_contextIsHMD) {
|
||||
auto client = DependencyManager::get<AudioClient>();
|
||||
connect(client.data(), &AudioClient::muteToggled, this, &Audio::onMutedChanged);
|
||||
auto client = DependencyManager::get<AudioClient>().data();
|
||||
connect(client, &AudioClient::muteToggled, this, &Audio::onMutedChanged);
|
||||
connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged);
|
||||
connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged);
|
||||
connect(&_devices._inputs, &AudioDeviceList::deviceChanged, this, &Audio::onInputChanged);
|
||||
enableNoiseReduction(enableNoiseReductionSetting.get());
|
||||
|
@ -88,6 +112,15 @@ void Audio::onInputChanged() {
|
|||
}
|
||||
}
|
||||
|
||||
void Audio::onInputLoudnessChanged(float loudness) {
|
||||
float level = loudnessToLevel(loudness);
|
||||
|
||||
if (_inputLevel != level) {
|
||||
_inputLevel = level;
|
||||
emit inputLevelChanged(_inputLevel);
|
||||
}
|
||||
}
|
||||
|
||||
QString Audio::getContext() const {
|
||||
return _contextIsHMD ? Audio::HMD : Audio::DESKTOP;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ class Audio : public AudioScriptingInterface {
|
|||
Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
|
||||
Q_PROPERTY(bool noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY noiseReductionChanged)
|
||||
Q_PROPERTY(float inputVolume READ getInputVolume WRITE setInputVolume NOTIFY inputVolumeChanged)
|
||||
Q_PROPERTY(float inputLevel READ getInputLevel NOTIFY inputLevelChanged)
|
||||
Q_PROPERTY(QString context READ getContext NOTIFY contextChanged)
|
||||
Q_PROPERTY(AudioDevices* devices READ getDevices NOTIFY nop)
|
||||
|
||||
|
@ -34,11 +35,14 @@ public:
|
|||
static QString HMD;
|
||||
static QString DESKTOP;
|
||||
|
||||
static float loudnessToLevel(float loudness);
|
||||
|
||||
virtual ~Audio() {}
|
||||
|
||||
bool isMuted() const { return _isMuted; }
|
||||
bool noiseReductionEnabled() const { return _enableNoiseReduction; }
|
||||
float getInputVolume() const { return _inputVolume; }
|
||||
float getInputLevel() const { return _inputLevel; }
|
||||
QString getContext() const;
|
||||
|
||||
void setMuted(bool muted);
|
||||
|
@ -54,12 +58,14 @@ signals:
|
|||
void mutedChanged(bool isMuted);
|
||||
void noiseReductionChanged(bool isEnabled);
|
||||
void inputVolumeChanged(float volume);
|
||||
void inputLevelChanged(float level);
|
||||
void contextChanged(const QString& context);
|
||||
|
||||
public slots:
|
||||
void onMutedChanged();
|
||||
void onContextChanged();
|
||||
void onInputChanged();
|
||||
void onInputLoudnessChanged(float loudness);
|
||||
|
||||
protected:
|
||||
// Audio must live on a separate thread from AudioClient to avoid deadlocks
|
||||
|
@ -68,6 +74,7 @@ protected:
|
|||
private:
|
||||
|
||||
float _inputVolume { 1.0f };
|
||||
float _inputLevel { 0.0f };
|
||||
bool _isMuted { false };
|
||||
bool _enableNoiseReduction;
|
||||
bool _contextIsHMD { false };
|
||||
|
|
|
@ -45,15 +45,6 @@ AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) {
|
|||
} \
|
||||
}
|
||||
|
||||
#define AI_UPDATE_FLOAT(name, src, epsilon) \
|
||||
{ \
|
||||
float val = src; \
|
||||
if (fabsf(_##name - val) >= epsilon) { \
|
||||
_##name = val; \
|
||||
emit name##Changed(); \
|
||||
} \
|
||||
}
|
||||
|
||||
float AvatarInputs::loudnessToAudioLevel(float loudness) {
|
||||
const float AUDIO_METER_AVERAGING = 0.5;
|
||||
const float LOG2 = log(2.0f);
|
||||
|
@ -85,27 +76,6 @@ void AvatarInputs::update() {
|
|||
AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking));
|
||||
AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking));
|
||||
AI_UPDATE(isHMD, qApp->isHMDMode());
|
||||
|
||||
auto audioIO = DependencyManager::get<AudioClient>();
|
||||
|
||||
const float audioLevel = loudnessToAudioLevel(DependencyManager::get<AudioClient>()->getLastInputLoudness());
|
||||
|
||||
AI_UPDATE_FLOAT(audioLevel, audioLevel, 0.01f);
|
||||
AI_UPDATE(audioClipping, ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f)));
|
||||
AI_UPDATE(audioMuted, audioIO->isMuted());
|
||||
|
||||
//// Make muted icon pulsate
|
||||
//static const float PULSE_MIN = 0.4f;
|
||||
//static const float PULSE_MAX = 1.0f;
|
||||
//static const float PULSE_FREQUENCY = 1.0f; // in Hz
|
||||
//qint64 now = usecTimestampNow();
|
||||
//if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) {
|
||||
// // Prevents t from getting too big, which would diminish glm::cos precision
|
||||
// _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND);
|
||||
//}
|
||||
//float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND;
|
||||
//float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f;
|
||||
//iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor;
|
||||
}
|
||||
|
||||
void AvatarInputs::setShowAudioTools(bool showAudioTools) {
|
||||
|
@ -124,10 +94,6 @@ void AvatarInputs::toggleCameraMute() {
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarInputs::toggleAudioMute() {
|
||||
DependencyManager::get<AudioClient>()->toggleMute();
|
||||
}
|
||||
|
||||
void AvatarInputs::resetSensors() {
|
||||
qApp->resetSensors();
|
||||
}
|
||||
|
|
|
@ -25,9 +25,6 @@ class AvatarInputs : public QQuickItem {
|
|||
|
||||
AI_PROPERTY(bool, cameraEnabled, false)
|
||||
AI_PROPERTY(bool, cameraMuted, false)
|
||||
AI_PROPERTY(bool, audioMuted, false)
|
||||
AI_PROPERTY(bool, audioClipping, false)
|
||||
AI_PROPERTY(float, audioLevel, 0)
|
||||
AI_PROPERTY(bool, isHMD, false)
|
||||
|
||||
Q_PROPERTY(bool showAudioTools READ showAudioTools WRITE setShowAudioTools NOTIFY showAudioToolsChanged)
|
||||
|
@ -45,16 +42,12 @@ public slots:
|
|||
signals:
|
||||
void cameraEnabledChanged();
|
||||
void cameraMutedChanged();
|
||||
void audioMutedChanged();
|
||||
void audioClippingChanged();
|
||||
void audioLevelChanged();
|
||||
void isHMDChanged();
|
||||
void showAudioToolsChanged(bool show);
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void resetSensors();
|
||||
Q_INVOKABLE void toggleCameraMute();
|
||||
Q_INVOKABLE void toggleAudioMute();
|
||||
|
||||
private:
|
||||
float _trailingAudioLoudness{ 0 };
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "avatar/AvatarManager.h"
|
||||
#include "scripting/GlobalServicesScriptingInterface.h"
|
||||
#include "ui/Snapshot.h"
|
||||
#include "SoundCache.h"
|
||||
|
||||
static const float DPI = 30.47f;
|
||||
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
|
||||
|
@ -199,6 +200,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("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
|
||||
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
|
||||
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data());
|
||||
|
|
|
@ -1023,6 +1023,8 @@ void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
|||
emit inputReceived(audioBuffer);
|
||||
}
|
||||
|
||||
emit inputLoudnessChanged(_lastInputLoudness);
|
||||
|
||||
// state machine to detect gate opening and closing
|
||||
bool audioGateOpen = (_lastInputLoudness != 0.0f);
|
||||
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
||||
|
|
|
@ -210,6 +210,7 @@ signals:
|
|||
bool muteToggled();
|
||||
void mutedByMixer();
|
||||
void inputReceived(const QByteArray& inputSamples);
|
||||
void inputLoudnessChanged(float loudness);
|
||||
void outputBytesToNetwork(int numBytes);
|
||||
void inputBytesFromNetwork(int numBytes);
|
||||
void noiseGateOpened();
|
||||
|
|
|
@ -246,8 +246,13 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityIt
|
|||
|
||||
// if this entity is a zone and visible, determine if it is the bestZone
|
||||
if (isZone && entity->getVisible()) {
|
||||
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
_layeredZones.insert(zone);
|
||||
auto renderID = std::dynamic_pointer_cast<RenderableZoneEntityItem>(entity)->getRenderItemID();
|
||||
bool isValidRenderID = (renderID != render::Item::INVALID_ITEM_ID);
|
||||
|
||||
if (isValidRenderID) {
|
||||
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
_layeredZones.insert(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -354,6 +359,7 @@ bool EntityTreeRenderer::applyLayeredZones() {
|
|||
|
||||
for (auto& zone : _layeredZones) {
|
||||
auto id = std::dynamic_pointer_cast<RenderableZoneEntityItem>(zone.zone)->getRenderItemID();
|
||||
Q_ASSERT(id != render::Item::INVALID_ITEM_ID);
|
||||
list.push_back(id);
|
||||
}
|
||||
render::Selection selection("RankedZones", list);
|
||||
|
|
|
@ -386,7 +386,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
return 0;
|
||||
}
|
||||
|
||||
qint64 clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
|
||||
int64_t clockSkew = 0;
|
||||
uint64_t maxPingRoundTrip = 33333; // two frames periods at 60 fps
|
||||
if (args.sourceNode) {
|
||||
clockSkew = args.sourceNode->getClockSkewUsec();
|
||||
const float MSECS_PER_USEC = 1000;
|
||||
maxPingRoundTrip += args.sourceNode->getPingMs() * MSECS_PER_USEC;
|
||||
}
|
||||
|
||||
BufferParser parser(data, bytesLeftToRead);
|
||||
|
||||
|
@ -653,7 +659,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
const QUuid& myNodeID = nodeList->getSessionUUID();
|
||||
bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
|
||||
|
||||
|
||||
// pack SimulationOwner and terse update properties near each other
|
||||
// NOTE: the server is authoritative for changes to simOwnerID so we always unpack ownership data
|
||||
// even when we would otherwise ignore the rest of the packet.
|
||||
|
@ -678,7 +683,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
if (newSimOwner.getID().isNull() && !_simulationOwner.pendingRelease(lastEditedFromBufferAdjusted)) {
|
||||
// entity-server is trying to clear our ownership (probably at our own request)
|
||||
// but we actually want to own it, therefore we ignore this clear event
|
||||
// and pretend that we own it (we assume we'll recover it soon)
|
||||
// and pretend that we own it (e.g. we assume we'll receive ownership soon)
|
||||
|
||||
// However, for now, when the server uses a newer time than what we sent, listen to what we're told.
|
||||
if (overwriteLocalData) {
|
||||
|
@ -690,16 +695,19 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
// recompute weOwnSimulation for later
|
||||
weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
|
||||
}
|
||||
} else if (newSimOwner.getID().isNull() && _simulationOwner.pendingTake(lastEditedFromBufferAdjusted)) {
|
||||
// entity-server is trying to clear someone else's ownership
|
||||
// but we want to own it, therefore we ignore this clear event
|
||||
// and pretend that we own it (we assume we'll get it soon)
|
||||
} else if (_simulationOwner.pendingTake(now - maxPingRoundTrip)) {
|
||||
// we sent a bid before this packet could have been sent from the server
|
||||
// so we ignore it and pretend we own the object's simulation
|
||||
weOwnSimulation = true;
|
||||
if (!_simulationOwner.isNull()) {
|
||||
// someone else really did own it
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
|
||||
somethingChanged = true;
|
||||
_simulationOwner.clearCurrentOwner();
|
||||
if (newSimOwner.getID().isNull()) {
|
||||
// entity-server is trying to clear someone else's ownership
|
||||
// but we want to own it, therefore we ignore this clear event
|
||||
if (!_simulationOwner.isNull()) {
|
||||
// someone else really did own it
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
|
||||
somethingChanged = true;
|
||||
_simulationOwner.clearCurrentOwner();
|
||||
}
|
||||
}
|
||||
} else if (newSimOwner.matchesValidID(myNodeID) && !_hasBidOnSimulation) {
|
||||
// entity-server tells us that we have simulation ownership while we never requested this for this EntityItem,
|
||||
|
|
|
@ -24,9 +24,10 @@ const int KTXCache::INVALID_VERSION = 0x00;
|
|||
const char* KTXCache::SETTING_VERSION_NAME = "hifi.ktx.cache_version";
|
||||
|
||||
KTXCache::KTXCache(const std::string& dir, const std::string& ext) :
|
||||
FileCache(dir, ext) {
|
||||
initialize();
|
||||
FileCache(dir, ext) { }
|
||||
|
||||
void KTXCache::initialize() {
|
||||
FileCache::initialize();
|
||||
Setting::Handle<int> cacheVersionHandle(SETTING_VERSION_NAME, INVALID_VERSION);
|
||||
auto cacheVersion = cacheVersionHandle.get();
|
||||
if (cacheVersion != CURRENT_VERSION) {
|
||||
|
@ -35,20 +36,9 @@ KTXCache::KTXCache(const std::string& dir, const std::string& ext) :
|
|||
}
|
||||
}
|
||||
|
||||
KTXFilePointer KTXCache::writeFile(const char* data, Metadata&& metadata) {
|
||||
FilePointer file = FileCache::writeFile(data, std::move(metadata), true);
|
||||
return std::static_pointer_cast<KTXFile>(file);
|
||||
}
|
||||
|
||||
KTXFilePointer KTXCache::getFile(const Key& key) {
|
||||
return std::static_pointer_cast<KTXFile>(FileCache::getFile(key));
|
||||
}
|
||||
|
||||
std::unique_ptr<File> KTXCache::createFile(Metadata&& metadata, const std::string& filepath) {
|
||||
qCInfo(file_cache) << "Wrote KTX" << metadata.key.c_str();
|
||||
return std::unique_ptr<File>(new KTXFile(std::move(metadata), filepath));
|
||||
return FileCache::createFile(std::move(metadata), filepath);
|
||||
}
|
||||
|
||||
KTXFile::KTXFile(Metadata&& metadata, const std::string& filepath) :
|
||||
cache::File(std::move(metadata), filepath) {}
|
||||
|
||||
|
|
|
@ -35,20 +35,10 @@ public:
|
|||
|
||||
KTXCache(const std::string& dir, const std::string& ext);
|
||||
|
||||
KTXFilePointer writeFile(const char* data, Metadata&& metadata);
|
||||
KTXFilePointer getFile(const Key& key);
|
||||
void initialize() override;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<cache::File> createFile(Metadata&& metadata, const std::string& filepath) override final;
|
||||
};
|
||||
|
||||
class KTXFile : public cache::File {
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
friend class KTXCache;
|
||||
|
||||
KTXFile(Metadata&& metadata, const std::string& filepath);
|
||||
};
|
||||
|
||||
#endif // hifi_KTXCache_h
|
||||
|
|
|
@ -58,8 +58,8 @@ static const QUrl SPECTATOR_CAMERA_FRAME_URL("resource://spectatorCameraFrame");
|
|||
static const float SKYBOX_LOAD_PRIORITY { 10.0f }; // Make sure skybox loads first
|
||||
static const float HIGH_MIPS_LOAD_PRIORITY { 9.0f }; // Make sure high mips loads after skybox but before models
|
||||
|
||||
TextureCache::TextureCache() :
|
||||
_ktxCache(KTX_DIRNAME, KTX_EXT) {
|
||||
TextureCache::TextureCache() {
|
||||
_ktxCache->initialize();
|
||||
setUnusedResourceCacheSize(0);
|
||||
setObjectName("TextureCache");
|
||||
}
|
||||
|
@ -718,7 +718,7 @@ void NetworkTexture::handleFinishedInitialLoad() {
|
|||
gpu::TexturePointer texture = textureCache->getTextureByHash(hash);
|
||||
|
||||
if (!texture) {
|
||||
KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash);
|
||||
auto ktxFile = textureCache->_ktxCache->getFile(hash);
|
||||
if (ktxFile) {
|
||||
texture = gpu::Texture::unserialize(ktxFile);
|
||||
if (texture) {
|
||||
|
@ -742,9 +742,9 @@ void NetworkTexture::handleFinishedInitialLoad() {
|
|||
// Move ktx to file
|
||||
const char* data = reinterpret_cast<const char*>(memKtx->_storage->data());
|
||||
size_t length = memKtx->_storage->size();
|
||||
KTXFilePointer file;
|
||||
cache::FilePointer file;
|
||||
auto& ktxCache = textureCache->_ktxCache;
|
||||
if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) {
|
||||
if (!memKtx || !(file = ktxCache->writeFile(data, KTXCache::Metadata(filename, length)))) {
|
||||
qCWarning(modelnetworking) << url << " failed to write cache file";
|
||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||
Q_ARG(gpu::TexturePointer, nullptr),
|
||||
|
@ -900,7 +900,7 @@ void ImageReader::read() {
|
|||
|
||||
// If there is no live texture, check if there's an existing KTX file
|
||||
if (!texture) {
|
||||
KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash);
|
||||
auto ktxFile = textureCache->_ktxCache->getFile(hash);
|
||||
if (ktxFile) {
|
||||
texture = gpu::Texture::unserialize(ktxFile);
|
||||
if (texture) {
|
||||
|
@ -950,7 +950,7 @@ void ImageReader::read() {
|
|||
const char* data = reinterpret_cast<const char*>(memKtx->_storage->data());
|
||||
size_t length = memKtx->_storage->size();
|
||||
auto& ktxCache = textureCache->_ktxCache;
|
||||
auto file = ktxCache.writeFile(data, KTXCache::Metadata(hash, length));
|
||||
auto file = ktxCache->writeFile(data, KTXCache::Metadata(hash, length));
|
||||
if (!file) {
|
||||
qCWarning(modelnetworking) << _url << "file cache failed";
|
||||
} else {
|
||||
|
|
|
@ -189,7 +189,7 @@ private:
|
|||
static const std::string KTX_DIRNAME;
|
||||
static const std::string KTX_EXT;
|
||||
|
||||
KTXCache _ktxCache;
|
||||
std::shared_ptr<cache::FileCache> _ktxCache { std::make_shared<KTXCache>(KTX_DIRNAME, KTX_EXT) };
|
||||
// Map from image hashes to texture weak pointers
|
||||
std::unordered_map<std::string, std::weak_ptr<gpu::Texture>> _texturesByHashes;
|
||||
std::mutex _texturesByHashesMutex;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// LocationScriptingInterface.cpp
|
||||
// interface/src/scripting
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Ryan Huffman on 4/29/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <AddressManager.h>
|
||||
#include "AddressManager.h"
|
||||
|
||||
#include "LocationScriptingInterface.h"
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// LocationScriptingInterface.h
|
||||
// interface/src/scripting
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Ryan Huffman on 4/29/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
|
@ -23,14 +23,16 @@ const uint16_t ObjectActionTractor::tractorVersion = 1;
|
|||
|
||||
ObjectActionTractor::ObjectActionTractor(const QUuid& id, EntityItemPointer ownerEntity) :
|
||||
ObjectAction(DYNAMIC_TYPE_TRACTOR, id, ownerEntity),
|
||||
_positionalTarget(glm::vec3(0.0f)),
|
||||
_desiredPositionalTarget(glm::vec3(0.0f)),
|
||||
_positionalTarget(0.0f),
|
||||
_desiredPositionalTarget(0.0f),
|
||||
_linearTimeScale(FLT_MAX),
|
||||
_positionalTargetSet(true),
|
||||
_rotationalTarget(glm::quat()),
|
||||
_desiredRotationalTarget(glm::quat()),
|
||||
_positionalTargetSet(false),
|
||||
_rotationalTarget(),
|
||||
_desiredRotationalTarget(),
|
||||
_angularTimeScale(FLT_MAX),
|
||||
_rotationalTargetSet(true) {
|
||||
_rotationalTargetSet(true),
|
||||
_linearVelocityTarget(0.0f)
|
||||
{
|
||||
#if WANT_DEBUG
|
||||
qCDebug(physics) << "ObjectActionTractor::ObjectActionTractor";
|
||||
#endif
|
||||
|
@ -77,7 +79,6 @@ bool ObjectActionTractor::prepareForTractorUpdate(btScalar deltaTimeStep) {
|
|||
|
||||
glm::quat rotation;
|
||||
glm::vec3 position;
|
||||
glm::vec3 linearVelocity;
|
||||
glm::vec3 angularVelocity;
|
||||
|
||||
bool linearValid = false;
|
||||
|
@ -117,7 +118,6 @@ bool ObjectActionTractor::prepareForTractorUpdate(btScalar deltaTimeStep) {
|
|||
linearValid = true;
|
||||
linearTractorCount++;
|
||||
position += positionForAction;
|
||||
linearVelocity += linearVelocityForAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,9 +126,18 @@ bool ObjectActionTractor::prepareForTractorUpdate(btScalar deltaTimeStep) {
|
|||
withWriteLock([&]{
|
||||
if (linearValid && linearTractorCount > 0) {
|
||||
position /= linearTractorCount;
|
||||
linearVelocity /= linearTractorCount;
|
||||
if (_positionalTargetSet) {
|
||||
_lastPositionTarget = _positionalTarget;
|
||||
} else {
|
||||
_lastPositionTarget = position;
|
||||
}
|
||||
_positionalTarget = position;
|
||||
_linearVelocityTarget = linearVelocity;
|
||||
if (deltaTimeStep > EPSILON) {
|
||||
// blend the new velocity with the old (low-pass filter)
|
||||
glm::vec3 newVelocity = (1.0f / deltaTimeStep) * (position - _lastPositionTarget);
|
||||
const float blend = 0.25f;
|
||||
_linearVelocityTarget = (1.0f - blend) * _linearVelocityTarget + blend * newVelocity;
|
||||
}
|
||||
_positionalTargetSet = true;
|
||||
_active = true;
|
||||
}
|
||||
|
@ -169,19 +178,19 @@ void ObjectActionTractor::updateActionWorker(btScalar deltaTimeStep) {
|
|||
}
|
||||
|
||||
if (_linearTimeScale < MAX_TRACTOR_TIMESCALE) {
|
||||
btVector3 targetVelocity(0.0f, 0.0f, 0.0f);
|
||||
btVector3 offsetVelocity(0.0f, 0.0f, 0.0f);
|
||||
btVector3 offset = rigidBody->getCenterOfMassPosition() - glmToBullet(_positionalTarget);
|
||||
float offsetLength = offset.length();
|
||||
if (offsetLength > FLT_EPSILON) {
|
||||
float speed = glm::min(offsetLength / _linearTimeScale, TRACTOR_MAX_SPEED);
|
||||
targetVelocity = (-speed / offsetLength) * offset;
|
||||
offsetVelocity = (-speed / offsetLength) * offset;
|
||||
if (speed > rigidBody->getLinearSleepingThreshold()) {
|
||||
forceBodyNonStatic();
|
||||
rigidBody->activate();
|
||||
}
|
||||
}
|
||||
// this action is aggresively critically damped and defeats the current velocity
|
||||
rigidBody->setLinearVelocity(targetVelocity);
|
||||
rigidBody->setLinearVelocity(glmToBullet(_linearVelocityTarget) + offsetVelocity);
|
||||
}
|
||||
|
||||
if (_angularTimeScale < MAX_TRACTOR_TIMESCALE) {
|
||||
|
|
|
@ -36,6 +36,7 @@ protected:
|
|||
|
||||
glm::vec3 _positionalTarget;
|
||||
glm::vec3 _desiredPositionalTarget;
|
||||
glm::vec3 _lastPositionTarget;
|
||||
float _linearTimeScale;
|
||||
bool _positionalTargetSet;
|
||||
|
||||
|
|
|
@ -124,6 +124,11 @@ signals:
|
|||
void dirtyEnabled();
|
||||
};
|
||||
|
||||
class TConfigProxy {
|
||||
public:
|
||||
using Config = JobConfig;
|
||||
};
|
||||
|
||||
class TaskConfig : public JobConfig {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -134,12 +139,37 @@ public:
|
|||
TaskConfig() = default ;
|
||||
TaskConfig(bool enabled) : JobConfig(enabled) {}
|
||||
|
||||
|
||||
|
||||
// Get a sub job config through task.getConfig(path)
|
||||
// where path can be:
|
||||
// - <job_name> search for the first job named job_name traversing the the sub graph of task and jobs (from this task as root)
|
||||
// - <parent_name>.[<sub_parent_names>.]<job_name>
|
||||
// Allowing to first look for the parent_name job (from this task as root) and then search from there for the
|
||||
// optional sub_parent_names and finally from there looking for the job_name (assuming every job in the path were found)
|
||||
//
|
||||
// getter for qml integration, prefer the templated getter
|
||||
Q_INVOKABLE QObject* getConfig(const QString& name) { return QObject::findChild<JobConfig*>(name); }
|
||||
Q_INVOKABLE QObject* getConfig(const QString& name) { return getConfig<TConfigProxy>(name.toStdString()); }
|
||||
// getter for cpp (strictly typed), prefer this getter
|
||||
template <class T> typename T::Config* getConfig(std::string job = "") const {
|
||||
QString name = job.empty() ? QString() : QString(job.c_str()); // an empty string is not a null string
|
||||
return findChild<typename T::Config*>(name);
|
||||
const TaskConfig* root = this;
|
||||
QString path = (job.empty() ? QString() : QString(job.c_str())); // an empty string is not a null string
|
||||
auto tokens = path.split('.', QString::SkipEmptyParts);
|
||||
|
||||
if (tokens.empty()) {
|
||||
tokens.push_back(QString());
|
||||
} else {
|
||||
while (tokens.size() > 1) {
|
||||
auto name = tokens.front();
|
||||
tokens.pop_front();
|
||||
root = QObject::findChild<TaskConfig*>(name);
|
||||
if (!root) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return root->findChild<typename T::Config*>(tokens.front());
|
||||
}
|
||||
|
||||
void connectChildConfig(QConfigPointer childConfig, const std::string& name);
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "AudioScriptingInterface.h"
|
||||
|
||||
#include <QVector3D>
|
||||
|
||||
#include "ScriptAudioInjector.h"
|
||||
#include "ScriptEngineLogging.h"
|
||||
|
||||
|
@ -19,6 +21,13 @@ void registerAudioMetaTypes(QScriptEngine* engine) {
|
|||
qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue);
|
||||
}
|
||||
|
||||
ScriptAudioInjector* AudioScriptingInterface::playSystemSound(SharedSoundPointer sound, const QVector3D& position) {
|
||||
AudioInjectorOptions options;
|
||||
options.position = glm::vec3(position.x(), position.y(), position.z());
|
||||
options.localOnly = true;
|
||||
return playSound(sound, options);
|
||||
}
|
||||
|
||||
ScriptAudioInjector* AudioScriptingInterface::playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
ScriptAudioInjector* injector = NULL;
|
||||
|
|
|
@ -30,8 +30,10 @@ public:
|
|||
protected:
|
||||
AudioScriptingInterface() {}
|
||||
|
||||
// this method is protected to stop C++ callers from calling, but invokable from script
|
||||
// these methods are protected to stop C++ callers from calling, but invokable from script
|
||||
Q_INVOKABLE ScriptAudioInjector* playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions());
|
||||
// FIXME: there is no way to play a positionless sound
|
||||
Q_INVOKABLE ScriptAudioInjector* playSystemSound(SharedSoundPointer sound, const QVector3D& position);
|
||||
|
||||
Q_INVOKABLE void setStereoInput(bool stereo);
|
||||
|
||||
|
|
182
libraries/script-engine/src/ConsoleScriptingInterface.cpp
Normal file
182
libraries/script-engine/src/ConsoleScriptingInterface.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
//
|
||||
// ConsoleScriptingInterface.cpp
|
||||
// libraries/script-engine/src
|
||||
//
|
||||
// Created by NeetBhagat on 6/1/17.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// ConsoleScriptingInterface is responsible for following functionality
|
||||
// Printing logs with various tags and grouping on debug Window and Logs/log file.
|
||||
// Debugging functionalities like Timer start-end, assertion, trace.
|
||||
// To use these functionalities, use "console" object in Javascript files.
|
||||
// For examples please refer "scripts/developer/tests/consoleObjectTest.js"
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ConsoleScriptingInterface.h"
|
||||
#include "ScriptEngine.h"
|
||||
|
||||
#define INDENTATION 4 // 1 Tab - 4 spaces
|
||||
const QString LINE_SEPARATOR = "\n ";
|
||||
const QString SPACE_SEPARATOR = " ";
|
||||
const QString STACK_TRACE_FORMAT = "\n[Stacktrace]%1%2";
|
||||
QList<QString> ConsoleScriptingInterface::_groupDetails = QList<QString>();
|
||||
|
||||
QScriptValue ConsoleScriptingInterface::info(QScriptContext* context, QScriptEngine* engine) {
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine)) {
|
||||
scriptEngine->scriptInfoMessage(appendArguments(context));
|
||||
}
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
QScriptValue ConsoleScriptingInterface::log(QScriptContext* context, QScriptEngine* engine) {
|
||||
QString message = appendArguments(context);
|
||||
if (_groupDetails.count() == 0) {
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine)) {
|
||||
scriptEngine->scriptPrintedMessage(message);
|
||||
}
|
||||
} else {
|
||||
logGroupMessage(message, engine);
|
||||
}
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
QScriptValue ConsoleScriptingInterface::debug(QScriptContext* context, QScriptEngine* engine) {
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine)) {
|
||||
scriptEngine->scriptPrintedMessage(appendArguments(context));
|
||||
}
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
QScriptValue ConsoleScriptingInterface::warn(QScriptContext* context, QScriptEngine* engine) {
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine)) {
|
||||
scriptEngine->scriptWarningMessage(appendArguments(context));
|
||||
}
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
QScriptValue ConsoleScriptingInterface::error(QScriptContext* context, QScriptEngine* engine) {
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine)) {
|
||||
scriptEngine->scriptErrorMessage(appendArguments(context));
|
||||
}
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
QScriptValue ConsoleScriptingInterface::exception(QScriptContext* context, QScriptEngine* engine) {
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine)) {
|
||||
scriptEngine->scriptErrorMessage(appendArguments(context));
|
||||
}
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
void ConsoleScriptingInterface::time(QString labelName) {
|
||||
_timerDetails.insert(labelName, QDateTime::currentDateTime().toUTC());
|
||||
QString message = QString("%1: Timer started").arg(labelName);
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine())) {
|
||||
scriptEngine->scriptPrintedMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleScriptingInterface::timeEnd(QString labelName) {
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine())) {
|
||||
if (!_timerDetails.contains(labelName)) {
|
||||
scriptEngine->scriptErrorMessage("No such label found " + labelName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_timerDetails.value(labelName).isNull()) {
|
||||
_timerDetails.remove(labelName);
|
||||
scriptEngine->scriptErrorMessage("Invalid start time for " + labelName);
|
||||
return;
|
||||
}
|
||||
QDateTime _startTime = _timerDetails.value(labelName);
|
||||
QDateTime _endTime = QDateTime::currentDateTime().toUTC();
|
||||
qint64 diffInMS = _startTime.msecsTo(_endTime);
|
||||
|
||||
QString message = QString("%1: %2ms").arg(labelName).arg(QString::number(diffInMS));
|
||||
_timerDetails.remove(labelName);
|
||||
|
||||
scriptEngine->scriptPrintedMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue ConsoleScriptingInterface::assertion(QScriptContext* context, QScriptEngine* engine) {
|
||||
QString message;
|
||||
bool condition = false;
|
||||
for (int i = 0; i < context->argumentCount(); i++) {
|
||||
if (i == 0) {
|
||||
condition = context->argument(i).toBool(); // accept first value as condition
|
||||
} else {
|
||||
message += SPACE_SEPARATOR + context->argument(i).toString(); // accept other parameters as message
|
||||
}
|
||||
}
|
||||
|
||||
QString assertionResult;
|
||||
if (!condition) {
|
||||
if (message.isEmpty()) {
|
||||
assertionResult = "Assertion failed";
|
||||
} else {
|
||||
assertionResult = QString("Assertion failed : %1").arg(message);
|
||||
}
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine)) {
|
||||
scriptEngine->scriptErrorMessage(assertionResult);
|
||||
}
|
||||
}
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
void ConsoleScriptingInterface::trace() {
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine())) {
|
||||
scriptEngine->scriptPrintedMessage
|
||||
(QString(STACK_TRACE_FORMAT).arg(LINE_SEPARATOR,
|
||||
scriptEngine->currentContext()->backtrace().join(LINE_SEPARATOR)));
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleScriptingInterface::clear() {
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine())) {
|
||||
scriptEngine->clearDebugLogWindow();
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue ConsoleScriptingInterface::group(QScriptContext* context, QScriptEngine* engine) {
|
||||
logGroupMessage(context->argument(0).toString(), engine); // accept first parameter as label
|
||||
_groupDetails.push_back(context->argument(0).toString());
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
QScriptValue ConsoleScriptingInterface::groupCollapsed(QScriptContext* context, QScriptEngine* engine) {
|
||||
logGroupMessage(context->argument(0).toString(), engine); // accept first parameter as label
|
||||
_groupDetails.push_back(context->argument(0).toString());
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
QScriptValue ConsoleScriptingInterface::groupEnd(QScriptContext* context, QScriptEngine* engine) {
|
||||
ConsoleScriptingInterface::_groupDetails.removeLast();
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
QString ConsoleScriptingInterface::appendArguments(QScriptContext* context) {
|
||||
QString message;
|
||||
for (int i = 0; i < context->argumentCount(); i++) {
|
||||
if (i > 0) {
|
||||
message += SPACE_SEPARATOR;
|
||||
}
|
||||
message += context->argument(i).toString();
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
void ConsoleScriptingInterface::logGroupMessage(QString message, QScriptEngine* engine) {
|
||||
int _addSpaces = _groupDetails.count() * INDENTATION;
|
||||
QString logMessage;
|
||||
for (int i = 0; i < _addSpaces; i++) {
|
||||
logMessage.append(SPACE_SEPARATOR);
|
||||
}
|
||||
logMessage.append(message);
|
||||
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine)) {
|
||||
scriptEngine->scriptPrintedMessage(logMessage);
|
||||
}
|
||||
}
|
56
libraries/script-engine/src/ConsoleScriptingInterface.h
Normal file
56
libraries/script-engine/src/ConsoleScriptingInterface.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// ConsoleScriptingInterface.h
|
||||
// libraries/script-engine/src
|
||||
//
|
||||
// Created by NeetBhagat on 6/1/17.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// ConsoleScriptingInterface is responsible for following functionality
|
||||
// Printing logs with various tags and grouping on debug Window and Logs/log file.
|
||||
// Debugging functionalities like Timer start-end, assertion, trace.
|
||||
// To use these functionalities, use "console" object in Javascript files.
|
||||
// For examples please refer "scripts/developer/tests/consoleObjectTest.js"
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_ConsoleScriptingInterface_h
|
||||
#define hifi_ConsoleScriptingInterface_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QString>
|
||||
#include <QtScript/QScriptable>
|
||||
#include <QList>
|
||||
#include <QHash>
|
||||
|
||||
// Scriptable interface of "console" object. Used exclusively in the JavaScript API
|
||||
class ConsoleScriptingInterface : public QObject, protected QScriptable {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QScriptValue info(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue log(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue debug(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue warn(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue error(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue exception(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue assertion(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue group(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue groupCollapsed(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue groupEnd(QScriptContext* context, QScriptEngine* engine);
|
||||
|
||||
public slots:
|
||||
void time(QString labelName);
|
||||
void timeEnd(QString labelName);
|
||||
void trace();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
QHash<QString, QDateTime> _timerDetails;
|
||||
static QList<QString> _groupDetails;
|
||||
static void logGroupMessage(QString message, QScriptEngine* engine);
|
||||
static QString appendArguments(QScriptContext* context);
|
||||
};
|
||||
|
||||
#endif // hifi_ConsoleScriptingInterface_h
|
|
@ -472,20 +472,24 @@ void ScriptEngine::scriptErrorMessage(const QString& message) {
|
|||
}
|
||||
|
||||
void ScriptEngine::scriptWarningMessage(const QString& message) {
|
||||
qCWarning(scriptengine) << message;
|
||||
qCWarning(scriptengine) << qPrintable(message);
|
||||
emit warningMessage(message, getFilename());
|
||||
}
|
||||
|
||||
void ScriptEngine::scriptInfoMessage(const QString& message) {
|
||||
qCInfo(scriptengine) << message;
|
||||
qCInfo(scriptengine) << qPrintable(message);
|
||||
emit infoMessage(message, getFilename());
|
||||
}
|
||||
|
||||
void ScriptEngine::scriptPrintedMessage(const QString& message) {
|
||||
qCDebug(scriptengine) << message;
|
||||
qCDebug(scriptengine) << qPrintable(message);
|
||||
emit printedMessage(message, getFilename());
|
||||
}
|
||||
|
||||
void ScriptEngine::clearDebugLogWindow() {
|
||||
emit clearDebugWindow();
|
||||
}
|
||||
|
||||
// Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of
|
||||
// callAnimationStateHandler requires that the type be registered.
|
||||
// These two are meaningful, if we ever do want to use them...
|
||||
|
@ -668,8 +672,18 @@ void ScriptEngine::init() {
|
|||
registerGlobalObject("Mat4", &_mat4Library);
|
||||
registerGlobalObject("Uuid", &_uuidLibrary);
|
||||
registerGlobalObject("Messages", DependencyManager::get<MessagesClient>().data());
|
||||
|
||||
registerGlobalObject("File", new FileScriptingInterface(this));
|
||||
registerGlobalObject("console", &_consoleScriptingInterface);
|
||||
registerFunction("console", "info", ConsoleScriptingInterface::info, currentContext()->argumentCount());
|
||||
registerFunction("console", "log", ConsoleScriptingInterface::log, currentContext()->argumentCount());
|
||||
registerFunction("console", "debug", ConsoleScriptingInterface::debug, currentContext()->argumentCount());
|
||||
registerFunction("console", "warn", ConsoleScriptingInterface::warn, currentContext()->argumentCount());
|
||||
registerFunction("console", "error", ConsoleScriptingInterface::error, currentContext()->argumentCount());
|
||||
registerFunction("console", "exception", ConsoleScriptingInterface::exception, currentContext()->argumentCount());
|
||||
registerFunction("console", "assert", ConsoleScriptingInterface::assertion, currentContext()->argumentCount());
|
||||
registerFunction("console", "group", ConsoleScriptingInterface::group, 1);
|
||||
registerFunction("console", "groupCollapsed", ConsoleScriptingInterface::groupCollapsed, 1);
|
||||
registerFunction("console", "groupEnd", ConsoleScriptingInterface::groupEnd, 0);
|
||||
|
||||
qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue);
|
||||
qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue);
|
||||
|
@ -1006,6 +1020,7 @@ void ScriptEngine::run() {
|
|||
emit runningStateChanged();
|
||||
|
||||
{
|
||||
PROFILE_RANGE(script, _fileNameString);
|
||||
evaluate(_scriptContents, _fileNameString);
|
||||
maybeEmitUncaughtException(__FUNCTION__);
|
||||
}
|
||||
|
@ -1269,6 +1284,7 @@ void ScriptEngine::timerFired() {
|
|||
|
||||
// call the associated JS function, if it exists
|
||||
if (timerData.function.isValid()) {
|
||||
PROFILE_RANGE(script, __FUNCTION__);
|
||||
auto preTimer = p_high_resolution_clock::now();
|
||||
callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, QScriptValueList());
|
||||
auto postTimer = p_high_resolution_clock::now();
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "ScriptCache.h"
|
||||
#include "ScriptUUID.h"
|
||||
#include "Vec3.h"
|
||||
#include "ConsoleScriptingInterface.h"
|
||||
#include "SettingHandle.h"
|
||||
|
||||
class QScriptEngineDebugger;
|
||||
|
@ -225,7 +226,7 @@ public:
|
|||
void scriptWarningMessage(const QString& message);
|
||||
void scriptInfoMessage(const QString& message);
|
||||
void scriptPrintedMessage(const QString& message);
|
||||
|
||||
void clearDebugLogWindow();
|
||||
int getNumRunningEntityScripts() const;
|
||||
bool getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const;
|
||||
|
||||
|
@ -245,6 +246,7 @@ signals:
|
|||
void warningMessage(const QString& message, const QString& scriptName);
|
||||
void infoMessage(const QString& message, const QString& scriptName);
|
||||
void runningStateChanged();
|
||||
void clearDebugWindow();
|
||||
void loadScript(const QString& scriptName, bool isUserLoaded);
|
||||
void reloadScript(const QString& scriptName, bool isUserLoaded);
|
||||
void doneRunning();
|
||||
|
@ -305,6 +307,7 @@ protected:
|
|||
Vec3 _vec3Library;
|
||||
Mat4 _mat4Library;
|
||||
ScriptUUID _uuidLibrary;
|
||||
ConsoleScriptingInterface _consoleScriptingInterface;
|
||||
std::atomic<bool> _isUserLoaded { false };
|
||||
bool _isReloading { false };
|
||||
|
||||
|
|
|
@ -54,6 +54,10 @@ void ScriptEngines::onInfoMessage(const QString& message, const QString& scriptN
|
|||
emit infoMessage(message, scriptName);
|
||||
}
|
||||
|
||||
void ScriptEngines::onClearDebugWindow() {
|
||||
emit clearDebugWindow();
|
||||
}
|
||||
|
||||
void ScriptEngines::onErrorLoadingScript(const QString& url) {
|
||||
emit errorLoadingScript(url);
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ signals:
|
|||
void warningMessage(const QString& message, const QString& engineName);
|
||||
void infoMessage(const QString& message, const QString& engineName);
|
||||
void errorLoadingScript(const QString& url);
|
||||
void clearDebugWindow();
|
||||
|
||||
public slots:
|
||||
void onPrintedMessage(const QString& message, const QString& scriptName);
|
||||
|
@ -86,6 +87,7 @@ public slots:
|
|||
void onWarningMessage(const QString& message, const QString& scriptName);
|
||||
void onInfoMessage(const QString& message, const QString& scriptName);
|
||||
void onErrorLoadingScript(const QString& url);
|
||||
void onClearDebugWindow();
|
||||
|
||||
protected slots:
|
||||
void onScriptFinished(const QString& fileNameString, ScriptEngine* engine);
|
||||
|
|
|
@ -614,15 +614,6 @@ void TabletProxy::removeButton(QObject* tabletButtonProxy) {
|
|||
}
|
||||
}
|
||||
|
||||
void TabletProxy::updateAudioBar(const double micLevel) {
|
||||
auto tablet = getQmlTablet();
|
||||
if (!tablet) {
|
||||
//qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
||||
} else {
|
||||
QMetaObject::invokeMethod(tablet, "setMicLevel", Qt::AutoConnection, Q_ARG(QVariant, QVariant(micLevel)));
|
||||
}
|
||||
}
|
||||
|
||||
void TabletProxy::emitScriptEvent(QVariant msg) {
|
||||
if (!_toolbarMode && _qmlOffscreenSurface) {
|
||||
QMetaObject::invokeMethod(_qmlOffscreenSurface, "emitScriptEvent", Qt::AutoConnection, Q_ARG(QVariant, msg));
|
||||
|
|
|
@ -152,13 +152,6 @@ public:
|
|||
*/
|
||||
Q_INVOKABLE void removeButton(QObject* tabletButtonProxy);
|
||||
|
||||
/**jsdoc
|
||||
* Updates the audio bar in tablet to reflect latest mic level
|
||||
* @function TabletProxy#updateAudioBar
|
||||
* @param micLevel {double} mic level value between 0 and 1
|
||||
*/
|
||||
Q_INVOKABLE void updateAudioBar(const double micLevel);
|
||||
|
||||
/**jsdoc
|
||||
* Used to send an event to the html/js embedded in the tablet
|
||||
* @function TabletProxy#emitScriptEvent
|
||||
|
|
|
@ -118,12 +118,18 @@ void FileCache::initialize() {
|
|||
_initialized = true;
|
||||
}
|
||||
|
||||
std::unique_ptr<File> FileCache::createFile(Metadata&& metadata, const std::string& filepath) {
|
||||
return std::unique_ptr<File>(new cache::File(std::move(metadata), filepath));
|
||||
}
|
||||
|
||||
FilePointer FileCache::addFile(Metadata&& metadata, const std::string& filepath) {
|
||||
FilePointer file(createFile(std::move(metadata), filepath).release(), std::mem_fn(&File::deleter));
|
||||
File* rawFile = createFile(std::move(metadata), filepath).release();
|
||||
FilePointer file(rawFile, std::bind(&File::deleter, rawFile));
|
||||
if (file) {
|
||||
_numTotalFiles += 1;
|
||||
_totalFilesSize += file->getLength();
|
||||
file->_cache = this;
|
||||
file->_parent = shared_from_this();
|
||||
file->_locked = true;
|
||||
emit dirty();
|
||||
|
||||
_files[file->getKey()] = file;
|
||||
|
@ -170,7 +176,7 @@ FilePointer FileCache::writeFile(const char* data, File::Metadata&& metadata, bo
|
|||
} else {
|
||||
qCWarning(file_cache, "[%s] Failed to write %s", _dirname.c_str(), metadata.key.c_str());
|
||||
}
|
||||
|
||||
assert(!file || (file->_locked && file->_parent.lock()));
|
||||
return file;
|
||||
}
|
||||
|
||||
|
@ -192,8 +198,12 @@ FilePointer FileCache::getFile(const Key& key) {
|
|||
file->touch();
|
||||
// if it exists, it is active - remove it from the cache
|
||||
if (_unusedFiles.erase(file)) {
|
||||
assert(!file->_locked);
|
||||
file->_locked = true;
|
||||
_numUnusedFiles -= 1;
|
||||
_unusedFilesSize -= file->getLength();
|
||||
} else {
|
||||
assert(file->_locked);
|
||||
}
|
||||
qCDebug(file_cache, "[%s] Found %s", _dirname.c_str(), key.c_str());
|
||||
emit dirty();
|
||||
|
@ -203,6 +213,7 @@ FilePointer FileCache::getFile(const Key& key) {
|
|||
}
|
||||
}
|
||||
|
||||
assert(!file || (file->_locked && file->_parent.lock()));
|
||||
return file;
|
||||
}
|
||||
|
||||
|
@ -213,7 +224,8 @@ std::string FileCache::getFilepath(const Key& key) {
|
|||
// This is a non-public function that uses the mutex because it's
|
||||
// essentially a public function specifically to a File object
|
||||
void FileCache::addUnusedFile(const FilePointer& file) {
|
||||
Lock lock(_mutex);
|
||||
assert(file->_locked);
|
||||
file->_locked = false;
|
||||
_files[file->getKey()] = file;
|
||||
_unusedFiles.insert(file);
|
||||
_numUnusedFiles += 1;
|
||||
|
@ -247,7 +259,7 @@ namespace cache {
|
|||
}
|
||||
|
||||
void FileCache::eject(const FilePointer& file) {
|
||||
file->_cache = nullptr;
|
||||
file->_locked = false;
|
||||
const auto& length = file->getLength();
|
||||
const auto& key = file->getKey();
|
||||
|
||||
|
@ -300,20 +312,34 @@ void FileCache::clear() {
|
|||
// Mark everything remaining as persisted while effectively ejecting from the cache
|
||||
for (auto& file : _unusedFiles) {
|
||||
file->_shouldPersist = true;
|
||||
file->_cache = nullptr;
|
||||
file->_parent.reset();
|
||||
qCDebug(file_cache, "[%s] Persisting %s", _dirname.c_str(), file->getKey().c_str());
|
||||
}
|
||||
_unusedFiles.clear();
|
||||
}
|
||||
|
||||
void File::deleter() {
|
||||
if (_cache) {
|
||||
_cache->addUnusedFile(FilePointer(this, std::mem_fn(&File::deleter)));
|
||||
void FileCache::releaseFile(File* file) {
|
||||
Lock lock(_mutex);
|
||||
if (file->_locked) {
|
||||
addUnusedFile(FilePointer(file, std::bind(&File::deleter, file)));
|
||||
} else {
|
||||
deleteLater();
|
||||
delete file;
|
||||
}
|
||||
}
|
||||
|
||||
void File::deleter(File* file) {
|
||||
// If the cache shut down before the file was destroyed, then we should leave the file alone (prevents crash on shutdown)
|
||||
FileCachePointer cache = file->_parent.lock();
|
||||
if (!cache) {
|
||||
file->_shouldPersist = true;
|
||||
delete file;
|
||||
return;
|
||||
}
|
||||
|
||||
// Any other operations we might do should be done inside a locked section, so we need to delegate to a FileCache member function
|
||||
cache->releaseFile(file);
|
||||
}
|
||||
|
||||
File::File(Metadata&& metadata, const std::string& filepath) :
|
||||
_key(std::move(metadata.key)),
|
||||
_length(metadata.length),
|
||||
|
@ -333,3 +359,4 @@ void File::touch() {
|
|||
utime(_filepath.c_str(), nullptr);
|
||||
_modified = std::max<int64_t>(QFileInfo(_filepath.c_str()).lastRead().toMSecsSinceEpoch(), _modified);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,12 +24,17 @@
|
|||
|
||||
Q_DECLARE_LOGGING_CATEGORY(file_cache)
|
||||
|
||||
class FileCacheTests;
|
||||
|
||||
namespace cache {
|
||||
|
||||
class File;
|
||||
using FilePointer = std::shared_ptr<File>;
|
||||
class FileCache;
|
||||
using FileCachePointer = std::shared_ptr<FileCache>;
|
||||
using FileCacheWeakPointer = std::weak_ptr<FileCache>;
|
||||
|
||||
class FileCache : public QObject {
|
||||
class FileCache : public QObject, public std::enable_shared_from_this<FileCache> {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(size_t numTotal READ getNumTotalFiles NOTIFY dirty)
|
||||
Q_PROPERTY(size_t numCached READ getNumCachedFiles NOTIFY dirty)
|
||||
|
@ -40,6 +45,8 @@ class FileCache : public QObject {
|
|||
static const size_t MAX_MAX_SIZE;
|
||||
static const size_t DEFAULT_MIN_FREE_STORAGE_SPACE;
|
||||
|
||||
friend class ::FileCacheTests;
|
||||
|
||||
public:
|
||||
// You can initialize the FileCache with a directory name (ex.: "temp_jpgs") that will be relative to the application local data, OR with a full path
|
||||
// The file cache will ignore any file that doesn't match the extension provided
|
||||
|
@ -86,14 +93,14 @@ signals:
|
|||
|
||||
public:
|
||||
/// must be called after construction to create the cache on the fs and restore persisted files
|
||||
void initialize();
|
||||
virtual void initialize();
|
||||
|
||||
// Add file to the cache and return the cache entry.
|
||||
FilePointer writeFile(const char* data, Metadata&& metadata, bool overwrite = false);
|
||||
FilePointer getFile(const Key& key);
|
||||
|
||||
/// create a file
|
||||
virtual std::unique_ptr<File> createFile(Metadata&& metadata, const std::string& filepath) = 0;
|
||||
virtual std::unique_ptr<File> createFile(Metadata&& metadata, const std::string& filepath);
|
||||
|
||||
private:
|
||||
using Mutex = std::recursive_mutex;
|
||||
|
@ -108,6 +115,7 @@ private:
|
|||
|
||||
FilePointer addFile(Metadata&& metadata, const std::string& filepath);
|
||||
void addUnusedFile(const FilePointer& file);
|
||||
void releaseFile(File* file);
|
||||
void clean();
|
||||
void clear();
|
||||
// Remove a file from the cache
|
||||
|
@ -134,9 +142,7 @@ private:
|
|||
Set _unusedFiles;
|
||||
};
|
||||
|
||||
class File : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
class File {
|
||||
public:
|
||||
using Key = FileCache::Key;
|
||||
using Metadata = FileCache::Metadata;
|
||||
|
@ -147,7 +153,7 @@ public:
|
|||
|
||||
virtual ~File();
|
||||
/// overrides should call File::deleter to maintain caching behavior
|
||||
virtual void deleter();
|
||||
static void deleter(File* file);
|
||||
|
||||
protected:
|
||||
/// when constructed, the file has already been created/written
|
||||
|
@ -156,14 +162,16 @@ protected:
|
|||
private:
|
||||
friend class FileCache;
|
||||
friend struct FilePointerComparator;
|
||||
friend class ::FileCacheTests;
|
||||
|
||||
const Key _key;
|
||||
const size_t _length;
|
||||
const std::string _filepath;
|
||||
|
||||
void touch();
|
||||
FileCache* _cache { nullptr };
|
||||
FileCacheWeakPointer _parent;
|
||||
int64_t _modified { 0 };
|
||||
bool _locked { false };
|
||||
|
||||
bool _shouldPersist { false };
|
||||
};
|
||||
|
|
|
@ -153,6 +153,9 @@ void QmlWindowClass::sendToQml(const QVariant& message) {
|
|||
QMetaObject::invokeMethod(asQuickItem(), "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
}
|
||||
|
||||
void QmlWindowClass::clearDebugWindow() {
|
||||
QMetaObject::invokeMethod(asQuickItem(), "clearDebugWindow", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void QmlWindowClass::emitScriptEvent(const QVariant& scriptMessage) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
|
|
|
@ -53,6 +53,7 @@ public slots:
|
|||
|
||||
// Scripts can use this to send a message to the QML object
|
||||
void sendToQml(const QVariant& message);
|
||||
void clearDebugWindow();
|
||||
|
||||
// QmlWindow content may include WebView requiring EventBridge.
|
||||
void emitScriptEvent(const QVariant& scriptMessage);
|
||||
|
|
|
@ -12,16 +12,16 @@
|
|||
var DEFAULT_PARAMETERS = {
|
||||
// Coefficient to use for linear drag. Higher numbers will cause motion to
|
||||
// slow down more quickly.
|
||||
DRAG_COEFFICIENT: 0.9,
|
||||
MAX_SPEED: 40.0,
|
||||
ACCELERATION: 1.0,
|
||||
DRAG_COEFFICIENT: 60.0,
|
||||
MAX_SPEED: 10.0,
|
||||
ACCELERATION: 10.0,
|
||||
|
||||
MOUSE_YAW_SCALE: -0.125,
|
||||
MOUSE_PITCH_SCALE: -0.125,
|
||||
MOUSE_SENSITIVITY: 0.5,
|
||||
|
||||
// Damping frequency, adjust to change mouse look behavior
|
||||
W: 4.2,
|
||||
W: 2.2,
|
||||
}
|
||||
|
||||
var BRAKE_PARAMETERS = {
|
||||
|
@ -35,18 +35,29 @@ var BRAKE_PARAMETERS = {
|
|||
MOUSE_SENSITIVITY: 0.5,
|
||||
}
|
||||
|
||||
var DRIVE_AVATAR_ENABLED = true;
|
||||
var UPDATE_RATE = 90;
|
||||
var USE_INTERVAL = true;
|
||||
|
||||
var movementParameters = DEFAULT_PARAMETERS;
|
||||
|
||||
|
||||
// Movement keys
|
||||
var KEY_BRAKE = "q";
|
||||
var KEY_FORWARD = "w";
|
||||
var KEY_BACKWARD = "s";
|
||||
var KEY_LEFT = "a";
|
||||
var KEY_RIGHT = "d";
|
||||
var KEY_UP = "e";
|
||||
var KEY_DOWN = "c";
|
||||
var KEY_ENABLE = "SPACE";
|
||||
var CAPTURED_KEYS = [KEY_BRAKE, KEY_FORWARD, KEY_BACKWARD, KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_ENABLE];
|
||||
var KEY_BRAKE = "Q";
|
||||
var KEY_FORWARD = "W";
|
||||
var KEY_BACKWARD = "S";
|
||||
var KEY_LEFT = "A";
|
||||
var KEY_RIGHT = "D";
|
||||
var KEY_UP = "E";
|
||||
var KEY_DOWN = "C";
|
||||
var KEY_TOGGLE= "Space";
|
||||
|
||||
var KEYS;
|
||||
if (DRIVE_AVATAR_ENABLED) {
|
||||
KEYS = [KEY_BRAKE, KEY_FORWARD, KEY_BACKWARD, KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN];
|
||||
} else {
|
||||
KEYS = [];
|
||||
}
|
||||
|
||||
// Global Variables
|
||||
var keys = {};
|
||||
|
@ -54,66 +65,27 @@ var velocity = { x: 0, y: 0, z: 0 };
|
|||
var velocityVertical = 0;
|
||||
var enabled = false;
|
||||
|
||||
var lastX = Reticle.getPosition().x;
|
||||
var lastY = Reticle.getPosition().y;
|
||||
var pos = Reticle.getPosition();
|
||||
var lastX = pos.x;
|
||||
var lastY = pos.y;
|
||||
var yawFromMouse = 0;
|
||||
var pitchFromMouse = 0;
|
||||
|
||||
var yawSpeed = 0;
|
||||
var pitchSpeed = 0;
|
||||
|
||||
function keyPressEvent(event) {
|
||||
if (event.text == "ESC") {
|
||||
disable();
|
||||
} else if (event.text == KEY_ENABLE) {
|
||||
if (Window.hasFocus()) {
|
||||
enable();
|
||||
}
|
||||
} else if (event.text == KEY_BRAKE) {
|
||||
movementParameters = BRAKE_PARAMETERS;
|
||||
}
|
||||
keys[event.text] = true;
|
||||
}
|
||||
|
||||
function keyReleaseEvent(event) {
|
||||
if (event.text == KEY_BRAKE) {
|
||||
movementParameters = DEFAULT_PARAMETERS;
|
||||
}
|
||||
|
||||
delete keys[event.text];
|
||||
}
|
||||
|
||||
function update(dt) {
|
||||
var maxMove = 3.0 * dt;
|
||||
var targetVelocity = { x: 0, y: 0, z: 0 };
|
||||
var targetVelocityVertical = 0;
|
||||
var acceleration = movementParameters.ACCELERATION;
|
||||
|
||||
if (keys[KEY_FORWARD]) {
|
||||
targetVelocity.z -= acceleration * dt;
|
||||
}
|
||||
if (keys[KEY_LEFT]) {
|
||||
targetVelocity.x -= acceleration * dt;
|
||||
}
|
||||
if (keys[KEY_BACKWARD]) {
|
||||
targetVelocity.z += acceleration * dt;
|
||||
}
|
||||
if (keys[KEY_RIGHT]) {
|
||||
targetVelocity.x += acceleration * dt;
|
||||
}
|
||||
if (keys[KEY_UP]) {
|
||||
targetVelocityVertical += acceleration * dt;
|
||||
}
|
||||
if (keys[KEY_DOWN]) {
|
||||
targetVelocityVertical -= acceleration * dt;
|
||||
}
|
||||
|
||||
if (enabled && Window.hasFocus()) {
|
||||
var x = Reticle.getPosition().x;
|
||||
var y = Reticle.getPosition().y;
|
||||
var pos = Reticle.getPosition();
|
||||
var x = pos.x;
|
||||
var y = pos.y;
|
||||
|
||||
yawFromMouse += ((x - lastX) * movementParameters.MOUSE_YAW_SCALE * movementParameters.MOUSE_SENSITIVITY);
|
||||
pitchFromMouse += ((y - lastY) * movementParameters.MOUSE_PITCH_SCALE * movementParameters.MOUSE_SENSITIVITY);
|
||||
var dx = x - lastX;
|
||||
var dy = y - lastY;
|
||||
|
||||
yawFromMouse += (dx * movementParameters.MOUSE_YAW_SCALE * movementParameters.MOUSE_SENSITIVITY);
|
||||
pitchFromMouse += (dy * movementParameters.MOUSE_PITCH_SCALE * movementParameters.MOUSE_SENSITIVITY);
|
||||
pitchFromMouse = Math.max(-180, Math.min(180, pitchFromMouse));
|
||||
|
||||
resetCursorPosition();
|
||||
|
@ -138,48 +110,82 @@ function update(dt) {
|
|||
MyAvatar.headPitch = newPitch;
|
||||
pitchFromMouse -= pitchMove;
|
||||
|
||||
// If force isn't being applied in a direction, add drag;
|
||||
if (targetVelocity.x == 0) {
|
||||
targetVelocity.x -= (velocity.x * movementParameters.DRAG_COEFFICIENT * dt);
|
||||
}
|
||||
if (targetVelocity.z == 0) {
|
||||
targetVelocity.z -= (velocity.z * movementParameters.DRAG_COEFFICIENT * dt);
|
||||
}
|
||||
velocity = Vec3.sum(velocity, targetVelocity);
|
||||
|
||||
var maxSpeed = movementParameters.MAX_SPEED;
|
||||
velocity.x = Math.max(-maxSpeed, Math.min(maxSpeed, velocity.x));
|
||||
velocity.z = Math.max(-maxSpeed, Math.min(maxSpeed, velocity.z));
|
||||
var v = Vec3.multiplyQbyV(MyAvatar.headOrientation, velocity);
|
||||
if (DRIVE_AVATAR_ENABLED) {
|
||||
var targetVelocity = { x: 0, y: 0, z: 0 };
|
||||
var targetVelocityVertical = 0;
|
||||
var acceleration = movementParameters.ACCELERATION;
|
||||
|
||||
if (targetVelocityVertical == 0) {
|
||||
targetVelocityVertical -= (velocityVertical * movementParameters.DRAG_COEFFICIENT * dt);
|
||||
if (keys[KEY_FORWARD]) {
|
||||
targetVelocity.z -= acceleration * dt;
|
||||
}
|
||||
if (keys[KEY_LEFT]) {
|
||||
targetVelocity.x -= acceleration * dt;
|
||||
}
|
||||
if (keys[KEY_BACKWARD]) {
|
||||
targetVelocity.z += acceleration * dt;
|
||||
}
|
||||
if (keys[KEY_RIGHT]) {
|
||||
targetVelocity.x += acceleration * dt;
|
||||
}
|
||||
if (keys[KEY_UP]) {
|
||||
targetVelocityVertical += acceleration * dt;
|
||||
}
|
||||
if (keys[KEY_DOWN]) {
|
||||
targetVelocityVertical -= acceleration * dt;
|
||||
}
|
||||
|
||||
// If force isn't being applied in a direction, add drag;
|
||||
var drag = Math.max(movementParameters.DRAG_COEFFICIENT * dt, 1.0);
|
||||
if (targetVelocity.x == 0) {
|
||||
targetVelocity.x = -velocity.x * drag;
|
||||
}
|
||||
if (targetVelocity.z == 0) {
|
||||
targetVelocity.z = -velocity.z * drag;
|
||||
}
|
||||
velocity = Vec3.sum(velocity, targetVelocity);
|
||||
|
||||
var maxSpeed = movementParameters.MAX_SPEED;
|
||||
velocity.x = Math.max(-maxSpeed, Math.min(maxSpeed, velocity.x));
|
||||
velocity.z = Math.max(-maxSpeed, Math.min(maxSpeed, velocity.z));
|
||||
var v = Vec3.multiplyQbyV(MyAvatar.headOrientation, velocity);
|
||||
|
||||
if (targetVelocityVertical == 0) {
|
||||
targetVelocityVertical -= (velocityVertical * movementParameters.DRAG_COEFFICIENT * dt);
|
||||
}
|
||||
velocityVertical += targetVelocityVertical;
|
||||
velocityVertical = Math.max(-maxSpeed, Math.min(maxSpeed, velocityVertical));
|
||||
v.y += velocityVertical;
|
||||
|
||||
MyAvatar.motorVelocity = v;
|
||||
}
|
||||
velocityVertical += targetVelocityVertical;
|
||||
velocityVertical = Math.max(-maxSpeed, Math.min(maxSpeed, velocityVertical));
|
||||
v.y += velocityVertical;
|
||||
|
||||
MyAvatar.setVelocity(v);
|
||||
}
|
||||
|
||||
function vecToString(vec) {
|
||||
return vec.x + ", " + vec.y + ", " + vec.z;
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
disable();
|
||||
}
|
||||
|
||||
function resetCursorPosition() {
|
||||
var newX = Window.x + Window.innerWidth / 2;
|
||||
var newY = Window.y + Window.innerHeight / 2;
|
||||
Reticle.setPosition({ x: newX, y: newY});
|
||||
var newX = Math.floor(Window.innerWidth / 2);
|
||||
var newY = Math.floor(Window.innerHeight / 2);
|
||||
Reticle.setPosition({ x: newX, y: newY });
|
||||
lastX = newX;
|
||||
lastY = newY;
|
||||
}
|
||||
|
||||
|
||||
function toggleEnabled() {
|
||||
if (enabled) {
|
||||
disable();
|
||||
} else {
|
||||
enable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var timerID = null;
|
||||
function enable() {
|
||||
if (!enabled) {
|
||||
if (!enabled && Window.hasFocus()) {
|
||||
enabled = true;
|
||||
|
||||
resetCursorPosition();
|
||||
|
@ -190,27 +196,94 @@ function enable() {
|
|||
yawSpeed = 0;
|
||||
pitchSpeed = 0;
|
||||
velocityVertical = 0;
|
||||
velocity = { x: 0, y: 0, z: 0 };
|
||||
|
||||
MyAvatar.motorReferenceFrame = 'world';
|
||||
MyAvatar.motorVelocity = { x: 0, y: 0, z: 0 };
|
||||
MyAvatar.motorTimescale = 1;
|
||||
|
||||
Controller.enableMapping(MAPPING_KEYS_NAME);
|
||||
|
||||
for (var i = 0; i < CAPTURED_KEYS.length; i++) {
|
||||
Controller.captureKeyEvents({ text: CAPTURED_KEYS[i] });
|
||||
}
|
||||
Reticle.setVisible(false);
|
||||
Script.update.connect(update);
|
||||
if (USE_INTERVAL) {
|
||||
var lastTime = Date.now();
|
||||
timerID = Script.setInterval(function() {
|
||||
var now = Date.now();
|
||||
var dt = now - lastTime;
|
||||
lastTime = now;
|
||||
update(dt / 1000);
|
||||
}, (1.0 / UPDATE_RATE) * 1000);
|
||||
} else {
|
||||
Script.update.connect(update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function disable() {
|
||||
if (enabled) {
|
||||
enabled = false;
|
||||
for (var i = 0; i < CAPTURED_KEYS.length; i++) {
|
||||
Controller.releaseKeyEvents({ text: CAPTURED_KEYS[i] });
|
||||
}
|
||||
Reticle.setVisible(true);
|
||||
Script.update.disconnect(update);
|
||||
|
||||
MyAvatar.motorVelocity = { x: 0, y: 0, z: 0 };
|
||||
|
||||
Controller.disableMapping(MAPPING_KEYS_NAME);
|
||||
|
||||
if (USE_INTERVAL) {
|
||||
Script.clearInterval(timerID);
|
||||
timerID = null;
|
||||
} else {
|
||||
Script.update.disconnect(update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
function scriptEnding() {
|
||||
disable();
|
||||
Controller.disableMapping(MAPPING_ENABLE_NAME);
|
||||
Controller.disableMapping(MAPPING_KEYS_NAME);
|
||||
}
|
||||
|
||||
|
||||
var MAPPING_ENABLE_NAME = 'io.highfidelity.gracefulControls.toggle';
|
||||
var MAPPING_KEYS_NAME = 'io.highfidelity.gracefulControls.keys';
|
||||
var keyControllerMapping = Controller.newMapping(MAPPING_KEYS_NAME);
|
||||
var enableControllerMapping = Controller.newMapping(MAPPING_ENABLE_NAME);
|
||||
|
||||
function onKeyPress(key, value) {
|
||||
print(key, value);
|
||||
keys[key] = value > 0;
|
||||
|
||||
if (value > 0) {
|
||||
if (key == KEY_TOGGLE) {
|
||||
toggleEnabled();
|
||||
} else if (key == KEY_BRAKE) {
|
||||
movementParameters = BRAKE_PARAMETERS;
|
||||
}
|
||||
} else {
|
||||
if (key == KEY_BRAKE) {
|
||||
movementParameters = DEFAULT_PARAMETERS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < KEYS.length; ++i) {
|
||||
var key = KEYS[i];
|
||||
var hw = Controller.Hardware.Keyboard[key];
|
||||
if (hw) {
|
||||
keyControllerMapping.from(hw).to(function(key) {
|
||||
return function(value) {
|
||||
onKeyPress(key, value);
|
||||
};
|
||||
}(key));
|
||||
} else {
|
||||
print("Unknown key: ", key);
|
||||
}
|
||||
}
|
||||
|
||||
enableControllerMapping.from(Controller.Hardware.Keyboard[KEY_TOGGLE]).to(function(value) {
|
||||
onKeyPress(KEY_TOGGLE, value);
|
||||
});
|
||||
|
||||
Controller.enableMapping(MAPPING_ENABLE_NAME);
|
||||
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
|
|
@ -49,4 +49,8 @@ ScriptDiscoveryService.infoMessage.connect(function(message, scriptFileName) {
|
|||
sendToLogWindow("INFO", message, scriptFileName);
|
||||
});
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
ScriptDiscoveryService.clearDebugWindow.connect(function() {
|
||||
window.clearDebugWindow();
|
||||
});
|
||||
|
||||
}());
|
||||
|
|
|
@ -40,6 +40,10 @@ Rectangle {
|
|||
}
|
||||
textArea.append(message);
|
||||
}
|
||||
|
||||
function clearWindow() {
|
||||
textArea.remove(0,textArea.length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
114
scripts/developer/tests/consoleObjectTest.js
Normal file
114
scripts/developer/tests/consoleObjectTest.js
Normal file
|
@ -0,0 +1,114 @@
|
|||
// Examples and understanding of console object. Include console methods like
|
||||
// info, log, debug, warn, error, exception, trace, clear, asserts, group, groupCollapsed, groupEnd, time, timeEnd.
|
||||
// Useful in debugging and exclusively made for JavaScript files.
|
||||
// To view the logs click on Developer -> script logs [logs on debug window] and for text file logs go to Logs/log file.
|
||||
|
||||
main();
|
||||
|
||||
function main() {
|
||||
|
||||
var someObject = { str: "Some text", id: 5 };
|
||||
var someValue = 5;
|
||||
|
||||
// console.info examples
|
||||
console.info("[console.info] Hello World.");
|
||||
console.info(5 + 6);
|
||||
console.info(someObject.str);
|
||||
console.info(a = 2 * 6);
|
||||
console.info(someValue);
|
||||
console.info('someObject id ' + someObject.id);
|
||||
console.info('Hello World ', 'someObject.id = ', someObject.id, "a = 2 * 6 = ", a = 2 * 6);
|
||||
|
||||
// console.log examples
|
||||
console.log("[console.log] Hello World");
|
||||
console.log(5 + 6);
|
||||
console.log(someObject.str);
|
||||
console.log(a = 2 * 6);
|
||||
console.log(someValue);
|
||||
console.log('someObject id ' + someObject.id);
|
||||
console.log('Hello World ', 'someObject.id = ', someObject.id, "a = 2 * 6 = ", a = 2 * 6);
|
||||
|
||||
// console.debug examples
|
||||
console.debug("[console.debug] Hello World.");
|
||||
console.debug(5 + 6);
|
||||
console.debug(someObject.str);
|
||||
console.debug(a = 2 * 6);
|
||||
console.debug(someValue);
|
||||
console.debug('someObject id ' + someObject.id);
|
||||
console.debug('Hello World ', 'someObject.id = ', someObject.id, "a = 2 * 6 = ", a = 2 * 6);
|
||||
|
||||
// console.warn examples
|
||||
console.warn("[console.warn] This is warning message.");
|
||||
console.warn(5 + 6);
|
||||
console.warn(someObject.str);
|
||||
console.warn(a = 2 * 6);
|
||||
console.warn(someValue);
|
||||
console.warn('someObject id ' + someObject.id);
|
||||
console.warn('Hello World ', 'someObject.id = ', someObject.id, "a = 2 * 6 = ", a = 2 * 6);
|
||||
|
||||
// console.error examples
|
||||
console.error('An error occurred!');
|
||||
console.error('An error occurred! ', 'Value = ', someValue);
|
||||
console.error('An error occurred! ' + 'Value = ' + someValue);
|
||||
|
||||
// console.exception examples
|
||||
console.exception('An exception occurred!');
|
||||
console.exception('An exception occurred! ', 'Value = ', someValue);
|
||||
console.exception('An exception occurred! ' + 'Value = ' + someValue);
|
||||
|
||||
// console.trace examples
|
||||
function fooA() {
|
||||
function fooB() {
|
||||
function fooC() {
|
||||
console.trace();
|
||||
}
|
||||
fooC();
|
||||
}
|
||||
fooB();
|
||||
}
|
||||
fooA();
|
||||
|
||||
// console.assert() examples
|
||||
var valA = 1, valB = "1";
|
||||
console.assert(valA === valB, "Value A doesn't equal to B");
|
||||
console.assert(valA === valB);
|
||||
console.assert(5 === 5, "5 equals to 5");
|
||||
console.assert(5 === 5);
|
||||
console.assert(5 > 6, "5 is not greater than 6");
|
||||
console.assert(5 > 6, "5 is not greater than 6", "This assertion will fail");
|
||||
|
||||
// console.group() examples.
|
||||
console.group("Group 1");
|
||||
console.log("Sentence 1");
|
||||
console.log("Sentence 2");
|
||||
console.group("Group 2");
|
||||
console.log("Sentence 3");
|
||||
console.log("Sentence 4");
|
||||
console.groupCollapsed("Group 3");
|
||||
console.log("Sentence 5");
|
||||
console.log("Sentence 6");
|
||||
console.groupEnd();
|
||||
console.log("Sentence 7");
|
||||
console.groupEnd();
|
||||
console.log("Sentence 8");
|
||||
console.groupEnd();
|
||||
console.log("Sentence 9");
|
||||
|
||||
// console.time(),console.timeEnd() examples
|
||||
console.time('MyTimer');
|
||||
// Do some process
|
||||
sleep(1000);
|
||||
console.timeEnd('MyTimer');
|
||||
|
||||
// use console.clear() to clean Debug Window logs
|
||||
// console.clear();
|
||||
}
|
||||
|
||||
function sleep(milliseconds) {
|
||||
var start = new Date().getTime();
|
||||
for (var i = 0; i < 1e7; i++) {
|
||||
if ((new Date().getTime() - start) > milliseconds){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,11 +49,15 @@ Item {
|
|||
|
||||
property var valueMax : 1
|
||||
|
||||
property var _values : new Array()
|
||||
property var _values
|
||||
property var tick : 0
|
||||
|
||||
function createValues() {
|
||||
if (!_values) {
|
||||
_values = new Array();
|
||||
}
|
||||
for (var i =0; i < plots.length; i++) {
|
||||
|
||||
var plot = plots[i];
|
||||
var object = plot["object"] || root.object;
|
||||
var value = plot["prop"];
|
||||
|
@ -93,7 +97,7 @@ Item {
|
|||
|
||||
var VALUE_HISTORY_SIZE = 100;
|
||||
tick++;
|
||||
|
||||
|
||||
var currentValueMax = 0
|
||||
for (var i = 0; i < _values.length; i++) {
|
||||
|
||||
|
@ -128,7 +132,6 @@ Item {
|
|||
if ((valueMax < currentValueMax) || (tick % VALUE_HISTORY_SIZE == 0)) {
|
||||
valueMax = currentValueMax;
|
||||
}
|
||||
|
||||
mycanvas.requestPaint()
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import "configSlider"
|
|||
import "../lib/plotperf"
|
||||
|
||||
Column {
|
||||
property var mainViewTask: Render.getConfig("RenderMainView")
|
||||
spacing: 8
|
||||
Column {
|
||||
id: surfaceGeometry
|
||||
|
@ -33,7 +32,7 @@ Column {
|
|||
ConfigSlider {
|
||||
label: qsTr(modelData.split(":")[0])
|
||||
integral: (modelData.split(":")[3] == 'true')
|
||||
config: mainViewTask.getConfig("AmbientOcclusion")
|
||||
config: Render.getConfig("RenderMainView.AmbientOcclusion")
|
||||
property: modelData.split(":")[1]
|
||||
max: modelData.split(":")[2]
|
||||
min: 0.0
|
||||
|
@ -51,8 +50,8 @@ Column {
|
|||
]
|
||||
CheckBox {
|
||||
text: qsTr(modelData.split(":")[0])
|
||||
checked: mainViewTask.getConfig("AmbientOcclusion")[modelData.split(":")[1]]
|
||||
onCheckedChanged: { mainViewTask.getConfig("AmbientOcclusion")[modelData.split(":")[1]] = checked }
|
||||
checked: Render.getConfig("RenderMainView.AmbientOcclusion")[modelData.split(":")[1]]
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.AmbientOcclusion")[modelData.split(":")[1]] = checked }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,8 +62,8 @@ Column {
|
|||
]
|
||||
CheckBox {
|
||||
text: qsTr(modelData.split(":")[0])
|
||||
checked: mainViewTask.getConfig("DebugAmbientOcclusion")[modelData.split(":")[1]]
|
||||
onCheckedChanged: { mainViewTask.getConfig("DebugAmbientOcclusion")[modelData.split(":")[1]] = checked }
|
||||
checked: Render.getConfig("RenderMainView.DebugAmbientOcclusion")[modelData.split(":")[1]]
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.DebugAmbientOcclusion")[modelData.split(":")[1]] = checked }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +72,7 @@ Column {
|
|||
PlotPerf {
|
||||
title: "Timing"
|
||||
height: 50
|
||||
object: mainViewTask.getConfig("AmbientOcclusion")
|
||||
object: Render.getConfig("RenderMainView.AmbientOcclusion")
|
||||
valueUnit: "ms"
|
||||
valueScale: 1
|
||||
valueNumDigits: "3"
|
||||
|
|
|
@ -14,9 +14,8 @@ import "configSlider"
|
|||
Column {
|
||||
id: root
|
||||
spacing: 8
|
||||
property var mainViewTask: Render.getConfig("RenderMainView");
|
||||
property var sceneOctree: mainViewTask.getConfig("DrawSceneOctree");
|
||||
property var itemSelection: mainViewTask.getConfig("DrawItemSelection");
|
||||
property var sceneOctree: Render.getConfig("RenderMainView.DrawSceneOctree");
|
||||
property var itemSelection: Render.getConfig("RenderMainView.DrawItemSelection");
|
||||
|
||||
Component.onCompleted: {
|
||||
sceneOctree.enabled = true;
|
||||
|
@ -31,8 +30,8 @@ Column {
|
|||
Component.onDestruction: {
|
||||
sceneOctree.enabled = false;
|
||||
itemSelection.enabled = false;
|
||||
mainViewTask.getConfig("FetchSceneSelection").freezeFrustum = false;
|
||||
mainViewTask.getConfig("CullSceneSelection").freezeFrustum = false;
|
||||
Render.getConfig("RenderMainView.FetchSceneSelection").freezeFrustum = false;
|
||||
Render.getConfig("RenderMainView.CullSceneSelection").freezeFrustum = false;
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
|
@ -46,8 +45,8 @@ Column {
|
|||
text: "Freeze Culling Frustum"
|
||||
checked: false
|
||||
onCheckedChanged: {
|
||||
mainViewTask.getConfig("FetchSceneSelection").freezeFrustum = checked;
|
||||
mainViewTask.getConfig("CullSceneSelection").freezeFrustum = checked;
|
||||
Render.getConfig("RenderMainView.FetchSceneSelection").freezeFrustum = checked;
|
||||
Render.getConfig("RenderMainView.CullSceneSelection").freezeFrustum = checked;
|
||||
}
|
||||
}
|
||||
Label {
|
||||
|
@ -99,12 +98,12 @@ Column {
|
|||
|
||||
Column{
|
||||
Repeater {
|
||||
model: [ "Opaque:DrawOpaqueDeferred", "Transparent:DrawTransparentDeferred", "Light:DrawLight",
|
||||
"Opaque Overlays:DrawOverlay3DOpaque", "Transparent Overlays:DrawOverlay3DTransparent" ]
|
||||
model: [ "Opaque:RenderMainView.DrawOpaqueDeferred", "Transparent:RenderMainView.DrawTransparentDeferred", "Light:RenderMainView.DrawLight",
|
||||
"Opaque Overlays:RenderMainView.DrawOverlay3DOpaque", "Transparent Overlays:RenderMainView.DrawOverlay3DTransparent" ]
|
||||
ConfigSlider {
|
||||
label: qsTr(modelData.split(":")[0])
|
||||
integral: true
|
||||
config: mainViewTask.getConfig(modelData.split(":")[1])
|
||||
config: Render.getConfig(modelData.split(":")[1])
|
||||
property: "maxDrawn"
|
||||
max: config.numDrawn
|
||||
min: -1
|
||||
|
|
|
@ -13,7 +13,7 @@ var qml = Script.resolvePath('ambientOcclusionPass.qml');
|
|||
var window = new OverlayWindow({
|
||||
title: 'Ambient Occlusion Pass',
|
||||
source: qml,
|
||||
width: 400, height: 250,
|
||||
width: 400, height: 300,
|
||||
});
|
||||
window.setPosition(Window.innerWidth - 420, 50 + 550 + 50);
|
||||
window.closed.connect(function() { Script.stop(); });
|
||||
|
|
|
@ -13,7 +13,7 @@ var qml = Script.resolvePath('deferredLighting.qml');
|
|||
var window = new OverlayWindow({
|
||||
title: 'Lighting',
|
||||
source: qml,
|
||||
width: 400, height:350,
|
||||
width: 400, height:400,
|
||||
});
|
||||
window.setPosition(Window.innerWidth - 420, 50);
|
||||
window.closed.connect(function() { Script.stop(); });
|
||||
|
|
|
@ -15,7 +15,7 @@ var window = new OverlayWindow({
|
|||
title: 'Light Clustering',
|
||||
source: qml,
|
||||
width: 400,
|
||||
height: 300
|
||||
height: 400
|
||||
});
|
||||
window.setPosition(Window.innerWidth - 420, 50 + 250 + 50 + 250 + 50 );
|
||||
window.closed.connect(function() { Script.stop(); });
|
|
@ -17,19 +17,18 @@ Column {
|
|||
Column {
|
||||
id: lightClustering
|
||||
spacing: 10
|
||||
property var mainViewTask: Render.getConfig("RenderMainView");
|
||||
|
||||
Column{
|
||||
PlotPerf {
|
||||
title: "Light CLustering Timing"
|
||||
height: 50
|
||||
object: mainViewTask.getConfig("LightClustering")
|
||||
object: Render.getConfig("RenderMainView.LightClustering")
|
||||
valueUnit: "ms"
|
||||
valueScale: 1
|
||||
valueNumDigits: "4"
|
||||
plots: [
|
||||
{
|
||||
object: mainViewTask.getConfig("LightClustering"),
|
||||
object: Render.getConfig("RenderMainView.LightClustering"),
|
||||
prop: "cpuRunTime",
|
||||
label: "time",
|
||||
scale: 1,
|
||||
|
@ -41,19 +40,19 @@ Column {
|
|||
PlotPerf {
|
||||
title: "Lights"
|
||||
height: 50
|
||||
object: mainViewTask.getConfig("LightClustering")
|
||||
object: Render.getConfig("RenderMainView.LightClustering")
|
||||
valueUnit: ""
|
||||
valueScale: 1
|
||||
valueNumDigits: "0"
|
||||
plots: [
|
||||
{
|
||||
object: mainViewTask.getConfig("LightClustering"),
|
||||
object: Render.getConfig("RenderMainView.LightClustering"),
|
||||
prop: "numClusteredLights",
|
||||
label: "visible",
|
||||
color: "#D959FE"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("LightClustering"),
|
||||
object: Render.getConfig("RenderMainView.LightClustering"),
|
||||
prop: "numInputLights",
|
||||
label: "input",
|
||||
color: "#FED959"
|
||||
|
@ -64,25 +63,25 @@ Column {
|
|||
PlotPerf {
|
||||
title: "Scene Lights"
|
||||
height: 80
|
||||
object: mainViewTask.getConfig("LightClustering")
|
||||
object: Render.getConfig("RenderMainView.LightClustering")
|
||||
valueUnit: ""
|
||||
valueScale: 1
|
||||
valueNumDigits: "0"
|
||||
plots: [
|
||||
{
|
||||
object: mainViewTask.getConfig("LightClustering"),
|
||||
object: Render.getConfig("RenderMainView.LightClustering"),
|
||||
prop: "numSceneLights",
|
||||
label: "current",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("LightClustering"),
|
||||
object: Render.getConfig("RenderMainView.LightClustering"),
|
||||
prop: "numFreeSceneLights",
|
||||
label: "free",
|
||||
color: "#1AC567"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("LightClustering"),
|
||||
object: Render.getConfig("RenderMainView.LightClustering"),
|
||||
prop: "numAllocatedSceneLights",
|
||||
label: "allocated",
|
||||
color: "#9495FF"
|
||||
|
@ -93,7 +92,7 @@ Column {
|
|||
ConfigSlider {
|
||||
label: qsTr("Range Near [m]")
|
||||
integral: false
|
||||
config: mainViewTask.getConfig("LightClustering")
|
||||
config: Render.getConfig("RenderMainView.LightClustering")
|
||||
property: "rangeNear"
|
||||
max: 20.0
|
||||
min: 0.1
|
||||
|
@ -101,7 +100,7 @@ Column {
|
|||
ConfigSlider {
|
||||
label: qsTr("Range Far [m]")
|
||||
integral: false
|
||||
config: mainViewTask.getConfig("LightClustering")
|
||||
config: Render.getConfig("RenderMainView.LightClustering")
|
||||
property: "rangeFar"
|
||||
max: 500.0
|
||||
min: 100.0
|
||||
|
@ -109,7 +108,7 @@ Column {
|
|||
ConfigSlider {
|
||||
label: qsTr("Grid X")
|
||||
integral: true
|
||||
config: mainViewTask.getConfig("LightClustering")
|
||||
config: Render.getConfig("RenderMainView.LightClustering")
|
||||
property: "dimX"
|
||||
max: 32
|
||||
min: 1
|
||||
|
@ -117,7 +116,7 @@ Column {
|
|||
ConfigSlider {
|
||||
label: qsTr("Grid Y")
|
||||
integral: true
|
||||
config: mainViewTask.getConfig("LightClustering")
|
||||
config: Render.getConfig("RenderMainView.LightClustering")
|
||||
property: "dimY"
|
||||
max: 32
|
||||
min: 1
|
||||
|
@ -125,33 +124,33 @@ Column {
|
|||
ConfigSlider {
|
||||
label: qsTr("Grid Z")
|
||||
integral: true
|
||||
config: mainViewTask.getConfig("LightClustering")
|
||||
config: Render.getConfig("RenderMainView.LightClustering")
|
||||
property: "dimZ"
|
||||
max: 31
|
||||
min: 1
|
||||
}
|
||||
CheckBox {
|
||||
text: "Freeze"
|
||||
checked: mainViewTask.getConfig("LightClustering")["freeze"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("LightClustering")["freeze"] = checked }
|
||||
checked: Render.getConfig("RenderMainView.LightClustering")["freeze"]
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.LightClustering")["freeze"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Draw Grid"
|
||||
checked: mainViewTask.getConfig("DebugLightClusters")["doDrawGrid"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("DebugLightClusters")["doDrawGrid"] = checked }
|
||||
checked: Render.getConfig("RenderMainView.DebugLightClusters")["doDrawGrid"]
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.DebugLightClusters")["doDrawGrid"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Draw Cluster From Depth"
|
||||
checked: mainViewTask.getConfig("DebugLightClusters")["doDrawClusterFromDepth"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("DebugLightClusters")["doDrawClusterFromDepth"] = checked }
|
||||
checked: Render.getConfig("RenderMainView.DebugLightClusters")["doDrawClusterFromDepth"]
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.DebugLightClusters")["doDrawClusterFromDepth"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Draw Content"
|
||||
checked: mainViewTask.getConfig("DebugLightClusters")["doDrawContent"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("DebugLightClusters")["doDrawContent"] = checked }
|
||||
checked: Render.getConfig("RenderMainView.DebugLightClusters")["doDrawContent"]
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.DebugLightClusters")["doDrawContent"] = checked }
|
||||
}
|
||||
Label {
|
||||
text: "Num Cluster Items = " + mainViewTask.getConfig("LightClustering")["numClusteredLightReferences"].toFixed(0)
|
||||
text: "Num Cluster Items = " + Render.getConfig("RenderMainView.LightClustering")["numClusteredLightReferences"].toFixed(0)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ var qml = Script.resolvePath('stats.qml');
|
|||
var window = new OverlayWindow({
|
||||
title: 'Render Stats',
|
||||
source: qml,
|
||||
width: 320,
|
||||
height: 720
|
||||
width: 400,
|
||||
height: 400
|
||||
});
|
||||
window.setPosition(500, 50);
|
||||
window.closed.connect(function() { Script.stop(); });
|
|
@ -21,99 +21,13 @@ Item {
|
|||
spacing: 8
|
||||
anchors.fill:parent
|
||||
|
||||
property var mainViewTask: Render.getConfig("RenderMainView");
|
||||
property var config: mainViewTask.getConfig("Stats")
|
||||
property var config: Render.getConfig("Stats")
|
||||
|
||||
function evalEvenHeight() {
|
||||
// Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ?
|
||||
return (height - spacing * (children.length - 1)) / children.length
|
||||
}
|
||||
|
||||
PlotPerf {
|
||||
title: "Num Buffers"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
plots: [
|
||||
{
|
||||
prop: "bufferCPUCount",
|
||||
label: "CPU",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
prop: "bufferGPUCount",
|
||||
label: "GPU",
|
||||
color: "#1AC567"
|
||||
}
|
||||
]
|
||||
}
|
||||
PlotPerf {
|
||||
title: "gpu::Buffer Memory"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
valueScale: 1048576
|
||||
valueUnit: "Mb"
|
||||
valueNumDigits: "1"
|
||||
plots: [
|
||||
{
|
||||
prop: "bufferCPUMemoryUsage",
|
||||
label: "CPU",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
prop: "bufferGPUMemoryUsage",
|
||||
label: "GPU",
|
||||
color: "#1AC567"
|
||||
}
|
||||
]
|
||||
}
|
||||
PlotPerf {
|
||||
title: "Num Textures"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
plots: [
|
||||
{
|
||||
prop: "textureCPUCount",
|
||||
label: "CPU",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
prop: "textureGPUCount",
|
||||
label: "GPU",
|
||||
color: "#1AC567"
|
||||
},
|
||||
{
|
||||
prop: "texturePendingGPUTransferCount",
|
||||
label: "Transfer",
|
||||
color: "#9495FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
PlotPerf {
|
||||
title: "gpu::Texture Memory"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
valueScale: 1048576
|
||||
valueUnit: "Mb"
|
||||
valueNumDigits: "1"
|
||||
plots: [
|
||||
{
|
||||
prop: "textureCPUMemoryUsage",
|
||||
label: "CPU",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
prop: "textureGPUMemoryUsage",
|
||||
label: "GPU",
|
||||
color: "#1AC567"
|
||||
},
|
||||
{
|
||||
prop: "textureGPUVirtualMemoryUsage",
|
||||
label: "GPU Virtual",
|
||||
color: "#9495FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
PlotPerf {
|
||||
title: "Triangles"
|
||||
height: parent.evalEvenHeight()
|
||||
|
@ -183,9 +97,9 @@ Item {
|
|||
]
|
||||
}
|
||||
|
||||
property var drawOpaqueConfig: mainViewTask.getConfig("DrawOpaqueDeferred")
|
||||
property var drawTransparentConfig: mainViewTask.getConfig("DrawTransparentDeferred")
|
||||
property var drawLightConfig: mainViewTask.getConfig("DrawLight")
|
||||
property var drawOpaqueConfig: Render.getConfig("RenderMainView.DrawOpaqueDeferred")
|
||||
property var drawTransparentConfig: Render.getConfig("RenderMainView.DrawTransparentDeferred")
|
||||
property var drawLightConfig: Render.getConfig("RenderMainView.DrawLight")
|
||||
|
||||
PlotPerf {
|
||||
title: "Items"
|
||||
|
@ -200,13 +114,13 @@ Item {
|
|||
color: "#1AC567"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("DrawTransparentDeferred"),
|
||||
object: Render.getConfig("RenderMainView.DrawTransparentDeferred"),
|
||||
prop: "numDrawn",
|
||||
label: "Translucents",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("DrawLight"),
|
||||
object: Render.getConfig("RenderMainView.DrawLight"),
|
||||
prop: "numDrawn",
|
||||
label: "Lights",
|
||||
color: "#FED959"
|
||||
|
@ -223,25 +137,25 @@ Item {
|
|||
valueNumDigits: "2"
|
||||
plots: [
|
||||
{
|
||||
object: mainViewTask.getConfig("DrawOpaqueDeferred"),
|
||||
object: Render.getConfig("RenderMainView.DrawOpaqueDeferred"),
|
||||
prop: "cpuRunTime",
|
||||
label: "Opaques",
|
||||
color: "#1AC567"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("DrawTransparentDeferred"),
|
||||
object: Render.getConfig("RenderMainView.DrawTransparentDeferred"),
|
||||
prop: "cpuRunTime",
|
||||
label: "Translucents",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("RenderDeferred"),
|
||||
object: Render.getConfig("RenderMainView.RenderDeferred"),
|
||||
prop: "cpuRunTime",
|
||||
label: "Lighting",
|
||||
color: "#FED959"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("RenderDeferredTask"),
|
||||
object: Render.getConfig("RenderMainView.RenderDeferredTask"),
|
||||
prop: "cpuRunTime",
|
||||
label: "RenderFrame",
|
||||
color: "#E2334D"
|
||||
|
|
|
@ -20,10 +20,7 @@ Item {
|
|||
id: stats
|
||||
spacing: 8
|
||||
anchors.fill:parent
|
||||
|
||||
property var mainViewTask: Render.getConfig("RenderMainView");
|
||||
property var config: mainViewTask.getConfig("Stats")
|
||||
|
||||
|
||||
function evalEvenHeight() {
|
||||
// Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ?
|
||||
return (height - spacing * (children.length - 1)) / children.length
|
||||
|
@ -39,31 +36,31 @@ Item {
|
|||
valueNumDigits: "4"
|
||||
plots: [
|
||||
{
|
||||
object: mainViewTask.getConfig("OpaqueRangeTimer"),
|
||||
object: Render.getConfig("RenderMainView.OpaqueRangeTimer"),
|
||||
prop: "gpuRunTime",
|
||||
label: "Opaque",
|
||||
color: "#FFFFFF"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("LinearDepth"),
|
||||
object: Render.getConfig("RenderMainView.LinearDepth"),
|
||||
prop: "gpuRunTime",
|
||||
label: "LinearDepth",
|
||||
color: "#00FF00"
|
||||
},{
|
||||
object: mainViewTask.getConfig("SurfaceGeometry"),
|
||||
object: Render.getConfig("RenderMainView.SurfaceGeometry"),
|
||||
prop: "gpuRunTime",
|
||||
label: "SurfaceGeometry",
|
||||
color: "#00FFFF"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("RenderDeferred"),
|
||||
object: Render.getConfig("RenderMainView.RenderDeferred"),
|
||||
prop: "gpuRunTime",
|
||||
label: "DeferredLighting",
|
||||
color: "#FF00FF"
|
||||
}
|
||||
,
|
||||
{
|
||||
object: mainViewTask.getConfig("ToneAndPostRangeTimer"),
|
||||
object: Render.getConfig("RenderMainView.ToneAndPostRangeTimer"),
|
||||
prop: "gpuRunTime",
|
||||
label: "tone and post",
|
||||
color: "#FF0000"
|
||||
|
@ -79,31 +76,31 @@ Item {
|
|||
valueNumDigits: "3"
|
||||
plots: [
|
||||
{
|
||||
object: mainViewTask.getConfig("OpaqueRangeTimer"),
|
||||
object: Render.getConfig("RenderMainView.OpaqueRangeTimer"),
|
||||
prop: "batchRunTime",
|
||||
label: "Opaque",
|
||||
color: "#FFFFFF"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("LinearDepth"),
|
||||
object: Render.getConfig("RenderMainView.LinearDepth"),
|
||||
prop: "batchRunTime",
|
||||
label: "LinearDepth",
|
||||
color: "#00FF00"
|
||||
},{
|
||||
object: mainViewTask.getConfig("SurfaceGeometry"),
|
||||
object: Render.getConfig("RenderMainView.SurfaceGeometry"),
|
||||
prop: "batchRunTime",
|
||||
label: "SurfaceGeometry",
|
||||
color: "#00FFFF"
|
||||
},
|
||||
{
|
||||
object: mainViewTask.getConfig("RenderDeferred"),
|
||||
object: Render.getConfig("RenderMainView.RenderDeferred"),
|
||||
prop: "batchRunTime",
|
||||
label: "DeferredLighting",
|
||||
color: "#FF00FF"
|
||||
}
|
||||
,
|
||||
{
|
||||
object: mainViewTask.getConfig("ToneAndPostRangeTimer"),
|
||||
object: Render.getConfig("RenderMainView.ToneAndPostRangeTimer"),
|
||||
prop: "batchRunTime",
|
||||
label: "tone and post",
|
||||
color: "#FF0000"
|
||||
|
|
|
@ -16,29 +16,28 @@ Column {
|
|||
Column {
|
||||
id: scattering
|
||||
spacing: 10
|
||||
property var mainViewTask: Render.getConfig("RenderMainView");
|
||||
|
||||
Column{
|
||||
Column{
|
||||
CheckBox {
|
||||
text: "Scattering"
|
||||
checked: mainViewTask.getConfig("Scattering").enableScattering
|
||||
onCheckedChanged: { mainViewTask.getConfig("Scattering").enableScattering = checked }
|
||||
checked: Render.getConfig("RenderMainView.Scattering").enableScattering
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.Scattering").enableScattering = checked }
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
text: "Show Scattering BRDF"
|
||||
checked: mainViewTask.getConfig("Scattering").showScatteringBRDF
|
||||
onCheckedChanged: { mainViewTask.getConfig("Scattering").showScatteringBRDF = checked }
|
||||
checked: Render.getConfig("RenderMainView.Scattering").showScatteringBRDF
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.Scattering").showScatteringBRDF = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Show Curvature"
|
||||
checked: mainViewTask.getConfig("Scattering").showCurvature
|
||||
onCheckedChanged: { mainViewTask.getConfig("Scattering").showCurvature = checked }
|
||||
checked: Render.getConfig("RenderMainView.Scattering").showCurvature
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.Scattering").showCurvature = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Show Diffused Normal"
|
||||
checked: mainViewTask.getConfig("Scattering").showDiffusedNormal
|
||||
onCheckedChanged: { mainViewTask.getConfig("Scattering").showDiffusedNormal = checked }
|
||||
checked: Render.getConfig("RenderMainView.Scattering").showDiffusedNormal
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.Scattering").showDiffusedNormal = checked }
|
||||
}
|
||||
Repeater {
|
||||
model: [ "Scattering Bent Red:Scattering:bentRed:2.0",
|
||||
|
@ -59,23 +58,23 @@ Column {
|
|||
}
|
||||
CheckBox {
|
||||
text: "Scattering Profile"
|
||||
checked: mainViewTask.getConfig("DebugScattering").showProfile
|
||||
onCheckedChanged: { mainViewTask.getConfig("DebugScattering").showProfile = checked }
|
||||
checked: Render.getConfig("RenderMainView.DebugScattering").showProfile
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.DebugScattering").showProfile = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Scattering Table"
|
||||
checked: mainViewTask.getConfig("DebugScattering").showLUT
|
||||
onCheckedChanged: { mainViewTask.getConfig("DebugScattering").showLUT = checked }
|
||||
checked: Render.getConfig("RenderMainView.DebugScattering").showLUT
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.DebugScattering").showLUT = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Cursor Pixel"
|
||||
checked: mainViewTask.getConfig("DebugScattering").showCursorPixel
|
||||
onCheckedChanged: { mainViewTask.getConfig("DebugScattering").showCursorPixel = checked }
|
||||
checked: Render.getConfig("RenderMainView.DebugScattering").showCursorPixel
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.DebugScattering").showCursorPixel = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Skin Specular Beckmann"
|
||||
checked: mainViewTask.getConfig("DebugScattering").showSpecularTable
|
||||
onCheckedChanged: { mainViewTask.getConfig("DebugScattering").showSpecularTable = checked }
|
||||
checked: Render.getConfig("RenderMainView.DebugScattering").showSpecularTable
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.DebugScattering").showSpecularTable = checked }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,12 @@ Column {
|
|||
Column {
|
||||
id: surfaceGeometry
|
||||
spacing: 10
|
||||
property var mainViewTask: Render.getConfig("RenderMainView");
|
||||
|
||||
Column{
|
||||
ConfigSlider {
|
||||
label: qsTr("Depth Threshold [cm]")
|
||||
integral: false
|
||||
config: mainViewTask.getConfig("SurfaceGeometry")
|
||||
config: Render.getConfig("RenderMainView.SurfaceGeometry")
|
||||
property: "depthThreshold"
|
||||
max: 5.0
|
||||
min: 0.0
|
||||
|
@ -35,7 +34,7 @@ Column {
|
|||
ConfigSlider {
|
||||
label: qsTr(modelData.split(":")[0])
|
||||
integral: (modelData.split(":")[3] == 'true')
|
||||
config: mainViewTask.getConfig("SurfaceGeometry")
|
||||
config: Render.getConfig("RenderMainView.SurfaceGeometry")
|
||||
property: modelData.split(":")[1]
|
||||
max: modelData.split(":")[2]
|
||||
min: 0.0
|
||||
|
@ -43,18 +42,18 @@ Column {
|
|||
}
|
||||
CheckBox {
|
||||
text: "Half Resolution"
|
||||
checked: mainViewTask.getConfig("SurfaceGeometry")["resolutionLevel"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("SurfaceGeometry")["resolutionLevel"] = checked }
|
||||
checked: Render.getConfig("RenderMainView.SurfaceGeometry")["resolutionLevel"]
|
||||
onCheckedChanged: { Render.getConfig("RenderMainView.SurfaceGeometry")["resolutionLevel"] = checked }
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: [ "Diffusion Scale:SurfaceGeometry:diffuseFilterScale:2.0",
|
||||
"Diffusion Depth Threshold:SurfaceGeometry:diffuseDepthThreshold:1.0"
|
||||
model: [ "Diffusion Scale:RenderMainView.SurfaceGeometry:diffuseFilterScale:2.0",
|
||||
"Diffusion Depth Threshold:RenderMainView.SurfaceGeometry:diffuseDepthThreshold:1.0"
|
||||
]
|
||||
ConfigSlider {
|
||||
label: qsTr(modelData.split(":")[0])
|
||||
integral: false
|
||||
config: mainViewTask.getConfig(modelData.split(":")[1])
|
||||
config: Render.getConfig(modelData.split(":")[1])
|
||||
property: modelData.split(":")[2]
|
||||
max: modelData.split(":")[3]
|
||||
min: 0.0
|
||||
|
|
|
@ -22,8 +22,7 @@ Item {
|
|||
spacing: 8
|
||||
anchors.fill:parent
|
||||
|
||||
property var mainViewTask: Render.getConfig("RenderMainView");
|
||||
property var config: mainViewTask.getConfig("Stats")
|
||||
property var config: Render.getConfig("Stats")
|
||||
|
||||
function evalEvenHeight() {
|
||||
// Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ?
|
||||
|
|
|
@ -622,7 +622,7 @@ var toolBar = (function () {
|
|||
}));
|
||||
isActive = active;
|
||||
activeButton.editProperties({isActive: isActive});
|
||||
|
||||
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
|
||||
if (!isActive) {
|
||||
|
@ -1519,6 +1519,8 @@ function importSVO(importURL) {
|
|||
// entities after they're imported so that they're all the correct distance in front of and with geometric mean
|
||||
// centered on the avatar/camera direction.
|
||||
var deltaPosition = Vec3.ZERO;
|
||||
var entityPositions = [];
|
||||
var entityParentIDs = [];
|
||||
|
||||
var properties = Entities.getEntityProperties(pastedEntityIDs[0], ["type"]);
|
||||
var NO_ADJUST_ENTITY_TYPES = ["Zone", "Light", "ParticleEffect"];
|
||||
|
@ -1534,10 +1536,9 @@ function importSVO(importURL) {
|
|||
var targetPosition = getPositionToCreateEntity();
|
||||
var deltaParallel = HALF_TREE_SCALE; // Distance to move entities parallel to targetDirection.
|
||||
var deltaPerpendicular = Vec3.ZERO; // Distance to move entities perpendicular to targetDirection.
|
||||
var entityPositions = [];
|
||||
for (var i = 0, length = pastedEntityIDs.length; i < length; i++) {
|
||||
var properties = Entities.getEntityProperties(pastedEntityIDs[i], ["position", "dimensions",
|
||||
"registrationPoint", "rotation"]);
|
||||
"registrationPoint", "rotation", "parentID"]);
|
||||
var adjustedPosition = adjustPositionPerBoundingBox(targetPosition, targetDirection,
|
||||
properties.registrationPoint, properties.dimensions, properties.rotation);
|
||||
var delta = Vec3.subtract(adjustedPosition, properties.position);
|
||||
|
@ -1546,6 +1547,7 @@ function importSVO(importURL) {
|
|||
deltaPerpendicular = Vec3.sum(Vec3.subtract(delta, Vec3.multiply(distance, targetDirection)),
|
||||
deltaPerpendicular);
|
||||
entityPositions[i] = properties.position;
|
||||
entityParentIDs[i] = properties.parentID;
|
||||
}
|
||||
deltaPerpendicular = Vec3.multiply(1 / pastedEntityIDs.length, deltaPerpendicular);
|
||||
deltaPosition = Vec3.sum(Vec3.multiply(deltaParallel, targetDirection), deltaPerpendicular);
|
||||
|
@ -1562,9 +1564,11 @@ function importSVO(importURL) {
|
|||
|
||||
if (!Vec3.equal(deltaPosition, Vec3.ZERO)) {
|
||||
for (var i = 0, length = pastedEntityIDs.length; i < length; i++) {
|
||||
Entities.editEntity(pastedEntityIDs[i], {
|
||||
position: Vec3.sum(deltaPosition, entityPositions[i])
|
||||
});
|
||||
if (Uuid.isNull(entityParentIDs[i])) {
|
||||
Entities.editEntity(pastedEntityIDs[i], {
|
||||
position: Vec3.sum(deltaPosition, entityPositions[i])
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,11 +183,6 @@
|
|||
return;
|
||||
}
|
||||
|
||||
//TODO: move to tablet qml?
|
||||
if (tabletShown) {
|
||||
gTablet.updateAudioBar(getMicLevel());
|
||||
}
|
||||
|
||||
if (now - validCheckTime > MSECS_PER_SEC) {
|
||||
validCheckTime = now;
|
||||
updateTabletWidthFromSettings();
|
||||
|
@ -268,12 +263,6 @@
|
|||
|
||||
Script.setInterval(updateShowTablet, 100);
|
||||
|
||||
// Calculate microphone level with the same scaling equation (log scale, exponentially averaged) in AvatarInputs and pal.js
|
||||
function getMicLevel() {
|
||||
//reuse already existing C++ code
|
||||
return AvatarInputs.loudnessToAudioLevel(MyAvatar.audioLoudness)
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
|
||||
// if we reload scripts in tablet mode make sure we close the currently open window, by calling gotoHomeScreen
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"Entities": [
|
||||
{
|
||||
"description": "Spawns balloons",
|
||||
"dimensions": {
|
||||
"x": 2,
|
||||
"y": 0.1,
|
||||
"z": 2
|
||||
},
|
||||
"name": "Balloon Spawner",
|
||||
"serverScripts": "http://mpassets.highfidelity.com/8410ef73-9506-4dc7-b364-0174998a859e-v1/Scripts/spawnBalloons.js",
|
||||
"type": "Shape",
|
||||
"shape": "Cube",
|
||||
"visible": "false",
|
||||
"collisionless": "true",
|
||||
"userData": "{\"spawnRate\":1000,\"xRangeMax\":1,\"zRangeMax\":1,\"gravityCoefficient\":0.25,\"balloonLifetime\":10,\"spawnDuration\":300,\"spawnMusicURL\":\"http://mpassets.highfidelity.com/8410ef73-9506-4dc7-b364-0174998a859e-v1/Audio/Blue_Skies.wav\",\"spawnMusicVolume\":0.1}"
|
||||
}
|
||||
],
|
||||
"Version": 63
|
||||
}
|
224
scripts/tutorials/entity_scripts/balloonSpawner/spawnBalloons.js
Normal file
224
scripts/tutorials/entity_scripts/balloonSpawner/spawnBalloons.js
Normal file
|
@ -0,0 +1,224 @@
|
|||
"use strict";
|
||||
|
||||
//
|
||||
// spawnBalloons.js
|
||||
//
|
||||
// Created by Johnathan Franck on 3 May 2017.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function () {
|
||||
var RED_BALLOON_URL = Script.resolvePath("../Models/redBalloon.fbx");
|
||||
var BLUE_BALLOON_URL = Script.resolvePath("../Models/blueBalloon.fbx");
|
||||
var GREEN_BALLOON_URL = Script.resolvePath("../Models/greenBalloon.fbx");
|
||||
var YELLOW_BALLOON_URL = Script.resolvePath("../Models/yellowBalloon.fbx");
|
||||
var ORANGE_BALLOON_URL = Script.resolvePath("../Models/orangeBalloon.fbx");
|
||||
var CYAN_BALLOON_URL = Script.resolvePath("../Models/cyanBalloon.fbx");
|
||||
var PURPLE_BALLOON_URL = Script.resolvePath("../Models/purpleBalloon.fbx");
|
||||
//'Blue Skies' by Silent Partner from youtube audio library. Listed as attribution not required
|
||||
var SPAWN_MUSIC_URL = Script.resolvePath("../Audio/Blue_Skies.wav");
|
||||
|
||||
var BALLOON_COLORS = ["red", "blue", "green", "yellow", "orange", "cyan", "purple"];
|
||||
var BALLOON_URLS = [RED_BALLOON_URL, BLUE_BALLOON_URL, GREEN_BALLOON_URL,
|
||||
YELLOW_BALLOON_URL, ORANGE_BALLOON_URL, CYAN_BALLOON_URL, PURPLE_BALLOON_URL];
|
||||
|
||||
var NUM_COLORS = 7;
|
||||
var COUNTDOWN_SECONDS = 9;
|
||||
//Lowering the spawn rate below 10 spawns so many balloons that the interface slows down
|
||||
var MIN_SPAWN_RATE = 10;
|
||||
var MILLISECONDS_IN_SECOND = 1000;
|
||||
|
||||
var _this = this;
|
||||
var spawnRate = 2000;
|
||||
var xRangeMax = 1;
|
||||
var zRangeMax = 1;
|
||||
var gravityCoefficient = 0.25;
|
||||
var balloonLifetime = 10;
|
||||
var spawnDuration = 300;
|
||||
var musicInjector;
|
||||
var spawnIntervalID;
|
||||
var spawnMusic;
|
||||
var countdownIntervalID;
|
||||
var countdownEntityID;
|
||||
|
||||
_this.preload = function (pEntityID) {
|
||||
var parentProperties = Entities.getEntityProperties(pEntityID, ["userData"]),
|
||||
spawnMusicURL,
|
||||
spawnerSettings;
|
||||
if (parentProperties.userData) {
|
||||
spawnerSettings = JSON.parse(parentProperties.userData);
|
||||
}
|
||||
spawnMusicURL = spawnerSettings.spawnMusicURL ? spawnerSettings.spawnMusicURL : SPAWN_MUSIC_URL;
|
||||
spawnMusic = SoundCache.getSound(spawnMusicURL);
|
||||
|
||||
_this.startCountdown(pEntityID);
|
||||
};
|
||||
|
||||
_this.startCountdown = function (pEntityID) {
|
||||
var countdownSeconds = COUNTDOWN_SECONDS,
|
||||
parentProperties = Entities.getEntityProperties(pEntityID, ["position"]),
|
||||
countdownEntityProperties;
|
||||
|
||||
countdownEntityProperties = {
|
||||
type: "Text",
|
||||
text: countdownSeconds,
|
||||
lineHeight: 0.71,
|
||||
dimensions: {
|
||||
x: 0.5,
|
||||
y: 1,
|
||||
z: 0.01
|
||||
},
|
||||
textColor: {
|
||||
red: 0,
|
||||
blue: 255,
|
||||
green: 0
|
||||
},
|
||||
backgroundColor: {
|
||||
red: 255,
|
||||
blue: 255,
|
||||
green: 255
|
||||
},
|
||||
parentID: pEntityID,
|
||||
position: parentProperties.position
|
||||
};
|
||||
|
||||
countdownEntityID = Entities.addEntity(countdownEntityProperties);
|
||||
countdownIntervalID = Script.setInterval(function () {
|
||||
countdownSeconds -= 1;
|
||||
if (countdownSeconds < 0) {
|
||||
Script.clearInterval(countdownIntervalID);
|
||||
Entities.deleteEntity(countdownEntityID);
|
||||
} else {
|
||||
Entities.editEntity(countdownEntityID, {"text": countdownSeconds});
|
||||
if (countdownSeconds === 0) {
|
||||
_this.spawnBalloons(pEntityID);
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
_this.spawnBalloons = function (pEntityID) {
|
||||
var parentProperties = Entities.getEntityProperties(pEntityID, ["position", "userData"]),
|
||||
spawnerSettings,
|
||||
spawnMusicVolume,
|
||||
spawnCount = 0;
|
||||
|
||||
if (parentProperties.userData) {
|
||||
spawnerSettings = JSON.parse(parentProperties.userData);
|
||||
}
|
||||
|
||||
xRangeMax = !isNaN(spawnerSettings.xRangeMax) ? spawnerSettings.xRangeMax : xRangeMax;
|
||||
zRangeMax = !isNaN(spawnerSettings.zRangeMax) ? spawnerSettings.zRangeMax : zRangeMax;
|
||||
gravityCoefficient = !isNaN(spawnerSettings.gravityCoefficient) ? spawnerSettings.gravityCoefficient : gravityCoefficient;
|
||||
spawnDuration = !isNaN(spawnerSettings.spawnDuration) ? spawnerSettings.spawnDuration : spawnDuration;
|
||||
balloonLifetime = !isNaN(spawnerSettings.balloonLifetime) ? spawnerSettings.balloonLifetime : balloonLifetime;
|
||||
spawnRate = !isNaN(spawnerSettings.spawnRate) ? spawnerSettings.spawnRate : spawnRate;
|
||||
spawnMusicVolume = !isNaN(spawnerSettings.spawnMusicVolume) ? spawnerSettings.spawnMusicVolume : 0.1;
|
||||
|
||||
if (spawnRate < MIN_SPAWN_RATE) {
|
||||
spawnRate = MIN_SPAWN_RATE;
|
||||
print("The lowest balloon spawn rate allowed is " + MIN_SPAWN_RATE);
|
||||
}
|
||||
|
||||
if (spawnMusic.downloaded) {
|
||||
musicInjector = Audio.playSound(spawnMusic, {
|
||||
position: parentProperties.position,
|
||||
volume: spawnMusicVolume,
|
||||
loop: true
|
||||
});
|
||||
}
|
||||
|
||||
spawnIntervalID = Script.setInterval(function () {
|
||||
var colorID = Math.floor(Math.random() * NUM_COLORS),
|
||||
color = BALLOON_COLORS[colorID],
|
||||
balloonURL = BALLOON_URLS[colorID],
|
||||
balloonPosition = {},
|
||||
balloonProperties;
|
||||
|
||||
spawnCount ++;
|
||||
//Randomize balloon spawn position
|
||||
balloonPosition.y = parentProperties.position.y + 0.5;
|
||||
balloonPosition.x = parentProperties.position.x + (Math.random() - 0.5) * 2 * xRangeMax;
|
||||
balloonPosition.z = parentProperties.position.z + (Math.random() - 0.5) * 2 * zRangeMax;
|
||||
|
||||
balloonProperties = {
|
||||
position: balloonPosition,
|
||||
lifetime: balloonLifetime,
|
||||
angularVelocity: {
|
||||
x: -0.03654664754867554,
|
||||
y: -0.4030083637684583664 + Math.random(),
|
||||
z: 0.02576472796499729
|
||||
},
|
||||
collisionsWillMove: 1,
|
||||
density: 100,
|
||||
description: "A happy " + color + " balloon",
|
||||
dimensions: {
|
||||
x: 0.3074322044849396,
|
||||
y: 0.40930506587028503,
|
||||
z: 0.30704551935195923
|
||||
},
|
||||
dynamic: 1,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: gravityCoefficient,
|
||||
z: 0
|
||||
},
|
||||
modelURL: balloonURL,
|
||||
name: color + " balloon",
|
||||
queryAACube: {
|
||||
scale: 0.596927285194397,
|
||||
x: -0.2984636425971985,
|
||||
y: -0.2984636425971985,
|
||||
z: -0.2984636425971985
|
||||
},
|
||||
restitution: 0.9900000095367432,
|
||||
rotation: {
|
||||
w: -0.10368101298809052,
|
||||
x: 0.5171623826026917,
|
||||
y: 0.1211432576179504,
|
||||
z: -0.670971691608429 + Math.random()
|
||||
},
|
||||
shapeType: "sphere",
|
||||
type : "Model",
|
||||
velocity: {
|
||||
x: 0.003623033408075571,
|
||||
y: 0.0005839366931468248,
|
||||
z: -0.01512028019875288
|
||||
}
|
||||
};
|
||||
Entities.addEntity(balloonProperties);
|
||||
|
||||
//Clean up after spawnDuration
|
||||
if (spawnCount * spawnRate / MILLISECONDS_IN_SECOND > spawnDuration) {
|
||||
_this.cleanUp(pEntityID);
|
||||
}
|
||||
}, spawnRate);
|
||||
};
|
||||
|
||||
_this.unload = function () {
|
||||
_this.cleanUp();
|
||||
};
|
||||
|
||||
_this.cleanUp = function (pEntityID) {
|
||||
if (spawnIntervalID ) {
|
||||
Script.clearInterval(spawnIntervalID);
|
||||
}
|
||||
if (countdownIntervalID) {
|
||||
Script.clearInterval(countdownIntervalID);
|
||||
}
|
||||
if (countdownEntityID) {
|
||||
Entities.deleteEntity(countdownEntityID);
|
||||
}
|
||||
if (musicInjector !== undefined && musicInjector.isPlaying) {
|
||||
musicInjector.stop();
|
||||
musicInjector = undefined;
|
||||
}
|
||||
if (pEntityID) {
|
||||
Entities.deleteEntity(pEntityID);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "FileCacheTests.h"
|
||||
|
||||
#include <FileCache.h>
|
||||
#include <shared/FileCache.h>
|
||||
|
||||
QTEST_GUILESS_MAIN(FileCacheTests)
|
||||
|
||||
|
@ -24,40 +24,6 @@ static std::string getFileKey(int i) {
|
|||
return QString(QByteArray { 1, (char)i }.toHex()).toStdString();
|
||||
}
|
||||
|
||||
class TestFile : public File {
|
||||
using Parent = File;
|
||||
public:
|
||||
TestFile(Metadata&& metadata, const std::string& filepath)
|
||||
: Parent(std::move(metadata), filepath) {
|
||||
}
|
||||
};
|
||||
|
||||
class TestFileCache : public FileCache {
|
||||
using Parent = FileCache;
|
||||
|
||||
public:
|
||||
TestFileCache(const std::string& dirname, const std::string& ext, QObject* parent = nullptr) : Parent(dirname, ext, nullptr) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
std::unique_ptr<File> createFile(Metadata&& metadata, const std::string& filepath) override {
|
||||
qCInfo(file_cache) << "Wrote KTX" << metadata.key.c_str();
|
||||
return std::unique_ptr<File>(new TestFile(std::move(metadata), filepath));
|
||||
}
|
||||
};
|
||||
|
||||
using CachePointer = std::shared_ptr<TestFileCache>;
|
||||
|
||||
// The FileCache relies on deleteLater to clear unused files, but QTest classes don't run a conventional event loop
|
||||
// so we need to call this function to force any pending deletes to occur in the File destructor
|
||||
static void forceDeletes() {
|
||||
while (QCoreApplication::hasPendingEvents()) {
|
||||
QCoreApplication::sendPostedEvents();
|
||||
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
size_t FileCacheTests::getCacheDirectorySize() const {
|
||||
size_t result = 0;
|
||||
QDir dir(_testDir.path());
|
||||
|
@ -67,8 +33,9 @@ size_t FileCacheTests::getCacheDirectorySize() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
CachePointer makeFileCache(QString& location) {
|
||||
auto result = std::make_shared<TestFileCache>(location.toStdString(), "tmp");
|
||||
FileCachePointer makeFileCache(QString& location) {
|
||||
auto result = std::make_shared<FileCache>(location.toStdString(), "tmp");
|
||||
result->initialize();
|
||||
result->setMaxSize(MAX_UNUSED_SIZE);
|
||||
return result;
|
||||
}
|
||||
|
@ -83,26 +50,38 @@ void FileCacheTests::testUnusedFiles() {
|
|||
{
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
std::string key = getFileKey(i);
|
||||
auto file = cache->writeFile(TEST_DATA.data(), TestFileCache::Metadata(key, TEST_DATA.size()));
|
||||
auto file = cache->writeFile(TEST_DATA.data(), FileCache::Metadata(key, TEST_DATA.size()));
|
||||
QVERIFY(file->_locked);
|
||||
inUseFiles.push_back(file);
|
||||
forceDeletes();
|
||||
|
||||
QThread::msleep(10);
|
||||
}
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)0);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)100);
|
||||
// Release the in-use files
|
||||
inUseFiles.clear();
|
||||
// Cache state is updated, but the directory state is unchanged,
|
||||
// because the file deletes are triggered by an event loop
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)10);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)10);
|
||||
QVERIFY(getCacheDirectorySize() > MAX_UNUSED_SIZE);
|
||||
forceDeletes();
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)10);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)10);
|
||||
QVERIFY(getCacheDirectorySize() <= MAX_UNUSED_SIZE);
|
||||
}
|
||||
|
||||
// Check behavior when destroying the cache BEFORE releasing the files
|
||||
cache = makeFileCache(_testDir.path());
|
||||
{
|
||||
auto directorySize = getCacheDirectorySize();
|
||||
|
||||
// Test files 90 to 99 are present
|
||||
for (int i = 90; i < 100; ++i) {
|
||||
std::string key = getFileKey(i);
|
||||
auto file = cache->getFile(key);
|
||||
QVERIFY(file.get());
|
||||
inUseFiles.push_back(file);
|
||||
}
|
||||
cache.reset();
|
||||
inUseFiles.clear();
|
||||
QCOMPARE(getCacheDirectorySize(), directorySize);
|
||||
}
|
||||
|
||||
// Reset the cache
|
||||
cache = makeFileCache(_testDir.path());
|
||||
{
|
||||
|
@ -151,8 +130,6 @@ void FileCacheTests::testFreeSpacePreservation() {
|
|||
auto cache = makeFileCache(_testDir.path());
|
||||
// Setting the min free space causes it to eject the oldest files that cause the cache to exceed the minimum space
|
||||
cache->setMinFreeSize(targetFreeSpace);
|
||||
QVERIFY(getFreeSpace() < targetFreeSpace);
|
||||
forceDeletes();
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)5);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)5);
|
||||
QVERIFY(getFreeSpace() >= targetFreeSpace);
|
||||
|
@ -176,8 +153,6 @@ void FileCacheTests::testWipe() {
|
|||
cache->wipe();
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)0);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)0);
|
||||
QVERIFY(getCacheDirectorySize() > 0);
|
||||
forceDeletes();
|
||||
QCOMPARE(getCacheDirectorySize(), (size_t)0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue