mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 10:17:40 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into rig
This commit is contained in:
commit
18197314c5
11 changed files with 679 additions and 11 deletions
265
examples/FlockOfbirds.js
Normal file
265
examples/FlockOfbirds.js
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
//
|
||||||
|
// flockOfbirds.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
// Creates a flock of birds that fly around and chirp, staying inside the corners of the box defined
|
||||||
|
// at the start of the script.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// The area over which the birds will fly
|
||||||
|
var lowerCorner = { x: 1, y: 1, z: 1 };
|
||||||
|
var upperCorner = { x: 10, y: 10, z: 10 };
|
||||||
|
var STARTING_FRACTION = 0.25;
|
||||||
|
|
||||||
|
var NUM_BIRDS = 50;
|
||||||
|
var playSounds = true;
|
||||||
|
var SOUND_PROBABILITY = 0.001;
|
||||||
|
var numPlaying = 0;
|
||||||
|
var BIRD_SIZE = 0.08;
|
||||||
|
var BIRD_MASTER_VOLUME = 0.1;
|
||||||
|
var FLAP_PROBABILITY = 0.005;
|
||||||
|
var RANDOM_FLAP_VELOCITY = 1.0;
|
||||||
|
var FLAP_UP = 1.0;
|
||||||
|
var BIRD_GRAVITY = -0.5;
|
||||||
|
var LINEAR_DAMPING = 0.2;
|
||||||
|
var FLAP_FALLING_PROBABILITY = 0.025;
|
||||||
|
var MIN_ALIGNMENT_VELOCITY = 0.0;
|
||||||
|
var MAX_ALIGNMENT_VELOCITY = 1.0;
|
||||||
|
var VERTICAL_ALIGNMENT_COUPLING = 0.0;
|
||||||
|
var ALIGNMENT_FORCE = 1.5;
|
||||||
|
var COHESION_FORCE = 1.0;
|
||||||
|
var MAX_COHESION_VELOCITY = 0.5;
|
||||||
|
|
||||||
|
var floor = false;
|
||||||
|
var MAKE_FLOOR = false;
|
||||||
|
|
||||||
|
var averageVelocity = { x: 0, y: 0, z: 0 };
|
||||||
|
var averagePosition = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
|
var birdsLoaded = false;
|
||||||
|
|
||||||
|
var birds = [];
|
||||||
|
var playing = [];
|
||||||
|
|
||||||
|
function randomVector(scale) {
|
||||||
|
return { x: Math.random() * scale - scale / 2.0, y: Math.random() * scale - scale / 2.0, z: Math.random() * scale - scale / 2.0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBirds(deltaTime) {
|
||||||
|
if (!Entities.serversExist() || !Entities.canRez()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!birdsLoaded) {
|
||||||
|
loadBirds(NUM_BIRDS);
|
||||||
|
birdsLoaded = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var sumVelocity = { x: 0, y: 0, z: 0 };
|
||||||
|
var sumPosition = { x: 0, y: 0, z: 0 };
|
||||||
|
var birdPositionsCounted = 0;
|
||||||
|
var birdVelocitiesCounted = 0;
|
||||||
|
for (var i = 0; i < birds.length; i++) {
|
||||||
|
if (birds[i].entityId) {
|
||||||
|
var properties = Entities.getEntityProperties(birds[i].entityId);
|
||||||
|
// If Bird has been deleted, bail
|
||||||
|
if (properties.id != birds[i].entityId) {
|
||||||
|
birds[i].entityId = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Sum up average position and velocity
|
||||||
|
if (Vec3.length(properties.velocity) > MIN_ALIGNMENT_VELOCITY) {
|
||||||
|
sumVelocity = Vec3.sum(sumVelocity, properties.velocity);
|
||||||
|
birdVelocitiesCounted += 1;
|
||||||
|
}
|
||||||
|
sumPosition = Vec3.sum(sumPosition, properties.position);
|
||||||
|
birdPositionsCounted += 1;
|
||||||
|
|
||||||
|
var downwardSpeed = (properties.velocity.y < 0) ? -properties.velocity.y : 0.0;
|
||||||
|
if ((properties.position.y < upperCorner.y) && (Math.random() < (FLAP_PROBABILITY + (downwardSpeed * FLAP_FALLING_PROBABILITY)))) {
|
||||||
|
// More likely to flap if falling
|
||||||
|
var randomVelocity = randomVector(RANDOM_FLAP_VELOCITY);
|
||||||
|
randomVelocity.y = FLAP_UP + Math.random() * FLAP_UP;
|
||||||
|
|
||||||
|
// Alignment Velocity
|
||||||
|
var alignmentVelocityMagnitude = Math.min(MAX_ALIGNMENT_VELOCITY, Vec3.length(Vec3.multiply(ALIGNMENT_FORCE, averageVelocity)));
|
||||||
|
var alignmentVelocity = Vec3.multiply(alignmentVelocityMagnitude, Vec3.normalize(averageVelocity));
|
||||||
|
alignmentVelocity.y *= VERTICAL_ALIGNMENT_COUPLING;
|
||||||
|
|
||||||
|
// Cohesion
|
||||||
|
var distanceFromCenter = Vec3.length(Vec3.subtract(averagePosition, properties.position));
|
||||||
|
var cohesionVelocitySize = Math.min(distanceFromCenter * COHESION_FORCE, MAX_COHESION_VELOCITY);
|
||||||
|
var cohesionVelocity = Vec3.multiply(cohesionVelocitySize, Vec3.normalize(Vec3.subtract(averagePosition, properties.position)));
|
||||||
|
|
||||||
|
var newVelocity = Vec3.sum(randomVelocity, Vec3.sum(alignmentVelocity, cohesionVelocity));
|
||||||
|
|
||||||
|
Entities.editEntity(birds[i].entityId, { velocity: Vec3.sum(properties.velocity, newVelocity) });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether to play a chirp
|
||||||
|
if (playSounds && (!birds[i].audioId || !birds[i].audioId.isPlaying) && (Math.random() < ((numPlaying > 0) ? SOUND_PROBABILITY / numPlaying : SOUND_PROBABILITY))) {
|
||||||
|
var options = {
|
||||||
|
position: properties.position,
|
||||||
|
volume: BIRD_MASTER_VOLUME
|
||||||
|
};
|
||||||
|
// Play chirp
|
||||||
|
if (birds[i].audioId) {
|
||||||
|
birds[i].audioId.setOptions(options);
|
||||||
|
birds[i].audioId.restart();
|
||||||
|
} else {
|
||||||
|
birds[i].audioId = Audio.playSound(birds[i].sound, options);
|
||||||
|
}
|
||||||
|
numPlaying++;
|
||||||
|
// Change size
|
||||||
|
Entities.editEntity(birds[i].entityId, { dimensions: Vec3.multiply(1.5, properties.dimensions)});
|
||||||
|
|
||||||
|
} else if (birds[i].audioId) {
|
||||||
|
// If bird is playing a chirp
|
||||||
|
if (!birds[i].audioId.isPlaying) {
|
||||||
|
Entities.editEntity(birds[i].entityId, { dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE }});
|
||||||
|
numPlaying--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep birds in their 'cage'
|
||||||
|
var bounce = false;
|
||||||
|
var newVelocity = properties.velocity;
|
||||||
|
var newPosition = properties.position;
|
||||||
|
if (properties.position.x < lowerCorner.x) {
|
||||||
|
newPosition.x = lowerCorner.x;
|
||||||
|
newVelocity.x *= -1.0;
|
||||||
|
bounce = true;
|
||||||
|
} else if (properties.position.x > upperCorner.x) {
|
||||||
|
newPosition.x = upperCorner.x;
|
||||||
|
newVelocity.x *= -1.0;
|
||||||
|
bounce = true;
|
||||||
|
}
|
||||||
|
if (properties.position.y < lowerCorner.y) {
|
||||||
|
newPosition.y = lowerCorner.y;
|
||||||
|
newVelocity.y *= -1.0;
|
||||||
|
bounce = true;
|
||||||
|
} else if (properties.position.y > upperCorner.y) {
|
||||||
|
newPosition.y = upperCorner.y;
|
||||||
|
newVelocity.y *= -1.0;
|
||||||
|
bounce = true;
|
||||||
|
}
|
||||||
|
if (properties.position.z < lowerCorner.z) {
|
||||||
|
newPosition.z = lowerCorner.z;
|
||||||
|
newVelocity.z *= -1.0;
|
||||||
|
bounce = true;
|
||||||
|
} else if (properties.position.z > upperCorner.z) {
|
||||||
|
newPosition.z = upperCorner.z;
|
||||||
|
newVelocity.z *= -1.0;
|
||||||
|
bounce = true;
|
||||||
|
}
|
||||||
|
if (bounce) {
|
||||||
|
Entities.editEntity(birds[i].entityId, { position: newPosition, velocity: newVelocity });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update average velocity and position of flock
|
||||||
|
if (birdVelocitiesCounted > 0) {
|
||||||
|
averageVelocity = Vec3.multiply(1.0 / birdVelocitiesCounted, sumVelocity);
|
||||||
|
//print(Vec3.length(averageVelocity));
|
||||||
|
}
|
||||||
|
if (birdPositionsCounted > 0) {
|
||||||
|
averagePosition = Vec3.multiply(1.0 / birdPositionsCounted, sumPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect a call back that happens every frame
|
||||||
|
Script.update.connect(updateBirds);
|
||||||
|
|
||||||
|
// Delete our little friends if script is stopped
|
||||||
|
Script.scriptEnding.connect(function() {
|
||||||
|
for (var i = 0; i < birds.length; i++) {
|
||||||
|
Entities.deleteEntity(birds[i].entityId);
|
||||||
|
}
|
||||||
|
if (floor) {
|
||||||
|
Entities.deleteEntity(floor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadBirds(howMany) {
|
||||||
|
while (!Entities.serversExist() || !Entities.canRez()) {
|
||||||
|
}
|
||||||
|
var sound_filenames = ["bushtit_1.raw", "bushtit_2.raw", "bushtit_3.raw"];
|
||||||
|
/* Here are more sounds/species you can use
|
||||||
|
, "mexicanWhipoorwill.raw",
|
||||||
|
"rosyfacedlovebird.raw", "saysphoebe.raw", "westernscreechowl.raw", "bandtailedpigeon.wav", "bridledtitmouse.wav",
|
||||||
|
"browncrestedflycatcher.wav", "commonnighthawk.wav", "commonpoorwill.wav", "doublecrestedcormorant.wav",
|
||||||
|
"gambelsquail.wav", "goldcrownedkinglet.wav", "greaterroadrunner.wav","groovebilledani.wav","hairywoodpecker.wav",
|
||||||
|
"housewren.wav","hummingbird.wav", "mountainchickadee.wav", "nightjar.wav", "piebilledgrieb.wav", "pygmynuthatch.wav",
|
||||||
|
"whistlingduck.wav", "woodpecker.wav"];
|
||||||
|
*/
|
||||||
|
|
||||||
|
var colors = [
|
||||||
|
{ red: 242, green: 207, blue: 013 },
|
||||||
|
{ red: 238, green: 94, blue: 11 },
|
||||||
|
{ red: 81, green: 30, blue: 7 },
|
||||||
|
{ red: 195, green: 176, blue: 81 },
|
||||||
|
{ red: 235, green: 190, blue: 152 },
|
||||||
|
{ red: 167, green: 99, blue: 52 },
|
||||||
|
{ red: 199, green: 122, blue: 108 },
|
||||||
|
{ red: 246, green: 220, blue: 189 },
|
||||||
|
{ red: 208, green: 145, blue: 65 },
|
||||||
|
{ red: 173, green: 120 , blue: 71 },
|
||||||
|
{ red: 132, green: 147, blue: 174 },
|
||||||
|
{ red: 164, green: 74, blue: 40 },
|
||||||
|
{ red: 131, green: 127, blue: 134 },
|
||||||
|
{ red: 209, green: 157, blue: 117 },
|
||||||
|
{ red: 205, green: 191, blue: 193 },
|
||||||
|
{ red: 193, green: 154, blue: 118 },
|
||||||
|
{ red: 205, green: 190, blue: 169 },
|
||||||
|
{ red: 199, green: 111, blue: 69 },
|
||||||
|
{ red: 221, green: 223, blue: 228 },
|
||||||
|
{ red: 115, green: 92, blue: 87 },
|
||||||
|
{ red: 214, green: 165, blue: 137 },
|
||||||
|
{ red: 160, green: 124, blue: 33 },
|
||||||
|
{ red: 117, green: 91, blue: 86 },
|
||||||
|
{ red: 113, green: 104, blue: 107 },
|
||||||
|
{ red: 216, green: 153, blue: 99 },
|
||||||
|
{ red: 242, green: 226, blue: 64 }
|
||||||
|
];
|
||||||
|
|
||||||
|
var SOUND_BASE_URL = "http://public.highfidelity.io/sounds/Animals/";
|
||||||
|
|
||||||
|
for (var i = 0; i < howMany; i++) {
|
||||||
|
var whichBird = Math.floor(Math.random() * sound_filenames.length);
|
||||||
|
var position = {
|
||||||
|
x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.x - lowerCorner.x) * STARTING_FRACTION,
|
||||||
|
y: lowerCorner.y + (upperCorner.y - lowerCorner.y) / 2.0 + (Math.random() - 0.5) * (upperCorner.y - lowerCorner.y) * STARTING_FRACTION,
|
||||||
|
z: lowerCorner.z + (upperCorner.z - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.z - lowerCorner.z) * STARTING_FRACTION
|
||||||
|
};
|
||||||
|
|
||||||
|
birds.push({
|
||||||
|
sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[whichBird]),
|
||||||
|
entityId: Entities.addEntity({
|
||||||
|
type: "Sphere",
|
||||||
|
position: position,
|
||||||
|
dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE },
|
||||||
|
gravity: { x: 0, y: BIRD_GRAVITY, z: 0 },
|
||||||
|
velocity: { x: 0, y: -0.1, z: 0 },
|
||||||
|
linearDamping: LINEAR_DAMPING,
|
||||||
|
collisionsWillMove: true,
|
||||||
|
color: colors[whichBird]
|
||||||
|
}),
|
||||||
|
audioId: false,
|
||||||
|
isPlaying: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (MAKE_FLOOR) {
|
||||||
|
var FLOOR_THICKNESS = 0.05;
|
||||||
|
floor = Entities.addEntity({ type: "Box", position: { x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0,
|
||||||
|
y: lowerCorner.y,
|
||||||
|
z: lowerCorner.z + (upperCorner.z - lowerCorner.z) / 2.0 },
|
||||||
|
dimensions: { x: (upperCorner.x - lowerCorner.x), y: FLOOR_THICKNESS, z: (upperCorner.z - lowerCorner.z)},
|
||||||
|
color: {red: 100, green: 100, blue: 100}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -656,7 +656,9 @@ function mouseMove(event) {
|
||||||
|
|
||||||
function handleIdleMouse() {
|
function handleIdleMouse() {
|
||||||
idleMouseTimerId = null;
|
idleMouseTimerId = null;
|
||||||
|
if (isActive) {
|
||||||
highlightEntityUnderCursor(lastMousePosition, true);
|
highlightEntityUnderCursor(lastMousePosition, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlightEntityUnderCursor(position, accurateRay) {
|
function highlightEntityUnderCursor(position, accurateRay) {
|
||||||
|
|
|
@ -2444,6 +2444,12 @@ void Application::updateDialogs(float deltaTime) {
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateDialogs()");
|
PerformanceWarning warn(showWarnings, "Application::updateDialogs()");
|
||||||
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||||
|
|
||||||
|
// Update audio stats dialog, if any
|
||||||
|
AudioStatsDialog* audioStatsDialog = dialogsManager->getAudioStatsDialog();
|
||||||
|
if(audioStatsDialog) {
|
||||||
|
audioStatsDialog->update();
|
||||||
|
}
|
||||||
|
|
||||||
// Update bandwidth dialog, if any
|
// Update bandwidth dialog, if any
|
||||||
BandwidthDialog* bandwidthDialog = dialogsManager->getBandwidthDialog();
|
BandwidthDialog* bandwidthDialog = dialogsManager->getBandwidthDialog();
|
||||||
if (bandwidthDialog) {
|
if (bandwidthDialog) {
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#include "devices/SixenseManager.h"
|
#include "devices/SixenseManager.h"
|
||||||
#include "scripting/ControllerScriptingInterface.h"
|
#include "scripting/ControllerScriptingInterface.h"
|
||||||
#include "scripting/WebWindowClass.h"
|
#include "scripting/WebWindowClass.h"
|
||||||
|
#include "ui/AudioStatsDialog.h"
|
||||||
#include "ui/BandwidthDialog.h"
|
#include "ui/BandwidthDialog.h"
|
||||||
#include "ui/HMDToolsDialog.h"
|
#include "ui/HMDToolsDialog.h"
|
||||||
#include "ui/ModelsBrowser.h"
|
#include "ui/ModelsBrowser.h"
|
||||||
|
|
|
@ -321,6 +321,8 @@ Menu::Menu() {
|
||||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log,
|
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log,
|
||||||
Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
||||||
qApp, SLOT(toggleLogDialog()));
|
qApp, SLOT(toggleLogDialog()));
|
||||||
|
addActionToQMenuAndActionHash(viewMenu, MenuOption::AudioNetworkStats, 0,
|
||||||
|
dialogsManager.data(), SLOT(audioStatsDetails()));
|
||||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0,
|
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0,
|
||||||
dialogsManager.data(), SLOT(bandwidthDetails()));
|
dialogsManager.data(), SLOT(bandwidthDetails()));
|
||||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0,
|
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0,
|
||||||
|
@ -586,15 +588,6 @@ Menu::Menu() {
|
||||||
audioScopeFramesGroup->addAction(fiftyFrames);
|
audioScopeFramesGroup->addAction(fiftyFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioStats,
|
|
||||||
Qt::CTRL | Qt::SHIFT | Qt::Key_A,
|
|
||||||
false); //, statsRenderer.data(), SLOT(toggle())); // TODO: convert to dialogbox
|
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioStatsShowInjectedStreams,
|
|
||||||
0,
|
|
||||||
false); //, statsRenderer.data(), SLOT(toggleShowInjectedStreams)); // TODO: convert to dialogbox
|
|
||||||
|
|
||||||
|
|
||||||
MenuWrapper* physicsOptionsMenu = developerMenu->addMenu("Physics");
|
MenuWrapper* physicsOptionsMenu = developerMenu->addMenu("Physics");
|
||||||
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned);
|
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned);
|
||||||
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls);
|
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls);
|
||||||
|
|
|
@ -145,7 +145,7 @@ namespace MenuOption {
|
||||||
const QString AudioScopeFrames = "Display Frames";
|
const QString AudioScopeFrames = "Display Frames";
|
||||||
const QString AudioScopePause = "Pause Scope";
|
const QString AudioScopePause = "Pause Scope";
|
||||||
const QString AudioScopeTwentyFrames = "Twenty";
|
const QString AudioScopeTwentyFrames = "Twenty";
|
||||||
const QString AudioStats = "Audio Stats";
|
const QString AudioNetworkStats = "Audio Network Stats";
|
||||||
const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams";
|
const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams";
|
||||||
const QString AutoMuteAudio = "Auto Mute Microphone";
|
const QString AutoMuteAudio = "Auto Mute Microphone";
|
||||||
const QString AvatarReceiveStats = "Show Receive Stats";
|
const QString AvatarReceiveStats = "Show Receive Stats";
|
||||||
|
|
|
@ -148,6 +148,7 @@ void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
|
void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
|
||||||
|
|
||||||
// Display stats and log text onscreen
|
// Display stats and log text onscreen
|
||||||
|
|
||||||
// Determine whether to compute timing details
|
// Determine whether to compute timing details
|
||||||
|
|
269
interface/src/ui/AudioStatsDialog.cpp
Normal file
269
interface/src/ui/AudioStatsDialog.cpp
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
//
|
||||||
|
// AudioStatsDialog.cpp
|
||||||
|
// interface/src/ui
|
||||||
|
//
|
||||||
|
// Created by Bridget Went on 7/9/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
|
#include <AudioClient.h>
|
||||||
|
#include <AudioConstants.h>
|
||||||
|
#include <AudioIOStats.h>
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
#include <GeometryCache.h>
|
||||||
|
#include <NodeList.h>
|
||||||
|
#include <Util.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "AudioStatsDialog.h"
|
||||||
|
|
||||||
|
const unsigned COLOR0 = 0x33cc99ff;
|
||||||
|
const unsigned COLOR1 = 0xffef40c0;
|
||||||
|
const unsigned COLOR2 = 0xd0d0d0a0;
|
||||||
|
const unsigned COLOR3 = 0x01DD7880;
|
||||||
|
|
||||||
|
|
||||||
|
AudioStatsDisplay::AudioStatsDisplay(QFormLayout* form,
|
||||||
|
QString text, unsigned colorRGBA) :
|
||||||
|
_text(text),
|
||||||
|
_colorRGBA(colorRGBA)
|
||||||
|
{
|
||||||
|
_label = new QLabel();
|
||||||
|
_label->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
|
QPalette palette = _label->palette();
|
||||||
|
unsigned rgb = colorRGBA >> 8;
|
||||||
|
rgb = ((rgb & 0xfefefeu) >> 1) + ((rgb & 0xf8f8f8) >> 3);
|
||||||
|
palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb));
|
||||||
|
_label->setPalette(palette);
|
||||||
|
|
||||||
|
form->addRow(_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioStatsDisplay::paint() {
|
||||||
|
_label->setText(_strBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioStatsDisplay::updatedDisplay(QString str) {
|
||||||
|
_strBuf = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AudioStatsDialog::AudioStatsDialog(QWidget* parent) :
|
||||||
|
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) {
|
||||||
|
|
||||||
|
_shouldShowInjectedStreams = false;
|
||||||
|
|
||||||
|
setWindowTitle("Audio Network Statistics");
|
||||||
|
|
||||||
|
// Get statistics from the Audio Client
|
||||||
|
_stats = &DependencyManager::get<AudioClient>()->getStats();
|
||||||
|
|
||||||
|
// Create layouter
|
||||||
|
_form = new QFormLayout();
|
||||||
|
QDialog::setLayout(_form);
|
||||||
|
|
||||||
|
// Load and initilize all channels
|
||||||
|
renderStats();
|
||||||
|
|
||||||
|
_audioDisplayChannels = QVector<QVector<AudioStatsDisplay*>>(1);
|
||||||
|
|
||||||
|
_audioMixerID = addChannel(_form, _audioMixerStats, COLOR0);
|
||||||
|
_upstreamClientID = addChannel(_form, _upstreamClientStats, COLOR1);
|
||||||
|
_upstreamMixerID = addChannel(_form, _upstreamMixerStats, COLOR2);
|
||||||
|
_downstreamID = addChannel(_form, _downstreamStats, COLOR3);
|
||||||
|
_upstreamInjectedID = addChannel(_form, _upstreamInjectedStats, COLOR0);
|
||||||
|
|
||||||
|
|
||||||
|
connect(averageUpdateTimer, SIGNAL(timeout()), this, SLOT(updateTimerTimeout()));
|
||||||
|
averageUpdateTimer->start(1000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int AudioStatsDialog::addChannel(QFormLayout* form, QVector<QString>& stats, const unsigned color) {
|
||||||
|
|
||||||
|
int channelID = _audioDisplayChannels.size() - 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < stats.size(); i++)
|
||||||
|
// Create new display label
|
||||||
|
_audioDisplayChannels[channelID].push_back(new AudioStatsDisplay(form, stats.at(i), color));
|
||||||
|
|
||||||
|
// Expand vector to fit next channel
|
||||||
|
_audioDisplayChannels.resize(_audioDisplayChannels.size() + 1);
|
||||||
|
|
||||||
|
return channelID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioStatsDialog::updateStats(QVector<QString>& stats, int channelID) {
|
||||||
|
// Update all stat displays at specified channel
|
||||||
|
for (int i = 0; i < stats.size(); i++)
|
||||||
|
_audioDisplayChannels[channelID].at(i)->updatedDisplay(stats.at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioStatsDialog::renderStats() {
|
||||||
|
|
||||||
|
// Clear current stats from all vectors
|
||||||
|
clearAllChannels();
|
||||||
|
|
||||||
|
double audioInputBufferLatency = 0.0,
|
||||||
|
inputRingBufferLatency = 0.0,
|
||||||
|
networkRoundtripLatency = 0.0,
|
||||||
|
mixerRingBufferLatency = 0.0,
|
||||||
|
outputRingBufferLatency = 0.0,
|
||||||
|
audioOutputBufferLatency = 0.0;
|
||||||
|
|
||||||
|
AudioStreamStats downstreamAudioStreamStats = _stats->getMixerDownstreamStats();
|
||||||
|
SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer);
|
||||||
|
|
||||||
|
if (!audioMixerNodePointer.isNull()) {
|
||||||
|
audioInputBufferLatency = (double)_stats->getAudioInputMsecsReadStats().getWindowAverage();
|
||||||
|
inputRingBufferLatency = (double)_stats->getInputRungBufferMsecsAvailableStats().getWindowAverage();
|
||||||
|
networkRoundtripLatency = (double) audioMixerNodePointer->getPingMs();
|
||||||
|
mixerRingBufferLatency = (double)_stats->getMixerAvatarStreamStats()._framesAvailableAverage * AudioConstants::NETWORK_FRAME_MSECS;
|
||||||
|
outputRingBufferLatency = (double)downstreamAudioStreamStats._framesAvailableAverage * AudioConstants::NETWORK_FRAME_MSECS;
|
||||||
|
audioOutputBufferLatency = (double)_stats->getAudioOutputMsecsUnplayedStats().getWindowAverage();
|
||||||
|
}
|
||||||
|
|
||||||
|
double totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency
|
||||||
|
+ outputRingBufferLatency + audioOutputBufferLatency;
|
||||||
|
|
||||||
|
_audioMixerStats.push_back(QString("Audio input buffer: %1ms").arg(
|
||||||
|
QString::number(audioInputBufferLatency, 'f', 2)) + QString(" - avg msecs of samples read to the audio input buffer in last 10s"));
|
||||||
|
|
||||||
|
_audioMixerStats.push_back(QString("Input ring buffer: %1ms").arg(
|
||||||
|
QString::number(inputRingBufferLatency, 'f', 2)) + QString(" - avg msecs of samples read to the input ring buffer in last 10s"));
|
||||||
|
_audioMixerStats.push_back(QString("Network to mixer: %1ms").arg(
|
||||||
|
QString::number((networkRoundtripLatency / 2.0), 'f', 2)) + QString(" - half of last ping value calculated by the node list"));
|
||||||
|
_audioMixerStats.push_back(QString("Network to client: %1ms").arg(
|
||||||
|
QString::number((mixerRingBufferLatency / 2.0),'f', 2)) + QString(" - half of last ping value calculated by the node list"));
|
||||||
|
_audioMixerStats.push_back(QString("Output ring buffer: %1ms").arg(
|
||||||
|
QString::number(outputRingBufferLatency,'f', 2)) + QString(" - avg msecs of samples in output ring buffer in last 10s"));
|
||||||
|
_audioMixerStats.push_back(QString("Audio output buffer: %1ms").arg(
|
||||||
|
QString::number(mixerRingBufferLatency,'f', 2)) + QString(" - avg msecs of samples in audio output buffer in last 10s"));
|
||||||
|
_audioMixerStats.push_back(QString("TOTAL: %1ms").arg(
|
||||||
|
QString::number(totalLatency, 'f', 2)) +QString(" - avg msecs of samples in audio output buffer in last 10s"));
|
||||||
|
|
||||||
|
|
||||||
|
const MovingMinMaxAvg<quint64>& packetSentTimeGaps = _stats->getPacketSentTimeGaps();
|
||||||
|
|
||||||
|
_upstreamClientStats.push_back(
|
||||||
|
QString("\nUpstream Mic Audio Packets Sent Gaps (by client):"));
|
||||||
|
|
||||||
|
_upstreamClientStats.push_back(
|
||||||
|
QString("Inter-packet timegaps (overall) | min: %1, max: %2, avg: %3").arg(formatUsecTime(packetSentTimeGaps.getMin()).toLatin1().data()).arg(formatUsecTime( packetSentTimeGaps.getMax()).toLatin1().data()).arg(formatUsecTime( packetSentTimeGaps.getAverage()).toLatin1().data()));
|
||||||
|
_upstreamClientStats.push_back(
|
||||||
|
QString("Inter-packet timegaps (last 30s) | min: %1, max: %2, avg: %3").arg(formatUsecTime(packetSentTimeGaps.getWindowMin()).toLatin1().data()).arg(formatUsecTime(packetSentTimeGaps.getWindowMax()).toLatin1().data()).arg(formatUsecTime(packetSentTimeGaps.getWindowAverage()).toLatin1().data()));
|
||||||
|
|
||||||
|
_upstreamMixerStats.push_back(QString("\nUpstream mic audio stats (received and reported by audio-mixer):"));
|
||||||
|
|
||||||
|
renderAudioStreamStats(&_stats->getMixerAvatarStreamStats(), &_upstreamMixerStats, true);
|
||||||
|
|
||||||
|
_downstreamStats.push_back(QString("\nDownstream mixed audio stats:"));
|
||||||
|
|
||||||
|
AudioStreamStats downstreamStats = _stats->getMixerDownstreamStats();
|
||||||
|
|
||||||
|
renderAudioStreamStats(&downstreamStats, &_downstreamStats, true);
|
||||||
|
|
||||||
|
|
||||||
|
if (_shouldShowInjectedStreams) {
|
||||||
|
|
||||||
|
foreach(const AudioStreamStats& injectedStreamAudioStats, _stats->getMixerInjectedStreamStatsMap()) {
|
||||||
|
|
||||||
|
_upstreamInjectedStats.push_back(QString("\nUpstream injected audio stats: stream ID: %1").arg( injectedStreamAudioStats._streamIdentifier.toString().toLatin1().data()));
|
||||||
|
|
||||||
|
renderAudioStreamStats(&injectedStreamAudioStats, &_upstreamInjectedStats, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioStatsDialog::renderAudioStreamStats(const AudioStreamStats* streamStats, QVector<QString>* audioStreamStats, bool isDownstreamStats) {
|
||||||
|
|
||||||
|
|
||||||
|
audioStreamStats->push_back(
|
||||||
|
QString("Packet loss | overall: %1% (%2 lost), last_30s: %3% (%4 lost)").arg(QString::number((int)(streamStats->_packetStreamStats.getLostRate() * 100.0f))).arg(QString::number((int)(streamStats->_packetStreamStats._lost))).arg(QString::number((int)(streamStats->_packetStreamWindowStats.getLostRate() * 100.0f))).arg(QString::number((int)(streamStats->_packetStreamWindowStats._lost)))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isDownstreamStats) {
|
||||||
|
audioStreamStats->push_back(
|
||||||
|
QString("Ringbuffer frames | desired: %1, avg_available(10s): %2 + %3, available: %4+%5").arg(QString::number(streamStats->_desiredJitterBufferFrames)).arg(QString::number(streamStats->_framesAvailableAverage)).arg(QString::number((int)((float)_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS))).arg(QString::number(streamStats->_framesAvailable)).arg(QString::number((int)(_stats->getAudioOutputMsecsUnplayedStats().getCurrentIntervalLastSample() / AudioConstants::NETWORK_FRAME_MSECS))));
|
||||||
|
} else {
|
||||||
|
audioStreamStats->push_back(
|
||||||
|
QString("Ringbuffer frames | desired: %1, avg_available(10s): %2, available: %3").arg(QString::number(streamStats->_desiredJitterBufferFrames)).arg(QString::number(streamStats->_framesAvailableAverage)).arg(QString::number(streamStats->_framesAvailable)));
|
||||||
|
}
|
||||||
|
|
||||||
|
audioStreamStats->push_back(
|
||||||
|
QString("Ringbuffer stats | starves: %1, prev_starve_lasted: %2, frames_dropped: %3, overflows: %4").arg(QString::number(streamStats->_starveCount)).arg(QString::number(streamStats->_consecutiveNotMixedCount)).arg(QString::number(streamStats->_framesDropped)).arg(QString::number(streamStats->_overflowCount)));
|
||||||
|
audioStreamStats->push_back(
|
||||||
|
QString("Inter-packet timegaps (overall) | min: %1, max: %2, avg: %3").arg(formatUsecTime(streamStats->_timeGapMin).toLatin1().data()).arg(formatUsecTime(streamStats->_timeGapMax).toLatin1().data()).arg(formatUsecTime(streamStats->_timeGapAverage).toLatin1().data()));
|
||||||
|
audioStreamStats->push_back(
|
||||||
|
QString("Inter-packet timegaps (last 30s) | min: %1, max: %2, avg: %3").arg(formatUsecTime(streamStats->_timeGapWindowMin).toLatin1().data()).arg(formatUsecTime(streamStats->_timeGapWindowMax).toLatin1().data()).arg(QString::number(streamStats->_timeGapWindowAverage).toLatin1().data()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioStatsDialog::clearAllChannels() {
|
||||||
|
_audioMixerStats.clear();
|
||||||
|
_upstreamClientStats.clear();
|
||||||
|
_upstreamMixerStats.clear();
|
||||||
|
_downstreamStats.clear();
|
||||||
|
_upstreamInjectedStats.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioStatsDialog::updateTimerTimeout() {
|
||||||
|
|
||||||
|
renderStats();
|
||||||
|
|
||||||
|
// Update all audio stats
|
||||||
|
updateStats(_audioMixerStats, _audioMixerID);
|
||||||
|
updateStats(_upstreamClientStats, _upstreamClientID);
|
||||||
|
updateStats(_upstreamMixerStats, _upstreamMixerID);
|
||||||
|
updateStats(_downstreamStats, _downstreamID);
|
||||||
|
updateStats(_upstreamInjectedStats, _upstreamInjectedID);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioStatsDialog::paintEvent(QPaintEvent* event) {
|
||||||
|
|
||||||
|
// Repaint each stat in each channel
|
||||||
|
for (int i = 0; i < _audioDisplayChannels.size(); i++) {
|
||||||
|
for(int j = 0; j < _audioDisplayChannels[i].size(); j++) {
|
||||||
|
_audioDisplayChannels[i].at(j)->paint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog::paintEvent(event);
|
||||||
|
setFixedSize(width(), height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioStatsDialog::reject() {
|
||||||
|
// Just regularly close upon ESC
|
||||||
|
QDialog::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioStatsDialog::closeEvent(QCloseEvent* event) {
|
||||||
|
QDialog::closeEvent(event);
|
||||||
|
emit closed();
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioStatsDialog::~AudioStatsDialog() {
|
||||||
|
clearAllChannels();
|
||||||
|
for (int i = 0; i < _audioDisplayChannels.size(); i++) {
|
||||||
|
_audioDisplayChannels[i].clear();
|
||||||
|
for(int j = 0; j < _audioDisplayChannels[i].size(); j++) {
|
||||||
|
delete _audioDisplayChannels[i].at(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
113
interface/src/ui/AudioStatsDialog.h
Normal file
113
interface/src/ui/AudioStatsDialog.h
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
//
|
||||||
|
// AudioStatsDialog.h
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Bridget Went on 7/9/15.
|
||||||
|
//
|
||||||
|
// 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__AudioStatsDialog__
|
||||||
|
#define __hifi__AudioStatsDialog__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
|
||||||
|
class AudioIOStats;
|
||||||
|
class AudioStreamStats;
|
||||||
|
|
||||||
|
//display
|
||||||
|
class AudioStatsDisplay : public QObject, public Dependency {
|
||||||
|
Q_OBJECT
|
||||||
|
SINGLETON_DEPENDENCY
|
||||||
|
public:
|
||||||
|
AudioStatsDisplay(QFormLayout* form, QString text, unsigned colorRGBA);
|
||||||
|
void updatedDisplay(QString str);
|
||||||
|
void paint();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _strBuf;
|
||||||
|
QLabel* _label;
|
||||||
|
QString _text;
|
||||||
|
unsigned _colorRGBA;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//dialog
|
||||||
|
class AudioStatsDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
AudioStatsDialog(QWidget* parent);
|
||||||
|
~AudioStatsDialog();
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// audio stats methods for rendering
|
||||||
|
QVector<QString> _audioMixerStats;
|
||||||
|
QVector<QString> _upstreamClientStats;
|
||||||
|
QVector<QString> _upstreamMixerStats;
|
||||||
|
QVector<QString> _downstreamStats;
|
||||||
|
QVector<QString> _upstreamInjectedStats;
|
||||||
|
|
||||||
|
int _audioMixerID;
|
||||||
|
int _upstreamClientID;
|
||||||
|
int _upstreamMixerID;
|
||||||
|
int _downstreamID;
|
||||||
|
int _upstreamInjectedID;
|
||||||
|
|
||||||
|
QVector<QVector<AudioStatsDisplay*>> _audioDisplayChannels;
|
||||||
|
|
||||||
|
int addChannel(QFormLayout* form, QVector<QString>& stats, const unsigned color);
|
||||||
|
void updateStats(QVector<QString>& stats, const int channelID);
|
||||||
|
void renderStats();
|
||||||
|
void clearAllChannels();
|
||||||
|
void renderAudioStreamStats(const AudioStreamStats* streamStats, QVector<QString>* audioStreamstats, bool isDownstreamStats);
|
||||||
|
|
||||||
|
|
||||||
|
const AudioIOStats* _stats;
|
||||||
|
QFormLayout* _form;
|
||||||
|
|
||||||
|
bool _isEnabled;
|
||||||
|
bool _shouldShowInjectedStreams;
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
|
||||||
|
void closed();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
|
||||||
|
void reject();
|
||||||
|
void updateTimerTimeout();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// Emits a 'closed' signal when this dialog is closed.
|
||||||
|
void closeEvent(QCloseEvent*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTimer* averageUpdateTimer = new QTimer(this);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* defined(__hifi__AudioStatsDialog__) */
|
||||||
|
|
|
@ -114,6 +114,20 @@ void DialogsManager::editAnimations() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DialogsManager::audioStatsDetails() {
|
||||||
|
if (! _audioStatsDialog) {
|
||||||
|
_audioStatsDialog = new AudioStatsDialog(qApp->getWindow());
|
||||||
|
connect(_audioStatsDialog, SIGNAL(closed()), _audioStatsDialog, SLOT(deleteLater()));
|
||||||
|
|
||||||
|
if (_hmdToolsDialog) {
|
||||||
|
_hmdToolsDialog->watchWindow(_audioStatsDialog->windowHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
_audioStatsDialog->show();
|
||||||
|
}
|
||||||
|
_audioStatsDialog->raise();
|
||||||
|
}
|
||||||
|
|
||||||
void DialogsManager::bandwidthDetails() {
|
void DialogsManager::bandwidthDetails() {
|
||||||
if (! _bandwidthDialog) {
|
if (! _bandwidthDialog) {
|
||||||
_bandwidthDialog = new BandwidthDialog(qApp->getWindow());
|
_bandwidthDialog = new BandwidthDialog(qApp->getWindow());
|
||||||
|
|
|
@ -24,6 +24,7 @@ class QAction;
|
||||||
class AddressBarDialog;
|
class AddressBarDialog;
|
||||||
class AnimationsDialog;
|
class AnimationsDialog;
|
||||||
class AttachmentsDialog;
|
class AttachmentsDialog;
|
||||||
|
class AudioStatsDialog;
|
||||||
class BandwidthDialog;
|
class BandwidthDialog;
|
||||||
class CachesSizeDialog;
|
class CachesSizeDialog;
|
||||||
class DiskCacheEditor;
|
class DiskCacheEditor;
|
||||||
|
@ -42,6 +43,7 @@ class DialogsManager : public QObject, public Dependency {
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
QPointer<AudioStatsDialog> getAudioStatsDialog() const { return _audioStatsDialog; }
|
||||||
QPointer<BandwidthDialog> getBandwidthDialog() const { return _bandwidthDialog; }
|
QPointer<BandwidthDialog> getBandwidthDialog() const { return _bandwidthDialog; }
|
||||||
QPointer<HMDToolsDialog> getHMDToolsDialog() const { return _hmdToolsDialog; }
|
QPointer<HMDToolsDialog> getHMDToolsDialog() const { return _hmdToolsDialog; }
|
||||||
QPointer<LodToolsDialog> getLodToolsDialog() const { return _lodToolsDialog; }
|
QPointer<LodToolsDialog> getLodToolsDialog() const { return _lodToolsDialog; }
|
||||||
|
@ -58,6 +60,7 @@ public slots:
|
||||||
void editPreferences();
|
void editPreferences();
|
||||||
void editAttachments();
|
void editAttachments();
|
||||||
void editAnimations();
|
void editAnimations();
|
||||||
|
void audioStatsDetails();
|
||||||
void bandwidthDetails();
|
void bandwidthDetails();
|
||||||
void lodTools();
|
void lodTools();
|
||||||
void hmdTools(bool showTools);
|
void hmdTools(bool showTools);
|
||||||
|
@ -93,6 +96,7 @@ private:
|
||||||
QPointer<AddressBarDialog> _addressBarDialog;
|
QPointer<AddressBarDialog> _addressBarDialog;
|
||||||
QPointer<AnimationsDialog> _animationsDialog;
|
QPointer<AnimationsDialog> _animationsDialog;
|
||||||
QPointer<AttachmentsDialog> _attachmentsDialog;
|
QPointer<AttachmentsDialog> _attachmentsDialog;
|
||||||
|
QPointer<AudioStatsDialog> _audioStatsDialog;
|
||||||
QPointer<BandwidthDialog> _bandwidthDialog;
|
QPointer<BandwidthDialog> _bandwidthDialog;
|
||||||
QPointer<CachesSizeDialog> _cachesSizeDialog;
|
QPointer<CachesSizeDialog> _cachesSizeDialog;
|
||||||
QPointer<DiskCacheEditor> _diskCacheEditor;
|
QPointer<DiskCacheEditor> _diskCacheEditor;
|
||||||
|
|
Loading…
Reference in a new issue