mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 19:59:28 +02:00
Merge branch 'tablet-ui' of github.com:highfidelity/hifi into tablet-notifcation
This commit is contained in:
commit
dac16af1df
37 changed files with 1759 additions and 340 deletions
|
@ -37,7 +37,6 @@ const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer";
|
||||||
|
|
||||||
// FIXME - what we'd actually like to do is send to users at ~50% of their present rate down to 30hz. Assume 90 for now.
|
// FIXME - what we'd actually like to do is send to users at ~50% of their present rate down to 30hz. Assume 90 for now.
|
||||||
const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
||||||
const unsigned int AVATAR_DATA_SEND_INTERVAL_MSECS = (1.0f / (float) AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND) * 1000;
|
|
||||||
|
|
||||||
AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
||||||
ThreadedAssignment(message)
|
ThreadedAssignment(message)
|
||||||
|
|
46
interface/resources/icons/tablet-icons/scope-auto.svg
Normal file
46
interface/resources/icons/tablet-icons/scope-auto.svg
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_2">
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M25.3,23.7c-0.6,0-1.2,0.2-1.6,0.7S23,25.4,23,26c0,0.6,0.2,1.1,0.7,1.6c0.5,0.5,1,0.7,1.6,0.7
|
||||||
|
c0.6,0,1.2-0.2,1.6-0.7c0.5-0.5,0.7-1,0.7-1.6c0-0.6-0.2-1.2-0.7-1.6C26.5,23.9,26,23.7,25.3,23.7z"/>
|
||||||
|
<path class="st0" d="M25.3,17.2c-5,0-9,4-9,9c0,5,4,9,9,9s9-4,9-9C34.4,21.2,30.3,17.2,25.3,17.2z M31.5,26c0,0.3-0.1,0.6-0.3,0.8
|
||||||
|
c-0.2,0.2-0.5,0.3-0.8,0.3c-0.2,0-0.3,0-0.5-0.1c-0.1,0-0.3,0-0.5-0.1c-0.2,0.6-0.3,1.1-0.6,1.4c0.2,0.1,0.3,0.2,0.4,0.3h0.1
|
||||||
|
c0.2,0.1,0.4,0.2,0.4,0.2c0.5,0.5,0.5,1.1,0,1.6c-0.2,0.2-0.5,0.3-0.8,0.3c-0.3,0-0.6-0.1-0.8-0.3c0,0-0.1-0.2-0.2-0.4
|
||||||
|
c0,0,0-0.1-0.1-0.1c-0.1-0.1-0.2-0.2-0.2-0.4c-0.4,0.3-0.9,0.5-1.4,0.6c0.1,0.2,0.1,0.4,0.1,0.5c0.1,0.2,0.1,0.3,0.1,0.5
|
||||||
|
c0,0.3-0.1,0.6-0.3,0.8c-0.2,0.2-0.5,0.3-0.8,0.3c-0.3,0-0.6-0.1-0.8-0.3c-0.2-0.2-0.3-0.5-0.3-0.8c0-0.2,0-0.3,0.1-0.5
|
||||||
|
c0-0.1,0-0.3,0.1-0.5c-0.5-0.1-1-0.3-1.4-0.6c-0.1,0.2-0.2,0.3-0.2,0.4L22.8,30c0,0.1-0.1,0.2-0.2,0.4c-0.2,0.2-0.5,0.3-0.8,0.3
|
||||||
|
c-0.3,0-0.6-0.1-0.8-0.3c-0.5-0.5-0.5-1.1,0-1.6c0.1-0.1,0.2-0.2,0.5-0.2c0-0.1,0.2-0.2,0.4-0.3c-0.2-0.3-0.4-0.8-0.6-1.4
|
||||||
|
C21.1,27,20.9,27,20.7,27V27c-0.1,0.1-0.2,0.1-0.5,0.1c-0.3,0-0.6-0.1-0.8-0.3c-0.2-0.2-0.3-0.5-0.3-0.8c0-0.3,0.1-0.6,0.3-0.8
|
||||||
|
c0.2-0.2,0.5-0.3,0.8-0.3c0.2,0,0.3,0,0.5,0.1c0.1,0,0.3,0,0.5,0.1c0.1-0.5,0.3-1,0.6-1.4c-0.1,0-0.2-0.1-0.4-0.2h-0.1
|
||||||
|
c-0.2-0.1-0.3-0.2-0.4-0.3c-0.5-0.5-0.5-1,0-1.5c0.5-0.5,1.1-0.5,1.6,0c0.1,0.1,0.2,0.2,0.2,0.4c0.1,0.1,0.2,0.2,0.3,0.5
|
||||||
|
c0.4-0.3,0.9-0.5,1.4-0.6c-0.1-0.2-0.1-0.3-0.1-0.5v-0.1c-0.1-0.2-0.1-0.3-0.1-0.5c0-0.3,0.1-0.6,0.3-0.8c0.2-0.2,0.5-0.3,0.8-0.3
|
||||||
|
c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.3,0.5,0.3,0.8c0,0.2,0,0.3-0.1,0.5v0.1c0,0.2,0,0.3-0.1,0.5c0.4,0.1,0.9,0.3,1.4,0.6
|
||||||
|
c0-0.2,0.1-0.3,0.2-0.5c0-0.1,0.1-0.2,0.3-0.4c0.2-0.2,0.4-0.3,0.8-0.3c0.3,0,0.6,0.1,0.8,0.3c0.5,0.5,0.5,1.1,0,1.6
|
||||||
|
c-0.2,0.2-0.3,0.2-0.4,0.3c-0.1,0.1-0.2,0.2-0.5,0.2c0.3,0.5,0.5,1,0.6,1.4c0.2-0.1,0.3-0.1,0.5-0.1H30c0.2-0.1,0.3-0.1,0.5-0.1
|
||||||
|
c0.3,0,0.6,0.1,0.8,0.3C31.4,25.5,31.5,25.7,31.5,26L31.5,26z"/>
|
||||||
|
</g>
|
||||||
|
<path class="st0" d="M22.3,15.4v-2.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v3.5C20.7,15.9,21.5,15.6,22.3,15.4z"/>
|
||||||
|
<path class="st0" d="M25.3,15c0.4,0,0.8,0,1.1,0.1V8.6c0-0.6-0.5-1.2-1.2-1.2S24.1,8,24.1,8.6V15C24.5,15,24.9,15,25.3,15z"/>
|
||||||
|
<path class="st0" d="M30.6,16.3V3.6c0-0.6-0.5-1.2-1.2-1.2S28.3,3,28.3,3.6v11.7C29.1,15.6,29.9,15.9,30.6,16.3z"/>
|
||||||
|
<path class="st0" d="M48,24.9h-0.6v-2.1c0-0.6-0.5-1.2-1.2-1.2S45,22.2,45,22.9v2.1h-1.8V12c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2
|
||||||
|
v12.9H39v-9.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2V36c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-8.7h1.8v12.9
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V27.3H45v2.9c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.9H48c0.6,0,1.2-0.5,1.2-1.2
|
||||||
|
S48.6,24.9,48,24.9z"/>
|
||||||
|
<path class="st0" d="M13.9,12c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v12.9H9.7v-4.6c0-0.6-0.5-1.2-1.2-1.2
|
||||||
|
c-0.6,0-1.2,0.5-1.2,1.2v4.6H5.5v-2.1c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2v2.1H2.6c-0.6,0-1.2,0.5-1.2,1.2s0.5,1.2,1.2,1.2h0.6
|
||||||
|
v2.1c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.1h1.8v6.2c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-6.2h1.8v12.1
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V12z"/>
|
||||||
|
<path class="st0" d="M28.3,37v9.8c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V36.1C29.9,36.5,29.1,36.8,28.3,37z"/>
|
||||||
|
<path class="st0" d="M25.3,37.5c-0.4,0-0.8,0-1.2-0.1v4.5c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-4.5
|
||||||
|
C26.1,37.4,25.7,37.5,25.3,37.5z"/>
|
||||||
|
<path class="st0" d="M19.9,36.1v3.3c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V37C21.5,36.8,20.7,36.5,19.9,36.1z"/>
|
||||||
|
<rect x="12" y="24.6" class="st0" width="6.9" height="3"/>
|
||||||
|
<rect x="32.9" y="24.6" class="st0" width="5.1" height="3"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4 KiB |
30
interface/resources/icons/tablet-icons/scope-pause.svg
Normal file
30
interface/resources/icons/tablet-icons/scope-pause.svg
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_2">
|
||||||
|
</g>
|
||||||
|
<path class="st0" d="M22.3,15.4v-2.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v3.5C20.7,15.9,21.5,15.6,22.3,15.4z"/>
|
||||||
|
<path class="st0" d="M25.3,15c0.4,0,0.8,0,1.1,0.1V8.6c0-0.6-0.5-1.2-1.2-1.2S24.1,8,24.1,8.6V15C24.5,15,24.9,15,25.3,15z"/>
|
||||||
|
<path class="st0" d="M30.6,16.3V3.6c0-0.6-0.5-1.2-1.2-1.2S28.3,3,28.3,3.6v11.7C29.1,15.6,29.9,15.9,30.6,16.3z"/>
|
||||||
|
<path class="st0" d="M48,24.9h-0.6v-2.1c0-0.6-0.5-1.2-1.2-1.2S45,22.2,45,22.9v2.1h-1.8V12c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2
|
||||||
|
v12.9H39v-9.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2V36c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-8.7h1.8v12.9
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V27.3H45v2.9c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.9H48c0.6,0,1.2-0.5,1.2-1.2
|
||||||
|
S48.6,24.9,48,24.9z"/>
|
||||||
|
<path class="st0" d="M13.9,12c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v12.9H9.7v-4.6c0-0.6-0.5-1.2-1.2-1.2
|
||||||
|
c-0.6,0-1.2,0.5-1.2,1.2v4.6H5.5v-2.1c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2v2.1H2.6c-0.6,0-1.2,0.5-1.2,1.2s0.5,1.2,1.2,1.2h0.6
|
||||||
|
v2.1c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.1h1.8v6.2c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-6.2h1.8v12.1
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V12z"/>
|
||||||
|
<path class="st0" d="M28.3,37v9.8c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V36.1C29.9,36.5,29.1,36.8,28.3,37z"/>
|
||||||
|
<path class="st0" d="M25.3,37.5c-0.4,0-0.8,0-1.2-0.1v4.5c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-4.5
|
||||||
|
C26.1,37.4,25.7,37.5,25.3,37.5z"/>
|
||||||
|
<path class="st0" d="M19.9,36.1v3.3c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V37C21.5,36.8,20.7,36.5,19.9,36.1z"/>
|
||||||
|
<rect x="12" y="24.6" class="st0" width="7.3" height="3"/>
|
||||||
|
<rect x="32.9" y="24.6" class="st0" width="5.3" height="3"/>
|
||||||
|
<path class="st0" d="M25.3,17c-5,0-9,4-9,9c0,5,4,9,9,9s9-4,9-9C34.4,21,30.3,17,25.3,17z M24.1,29.7c0,0.5-0.6,1-1.4,1
|
||||||
|
s-1.4-0.4-1.4-1v-7.3c0-0.5,0.6-1,1.4-1s1.4,0.4,1.4,1V29.7z M29.3,29.7c0,0.5-0.6,1-1.4,1c-0.8,0-1.4-0.4-1.4-1v-7.3
|
||||||
|
c0-0.5,0.6-1,1.4-1c0.8,0,1.4,0.4,1.4,1V29.7z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
30
interface/resources/icons/tablet-icons/scope-play.svg
Normal file
30
interface/resources/icons/tablet-icons/scope-play.svg
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_2">
|
||||||
|
</g>
|
||||||
|
<path class="st0" d="M22.3,15.4v-2.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v3.5C20.7,15.9,21.5,15.6,22.3,15.4z"/>
|
||||||
|
<path class="st0" d="M25.3,15c0.4,0,0.8,0,1.1,0.1V8.6c0-0.6-0.5-1.2-1.2-1.2S24.1,8,24.1,8.6V15C24.5,15,24.9,15,25.3,15z"/>
|
||||||
|
<path class="st0" d="M30.6,16.3V3.6c0-0.6-0.5-1.2-1.2-1.2S28.3,3,28.3,3.6v11.7C29.1,15.6,29.9,15.9,30.6,16.3z"/>
|
||||||
|
<path class="st0" d="M48,24.9h-0.6v-2.1c0-0.6-0.5-1.2-1.2-1.2S45,22.2,45,22.9v2.1h-1.8V12c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2
|
||||||
|
v12.9H39v-9.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2V36c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-8.7h1.8v12.9
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V27.3H45v2.9c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.9H48c0.6,0,1.2-0.5,1.2-1.2
|
||||||
|
S48.6,24.9,48,24.9z"/>
|
||||||
|
<path class="st0" d="M13.9,12c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v12.9H9.7v-4.6c0-0.6-0.5-1.2-1.2-1.2
|
||||||
|
c-0.6,0-1.2,0.5-1.2,1.2v4.6H5.5v-2.1c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2v2.1H2.6c-0.6,0-1.2,0.5-1.2,1.2s0.5,1.2,1.2,1.2h0.6
|
||||||
|
v2.1c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.1h1.8v6.2c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-6.2h1.8v12.1
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V12z"/>
|
||||||
|
<path class="st0" d="M28.3,37v9.8c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V36.1C29.9,36.5,29.1,36.8,28.3,37z"/>
|
||||||
|
<path class="st0" d="M25.3,37.5c-0.4,0-0.8,0-1.2-0.1v4.5c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-4.5
|
||||||
|
C26.1,37.4,25.7,37.5,25.3,37.5z"/>
|
||||||
|
<path class="st0" d="M19.9,36.1v3.3c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V37C21.5,36.8,20.7,36.5,19.9,36.1z"/>
|
||||||
|
<path class="st0" d="M25.3,17.2c-5,0-9,4-9,9c0,5,4,9,9,9s9-4,9-9C34.4,21.2,30.3,17.2,25.3,17.2z M30.3,26.1l-6,5.4
|
||||||
|
c-0.1,0.1-0.2,0.1-0.4,0.1c-0.1,0-0.3,0-0.3-0.1c-0.3-0.1-0.5-0.4-0.5-0.5V20.9c0-0.1,0.2-0.4,0.4-0.5c0.1,0,0.2-0.1,0.3-0.1
|
||||||
|
c0.2,0,0.3,0,0.4,0.1l6,4.8c0.1,0.1,0.2,0.3,0.2,0.4C30.5,25.8,30.4,26,30.3,26.1z"/>
|
||||||
|
<rect x="12" y="24.6" class="st0" width="7.3" height="3"/>
|
||||||
|
<rect x="32.9" y="24.6" class="st0" width="7.3" height="3"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -181,6 +181,31 @@ Item {
|
||||||
root.avatarMixerOutPps + "pps, " +
|
root.avatarMixerOutPps + "pps, " +
|
||||||
root.myAvatarSendRate.toFixed(2) + "hz";
|
root.myAvatarSendRate.toFixed(2) + "hz";
|
||||||
}
|
}
|
||||||
|
StatText {
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "Audio Mixer In: " + root.audioMixerInKbps + " kbps, " +
|
||||||
|
root.audioMixerInPps + "pps";
|
||||||
|
}
|
||||||
|
StatText {
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "Audio In Audio: " + root.audioAudioInboundPPS + " pps, " +
|
||||||
|
"Silent: " + root.audioSilentInboundPPS + " pps";
|
||||||
|
}
|
||||||
|
StatText {
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "Audio Mixer Out: " + root.audioMixerOutKbps + " kbps, " +
|
||||||
|
root.audioMixerOutPps + "pps";
|
||||||
|
}
|
||||||
|
StatText {
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "Audio Out Mic: " + root.audioMicOutboundPPS + " pps, " +
|
||||||
|
"Silent: " + root.audioSilentOutboundPPS + " pps";
|
||||||
|
}
|
||||||
|
StatText {
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "Audio Codec: " + root.audioCodec + " Noise Gate: " +
|
||||||
|
root.audioNoiseGate;
|
||||||
|
}
|
||||||
StatText {
|
StatText {
|
||||||
visible: root.expanded;
|
visible: root.expanded;
|
||||||
text: "Downloads: " + root.downloads + "/" + root.downloadLimit +
|
text: "Downloads: " + root.downloads + "/" + root.downloadLimit +
|
||||||
|
|
244
interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml
Normal file
244
interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
//
|
||||||
|
// TabletEntityStatistics.qml
|
||||||
|
//
|
||||||
|
// Created by Vlad Stelmahovsky on 3/11/17
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import Qt.labs.settings 1.0
|
||||||
|
|
||||||
|
import "../../styles-uit"
|
||||||
|
import "../../controls-uit" as HifiControls
|
||||||
|
import "../../windows"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
objectName: "EntityStatistics"
|
||||||
|
|
||||||
|
property var eventBridge;
|
||||||
|
signal sendToScript(var message);
|
||||||
|
property bool isHMD: false
|
||||||
|
|
||||||
|
color: hifi.colors.baseGray
|
||||||
|
|
||||||
|
property int colorScheme: hifi.colorSchemes.dark
|
||||||
|
|
||||||
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
OctreeStats.startUpdates()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onDestruction: {
|
||||||
|
OctreeStats.stopUpdates()
|
||||||
|
}
|
||||||
|
|
||||||
|
Flickable {
|
||||||
|
id: scrollView
|
||||||
|
width: parent.width
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: hifi.dimensions.tabletMenuHeader
|
||||||
|
contentWidth: column.implicitWidth
|
||||||
|
contentHeight: column.implicitHeight
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: column
|
||||||
|
anchors.margins: 10
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
y: hifi.dimensions.tabletMenuHeader //-bgNavBar
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Elements on Servers:")
|
||||||
|
text: OctreeStats.serverElements
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Local Elements:")
|
||||||
|
text: OctreeStats.localElements
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Elements Memory:")
|
||||||
|
text: OctreeStats.localElementsMemory
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Sending Mode:")
|
||||||
|
text: OctreeStats.sendingMode
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Incoming Entity Packets:")
|
||||||
|
text: OctreeStats.processedPackets
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Processed Packets Elements:")
|
||||||
|
text: OctreeStats.processedPacketsElements
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Processed Packets Entities:")
|
||||||
|
text: OctreeStats.processedPacketsEntities
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Processed Packets Timing:")
|
||||||
|
text: OctreeStats.processedPacketsTiming
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Outbound Entity Packets:")
|
||||||
|
text: OctreeStats.outboundEditPackets
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Entity Update Time:")
|
||||||
|
text: OctreeStats.entityUpdateTime
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
titleText: qsTr("Entity Updates:")
|
||||||
|
text: OctreeStats.entityUpdates
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: OctreeStats.serversNum
|
||||||
|
|
||||||
|
delegate: Column {
|
||||||
|
id: serverColumn
|
||||||
|
width: scrollView.width - 10
|
||||||
|
x: 5
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
state: "less"
|
||||||
|
|
||||||
|
TabletEntityStatisticsItem {
|
||||||
|
id: serverStats
|
||||||
|
width: parent.width
|
||||||
|
titleText: qsTr("Entity Server ") + (index+1) + ":"
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
color: OctreeStats.getColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: buttonsRow
|
||||||
|
width: parent.width
|
||||||
|
height: 30
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
HifiControls.Button {
|
||||||
|
id: moreButton
|
||||||
|
color: hifi.buttons.blue
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
width: parent.width / 2 - 10
|
||||||
|
height: 30
|
||||||
|
onClicked: {
|
||||||
|
if (serverColumn.state === "less") {
|
||||||
|
serverColumn.state = "more"
|
||||||
|
} else if (serverColumn.state === "more") {
|
||||||
|
serverColumn.state = "most"
|
||||||
|
} else {
|
||||||
|
serverColumn.state = "more"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HifiControls.Button {
|
||||||
|
id: mostButton
|
||||||
|
color: hifi.buttons.blue
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
height: 30
|
||||||
|
width: parent.width / 2 - 10
|
||||||
|
onClicked: {
|
||||||
|
if (serverColumn.state === "less") {
|
||||||
|
serverColumn.state = "most"
|
||||||
|
} else if (serverColumn.state === "more") {
|
||||||
|
serverColumn.state = "less"
|
||||||
|
} else {
|
||||||
|
serverColumn.state = "less"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "less"
|
||||||
|
PropertyChanges { target: moreButton; text: qsTr("more..."); }
|
||||||
|
PropertyChanges { target: mostButton; text: qsTr("most..."); }
|
||||||
|
PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3]; }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "more"
|
||||||
|
PropertyChanges { target: moreButton; text: qsTr("most..."); }
|
||||||
|
PropertyChanges { target: mostButton; text: qsTr("less..."); }
|
||||||
|
PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3] +
|
||||||
|
OctreeStats.servers[index*3 + 1]; }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "most"
|
||||||
|
PropertyChanges { target: moreButton; text: qsTr("less..."); }
|
||||||
|
PropertyChanges { target: mostButton; text: qsTr("least..."); }
|
||||||
|
PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3] +
|
||||||
|
OctreeStats.servers[index*3 + 1] +
|
||||||
|
OctreeStats.servers[index*3 + 2]; }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
} //servers column
|
||||||
|
} //repeater
|
||||||
|
} //column
|
||||||
|
} //flickable
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
//
|
||||||
|
// TabletEntityStatistics.qml
|
||||||
|
//
|
||||||
|
// Created by Vlad Stelmahovsky on 3/11/17
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import Qt.labs.settings 1.0
|
||||||
|
|
||||||
|
import "../../styles-uit"
|
||||||
|
import "../../controls-uit" as HifiControls
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: root
|
||||||
|
property int colorScheme: hifi.colorSchemes.dark
|
||||||
|
|
||||||
|
property alias titleText: titleLabel.text
|
||||||
|
property alias text: valueLabel.text
|
||||||
|
property alias color: valueLabel.color
|
||||||
|
|
||||||
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
HifiControls.Label {
|
||||||
|
id: titleLabel
|
||||||
|
size: 20
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
}
|
||||||
|
|
||||||
|
RalewaySemiBold {
|
||||||
|
id: valueLabel
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
size: 16
|
||||||
|
color: enabled ? (root.colorScheme == hifi.colorSchemes.light ? hifi.colors.lightGray : hifi.colors.lightGrayText)
|
||||||
|
: (root.colorScheme == hifi.colorSchemes.light ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight);
|
||||||
|
}
|
||||||
|
}
|
|
@ -79,266 +79,297 @@ Rectangle {
|
||||||
scripts.stopAllScripts();
|
scripts.stopAllScripts();
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Flickable {
|
||||||
|
id: flickable
|
||||||
width: parent.width
|
width: parent.width
|
||||||
HifiControls.TabletContentSection {
|
height: parent.height - (keyboard.raised ? keyboard.raisedHeight : 0)
|
||||||
name: "Currently Running"
|
contentWidth: parent.width
|
||||||
isFirst: true
|
contentHeight: column.childrenRect.height
|
||||||
|
clip: true
|
||||||
|
|
||||||
HifiControls.VerticalSpacer {}
|
Column {
|
||||||
|
id: column
|
||||||
|
width: parent.width
|
||||||
|
HifiControls.TabletContentSection {
|
||||||
|
id: firstSection
|
||||||
|
name: "Currently Running"
|
||||||
|
isFirst: true
|
||||||
|
|
||||||
Row {
|
HifiControls.VerticalSpacer {}
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
HifiControls.Button {
|
Row {
|
||||||
text: "Reload All"
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
color: hifi.buttons.black
|
|
||||||
onClicked: reloadAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.Button {
|
HifiControls.Button {
|
||||||
text: "Remove All"
|
text: "Reload All"
|
||||||
color: hifi.buttons.red
|
color: hifi.buttons.black
|
||||||
onClicked: stopAll()
|
onClicked: reloadAll()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.VerticalSpacer {
|
|
||||||
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.Table {
|
|
||||||
model: runningScriptsModel
|
|
||||||
id: table
|
|
||||||
height: 185
|
|
||||||
colorScheme: hifi.colorSchemes.dark
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
expandSelectedRow: true
|
|
||||||
|
|
||||||
itemDelegate: Item {
|
|
||||||
anchors {
|
|
||||||
left: parent ? parent.left : undefined
|
|
||||||
leftMargin: hifi.dimensions.tablePadding
|
|
||||||
right: parent ? parent.right : undefined
|
|
||||||
rightMargin: hifi.dimensions.tablePadding
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FiraSansSemiBold {
|
HifiControls.Button {
|
||||||
id: textItem
|
text: "Remove All"
|
||||||
text: styleData.value
|
color: hifi.buttons.red
|
||||||
size: hifi.fontSizes.tableText
|
onClicked: stopAll()
|
||||||
color: table.colorScheme == hifi.colorSchemes.light
|
}
|
||||||
? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight)
|
}
|
||||||
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
|
|
||||||
|
HifiControls.VerticalSpacer {
|
||||||
|
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.Table {
|
||||||
|
model: runningScriptsModel
|
||||||
|
id: table
|
||||||
|
height: 185
|
||||||
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
expandSelectedRow: true
|
||||||
|
|
||||||
|
itemDelegate: Item {
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: parent ? parent.left : undefined
|
||||||
right: parent.right
|
leftMargin: hifi.dimensions.tablePadding
|
||||||
top: parent.top
|
right: parent ? parent.right : undefined
|
||||||
topMargin: 3
|
rightMargin: hifi.dimensions.tablePadding
|
||||||
}
|
}
|
||||||
|
|
||||||
HiFiGlyphs {
|
FiraSansSemiBold {
|
||||||
id: reloadButton
|
id: textItem
|
||||||
text: hifi.glyphs.reloadSmall
|
text: styleData.value
|
||||||
color: reloadButtonArea.pressed ? hifi.colors.white : parent.color
|
size: hifi.fontSizes.tableText
|
||||||
|
color: table.colorScheme == hifi.colorSchemes.light
|
||||||
|
? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight)
|
||||||
|
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
|
||||||
anchors {
|
anchors {
|
||||||
top: parent.top
|
left: parent.left
|
||||||
right: stopButton.left
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
MouseArea {
|
|
||||||
id: reloadButtonArea
|
|
||||||
anchors { fill: parent; margins: -2 }
|
|
||||||
onClicked: reloadScript(model.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HiFiGlyphs {
|
|
||||||
id: stopButton
|
|
||||||
text: hifi.glyphs.closeSmall
|
|
||||||
color: stopButtonArea.pressed ? hifi.colors.white : parent.color
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
right: parent.right
|
right: parent.right
|
||||||
verticalCenter: parent.verticalCenter
|
top: parent.top
|
||||||
|
topMargin: 3
|
||||||
}
|
}
|
||||||
MouseArea {
|
|
||||||
id: stopButtonArea
|
HiFiGlyphs {
|
||||||
anchors { fill: parent; margins: -2 }
|
id: reloadButton
|
||||||
onClicked: stopScript(model.url)
|
text: hifi.glyphs.reloadSmall
|
||||||
|
color: reloadButtonArea.pressed ? hifi.colors.white : parent.color
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
right: stopButton.left
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
id: reloadButtonArea
|
||||||
|
anchors { fill: parent; margins: -2 }
|
||||||
|
onClicked: reloadScript(model.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HiFiGlyphs {
|
||||||
|
id: stopButton
|
||||||
|
text: hifi.glyphs.closeSmall
|
||||||
|
color: stopButtonArea.pressed ? hifi.colors.white : parent.color
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
right: parent.right
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
id: stopButtonArea
|
||||||
|
anchors { fill: parent; margins: -2 }
|
||||||
|
onClicked: stopScript(model.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FiraSansSemiBold {
|
||||||
|
text: runningScriptsModel.get(styleData.row) ? runningScriptsModel.get(styleData.row).url : ""
|
||||||
|
elide: Text.ElideMiddle
|
||||||
|
size: hifi.fontSizes.tableText
|
||||||
|
color: table.colorScheme == hifi.colorSchemes.light
|
||||||
|
? (styleData.selected ? hifi.colors.black : hifi.colors.lightGray)
|
||||||
|
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
|
||||||
|
anchors {
|
||||||
|
top: textItem.bottom
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
visible: styleData.selected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TableViewColumn {
|
||||||
|
role: "name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.VerticalSpacer {
|
||||||
|
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.TabletContentSection {
|
||||||
|
name: "Load Scripts"
|
||||||
|
|
||||||
|
HifiControls.VerticalSpacer {}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
|
|
||||||
|
HifiControls.Button {
|
||||||
|
text: "from URL"
|
||||||
|
color: hifi.buttons.black
|
||||||
|
height: 26
|
||||||
|
onClicked: fromUrlTimer.running = true
|
||||||
|
|
||||||
|
// For some reason trigginer an API that enters
|
||||||
|
// an internal event loop directly from the button clicked
|
||||||
|
// trigger below causes the appliction to behave oddly.
|
||||||
|
// Most likely because the button onClicked handling is never
|
||||||
|
// completed until the function returns.
|
||||||
|
// FIXME find a better way of handling the input dialogs that
|
||||||
|
// doesn't trigger this.
|
||||||
|
Timer {
|
||||||
|
id: fromUrlTimer
|
||||||
|
interval: 5
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
onTriggered: ApplicationInterface.loadScriptURLDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.Button {
|
||||||
|
text: "from Disk"
|
||||||
|
color: hifi.buttons.black
|
||||||
|
height: 26
|
||||||
|
onClicked: fromDiskTimer.running = true
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: fromDiskTimer
|
||||||
|
interval: 5
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
onTriggered: ApplicationInterface.loadDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.Button {
|
||||||
|
text: "Load Defaults"
|
||||||
|
color: hifi.buttons.black
|
||||||
|
height: 26
|
||||||
|
onClicked: loadDefaults()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.VerticalSpacer {}
|
||||||
|
|
||||||
|
HifiControls.TextField {
|
||||||
|
id: filterEdit
|
||||||
|
isSearchField: true
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
placeholderText: "Filter"
|
||||||
|
onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i")
|
||||||
|
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
|
||||||
|
onActiveFocusChanged: {
|
||||||
|
// raise the keyboard
|
||||||
|
keyboard.raised = activeFocus;
|
||||||
|
|
||||||
|
// scroll to the bottom of the content area.
|
||||||
|
if (activeFocus) {
|
||||||
|
flickable.contentY = (flickable.contentHeight - flickable.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.VerticalSpacer {
|
||||||
|
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.Tree {
|
||||||
|
id: treeView
|
||||||
|
height: 155
|
||||||
|
treeModel: scriptsModel
|
||||||
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.VerticalSpacer {
|
||||||
|
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.TextField {
|
||||||
|
id: selectedScript
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: loadButton.width + hifi.dimensions.contentSpacing.x
|
||||||
|
|
||||||
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
readOnly: true
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: treeView
|
||||||
|
onCurrentIndexChanged: {
|
||||||
|
var path = scriptsModel.data(treeView.currentIndex, 0x100)
|
||||||
|
if (path) {
|
||||||
|
selectedScript.text = path
|
||||||
|
} else {
|
||||||
|
selectedScript.text = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
FiraSansSemiBold {
|
|
||||||
text: runningScriptsModel.get(styleData.row) ? runningScriptsModel.get(styleData.row).url : ""
|
|
||||||
elide: Text.ElideMiddle
|
|
||||||
size: hifi.fontSizes.tableText
|
|
||||||
color: table.colorScheme == hifi.colorSchemes.light
|
|
||||||
? (styleData.selected ? hifi.colors.black : hifi.colors.lightGray)
|
|
||||||
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
|
|
||||||
anchors {
|
|
||||||
top: textItem.bottom
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
}
|
|
||||||
visible: styleData.selected
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TableViewColumn {
|
Item {
|
||||||
role: "name"
|
// Take the loadButton out of the column flow.
|
||||||
}
|
id: loadButtonContainer
|
||||||
}
|
anchors.top: selectedScript.top
|
||||||
|
|
||||||
HifiControls.VerticalSpacer {
|
|
||||||
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.TabletContentSection {
|
|
||||||
name: "Load Scripts"
|
|
||||||
|
|
||||||
HifiControls.VerticalSpacer {}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
HifiControls.Button {
|
|
||||||
text: "from URL"
|
|
||||||
color: hifi.buttons.black
|
|
||||||
height: 26
|
|
||||||
onClicked: fromUrlTimer.running = true
|
|
||||||
|
|
||||||
// For some reason trigginer an API that enters
|
|
||||||
// an internal event loop directly from the button clicked
|
|
||||||
// trigger below causes the appliction to behave oddly.
|
|
||||||
// Most likely because the button onClicked handling is never
|
|
||||||
// completed until the function returns.
|
|
||||||
// FIXME find a better way of handling the input dialogs that
|
|
||||||
// doesn't trigger this.
|
|
||||||
Timer {
|
|
||||||
id: fromUrlTimer
|
|
||||||
interval: 5
|
|
||||||
repeat: false
|
|
||||||
running: false
|
|
||||||
onTriggered: ApplicationInterface.loadScriptURLDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.Button {
|
|
||||||
text: "from Disk"
|
|
||||||
color: hifi.buttons.black
|
|
||||||
height: 26
|
|
||||||
onClicked: fromDiskTimer.running = true
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: fromDiskTimer
|
|
||||||
interval: 5
|
|
||||||
repeat: false
|
|
||||||
running: false
|
|
||||||
onTriggered: ApplicationInterface.loadDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.Button {
|
|
||||||
text: "Load Defaults"
|
|
||||||
color: hifi.buttons.black
|
|
||||||
height: 26
|
|
||||||
onClicked: loadDefaults()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.VerticalSpacer {}
|
|
||||||
|
|
||||||
HifiControls.TextField {
|
|
||||||
id: filterEdit
|
|
||||||
isSearchField: true
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
colorScheme: hifi.colorSchemes.dark
|
|
||||||
placeholderText: "Filter"
|
|
||||||
onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i")
|
|
||||||
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.VerticalSpacer {
|
|
||||||
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.Tree {
|
|
||||||
id: treeView
|
|
||||||
height: 155
|
|
||||||
treeModel: scriptsModel
|
|
||||||
colorScheme: hifi.colorSchemes.dark
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.VerticalSpacer {
|
|
||||||
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.TextField {
|
|
||||||
id: selectedScript
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: loadButton.width + hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
colorScheme: hifi.colorSchemes.dark
|
|
||||||
readOnly: true
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: treeView
|
|
||||||
onCurrentIndexChanged: {
|
|
||||||
var path = scriptsModel.data(treeView.currentIndex, 0x100)
|
|
||||||
if (path) {
|
|
||||||
selectedScript.text = path
|
|
||||||
} else {
|
|
||||||
selectedScript.text = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
// Take the loadButton out of the column flow.
|
|
||||||
id: loadButtonContainer
|
|
||||||
anchors.top: selectedScript.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
HifiControls.Button {
|
|
||||||
id: loadButton
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
text: "Load"
|
HifiControls.Button {
|
||||||
color: hifi.buttons.blue
|
id: loadButton
|
||||||
enabled: selectedScript.text != ""
|
anchors.right: parent.right
|
||||||
onClicked: root.loadScript(selectedScript.text)
|
|
||||||
|
text: "Load"
|
||||||
|
color: hifi.buttons.blue
|
||||||
|
enabled: selectedScript.text != ""
|
||||||
|
onClicked: root.loadScript(selectedScript.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.VerticalSpacer {
|
||||||
|
height: hifi.dimensions.controlInterlineHeight - (!isHMD ? 3 : 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.TextAction {
|
||||||
|
id: directoryButton
|
||||||
|
icon: hifi.glyphs.script
|
||||||
|
iconSize: 24
|
||||||
|
text: "Reveal Scripts Folder"
|
||||||
|
onClicked: fileDialogHelper.openDirectory(scripts.defaultScriptsPath)
|
||||||
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
anchors.left: parent.left
|
||||||
|
visible: !isHMD
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.VerticalSpacer {
|
||||||
|
height: hifi.dimensions.controlInterlineHeight - 3
|
||||||
|
visible: !isHMD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HifiControls.VerticalSpacer {
|
HifiControls.Keyboard {
|
||||||
height: hifi.dimensions.controlInterlineHeight - (!isHMD ? 3 : 0)
|
id: keyboard
|
||||||
}
|
raised: false
|
||||||
|
numeric: false
|
||||||
HifiControls.TextAction {
|
anchors {
|
||||||
id: directoryButton
|
bottom: parent.bottom
|
||||||
icon: hifi.glyphs.script
|
left: parent.left
|
||||||
iconSize: 24
|
right: parent.right
|
||||||
text: "Reveal Scripts Folder"
|
|
||||||
onClicked: fileDialogHelper.openDirectory(scripts.defaultScriptsPath)
|
|
||||||
colorScheme: hifi.colorSchemes.dark
|
|
||||||
anchors.left: parent.left
|
|
||||||
visible: !isHMD
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControls.VerticalSpacer {
|
|
||||||
height: hifi.dimensions.controlInterlineHeight - 3
|
|
||||||
visible: !isHMD
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ Item {
|
||||||
id: root
|
id: root
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
objectName: "tabletMenuHandlerItem"
|
objectName: "tabletMenuHandlerItem"
|
||||||
|
|
||||||
StackView {
|
StackView {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
id: d
|
id: d
|
||||||
|
@ -54,6 +54,10 @@ Item {
|
||||||
d.currentItem.focus = true;
|
d.currentItem.focus = true;
|
||||||
d.currentItem.forceActiveFocus();
|
d.currentItem.forceActiveFocus();
|
||||||
breadcrumbText.text = d.currentItem.title;
|
breadcrumbText.text = d.currentItem.title;
|
||||||
|
if (typeof bgNavBar !== "undefined") {
|
||||||
|
d.currentItem.y = bgNavBar.height;
|
||||||
|
d.currentItem.height -= bgNavBar.height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function popSource() {
|
function popSource() {
|
||||||
|
|
|
@ -173,6 +173,7 @@
|
||||||
#include "ui/overlays/Overlays.h"
|
#include "ui/overlays/Overlays.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "InterfaceParentFinder.h"
|
#include "InterfaceParentFinder.h"
|
||||||
|
#include "ui/OctreeStatsProvider.h"
|
||||||
|
|
||||||
#include "FrameTimingsScriptingInterface.h"
|
#include "FrameTimingsScriptingInterface.h"
|
||||||
#include <GPUIdent.h>
|
#include <GPUIdent.h>
|
||||||
|
@ -523,6 +524,7 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
DependencyManager::set<OffscreenQmlSurfaceCache>();
|
DependencyManager::set<OffscreenQmlSurfaceCache>();
|
||||||
DependencyManager::set<EntityScriptClient>();
|
DependencyManager::set<EntityScriptClient>();
|
||||||
DependencyManager::set<EntityScriptServerLogClient>();
|
DependencyManager::set<EntityScriptServerLogClient>();
|
||||||
|
DependencyManager::set<OctreeStatsProvider>(nullptr, qApp->getOcteeSceneStats());
|
||||||
return previousSessionCrashed;
|
return previousSessionCrashed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,7 +552,7 @@ const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f;
|
||||||
const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true;
|
const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true;
|
||||||
const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false;
|
const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false;
|
||||||
const bool DEFAULT_TABLET_VISIBLE_TO_OTHERS = false;
|
const bool DEFAULT_TABLET_VISIBLE_TO_OTHERS = false;
|
||||||
const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false;
|
const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = true;
|
||||||
|
|
||||||
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) :
|
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) :
|
||||||
QApplication(argc, argv),
|
QApplication(argc, argv),
|
||||||
|
@ -1188,6 +1190,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
// set the local loopback interface for local sounds
|
// set the local loopback interface for local sounds
|
||||||
AudioInjector::setLocalAudioInterface(audioIO.data());
|
AudioInjector::setLocalAudioInterface(audioIO.data());
|
||||||
AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data());
|
AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data());
|
||||||
|
connect(audioIO.data(), &AudioClient::noiseGateOpened, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::noiseGateOpened);
|
||||||
|
connect(audioIO.data(), &AudioClient::noiseGateClosed, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::noiseGateClosed);
|
||||||
|
connect(audioIO.data(), &AudioClient::inputReceived, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::inputReceived);
|
||||||
|
|
||||||
|
|
||||||
this->installEventFilter(this);
|
this->installEventFilter(this);
|
||||||
|
|
||||||
|
@ -1625,9 +1631,10 @@ QString Application::getUserAgent() {
|
||||||
|
|
||||||
void Application::toggleTabletUI() const {
|
void Application::toggleTabletUI() const {
|
||||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||||
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||||
bool messageOpen = tablet->isMessageDialogOpen();
|
bool messageOpen = tablet->isMessageDialogOpen();
|
||||||
if (!messageOpen) {
|
if (!messageOpen || (messageOpen && !hmd->getShouldShowTablet())) {
|
||||||
auto HMD = DependencyManager::get<HMDScriptingInterface>();
|
auto HMD = DependencyManager::get<HMDScriptingInterface>();
|
||||||
HMD->toggleShouldShowTablet();
|
HMD->toggleShouldShowTablet();
|
||||||
}
|
}
|
||||||
|
@ -1803,6 +1810,7 @@ Application::~Application() {
|
||||||
DependencyManager::destroy<GeometryCache>();
|
DependencyManager::destroy<GeometryCache>();
|
||||||
DependencyManager::destroy<ScriptCache>();
|
DependencyManager::destroy<ScriptCache>();
|
||||||
DependencyManager::destroy<SoundCache>();
|
DependencyManager::destroy<SoundCache>();
|
||||||
|
DependencyManager::destroy<OctreeStatsProvider>();
|
||||||
|
|
||||||
ResourceManager::cleanup();
|
ResourceManager::cleanup();
|
||||||
|
|
||||||
|
@ -1950,6 +1958,8 @@ void Application::initializeUi() {
|
||||||
rootContext->setContextProperty("ApplicationInterface", this);
|
rootContext->setContextProperty("ApplicationInterface", this);
|
||||||
rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance());
|
rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance());
|
||||||
rootContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
rootContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
||||||
|
rootContext->setContextProperty("AudioScope", DependencyManager::get<AudioScope>().data());
|
||||||
|
|
||||||
rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
||||||
rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
|
rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
|
||||||
_fileDownload = new FileScriptingInterface(engine);
|
_fileDownload = new FileScriptingInterface(engine);
|
||||||
|
@ -3178,7 +3188,23 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::mouseDoublePressEvent(QMouseEvent* event) const {
|
void Application::mouseDoublePressEvent(QMouseEvent* event) {
|
||||||
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
|
auto eventPosition = getApplicationCompositor().getMouseEventPosition(event);
|
||||||
|
QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget);
|
||||||
|
QMouseEvent mappedEvent(event->type(),
|
||||||
|
transformedPos,
|
||||||
|
event->screenPos(), event->button(),
|
||||||
|
event->buttons(), event->modifiers());
|
||||||
|
|
||||||
|
if (!_aboutToQuit) {
|
||||||
|
getOverlays().mouseDoublePressEvent(&mappedEvent);
|
||||||
|
if (!_controllerScriptingInterface->areEntityClicksCaptured()) {
|
||||||
|
getEntities()->mouseDoublePressEvent(&mappedEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
if (_controllerScriptingInterface->isMouseCaptured()) {
|
if (_controllerScriptingInterface->isMouseCaptured()) {
|
||||||
return;
|
return;
|
||||||
|
@ -5525,6 +5551,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
||||||
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
|
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
|
||||||
scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
|
scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
|
||||||
scriptEngine->registerGlobalObject("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
scriptEngine->registerGlobalObject("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
||||||
|
scriptEngine->registerGlobalObject("AudioScope", DependencyManager::get<AudioScope>().data());
|
||||||
|
|
||||||
// Caches
|
// Caches
|
||||||
scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||||
|
@ -6375,6 +6402,18 @@ void Application::loadLODToolsDialog() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Application::loadEntityStatisticsDialog() {
|
||||||
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||||
|
if (tablet->getToolbarMode() || (!tablet->getTabletRoot() && !isHMDMode())) {
|
||||||
|
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||||
|
dialogsManager->octreeStatsDetails();
|
||||||
|
} else {
|
||||||
|
tablet->pushOntoStack("../../hifi/dialogs/TabletEntityStatistics.qml");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
void Application::toggleLogDialog() {
|
void Application::toggleLogDialog() {
|
||||||
if (! _logDialog) {
|
if (! _logDialog) {
|
||||||
_logDialog = new LogDialog(nullptr, getLogger());
|
_logDialog = new LogDialog(nullptr, getLogger());
|
||||||
|
|
|
@ -404,6 +404,7 @@ public slots:
|
||||||
|
|
||||||
Q_INVOKABLE void toggleMuteAudio();
|
Q_INVOKABLE void toggleMuteAudio();
|
||||||
void loadLODToolsDialog();
|
void loadLODToolsDialog();
|
||||||
|
void loadEntityStatisticsDialog();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void showDesktop();
|
void showDesktop();
|
||||||
|
@ -497,7 +498,7 @@ private:
|
||||||
|
|
||||||
void mouseMoveEvent(QMouseEvent* event);
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
void mousePressEvent(QMouseEvent* event);
|
void mousePressEvent(QMouseEvent* event);
|
||||||
void mouseDoublePressEvent(QMouseEvent* event) const;
|
void mouseDoublePressEvent(QMouseEvent* event);
|
||||||
void mouseReleaseEvent(QMouseEvent* event);
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
|
||||||
void touchBeginEvent(QTouchEvent* event);
|
void touchBeginEvent(QTouchEvent* event);
|
||||||
|
|
|
@ -547,8 +547,10 @@ Menu::Menu() {
|
||||||
|
|
||||||
// Developer > Entities >>>
|
// Developer > Entities >>>
|
||||||
MenuWrapper* entitiesOptionsMenu = developerMenu->addMenu("Entities");
|
MenuWrapper* entitiesOptionsMenu = developerMenu->addMenu("Entities");
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(entitiesOptionsMenu, MenuOption::OctreeStats, 0,
|
addActionToQMenuAndActionHash(entitiesOptionsMenu, MenuOption::OctreeStats, 0,
|
||||||
dialogsManager.data(), SLOT(octreeStatsDetails()));
|
qApp, SLOT(loadEntityStatisticsDialog()));
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(entitiesOptionsMenu, MenuOption::ShowRealtimeEntityStats);
|
addCheckableActionToQMenuAndActionHash(entitiesOptionsMenu, MenuOption::ShowRealtimeEntityStats);
|
||||||
|
|
||||||
// Developer > Network >>>
|
// Developer > Network >>>
|
||||||
|
|
|
@ -52,12 +52,14 @@ AudioScope::AudioScope() :
|
||||||
connect(audioIO.data(), &AudioClient::inputReceived, this, &AudioScope::addInputToScope);
|
connect(audioIO.data(), &AudioClient::inputReceived, this, &AudioScope::addInputToScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioScope::toggle() {
|
void AudioScope::setVisible(bool visible) {
|
||||||
_isEnabled = !_isEnabled;
|
if (_isEnabled != visible) {
|
||||||
if (_isEnabled) {
|
_isEnabled = visible;
|
||||||
allocateScope();
|
if (_isEnabled) {
|
||||||
} else {
|
allocateScope();
|
||||||
freeScope();
|
} else {
|
||||||
|
freeScope();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,14 @@ public:
|
||||||
void render(RenderArgs* renderArgs, int width, int height);
|
void render(RenderArgs* renderArgs, int width, int height);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void toggle();
|
void toggle() { setVisible(!_isEnabled); }
|
||||||
|
void setVisible(bool visible);
|
||||||
|
bool getVisible() const { return _isEnabled; }
|
||||||
|
|
||||||
void togglePause() { _isPaused = !_isPaused; }
|
void togglePause() { _isPaused = !_isPaused; }
|
||||||
|
void setPause(bool paused) { _isPaused = paused; }
|
||||||
|
bool getPause() { return _isPaused; }
|
||||||
|
|
||||||
void selectAudioScopeFiveFrames();
|
void selectAudioScopeFiveFrames();
|
||||||
void selectAudioScopeTwentyFrames();
|
void selectAudioScopeTwentyFrames();
|
||||||
void selectAudioScopeFiftyFrames();
|
void selectAudioScopeFiftyFrames();
|
||||||
|
@ -74,7 +80,6 @@ private:
|
||||||
int _inputID;
|
int _inputID;
|
||||||
int _outputLeftID;
|
int _outputLeftID;
|
||||||
int _outputRightD;
|
int _outputRightD;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AudioScope_h
|
#endif // hifi_AudioScope_h
|
||||||
|
|
377
interface/src/ui/OctreeStatsProvider.cpp
Normal file
377
interface/src/ui/OctreeStatsProvider.cpp
Normal file
|
@ -0,0 +1,377 @@
|
||||||
|
//
|
||||||
|
// OctreeStatsProvider.cpp
|
||||||
|
// interface/src/ui
|
||||||
|
//
|
||||||
|
// Created by Vlad Stelmahovsky on 3/12/17.
|
||||||
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
#include "../octree/OctreePacketProcessor.h"
|
||||||
|
#include "ui/OctreeStatsProvider.h"
|
||||||
|
|
||||||
|
OctreeStatsProvider::OctreeStatsProvider(QObject* parent, NodeToOctreeSceneStats* model) :
|
||||||
|
QObject(parent),
|
||||||
|
_model(model)
|
||||||
|
, _statCount(0)
|
||||||
|
, _averageUpdatesPerSecond(SAMPLES_PER_SECOND)
|
||||||
|
{
|
||||||
|
//schedule updates
|
||||||
|
connect(&_updateTimer, &QTimer::timeout, this, &OctreeStatsProvider::updateOctreeStatsData);
|
||||||
|
_updateTimer.setInterval(100);
|
||||||
|
//timer will be rescheduled on each new timeout
|
||||||
|
_updateTimer.setSingleShot(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start updates statistics
|
||||||
|
*/
|
||||||
|
void OctreeStatsProvider::startUpdates() {
|
||||||
|
_updateTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop updates statistics
|
||||||
|
*/
|
||||||
|
void OctreeStatsProvider::stopUpdates() {
|
||||||
|
_updateTimer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor OctreeStatsProvider::getColor() const {
|
||||||
|
static int statIndex = 1;
|
||||||
|
static quint32 rotatingColors[] = { GREENISH, YELLOWISH, GREYISH };
|
||||||
|
quint32 colorRGBA = rotatingColors[statIndex % (sizeof(rotatingColors)/sizeof(rotatingColors[0]))];
|
||||||
|
quint32 rgb = colorRGBA >> 8;
|
||||||
|
const quint32 colorpart1 = 0xfefefeu;
|
||||||
|
const quint32 colorpart2 = 0xf8f8f8;
|
||||||
|
rgb = ((rgb & colorpart1) >> 1) + ((rgb & colorpart2) >> 3);
|
||||||
|
statIndex++;
|
||||||
|
return QColor::fromRgb(rgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
OctreeStatsProvider::~OctreeStatsProvider() {
|
||||||
|
_updateTimer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
int OctreeStatsProvider::serversNum() const {
|
||||||
|
return m_serversNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctreeStatsProvider::updateOctreeStatsData() {
|
||||||
|
|
||||||
|
// Processed Entities Related stats
|
||||||
|
auto entities = qApp->getEntities();
|
||||||
|
auto entitiesTree = entities->getTree();
|
||||||
|
|
||||||
|
// Do this ever paint event... even if we don't update
|
||||||
|
auto totalTrackedEdits = entitiesTree->getTotalTrackedEdits();
|
||||||
|
|
||||||
|
const quint64 SAMPLING_WINDOW = USECS_PER_SECOND / SAMPLES_PER_SECOND;
|
||||||
|
quint64 now = usecTimestampNow();
|
||||||
|
quint64 sinceLastWindow = now - _lastWindowAt;
|
||||||
|
auto editsInLastWindow = totalTrackedEdits - _lastKnownTrackedEdits;
|
||||||
|
float sinceLastWindowInSeconds = (float)sinceLastWindow / (float)USECS_PER_SECOND;
|
||||||
|
float recentUpdatesPerSecond = (float)editsInLastWindow / sinceLastWindowInSeconds;
|
||||||
|
if (sinceLastWindow > SAMPLING_WINDOW) {
|
||||||
|
_averageUpdatesPerSecond.updateAverage(recentUpdatesPerSecond);
|
||||||
|
_lastWindowAt = now;
|
||||||
|
_lastKnownTrackedEdits = totalTrackedEdits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only refresh our stats every once in a while, unless asked for realtime
|
||||||
|
quint64 REFRESH_AFTER = Menu::getInstance()->isOptionChecked(MenuOption::ShowRealtimeEntityStats) ? 0 : USECS_PER_SECOND;
|
||||||
|
quint64 sinceLastRefresh = now - _lastRefresh;
|
||||||
|
if (sinceLastRefresh < REFRESH_AFTER) {
|
||||||
|
_updateTimer.start((REFRESH_AFTER - sinceLastRefresh)/1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Only refresh our stats every once in a while, unless asked for realtime
|
||||||
|
//if no realtime, then update once per second. Otherwise consider 60FPS update, ie 16ms interval
|
||||||
|
//int updateinterval = Menu::getInstance()->isOptionChecked(MenuOption::ShowRealtimeEntityStats) ? 16 : 1000;
|
||||||
|
_updateTimer.start(REFRESH_AFTER/1000);
|
||||||
|
|
||||||
|
const int FLOATING_POINT_PRECISION = 3;
|
||||||
|
|
||||||
|
m_localElementsMemory = QString("Elements RAM: %1MB").arg(OctreeElement::getTotalMemoryUsage() / 1000000.0f, 5, 'f', 4);
|
||||||
|
emit localElementsMemoryChanged(m_localElementsMemory);
|
||||||
|
|
||||||
|
// Local Elements
|
||||||
|
m_localElements = QString("Total: %1 / Internal: %2 / Leaves: %3").
|
||||||
|
arg(OctreeElement::getNodeCount()).
|
||||||
|
arg(OctreeElement::getInternalNodeCount()).
|
||||||
|
arg(OctreeElement::getLeafNodeCount());
|
||||||
|
emit localElementsChanged(m_localElements);
|
||||||
|
|
||||||
|
// iterate all the current octree stats, and list their sending modes, total their octree elements, etc...
|
||||||
|
int serverCount = 0;
|
||||||
|
int movingServerCount = 0;
|
||||||
|
unsigned long totalNodes = 0;
|
||||||
|
unsigned long totalInternal = 0;
|
||||||
|
unsigned long totalLeaves = 0;
|
||||||
|
|
||||||
|
m_sendingMode.clear();
|
||||||
|
NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats();
|
||||||
|
sceneStats->withReadLock([&] {
|
||||||
|
for (NodeToOctreeSceneStatsIterator i = sceneStats->begin(); i != sceneStats->end(); i++) {
|
||||||
|
//const QUuid& uuid = i->first;
|
||||||
|
OctreeSceneStats& stats = i->second;
|
||||||
|
serverCount++;
|
||||||
|
|
||||||
|
// calculate server node totals
|
||||||
|
totalNodes += stats.getTotalElements();
|
||||||
|
totalInternal += stats.getTotalInternal();
|
||||||
|
totalLeaves += stats.getTotalLeaves();
|
||||||
|
|
||||||
|
// Sending mode
|
||||||
|
if (serverCount > 1) {
|
||||||
|
m_sendingMode += ",";
|
||||||
|
}
|
||||||
|
if (stats.isMoving()) {
|
||||||
|
m_sendingMode += "M";
|
||||||
|
movingServerCount++;
|
||||||
|
} else {
|
||||||
|
m_sendingMode += "S";
|
||||||
|
}
|
||||||
|
if (stats.isFullScene()) {
|
||||||
|
m_sendingMode += "F";
|
||||||
|
} else {
|
||||||
|
m_sendingMode += "p";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
m_sendingMode += QString(" - %1 servers").arg(serverCount);
|
||||||
|
if (movingServerCount > 0) {
|
||||||
|
m_sendingMode += " <SCENE NOT STABLE> ";
|
||||||
|
} else {
|
||||||
|
m_sendingMode += " <SCENE STABLE> ";
|
||||||
|
}
|
||||||
|
|
||||||
|
emit sendingModeChanged(m_sendingMode);
|
||||||
|
|
||||||
|
// Server Elements
|
||||||
|
m_serverElements = QString("Total: %1 / Internal: %2 / Leaves: %3").
|
||||||
|
arg(totalNodes).arg(totalInternal).arg(totalLeaves);
|
||||||
|
emit serverElementsChanged(m_serverElements);
|
||||||
|
|
||||||
|
|
||||||
|
// Processed Packets Elements
|
||||||
|
auto averageElementsPerPacket = entities->getAverageElementsPerPacket();
|
||||||
|
auto averageEntitiesPerPacket = entities->getAverageEntitiesPerPacket();
|
||||||
|
|
||||||
|
auto averageElementsPerSecond = entities->getAverageElementsPerSecond();
|
||||||
|
auto averageEntitiesPerSecond = entities->getAverageEntitiesPerSecond();
|
||||||
|
|
||||||
|
auto averageWaitLockPerPacket = entities->getAverageWaitLockPerPacket();
|
||||||
|
auto averageUncompressPerPacket = entities->getAverageUncompressPerPacket();
|
||||||
|
auto averageReadBitstreamPerPacket = entities->getAverageReadBitstreamPerPacket();
|
||||||
|
|
||||||
|
const OctreePacketProcessor& entitiesPacketProcessor = qApp->getOctreePacketProcessor();
|
||||||
|
|
||||||
|
auto incomingPacketsDepth = entitiesPacketProcessor.packetsToProcessCount();
|
||||||
|
auto incomingPPS = entitiesPacketProcessor.getIncomingPPS();
|
||||||
|
auto processedPPS = entitiesPacketProcessor.getProcessedPPS();
|
||||||
|
auto treeProcessedPPS = entities->getAveragePacketsPerSecond();
|
||||||
|
|
||||||
|
m_processedPackets = QString("Queue Size: %1 Packets / Network IN: %2 PPS / Queue OUT: %3 PPS / Tree IN: %4 PPS")
|
||||||
|
.arg(incomingPacketsDepth)
|
||||||
|
.arg(incomingPPS, 5, 'f', FLOATING_POINT_PRECISION)
|
||||||
|
.arg(processedPPS, 5, 'f', FLOATING_POINT_PRECISION)
|
||||||
|
.arg(treeProcessedPPS, 5, 'f', FLOATING_POINT_PRECISION);
|
||||||
|
emit processedPacketsChanged(m_processedPackets);
|
||||||
|
|
||||||
|
m_processedPacketsElements = QString("%1 per packet / %2 per second")
|
||||||
|
.arg(averageElementsPerPacket, 5, 'f', FLOATING_POINT_PRECISION)
|
||||||
|
.arg(averageElementsPerSecond, 5, 'f', FLOATING_POINT_PRECISION);
|
||||||
|
emit processedPacketsElementsChanged(m_processedPacketsElements);
|
||||||
|
|
||||||
|
m_processedPacketsEntities = QString("%1 per packet / %2 per second")
|
||||||
|
.arg(averageEntitiesPerPacket, 5, 'f', FLOATING_POINT_PRECISION)
|
||||||
|
.arg(averageEntitiesPerSecond, 5, 'f', FLOATING_POINT_PRECISION);
|
||||||
|
emit processedPacketsEntitiesChanged(m_processedPacketsEntities);
|
||||||
|
|
||||||
|
m_processedPacketsTiming = QString("Lock Wait: %1 (usecs) / Uncompress: %2 (usecs) / Process: %3 (usecs)")
|
||||||
|
.arg(averageWaitLockPerPacket)
|
||||||
|
.arg(averageUncompressPerPacket)
|
||||||
|
.arg(averageReadBitstreamPerPacket);
|
||||||
|
emit processedPacketsTimingChanged(m_processedPacketsTiming);
|
||||||
|
|
||||||
|
auto entitiesEditPacketSender = qApp->getEntityEditPacketSender();
|
||||||
|
auto outboundPacketsDepth = entitiesEditPacketSender->packetsToSendCount();
|
||||||
|
auto outboundQueuedPPS = entitiesEditPacketSender->getLifetimePPSQueued();
|
||||||
|
auto outboundSentPPS = entitiesEditPacketSender->getLifetimePPS();
|
||||||
|
|
||||||
|
m_outboundEditPackets = QString("Queue Size: %1 packets / Queued IN: %2 PPS / Sent OUT: %3 PPS")
|
||||||
|
.arg(outboundPacketsDepth)
|
||||||
|
.arg(outboundQueuedPPS, 5, 'f', FLOATING_POINT_PRECISION)
|
||||||
|
.arg(outboundSentPPS, 5, 'f', FLOATING_POINT_PRECISION);
|
||||||
|
emit outboundEditPacketsChanged(m_outboundEditPackets);
|
||||||
|
|
||||||
|
// Entity Edits update time
|
||||||
|
auto averageEditDelta = entitiesTree->getAverageEditDeltas();
|
||||||
|
auto maxEditDelta = entitiesTree->getMaxEditDelta();
|
||||||
|
|
||||||
|
m_entityUpdateTime = QString("Average: %1 (usecs) / Max: %2 (usecs)")
|
||||||
|
.arg(averageEditDelta)
|
||||||
|
.arg(maxEditDelta);
|
||||||
|
emit entityUpdateTimeChanged(m_entityUpdateTime);
|
||||||
|
|
||||||
|
// Entity Edits
|
||||||
|
auto bytesPerEdit = entitiesTree->getAverageEditBytes();
|
||||||
|
|
||||||
|
auto updatesPerSecond = _averageUpdatesPerSecond.getAverage();
|
||||||
|
if (updatesPerSecond < 1) {
|
||||||
|
updatesPerSecond = 0; // we don't really care about small updates per second so suppress those
|
||||||
|
}
|
||||||
|
|
||||||
|
m_entityUpdates = QString("%1 updates per second / %2 total updates / Average Size: %3 bytes")
|
||||||
|
.arg(updatesPerSecond, 5, 'f', FLOATING_POINT_PRECISION)
|
||||||
|
.arg(totalTrackedEdits)
|
||||||
|
.arg(bytesPerEdit);
|
||||||
|
emit entityUpdatesChanged(m_entityUpdates);
|
||||||
|
|
||||||
|
updateOctreeServers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctreeStatsProvider::updateOctreeServers() {
|
||||||
|
int serverCount = 0;
|
||||||
|
|
||||||
|
showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity",
|
||||||
|
qApp->getEntityServerJurisdictions());
|
||||||
|
if (m_serversNum != serverCount) {
|
||||||
|
m_serversNum = serverCount;
|
||||||
|
emit serversNumChanged(m_serversNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctreeStatsProvider::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName,
|
||||||
|
NodeToJurisdictionMap& serverJurisdictions) {
|
||||||
|
|
||||||
|
m_servers.clear();
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||||
|
|
||||||
|
// only send to the NodeTypes that are NodeType_t_VOXEL_SERVER
|
||||||
|
if (node->getType() == serverType) {
|
||||||
|
serverCount++;
|
||||||
|
|
||||||
|
QString lesserDetails;
|
||||||
|
QString moreDetails;
|
||||||
|
QString mostDetails;
|
||||||
|
|
||||||
|
if (node->getActiveSocket()) {
|
||||||
|
lesserDetails += "active ";
|
||||||
|
} else {
|
||||||
|
lesserDetails += "inactive ";
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid nodeUUID = node->getUUID();
|
||||||
|
|
||||||
|
// lookup our nodeUUID in the jurisdiction map, if it's missing then we're
|
||||||
|
// missing at least one jurisdiction
|
||||||
|
serverJurisdictions.withReadLock([&] {
|
||||||
|
if (serverJurisdictions.find(nodeUUID) == serverJurisdictions.end()) {
|
||||||
|
lesserDetails += " unknown jurisdiction ";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const JurisdictionMap& map = serverJurisdictions[nodeUUID];
|
||||||
|
|
||||||
|
auto rootCode = map.getRootOctalCode();
|
||||||
|
|
||||||
|
if (rootCode) {
|
||||||
|
QString rootCodeHex = octalCodeToHexString(rootCode.get());
|
||||||
|
|
||||||
|
VoxelPositionSize rootDetails;
|
||||||
|
voxelDetailsForCode(rootCode.get(), rootDetails);
|
||||||
|
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
|
||||||
|
lesserDetails += QString(" jurisdiction: %1 [%2, %3, %4: %5]")
|
||||||
|
.arg(rootCodeHex)
|
||||||
|
.arg(rootDetails.x)
|
||||||
|
.arg(rootDetails.y)
|
||||||
|
.arg(rootDetails.z)
|
||||||
|
.arg(rootDetails.s);
|
||||||
|
} else {
|
||||||
|
lesserDetails += " jurisdiction has no rootCode";
|
||||||
|
} // root code
|
||||||
|
});
|
||||||
|
|
||||||
|
// now lookup stats details for this server...
|
||||||
|
NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats();
|
||||||
|
sceneStats->withReadLock([&] {
|
||||||
|
if (sceneStats->find(nodeUUID) != sceneStats->end()) {
|
||||||
|
OctreeSceneStats& stats = sceneStats->at(nodeUUID);
|
||||||
|
|
||||||
|
float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC;
|
||||||
|
float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC;
|
||||||
|
float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND;
|
||||||
|
float lastFullPackets = stats.getLastFullTotalPackets();
|
||||||
|
float lastFullPPS = lastFullPackets;
|
||||||
|
if (lastFullSendInSeconds > 0) {
|
||||||
|
lastFullPPS = lastFullPackets / lastFullSendInSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
mostDetails += QString("<br/><br/>Last Full Scene... Encode: %1 ms Send: %2 ms Packets: %3 Bytes: %4 Rate: %5 PPS")
|
||||||
|
.arg(lastFullEncode)
|
||||||
|
.arg(lastFullSend)
|
||||||
|
.arg(lastFullPackets)
|
||||||
|
.arg(stats.getLastFullTotalBytes())
|
||||||
|
.arg(lastFullPPS);
|
||||||
|
|
||||||
|
for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) {
|
||||||
|
OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i);
|
||||||
|
OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item);
|
||||||
|
mostDetails += QString("<br/> %1 %2")
|
||||||
|
.arg(itemInfo.caption).arg(stats.getItemValue(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
moreDetails += "<br/>Node UUID: " +nodeUUID.toString() + " ";
|
||||||
|
|
||||||
|
moreDetails += QString("<br/>Elements: %1 total %2 internal %3 leaves ")
|
||||||
|
.arg(stats.getTotalElements())
|
||||||
|
.arg(stats.getTotalInternal())
|
||||||
|
.arg(stats.getTotalLeaves());
|
||||||
|
|
||||||
|
const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats();
|
||||||
|
qint64 clockSkewInUsecs = node->getClockSkewUsec();
|
||||||
|
qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC;
|
||||||
|
|
||||||
|
moreDetails += QString("<br/>Incoming Packets: %1/ Lost: %2/ Recovered: %3")
|
||||||
|
.arg(stats.getIncomingPackets())
|
||||||
|
.arg(seqStats.getLost())
|
||||||
|
.arg(seqStats.getRecovered());
|
||||||
|
|
||||||
|
moreDetails += QString("<br/> Out of Order: %1/ Early: %2/ Late: %3/ Unreasonable: %4")
|
||||||
|
.arg(seqStats.getOutOfOrder())
|
||||||
|
.arg(seqStats.getEarly())
|
||||||
|
.arg(seqStats.getLate())
|
||||||
|
.arg(seqStats.getUnreasonable());
|
||||||
|
|
||||||
|
moreDetails += QString("<br/> Average Flight Time: %1 msecs")
|
||||||
|
.arg(stats.getIncomingFlightTimeAverage());
|
||||||
|
|
||||||
|
moreDetails += QString("<br/> Average Ping Time: %1 msecs")
|
||||||
|
.arg(node->getPingMs());
|
||||||
|
|
||||||
|
moreDetails += QString("<br/> Average Clock Skew: %1 msecs [%2]")
|
||||||
|
.arg(clockSkewInMS)
|
||||||
|
.arg(formatUsecTime(clockSkewInUsecs));
|
||||||
|
|
||||||
|
|
||||||
|
moreDetails += QString("<br/>Incoming Bytes: %1 Wasted Bytes: %2")
|
||||||
|
.arg(stats.getIncomingBytes())
|
||||||
|
.arg(stats.getIncomingWastedBytes());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
m_servers.append(lesserDetails);
|
||||||
|
m_servers.append(moreDetails);
|
||||||
|
m_servers.append(mostDetails);
|
||||||
|
} // is VOXEL_SERVER
|
||||||
|
});
|
||||||
|
emit serversChanged(m_servers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
154
interface/src/ui/OctreeStatsProvider.h
Normal file
154
interface/src/ui/OctreeStatsProvider.h
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
//
|
||||||
|
// OctreeStatsProvider.h
|
||||||
|
// interface/src/ui
|
||||||
|
//
|
||||||
|
// Created by Vlad Stelmahovsky on 3/12/17.
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_OctreeStatsProvider_h
|
||||||
|
#define hifi_OctreeStatsProvider_h
|
||||||
|
|
||||||
|
#include <OctreeSceneStats.h>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
#include "DependencyManager.h"
|
||||||
|
|
||||||
|
#define MAX_STATS 100
|
||||||
|
#define MAX_VOXEL_SERVERS 50
|
||||||
|
#define DEFAULT_COLOR 0
|
||||||
|
|
||||||
|
class OctreeStatsProvider : public QObject, public Dependency {
|
||||||
|
Q_OBJECT
|
||||||
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
|
Q_PROPERTY(int serversNum READ serversNum NOTIFY serversNumChanged)
|
||||||
|
Q_PROPERTY(QString serverElements READ serverElements NOTIFY serverElementsChanged)
|
||||||
|
Q_PROPERTY(QString localElements READ localElements NOTIFY localElementsChanged)
|
||||||
|
Q_PROPERTY(QString localElementsMemory READ localElementsMemory NOTIFY localElementsMemoryChanged)
|
||||||
|
Q_PROPERTY(QString sendingMode READ sendingMode NOTIFY sendingModeChanged)
|
||||||
|
Q_PROPERTY(QString processedPackets READ processedPackets NOTIFY processedPacketsChanged)
|
||||||
|
Q_PROPERTY(QString processedPacketsElements READ processedPacketsElements NOTIFY processedPacketsElementsChanged)
|
||||||
|
Q_PROPERTY(QString processedPacketsEntities READ processedPacketsEntities NOTIFY processedPacketsEntitiesChanged)
|
||||||
|
Q_PROPERTY(QString processedPacketsTiming READ processedPacketsTiming NOTIFY processedPacketsTimingChanged)
|
||||||
|
Q_PROPERTY(QString outboundEditPackets READ outboundEditPackets NOTIFY outboundEditPacketsChanged)
|
||||||
|
Q_PROPERTY(QString entityUpdateTime READ entityUpdateTime NOTIFY entityUpdateTimeChanged)
|
||||||
|
Q_PROPERTY(QString entityUpdates READ entityUpdates NOTIFY entityUpdatesChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(QStringList servers READ servers NOTIFY serversChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
OctreeStatsProvider(QObject* parent, NodeToOctreeSceneStats* model);
|
||||||
|
~OctreeStatsProvider();
|
||||||
|
|
||||||
|
int serversNum() const;
|
||||||
|
|
||||||
|
QString serverElements() const {
|
||||||
|
return m_serverElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString localElements() const {
|
||||||
|
return m_localElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString localElementsMemory() const {
|
||||||
|
return m_localElementsMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString sendingMode() const {
|
||||||
|
return m_sendingMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString processedPackets() const {
|
||||||
|
return m_processedPackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString processedPacketsElements() const {
|
||||||
|
return m_processedPacketsElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString processedPacketsEntities() const {
|
||||||
|
return m_processedPacketsEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString processedPacketsTiming() const {
|
||||||
|
return m_processedPacketsTiming;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString outboundEditPackets() const {
|
||||||
|
return m_outboundEditPackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString entityUpdateTime() const {
|
||||||
|
return m_entityUpdateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString entityUpdates() const {
|
||||||
|
return m_entityUpdates;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList servers() const {
|
||||||
|
return m_servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void serversNumChanged(int serversNum);
|
||||||
|
void serverElementsChanged(const QString &serverElements);
|
||||||
|
void localElementsChanged(const QString &localElements);
|
||||||
|
void sendingModeChanged(const QString &sendingMode);
|
||||||
|
void processedPacketsChanged(const QString &processedPackets);
|
||||||
|
void localElementsMemoryChanged(const QString &localElementsMemory);
|
||||||
|
void processedPacketsElementsChanged(const QString &processedPacketsElements);
|
||||||
|
void processedPacketsEntitiesChanged(const QString &processedPacketsEntities);
|
||||||
|
void processedPacketsTimingChanged(const QString &processedPacketsTiming);
|
||||||
|
void outboundEditPacketsChanged(const QString &outboundEditPackets);
|
||||||
|
void entityUpdateTimeChanged(const QString &entityUpdateTime);
|
||||||
|
void entityUpdatesChanged(const QString &entityUpdates);
|
||||||
|
|
||||||
|
void serversChanged(const QStringList &servers);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void startUpdates();
|
||||||
|
void stopUpdates();
|
||||||
|
QColor getColor() const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateOctreeStatsData();
|
||||||
|
protected:
|
||||||
|
void updateOctreeServers();
|
||||||
|
void showOctreeServersOfType(int& serverNumber, NodeType_t serverType,
|
||||||
|
const char* serverTypeName, NodeToJurisdictionMap& serverJurisdictions);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NodeToOctreeSceneStats* _model;
|
||||||
|
int _statCount;
|
||||||
|
|
||||||
|
const int SAMPLES_PER_SECOND = 10;
|
||||||
|
SimpleMovingAverage _averageUpdatesPerSecond;
|
||||||
|
quint64 _lastWindowAt = usecTimestampNow();
|
||||||
|
quint64 _lastKnownTrackedEdits = 0;
|
||||||
|
|
||||||
|
quint64 _lastRefresh = 0;
|
||||||
|
|
||||||
|
QTimer _updateTimer;
|
||||||
|
int m_serversNum {0};
|
||||||
|
QString m_serverElements;
|
||||||
|
QString m_localElements;
|
||||||
|
QString m_localElementsMemory;
|
||||||
|
QString m_sendingMode;
|
||||||
|
QString m_processedPackets;
|
||||||
|
QString m_processedPacketsElements;
|
||||||
|
QString m_processedPacketsEntities;
|
||||||
|
QString m_processedPacketsTiming;
|
||||||
|
QString m_outboundEditPackets;
|
||||||
|
QString m_entityUpdateTime;
|
||||||
|
QString m_entityUpdates;
|
||||||
|
QStringList m_servers;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_OctreeStatsProvider_h
|
|
@ -198,15 +198,16 @@ void Stats::updateStats(bool force) {
|
||||||
STAT_UPDATE(avatarMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer)));
|
STAT_UPDATE(avatarMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer)));
|
||||||
STAT_UPDATE(avatarMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer)));
|
STAT_UPDATE(avatarMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer)));
|
||||||
STAT_UPDATE(avatarMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer)));
|
STAT_UPDATE(avatarMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer)));
|
||||||
STAT_UPDATE(myAvatarSendRate, avatarManager->getMyAvatarSendRate());
|
|
||||||
} else {
|
} else {
|
||||||
STAT_UPDATE(avatarMixerInKbps, -1);
|
STAT_UPDATE(avatarMixerInKbps, -1);
|
||||||
STAT_UPDATE(avatarMixerInPps, -1);
|
STAT_UPDATE(avatarMixerInPps, -1);
|
||||||
STAT_UPDATE(avatarMixerOutKbps, -1);
|
STAT_UPDATE(avatarMixerOutKbps, -1);
|
||||||
STAT_UPDATE(avatarMixerOutPps, -1);
|
STAT_UPDATE(avatarMixerOutPps, -1);
|
||||||
STAT_UPDATE(myAvatarSendRate, avatarManager->getMyAvatarSendRate());
|
|
||||||
}
|
}
|
||||||
|
STAT_UPDATE(myAvatarSendRate, avatarManager->getMyAvatarSendRate());
|
||||||
|
|
||||||
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
||||||
|
auto audioClient = DependencyManager::get<AudioClient>();
|
||||||
if (audioMixerNode || force) {
|
if (audioMixerNode || force) {
|
||||||
STAT_UPDATE(audioMixerKbps, roundf(
|
STAT_UPDATE(audioMixerKbps, roundf(
|
||||||
bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +
|
bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +
|
||||||
|
@ -214,10 +215,30 @@ void Stats::updateStats(bool force) {
|
||||||
STAT_UPDATE(audioMixerPps, roundf(
|
STAT_UPDATE(audioMixerPps, roundf(
|
||||||
bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +
|
bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +
|
||||||
bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
|
bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
|
||||||
|
|
||||||
|
STAT_UPDATE(audioMixerInKbps, roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer)));
|
||||||
|
STAT_UPDATE(audioMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer)));
|
||||||
|
STAT_UPDATE(audioMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer)));
|
||||||
|
STAT_UPDATE(audioMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
|
||||||
|
STAT_UPDATE(audioMicOutboundPPS, audioClient->getMicAudioOutboundPPS());
|
||||||
|
STAT_UPDATE(audioSilentOutboundPPS, audioClient->getSilentOutboundPPS());
|
||||||
|
STAT_UPDATE(audioAudioInboundPPS, audioClient->getAudioInboundPPS());
|
||||||
|
STAT_UPDATE(audioSilentInboundPPS, audioClient->getSilentInboundPPS());
|
||||||
} else {
|
} else {
|
||||||
STAT_UPDATE(audioMixerKbps, -1);
|
STAT_UPDATE(audioMixerKbps, -1);
|
||||||
STAT_UPDATE(audioMixerPps, -1);
|
STAT_UPDATE(audioMixerPps, -1);
|
||||||
|
STAT_UPDATE(audioMixerInKbps, -1);
|
||||||
|
STAT_UPDATE(audioMixerInPps, -1);
|
||||||
|
STAT_UPDATE(audioMixerOutKbps, -1);
|
||||||
|
STAT_UPDATE(audioMixerOutPps, -1);
|
||||||
|
STAT_UPDATE(audioMicOutboundPPS, -1);
|
||||||
|
STAT_UPDATE(audioSilentOutboundPPS, -1);
|
||||||
|
STAT_UPDATE(audioAudioInboundPPS, -1);
|
||||||
|
STAT_UPDATE(audioSilentInboundPPS, -1);
|
||||||
}
|
}
|
||||||
|
STAT_UPDATE(audioCodec, audioClient->getSelectedAudioFormat());
|
||||||
|
STAT_UPDATE(audioNoiseGate, audioClient->getNoiseGateOpen() ? "Open" : "Closed");
|
||||||
|
|
||||||
|
|
||||||
auto loadingRequests = ResourceCache::getLoadingRequests();
|
auto loadingRequests = ResourceCache::getLoadingRequests();
|
||||||
STAT_UPDATE(downloads, loadingRequests.size());
|
STAT_UPDATE(downloads, loadingRequests.size());
|
||||||
|
|
|
@ -70,8 +70,20 @@ class Stats : public QQuickItem {
|
||||||
STATS_PROPERTY(int, avatarMixerOutKbps, 0)
|
STATS_PROPERTY(int, avatarMixerOutKbps, 0)
|
||||||
STATS_PROPERTY(int, avatarMixerOutPps, 0)
|
STATS_PROPERTY(int, avatarMixerOutPps, 0)
|
||||||
STATS_PROPERTY(float, myAvatarSendRate, 0)
|
STATS_PROPERTY(float, myAvatarSendRate, 0)
|
||||||
|
|
||||||
|
STATS_PROPERTY(int, audioMixerInKbps, 0)
|
||||||
|
STATS_PROPERTY(int, audioMixerInPps, 0)
|
||||||
|
STATS_PROPERTY(int, audioMixerOutKbps, 0)
|
||||||
|
STATS_PROPERTY(int, audioMixerOutPps, 0)
|
||||||
STATS_PROPERTY(int, audioMixerKbps, 0)
|
STATS_PROPERTY(int, audioMixerKbps, 0)
|
||||||
STATS_PROPERTY(int, audioMixerPps, 0)
|
STATS_PROPERTY(int, audioMixerPps, 0)
|
||||||
|
STATS_PROPERTY(int, audioMicOutboundPPS, 0)
|
||||||
|
STATS_PROPERTY(int, audioSilentOutboundPPS, 0)
|
||||||
|
STATS_PROPERTY(int, audioAudioInboundPPS, 0)
|
||||||
|
STATS_PROPERTY(int, audioSilentInboundPPS, 0)
|
||||||
|
STATS_PROPERTY(QString, audioCodec, QString())
|
||||||
|
STATS_PROPERTY(QString, audioNoiseGate, QString())
|
||||||
|
|
||||||
STATS_PROPERTY(int, downloads, 0)
|
STATS_PROPERTY(int, downloads, 0)
|
||||||
STATS_PROPERTY(int, downloadLimit, 0)
|
STATS_PROPERTY(int, downloadLimit, 0)
|
||||||
STATS_PROPERTY(int, downloadsPending, 0)
|
STATS_PROPERTY(int, downloadsPending, 0)
|
||||||
|
@ -180,8 +192,19 @@ signals:
|
||||||
void avatarMixerOutKbpsChanged();
|
void avatarMixerOutKbpsChanged();
|
||||||
void avatarMixerOutPpsChanged();
|
void avatarMixerOutPpsChanged();
|
||||||
void myAvatarSendRateChanged();
|
void myAvatarSendRateChanged();
|
||||||
|
void audioMixerInKbpsChanged();
|
||||||
|
void audioMixerInPpsChanged();
|
||||||
|
void audioMixerOutKbpsChanged();
|
||||||
|
void audioMixerOutPpsChanged();
|
||||||
void audioMixerKbpsChanged();
|
void audioMixerKbpsChanged();
|
||||||
void audioMixerPpsChanged();
|
void audioMixerPpsChanged();
|
||||||
|
void audioMicOutboundPPSChanged();
|
||||||
|
void audioSilentOutboundPPSChanged();
|
||||||
|
void audioAudioInboundPPSChanged();
|
||||||
|
void audioSilentInboundPPSChanged();
|
||||||
|
void audioCodecChanged();
|
||||||
|
void audioNoiseGateChanged();
|
||||||
|
|
||||||
void downloadsChanged();
|
void downloadsChanged();
|
||||||
void downloadLimitChanged();
|
void downloadLimitChanged();
|
||||||
void downloadsPendingChanged();
|
void downloadsPendingChanged();
|
||||||
|
|
|
@ -768,6 +768,26 @@ bool Overlays::mousePressEvent(QMouseEvent* event) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
|
||||||
|
PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent");
|
||||||
|
|
||||||
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
|
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
||||||
|
if (rayPickResult.intersects) {
|
||||||
|
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||||
|
|
||||||
|
// Only Web overlays can have focus.
|
||||||
|
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(_currentClickingOnOverlayID));
|
||||||
|
if (thisOverlay) {
|
||||||
|
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Press);
|
||||||
|
emit mouseDoublePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit mouseDoublePressOffOverlay();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,7 @@ public:
|
||||||
OverlayID addOverlay(Overlay::Pointer overlay);
|
OverlayID addOverlay(Overlay::Pointer overlay);
|
||||||
|
|
||||||
bool mousePressEvent(QMouseEvent* event);
|
bool mousePressEvent(QMouseEvent* event);
|
||||||
|
bool mouseDoublePressEvent(QMouseEvent* event);
|
||||||
bool mouseReleaseEvent(QMouseEvent* event);
|
bool mouseReleaseEvent(QMouseEvent* event);
|
||||||
bool mouseMoveEvent(QMouseEvent* event);
|
bool mouseMoveEvent(QMouseEvent* event);
|
||||||
|
|
||||||
|
@ -300,9 +301,11 @@ signals:
|
||||||
void panelDeleted(OverlayID id);
|
void panelDeleted(OverlayID id);
|
||||||
|
|
||||||
void mousePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void mousePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
|
void mouseDoublePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
void mouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void mouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
void mouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void mouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
void mousePressOffOverlay();
|
void mousePressOffOverlay();
|
||||||
|
void mouseDoublePressOffOverlay();
|
||||||
|
|
||||||
void hoverEnterOverlay(OverlayID overlayID, const PointerEvent& event);
|
void hoverEnterOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
void hoverOverOverlay(OverlayID overlayID, const PointerEvent& event);
|
void hoverOverOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "avatar/AvatarManager.h"
|
#include "avatar/AvatarManager.h"
|
||||||
#include "AudioClient.h"
|
#include "AudioClient.h"
|
||||||
#include "LODManager.h"
|
#include "LODManager.h"
|
||||||
|
#include "ui/OctreeStatsProvider.h"
|
||||||
|
|
||||||
static const float DPI = 30.47f;
|
static const float DPI = 30.47f;
|
||||||
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
|
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
|
||||||
|
@ -185,6 +186,7 @@ void Web3DOverlay::loadSourceURL() {
|
||||||
_webSurface->getRootContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
_webSurface->getRootContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
||||||
_webSurface->getRootContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
|
_webSurface->getRootContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
|
||||||
_webSurface->getRootContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
|
_webSurface->getRootContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
|
||||||
|
_webSurface->getRootContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
|
||||||
_webSurface->getRootContext()->setContextProperty("pathToFonts", "../../");
|
_webSurface->getRootContext()->setContextProperty("pathToFonts", "../../");
|
||||||
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data());
|
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data());
|
||||||
|
|
||||||
|
|
|
@ -608,6 +608,13 @@ void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessag
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message) {
|
void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
|
|
||||||
|
if (message->getType() == PacketType::SilentAudioFrame) {
|
||||||
|
_silentInbound.increment();
|
||||||
|
} else {
|
||||||
|
_audioInbound.increment();
|
||||||
|
}
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
nodeList->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket);
|
nodeList->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket);
|
||||||
|
|
||||||
|
@ -1021,9 +1028,10 @@ void AudioClient::handleAudioInput() {
|
||||||
// if we performed the noise gate we can get values from it instead of enumerating the samples again
|
// if we performed the noise gate we can get values from it instead of enumerating the samples again
|
||||||
_lastInputLoudness = _inputGate.getLastLoudness();
|
_lastInputLoudness = _inputGate.getLastLoudness();
|
||||||
|
|
||||||
if (_inputGate.clippedInLastFrame()) {
|
if (_inputGate.clippedInLastBlock()) {
|
||||||
_timeSinceLastClip = 0.0f;
|
_timeSinceLastClip = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
float loudness = 0.0f;
|
float loudness = 0.0f;
|
||||||
|
|
||||||
|
@ -1041,6 +1049,12 @@ void AudioClient::handleAudioInput() {
|
||||||
|
|
||||||
emit inputReceived({ reinterpret_cast<char*>(networkAudioSamples), numNetworkBytes });
|
emit inputReceived({ reinterpret_cast<char*>(networkAudioSamples), numNetworkBytes });
|
||||||
|
|
||||||
|
if (_inputGate.openedInLastBlock()) {
|
||||||
|
emit noiseGateOpened();
|
||||||
|
} else if (_inputGate.closedInLastBlock()) {
|
||||||
|
emit noiseGateClosed();
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// our input loudness is 0, since we're muted
|
// our input loudness is 0, since we're muted
|
||||||
_lastInputLoudness = 0;
|
_lastInputLoudness = 0;
|
||||||
|
@ -1057,9 +1071,13 @@ void AudioClient::handleAudioInput() {
|
||||||
// the output from the input gate (eventually, this could be crossfaded)
|
// the output from the input gate (eventually, this could be crossfaded)
|
||||||
// and allow the codec to properly encode down to silent/zero. If we still
|
// and allow the codec to properly encode down to silent/zero. If we still
|
||||||
// have _lastInputLoudness of 0 in our NEXT frame, we will send a silent packet
|
// have _lastInputLoudness of 0 in our NEXT frame, we will send a silent packet
|
||||||
if (_lastInputLoudness == 0 && !_inputGate.closedInLastFrame()) {
|
if (_lastInputLoudness == 0 && !_inputGate.closedInLastBlock()) {
|
||||||
packetType = PacketType::SilentAudioFrame;
|
packetType = PacketType::SilentAudioFrame;
|
||||||
|
_silentOutbound.increment();
|
||||||
|
} else {
|
||||||
|
_micAudioOutbound.increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform audioTransform;
|
Transform audioTransform;
|
||||||
audioTransform.setTranslation(_positionGetter());
|
audioTransform.setTranslation(_positionGetter());
|
||||||
audioTransform.setRotation(_orientationGetter());
|
audioTransform.setRotation(_orientationGetter());
|
||||||
|
@ -1084,6 +1102,7 @@ void AudioClient::handleAudioInput() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME - should this go through the noise gate and honor mute and echo?
|
||||||
void AudioClient::handleRecordedAudioInput(const QByteArray& audio) {
|
void AudioClient::handleRecordedAudioInput(const QByteArray& audio) {
|
||||||
Transform audioTransform;
|
Transform audioTransform;
|
||||||
audioTransform.setTranslation(_positionGetter());
|
audioTransform.setTranslation(_positionGetter());
|
||||||
|
@ -1096,6 +1115,8 @@ void AudioClient::handleRecordedAudioInput(const QByteArray& audio) {
|
||||||
encodedBuffer = audio;
|
encodedBuffer = audio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_micAudioOutbound.increment();
|
||||||
|
|
||||||
// FIXME check a flag to see if we should echo audio?
|
// FIXME check a flag to see if we should echo audio?
|
||||||
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber,
|
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber,
|
||||||
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
#include <AudioLimiter.h>
|
#include <AudioLimiter.h>
|
||||||
#include <AudioConstants.h>
|
#include <AudioConstants.h>
|
||||||
|
|
||||||
|
#include <shared/RateCounter.h>
|
||||||
|
|
||||||
#include <plugins/CodecPlugin.h>
|
#include <plugins/CodecPlugin.h>
|
||||||
|
|
||||||
#include "AudioIOStats.h"
|
#include "AudioIOStats.h"
|
||||||
|
@ -121,6 +123,13 @@ public:
|
||||||
void negotiateAudioFormat();
|
void negotiateAudioFormat();
|
||||||
void selectAudioFormat(const QString& selectedCodecName);
|
void selectAudioFormat(const QString& selectedCodecName);
|
||||||
|
|
||||||
|
Q_INVOKABLE QString getSelectedAudioFormat() const { return _selectedCodecName; }
|
||||||
|
Q_INVOKABLE bool getNoiseGateOpen() const { return _inputGate.isOpen(); }
|
||||||
|
Q_INVOKABLE float getSilentOutboundPPS() const { return _silentOutbound.rate(); }
|
||||||
|
Q_INVOKABLE float getMicAudioOutboundPPS() const { return _micAudioOutbound.rate(); }
|
||||||
|
Q_INVOKABLE float getSilentInboundPPS() const { return _silentInbound.rate(); }
|
||||||
|
Q_INVOKABLE float getAudioInboundPPS() const { return _audioInbound.rate(); }
|
||||||
|
|
||||||
const MixedProcessedAudioStream& getReceivedAudioStream() const { return _receivedAudioStream; }
|
const MixedProcessedAudioStream& getReceivedAudioStream() const { return _receivedAudioStream; }
|
||||||
MixedProcessedAudioStream& getReceivedAudioStream() { return _receivedAudioStream; }
|
MixedProcessedAudioStream& getReceivedAudioStream() { return _receivedAudioStream; }
|
||||||
|
|
||||||
|
@ -218,6 +227,8 @@ signals:
|
||||||
void inputReceived(const QByteArray& inputSamples);
|
void inputReceived(const QByteArray& inputSamples);
|
||||||
void outputBytesToNetwork(int numBytes);
|
void outputBytesToNetwork(int numBytes);
|
||||||
void inputBytesFromNetwork(int numBytes);
|
void inputBytesFromNetwork(int numBytes);
|
||||||
|
void noiseGateOpened();
|
||||||
|
void noiseGateClosed();
|
||||||
|
|
||||||
void changeDevice(const QAudioDeviceInfo& outputDeviceInfo);
|
void changeDevice(const QAudioDeviceInfo& outputDeviceInfo);
|
||||||
void deviceChanged();
|
void deviceChanged();
|
||||||
|
@ -382,6 +393,11 @@ private:
|
||||||
Encoder* _encoder { nullptr }; // for outbound mic stream
|
Encoder* _encoder { nullptr }; // for outbound mic stream
|
||||||
|
|
||||||
QThread* _checkDevicesThread { nullptr };
|
QThread* _checkDevicesThread { nullptr };
|
||||||
|
|
||||||
|
RateCounter<> _silentOutbound;
|
||||||
|
RateCounter<> _micAudioOutbound;
|
||||||
|
RateCounter<> _silentInbound;
|
||||||
|
RateCounter<> _audioInbound;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,16 +19,16 @@
|
||||||
const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f;
|
const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f;
|
||||||
|
|
||||||
AudioNoiseGate::AudioNoiseGate() :
|
AudioNoiseGate::AudioNoiseGate() :
|
||||||
_inputFrameCounter(0),
|
_inputBlockCounter(0),
|
||||||
_lastLoudness(0.0f),
|
_lastLoudness(0.0f),
|
||||||
_quietestFrame(std::numeric_limits<float>::max()),
|
_quietestBlock(std::numeric_limits<float>::max()),
|
||||||
_loudestFrame(0.0f),
|
_loudestBlock(0.0f),
|
||||||
_didClipInLastFrame(false),
|
_didClipInLastBlock(false),
|
||||||
_dcOffset(0.0f),
|
_dcOffset(0.0f),
|
||||||
_measuredFloor(0.0f),
|
_measuredFloor(0.0f),
|
||||||
_sampleCounter(0),
|
_sampleCounter(0),
|
||||||
_isOpen(false),
|
_isOpen(false),
|
||||||
_framesToClose(0)
|
_blocksToClose(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
|
||||||
//
|
//
|
||||||
// DC Offset correction
|
// DC Offset correction
|
||||||
//
|
//
|
||||||
// Measure the DC offset over a trailing number of frames, and remove it from the input signal.
|
// Measure the DC offset over a trailing number of blocks, and remove it from the input signal.
|
||||||
// This causes the noise background measurements and server muting to be more accurate. Many off-board
|
// This causes the noise background measurements and server muting to be more accurate. Many off-board
|
||||||
// ADC's have a noticeable DC offset.
|
// ADC's have a noticeable DC offset.
|
||||||
//
|
//
|
||||||
|
@ -51,7 +51,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
|
||||||
// Update measured DC offset
|
// Update measured DC offset
|
||||||
measuredDcOffset /= numSamples;
|
measuredDcOffset /= numSamples;
|
||||||
if (_dcOffset == 0.0f) {
|
if (_dcOffset == 0.0f) {
|
||||||
// On first frame, copy over measured offset
|
// On first block, copy over measured offset
|
||||||
_dcOffset = measuredDcOffset;
|
_dcOffset = measuredDcOffset;
|
||||||
} else {
|
} else {
|
||||||
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
|
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
|
||||||
|
@ -69,13 +69,13 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
||||||
//
|
//
|
||||||
// NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate.
|
// NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate.
|
||||||
// Make this value lower for more sensitivity and less rejection of noise.
|
// Make this value lower for more sensitivity and less rejection of noise.
|
||||||
// NOISE_GATE_WIDTH: The number of samples in an audio frame for which the height must be exceeded
|
// NOISE_GATE_WIDTH: The number of samples in an audio block for which the height must be exceeded
|
||||||
// to open the gate.
|
// to open the gate.
|
||||||
// NOISE_GATE_CLOSE_FRAME_DELAY: Once the noise is below the gate height for the frame, how many frames
|
// NOISE_GATE_CLOSE_BLOCK_DELAY: Once the noise is below the gate height for the block, how many blocks
|
||||||
// will we wait before closing the gate.
|
// will we wait before closing the gate.
|
||||||
// NOISE_GATE_FRAMES_TO_AVERAGE: How many audio frames should we average together to compute noise floor.
|
// NOISE_GATE_BLOCKS_TO_AVERAGE: How many audio blocks should we average together to compute noise floor.
|
||||||
// More means better rejection but also can reject continuous things like singing.
|
// More means better rejection but also can reject continuous things like singing.
|
||||||
// NUMBER_OF_NOISE_SAMPLE_FRAMES: How often should we re-evaluate the noise floor?
|
// NUMBER_OF_NOISE_SAMPLE_BLOCKS: How often should we re-evaluate the noise floor?
|
||||||
|
|
||||||
float loudness = 0;
|
float loudness = 0;
|
||||||
int thisSample = 0;
|
int thisSample = 0;
|
||||||
|
@ -83,16 +83,16 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
||||||
|
|
||||||
const float NOISE_GATE_HEIGHT = 7.0f;
|
const float NOISE_GATE_HEIGHT = 7.0f;
|
||||||
const int NOISE_GATE_WIDTH = 5;
|
const int NOISE_GATE_WIDTH = 5;
|
||||||
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
|
const int NOISE_GATE_CLOSE_BLOCK_DELAY = 5;
|
||||||
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
|
const int NOISE_GATE_BLOCKS_TO_AVERAGE = 5;
|
||||||
|
|
||||||
// Check clipping, and check if should open noise gate
|
// Check clipping, and check if should open noise gate
|
||||||
_didClipInLastFrame = false;
|
_didClipInLastBlock = false;
|
||||||
|
|
||||||
for (int i = 0; i < numSamples; i++) {
|
for (int i = 0; i < numSamples; i++) {
|
||||||
thisSample = std::abs(samples[i]);
|
thisSample = std::abs(samples[i]);
|
||||||
if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
|
if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
|
||||||
_didClipInLastFrame = true;
|
_didClipInLastBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
loudness += thisSample;
|
loudness += thisSample;
|
||||||
|
@ -104,54 +104,81 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
||||||
|
|
||||||
_lastLoudness = fabs(loudness / numSamples);
|
_lastLoudness = fabs(loudness / numSamples);
|
||||||
|
|
||||||
if (_quietestFrame > _lastLoudness) {
|
if (_quietestBlock > _lastLoudness) {
|
||||||
_quietestFrame = _lastLoudness;
|
_quietestBlock = _lastLoudness;
|
||||||
}
|
}
|
||||||
if (_loudestFrame < _lastLoudness) {
|
if (_loudestBlock < _lastLoudness) {
|
||||||
_loudestFrame = _lastLoudness;
|
_loudestBlock = _lastLoudness;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int FRAMES_FOR_NOISE_DETECTION = 400;
|
const int FRAMES_FOR_NOISE_DETECTION = 400;
|
||||||
if (_inputFrameCounter++ > FRAMES_FOR_NOISE_DETECTION) {
|
if (_inputBlockCounter++ > FRAMES_FOR_NOISE_DETECTION) {
|
||||||
_quietestFrame = std::numeric_limits<float>::max();
|
_quietestBlock = std::numeric_limits<float>::max();
|
||||||
_loudestFrame = 0.0f;
|
_loudestBlock = 0.0f;
|
||||||
_inputFrameCounter = 0;
|
_inputBlockCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Noise Gate is enabled, check and turn the gate on and off
|
// If Noise Gate is enabled, check and turn the gate on and off
|
||||||
float averageOfAllSampleFrames = 0.0f;
|
float averageOfAllSampleBlocks = 0.0f;
|
||||||
_sampleFrames[_sampleCounter++] = _lastLoudness;
|
_sampleBlocks[_sampleCounter++] = _lastLoudness;
|
||||||
if (_sampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) {
|
if (_sampleCounter == NUMBER_OF_NOISE_SAMPLE_BLOCKS) {
|
||||||
float smallestSample = std::numeric_limits<float>::max();
|
float smallestSample = std::numeric_limits<float>::max();
|
||||||
for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i += NOISE_GATE_FRAMES_TO_AVERAGE) {
|
for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_BLOCKS - NOISE_GATE_BLOCKS_TO_AVERAGE; i += NOISE_GATE_BLOCKS_TO_AVERAGE) {
|
||||||
float thisAverage = 0.0f;
|
float thisAverage = 0.0f;
|
||||||
for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) {
|
for (int j = i; j < i + NOISE_GATE_BLOCKS_TO_AVERAGE; j++) {
|
||||||
thisAverage += _sampleFrames[j];
|
thisAverage += _sampleBlocks[j];
|
||||||
averageOfAllSampleFrames += _sampleFrames[j];
|
averageOfAllSampleBlocks += _sampleBlocks[j];
|
||||||
}
|
}
|
||||||
thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE;
|
thisAverage /= NOISE_GATE_BLOCKS_TO_AVERAGE;
|
||||||
|
|
||||||
if (thisAverage < smallestSample) {
|
if (thisAverage < smallestSample) {
|
||||||
smallestSample = thisAverage;
|
smallestSample = thisAverage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES;
|
averageOfAllSampleBlocks /= NUMBER_OF_NOISE_SAMPLE_BLOCKS;
|
||||||
_measuredFloor = smallestSample;
|
_measuredFloor = smallestSample;
|
||||||
_sampleCounter = 0;
|
_sampleCounter = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_closedInLastBlock = false;
|
||||||
|
_openedInLastBlock = false;
|
||||||
|
|
||||||
if (samplesOverNoiseGate > NOISE_GATE_WIDTH) {
|
if (samplesOverNoiseGate > NOISE_GATE_WIDTH) {
|
||||||
|
_openedInLastBlock = !_isOpen;
|
||||||
_isOpen = true;
|
_isOpen = true;
|
||||||
_framesToClose = NOISE_GATE_CLOSE_FRAME_DELAY;
|
_blocksToClose = NOISE_GATE_CLOSE_BLOCK_DELAY;
|
||||||
} else {
|
} else {
|
||||||
if (--_framesToClose == 0) {
|
if (--_blocksToClose == 0) {
|
||||||
_closedInLastFrame = !_isOpen;
|
_closedInLastBlock = _isOpen;
|
||||||
_isOpen = false;
|
_isOpen = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!_isOpen) {
|
if (!_isOpen) {
|
||||||
memset(samples, 0, numSamples * sizeof(int16_t));
|
// First block after being closed gets faded to silence, we fade across
|
||||||
|
// the entire block on fading out. All subsequent blocks are muted by being slammed
|
||||||
|
// to zeros
|
||||||
|
if (_closedInLastBlock) {
|
||||||
|
float fadeSlope = (1.0f / numSamples);
|
||||||
|
for (int i = 0; i < numSamples; i++) {
|
||||||
|
float fadedSample = (1.0f - ((float)i * fadeSlope)) * (float)samples[i];
|
||||||
|
samples[i] = (int16_t)fadedSample;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memset(samples, 0, numSamples * sizeof(int16_t));
|
||||||
|
}
|
||||||
_lastLoudness = 0;
|
_lastLoudness = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_openedInLastBlock) {
|
||||||
|
// would be nice to do a little crossfade from silence, but we only want to fade
|
||||||
|
// across the first 1/10th of the block, because we don't want to miss early
|
||||||
|
// transients.
|
||||||
|
int fadeSamples = numSamples / 10; // fade over 1/10th of the samples
|
||||||
|
float fadeSlope = (1.0f / fadeSamples);
|
||||||
|
for (int i = 0; i < fadeSamples; i++) {
|
||||||
|
float fadedSample = (float)i * fadeSlope * (float)samples[i];
|
||||||
|
samples[i] = (int16_t)fadedSample;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300;
|
const int NUMBER_OF_NOISE_SAMPLE_BLOCKS = 300;
|
||||||
|
|
||||||
class AudioNoiseGate {
|
class AudioNoiseGate {
|
||||||
public:
|
public:
|
||||||
|
@ -23,26 +23,29 @@ public:
|
||||||
void gateSamples(int16_t* samples, int numSamples);
|
void gateSamples(int16_t* samples, int numSamples);
|
||||||
void removeDCOffset(int16_t* samples, int numSamples);
|
void removeDCOffset(int16_t* samples, int numSamples);
|
||||||
|
|
||||||
bool clippedInLastFrame() const { return _didClipInLastFrame; }
|
bool clippedInLastBlock() const { return _didClipInLastBlock; }
|
||||||
bool closedInLastFrame() const { return _closedInLastFrame; }
|
bool closedInLastBlock() const { return _closedInLastBlock; }
|
||||||
|
bool openedInLastBlock() const { return _openedInLastBlock; }
|
||||||
|
bool isOpen() const { return _isOpen; }
|
||||||
float getMeasuredFloor() const { return _measuredFloor; }
|
float getMeasuredFloor() const { return _measuredFloor; }
|
||||||
float getLastLoudness() const { return _lastLoudness; }
|
float getLastLoudness() const { return _lastLoudness; }
|
||||||
|
|
||||||
static const float CLIPPING_THRESHOLD;
|
static const float CLIPPING_THRESHOLD;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _inputFrameCounter;
|
int _inputBlockCounter;
|
||||||
float _lastLoudness;
|
float _lastLoudness;
|
||||||
float _quietestFrame;
|
float _quietestBlock;
|
||||||
float _loudestFrame;
|
float _loudestBlock;
|
||||||
bool _didClipInLastFrame;
|
bool _didClipInLastBlock;
|
||||||
float _dcOffset;
|
float _dcOffset;
|
||||||
float _measuredFloor;
|
float _measuredFloor;
|
||||||
float _sampleFrames[NUMBER_OF_NOISE_SAMPLE_FRAMES];
|
float _sampleBlocks[NUMBER_OF_NOISE_SAMPLE_BLOCKS];
|
||||||
int _sampleCounter;
|
int _sampleCounter;
|
||||||
bool _isOpen;
|
bool _isOpen;
|
||||||
bool _closedInLastFrame { false };
|
bool _closedInLastBlock { false };
|
||||||
int _framesToClose;
|
bool _openedInLastBlock { false };
|
||||||
|
int _blocksToClose;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AudioNoiseGate_h
|
#endif // hifi_AudioNoiseGate_h
|
|
@ -736,6 +736,52 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) {
|
||||||
|
// If we don't have a tree, or we're in the process of shutting down, then don't
|
||||||
|
// process these events.
|
||||||
|
if (!_tree || _shuttingDown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PerformanceTimer perfTimer("EntityTreeRenderer::mouseDoublePressEvent");
|
||||||
|
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
||||||
|
|
||||||
|
bool precisionPicking = !_dontDoPrecisionPicking;
|
||||||
|
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking);
|
||||||
|
if (rayPickResult.intersects) {
|
||||||
|
//qCDebug(entitiesrenderer) << "mouseDoublePressEvent over entity:" << rayPickResult.entityID;
|
||||||
|
|
||||||
|
QString urlString = rayPickResult.properties.getHref();
|
||||||
|
QUrl url = QUrl(urlString, QUrl::StrictMode);
|
||||||
|
if (url.isValid() && !url.isEmpty()){
|
||||||
|
DependencyManager::get<AddressManager>()->handleLookupString(urlString);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||||
|
PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID,
|
||||||
|
pos2D, rayPickResult.intersection,
|
||||||
|
rayPickResult.surfaceNormal, ray.direction,
|
||||||
|
toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier);
|
||||||
|
|
||||||
|
emit mouseDoublePressOnEntity(rayPickResult.entityID, pointerEvent);
|
||||||
|
|
||||||
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseDoublePressOnEntity", pointerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentClickingOnEntityID = rayPickResult.entityID;
|
||||||
|
emit clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
|
||||||
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "doubleclickOnEntity", pointerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastPointerEvent = pointerEvent;
|
||||||
|
_lastPointerEventValid = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
emit mouseDoublePressOffEntity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
// If we don't have a tree, or we're in the process of shutting down, then don't
|
// If we don't have a tree, or we're in the process of shutting down, then don't
|
||||||
// process these events.
|
// process these events.
|
||||||
|
|
|
@ -90,6 +90,7 @@ public:
|
||||||
// event handles which may generate entity related events
|
// event handles which may generate entity related events
|
||||||
void mouseReleaseEvent(QMouseEvent* event);
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
void mousePressEvent(QMouseEvent* event);
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseDoublePressEvent(QMouseEvent* event);
|
||||||
void mouseMoveEvent(QMouseEvent* event);
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
|
|
||||||
/// connect our signals to anEntityScriptingInterface for firing of events related clicking,
|
/// connect our signals to anEntityScriptingInterface for firing of events related clicking,
|
||||||
|
@ -103,9 +104,11 @@ public:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
|
void mouseDoublePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
void mousePressOffEntity();
|
void mousePressOffEntity();
|
||||||
|
void mouseDoublePressOffEntity();
|
||||||
|
|
||||||
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
|
|
|
@ -143,12 +143,35 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) {
|
void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) {
|
||||||
// first bump and prune contacts for all objects in the list
|
// bump and prune contacts for all objects in the list
|
||||||
for (auto object : objects) {
|
for (auto object : objects) {
|
||||||
bumpAndPruneContacts(object);
|
bumpAndPruneContacts(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
// then remove them
|
if (_activeStaticBodies.size() > 0) {
|
||||||
|
// _activeStaticBodies was not cleared last frame.
|
||||||
|
// The only way to get here is if a static object were moved but we did not actually step the simulation last
|
||||||
|
// frame (because the framerate is faster than our physics simulation rate). When this happens we must scan
|
||||||
|
// _activeStaticBodies for objects that were recently deleted so we don't try to access a dangling pointer.
|
||||||
|
for (auto object : objects) {
|
||||||
|
btRigidBody* body = object->getRigidBody();
|
||||||
|
|
||||||
|
std::vector<btRigidBody*>::reverse_iterator itr = _activeStaticBodies.rbegin();
|
||||||
|
while (itr != _activeStaticBodies.rend()) {
|
||||||
|
if (body == *itr) {
|
||||||
|
if (*itr != *(_activeStaticBodies.rbegin())) {
|
||||||
|
// swap with rbegin
|
||||||
|
*itr = *(_activeStaticBodies.rbegin());
|
||||||
|
}
|
||||||
|
_activeStaticBodies.pop_back();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove bodies
|
||||||
for (auto object : objects) {
|
for (auto object : objects) {
|
||||||
btRigidBody* body = object->getRigidBody();
|
btRigidBody* body = object->getRigidBody();
|
||||||
if (body) {
|
if (body) {
|
||||||
|
|
|
@ -32,10 +32,13 @@ protected:
|
||||||
Q_INVOKABLE void setStereoInput(bool stereo);
|
Q_INVOKABLE void setStereoInput(bool stereo);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void mutedByMixer();
|
void mutedByMixer(); /// the client has been muted by the mixer
|
||||||
void environmentMuted();
|
void environmentMuted(); /// the entire environment has been muted by the mixer
|
||||||
void receivedFirstPacket();
|
void receivedFirstPacket(); /// the client has received its first packet from the audio mixer
|
||||||
void disconnected();
|
void disconnected(); /// the client has been disconnected from the audio mixer
|
||||||
|
void noiseGateOpened(); /// the noise gate has opened
|
||||||
|
void noiseGateClosed(); /// the noise gate has closed
|
||||||
|
void inputReceived(const QByteArray& inputSamples); /// a frame of mic input audio has been received and processed
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioScriptingInterface();
|
AudioScriptingInterface();
|
||||||
|
|
|
@ -142,7 +142,7 @@ QString encodeEntityIdIntoEntityUrl(const QString& url, const QString& entityID)
|
||||||
|
|
||||||
QString ScriptEngine::logException(const QScriptValue& exception) {
|
QString ScriptEngine::logException(const QScriptValue& exception) {
|
||||||
auto message = formatException(exception);
|
auto message = formatException(exception);
|
||||||
scriptErrorMessage(qPrintable(message));
|
scriptErrorMessage(message);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,7 +453,7 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::scriptErrorMessage(const QString& message) {
|
void ScriptEngine::scriptErrorMessage(const QString& message) {
|
||||||
qCCritical(scriptengine) << message;
|
qCCritical(scriptengine) << qPrintable(message);
|
||||||
emit errorMessage(message);
|
emit errorMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,9 @@ QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEve
|
||||||
case Press:
|
case Press:
|
||||||
obj.setProperty("type", "Press");
|
obj.setProperty("type", "Press");
|
||||||
break;
|
break;
|
||||||
|
case DoublePress:
|
||||||
|
obj.setProperty("type", "DoublePress");
|
||||||
|
break;
|
||||||
case Release:
|
case Release:
|
||||||
obj.setProperty("type", "Release");
|
obj.setProperty("type", "Release");
|
||||||
break;
|
break;
|
||||||
|
@ -131,6 +134,8 @@ void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& eve
|
||||||
QString typeStr = type.isString() ? type.toString() : "Move";
|
QString typeStr = type.isString() ? type.toString() : "Move";
|
||||||
if (typeStr == "Press") {
|
if (typeStr == "Press") {
|
||||||
event._type = Press;
|
event._type = Press;
|
||||||
|
} else if (typeStr == "DoublePress") {
|
||||||
|
event._type = DoublePress;
|
||||||
} else if (typeStr == "Release") {
|
} else if (typeStr == "Release") {
|
||||||
event._type = Release;
|
event._type = Release;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -28,9 +28,10 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EventType {
|
enum EventType {
|
||||||
Press, // A button has just been pressed
|
Press, // A button has just been pressed
|
||||||
Release, // A button has just been released
|
DoublePress, // A button has just been double pressed
|
||||||
Move // The pointer has just moved
|
Release, // A button has just been released
|
||||||
|
Move // The pointer has just moved
|
||||||
};
|
};
|
||||||
|
|
||||||
PointerEvent();
|
PointerEvent();
|
||||||
|
|
|
@ -24,29 +24,34 @@ public:
|
||||||
RateCounter() { _rate = 0; } // avoid use of std::atomic copy ctor
|
RateCounter() { _rate = 0; } // avoid use of std::atomic copy ctor
|
||||||
|
|
||||||
void increment(size_t count = 1) {
|
void increment(size_t count = 1) {
|
||||||
auto now = usecTimestampNow();
|
checkRate();
|
||||||
float currentIntervalMs = (now - _start) / (float) USECS_PER_MSEC;
|
|
||||||
if (currentIntervalMs > (float) INTERVAL) {
|
|
||||||
float currentCount = _count;
|
|
||||||
float intervalSeconds = currentIntervalMs / (float) MSECS_PER_SECOND;
|
|
||||||
_rate = roundf(currentCount / intervalSeconds * _scale) / _scale;
|
|
||||||
_start = now;
|
|
||||||
_count = 0;
|
|
||||||
};
|
|
||||||
_count += count;
|
_count += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
float rate() const { return _rate; }
|
float rate() const { checkRate(); return _rate; }
|
||||||
|
|
||||||
uint8_t precision() const { return PRECISION; }
|
uint8_t precision() const { return PRECISION; }
|
||||||
|
|
||||||
uint32_t interval() const { return INTERVAL; }
|
uint32_t interval() const { return INTERVAL; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t _start { usecTimestampNow() };
|
mutable uint64_t _start { usecTimestampNow() };
|
||||||
size_t _count { 0 };
|
mutable size_t _count { 0 };
|
||||||
const float _scale { powf(10, PRECISION) };
|
const float _scale { powf(10, PRECISION) };
|
||||||
std::atomic<float> _rate;
|
mutable std::atomic<float> _rate;
|
||||||
|
|
||||||
|
void checkRate() const {
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
float currentIntervalMs = (now - _start) / (float)USECS_PER_MSEC;
|
||||||
|
if (currentIntervalMs > (float)INTERVAL) {
|
||||||
|
float currentCount = _count;
|
||||||
|
float intervalSeconds = currentIntervalMs / (float)MSECS_PER_SECOND;
|
||||||
|
_rate = roundf(currentCount / intervalSeconds * _scale) / _scale;
|
||||||
|
_start = now;
|
||||||
|
_count = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
19
script-archive/entityScripts/doubleClickExample.js
Normal file
19
script-archive/entityScripts/doubleClickExample.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
(function() {
|
||||||
|
var _this;
|
||||||
|
function DoubleClickExample() {
|
||||||
|
_this = this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleClickExample.prototype = {
|
||||||
|
clickDownOnEntity: function() {
|
||||||
|
print("clickDownOnEntity");
|
||||||
|
},
|
||||||
|
|
||||||
|
doubleclickOnEntity: function() {
|
||||||
|
print("doubleclickOnEntity");
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return new DoubleClickExample();
|
||||||
|
});
|
|
@ -11,7 +11,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
var DEFAULT_SCRIPTS = [
|
var DEFAULT_SCRIPTS_COMBINED = [
|
||||||
"system/progress.js",
|
"system/progress.js",
|
||||||
"system/away.js",
|
"system/away.js",
|
||||||
"system/audio.js",
|
"system/audio.js",
|
||||||
|
@ -27,17 +27,13 @@ var DEFAULT_SCRIPTS = [
|
||||||
"system/tablet-users.js",
|
"system/tablet-users.js",
|
||||||
"system/selectAudioDevice.js",
|
"system/selectAudioDevice.js",
|
||||||
"system/notifications.js",
|
"system/notifications.js",
|
||||||
"system/controllers/squeezeHands.js",
|
|
||||||
"system/controllers/controllerDisplayManager.js",
|
|
||||||
"system/controllers/handControllerGrab.js",
|
|
||||||
"system/controllers/handControllerPointer.js",
|
|
||||||
"system/controllers/grab.js",
|
|
||||||
"system/controllers/teleport.js",
|
|
||||||
"system/controllers/toggleAdvancedMovementForHandControllers.js",
|
|
||||||
"system/dialTone.js",
|
"system/dialTone.js",
|
||||||
"system/firstPersonHMD.js",
|
"system/firstPersonHMD.js",
|
||||||
"system/tablet-ui/tabletUI.js"
|
"system/tablet-ui/tabletUI.js"
|
||||||
];
|
];
|
||||||
|
var DEFAULT_SCRIPTS_SEPARATE = [
|
||||||
|
"system/controllers/controllerScripts.js"
|
||||||
|
];
|
||||||
|
|
||||||
// add a menu item for debugging
|
// add a menu item for debugging
|
||||||
var MENU_CATEGORY = "Developer";
|
var MENU_CATEGORY = "Developer";
|
||||||
|
@ -64,16 +60,24 @@ if (Menu.menuExists(MENU_CATEGORY) && !Menu.menuItemExists(MENU_CATEGORY, MENU_I
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function runDefaultsTogether() {
|
function loadSeparateDefaults() {
|
||||||
for (var j in DEFAULT_SCRIPTS) {
|
for (var i in DEFAULT_SCRIPTS_SEPARATE) {
|
||||||
Script.include(DEFAULT_SCRIPTS[j]);
|
Script.load(DEFAULT_SCRIPTS_SEPARATE[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runDefaultsSeparately() {
|
function runDefaultsTogether() {
|
||||||
for (var i in DEFAULT_SCRIPTS) {
|
for (var i in DEFAULT_SCRIPTS_COMBINED) {
|
||||||
Script.load(DEFAULT_SCRIPTS[i]);
|
Script.include(DEFAULT_SCRIPTS_COMBINED[i]);
|
||||||
}
|
}
|
||||||
|
loadSeparateDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
function runDefaultsSeparately() {
|
||||||
|
for (var i in DEFAULT_SCRIPTS_COMBINED) {
|
||||||
|
Script.load(DEFAULT_SCRIPTS_COMBINED[i]);
|
||||||
|
}
|
||||||
|
loadSeparateDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
// start all scripts
|
// start all scripts
|
||||||
|
|
95
scripts/system/audioScope.js
Normal file
95
scripts/system/audioScope.js
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
"use strict";
|
||||||
|
//
|
||||||
|
// audioScope.js
|
||||||
|
// scripts/system/
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 3/10/2016
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
/* global Script, Tablet, AudioScope, Audio */
|
||||||
|
|
||||||
|
(function () { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
|
var scopeVisibile = AudioScope.getVisible();
|
||||||
|
var scopePaused = AudioScope.getPause();
|
||||||
|
var autoPause = false;
|
||||||
|
|
||||||
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
var showScopeButton = tablet.addButton({
|
||||||
|
icon: "icons/tablet-icons/scope.svg",
|
||||||
|
text: "Audio Scope",
|
||||||
|
isActive: scopeVisibile
|
||||||
|
});
|
||||||
|
|
||||||
|
var scopePauseImage = "icons/tablet-icons/scope-pause.svg";
|
||||||
|
var scopePlayImage = "icons/tablet-icons/scope-play.svg";
|
||||||
|
|
||||||
|
var pauseScopeButton = tablet.addButton({
|
||||||
|
icon: scopePaused ? scopePlayImage : scopePauseImage,
|
||||||
|
text: scopePaused ? "Unpause" : "Pause",
|
||||||
|
isActive: scopePaused
|
||||||
|
});
|
||||||
|
|
||||||
|
var autoPauseScopeButton = tablet.addButton({
|
||||||
|
icon: "icons/tablet-icons/scope-auto.svg",
|
||||||
|
text: "Auto Pause",
|
||||||
|
isActive: autoPause
|
||||||
|
});
|
||||||
|
|
||||||
|
function setScopePause(paused) {
|
||||||
|
scopePaused = paused;
|
||||||
|
pauseScopeButton.editProperties({
|
||||||
|
isActive: scopePaused,
|
||||||
|
icon: scopePaused ? scopePlayImage : scopePauseImage,
|
||||||
|
text: scopePaused ? "Unpause" : "Pause"
|
||||||
|
});
|
||||||
|
AudioScope.setPause(scopePaused);
|
||||||
|
}
|
||||||
|
|
||||||
|
showScopeButton.clicked.connect(function () {
|
||||||
|
// toggle button active state
|
||||||
|
scopeVisibile = !scopeVisibile;
|
||||||
|
showScopeButton.editProperties({
|
||||||
|
isActive: scopeVisibile
|
||||||
|
});
|
||||||
|
|
||||||
|
AudioScope.setVisible(scopeVisibile);
|
||||||
|
});
|
||||||
|
|
||||||
|
pauseScopeButton.clicked.connect(function () {
|
||||||
|
// toggle button active state
|
||||||
|
setScopePause(!scopePaused);
|
||||||
|
});
|
||||||
|
|
||||||
|
autoPauseScopeButton.clicked.connect(function () {
|
||||||
|
// toggle button active state
|
||||||
|
autoPause = !autoPause;
|
||||||
|
autoPauseScopeButton.editProperties({
|
||||||
|
isActive: autoPause,
|
||||||
|
text: autoPause ? "Auto Pause" : "Manual"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function () {
|
||||||
|
tablet.removeButton(showScopeButton);
|
||||||
|
tablet.removeButton(pauseScopeButton);
|
||||||
|
tablet.removeButton(autoPauseScopeButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
Audio.noiseGateOpened.connect(function(){
|
||||||
|
if (autoPause) {
|
||||||
|
setScopePause(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Audio.noiseGateClosed.connect(function(){
|
||||||
|
// noise gate closed
|
||||||
|
if (autoPause) {
|
||||||
|
setScopePause(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}()); // END LOCAL_SCOPE
|
41
scripts/system/controllers/controllerScripts.js
Normal file
41
scripts/system/controllers/controllerScripts.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// controllerScripts.js
|
||||||
|
//
|
||||||
|
// Created by David Rowe on 15 Mar 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
|
||||||
|
//
|
||||||
|
|
||||||
|
var CONTOLLER_SCRIPTS = [
|
||||||
|
"squeezeHands.js",
|
||||||
|
"controllerDisplayManager.js",
|
||||||
|
"handControllerGrab.js",
|
||||||
|
"handControllerPointer.js",
|
||||||
|
"grab.js",
|
||||||
|
"teleport.js",
|
||||||
|
"toggleAdvancedMovementForHandControllers.js",
|
||||||
|
];
|
||||||
|
|
||||||
|
var DEBUG_MENU_ITEM = "Debug defaultScripts.js";
|
||||||
|
|
||||||
|
|
||||||
|
function runDefaultsTogether() {
|
||||||
|
for (var j in CONTOLLER_SCRIPTS) {
|
||||||
|
Script.include(CONTOLLER_SCRIPTS[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function runDefaultsSeparately() {
|
||||||
|
for (var i in CONTOLLER_SCRIPTS) {
|
||||||
|
Script.load(CONTOLLER_SCRIPTS[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Menu.isOptionChecked(DEBUG_MENU_ITEM)) {
|
||||||
|
runDefaultsSeparately();
|
||||||
|
} else {
|
||||||
|
runDefaultsTogether();
|
||||||
|
}
|
Loading…
Reference in a new issue