mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-05-10 07:58:20 +02:00
Merge branch 'master' into 20280
Conflicts: libraries/networking/src/LimitedNodeList.h
This commit is contained in:
commit
d9e353e498
34 changed files with 819 additions and 434 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -38,3 +38,5 @@ interface/resources/visage/*
|
||||||
|
|
||||||
# Ignore interfaceCache for Linux users
|
# Ignore interfaceCache for Linux users
|
||||||
interface/interfaceCache/
|
interface/interfaceCache/
|
||||||
|
|
||||||
|
TAGS
|
||||||
|
|
109
examples/dice.js
Normal file
109
examples/dice.js
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
//
|
||||||
|
// dice.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on February 2, 2015
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Press the dice button to throw some dice from the center of the screen.
|
||||||
|
// Change NUMBER_OF_DICE to change the number thrown (Yahtzee, anyone?)
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var isDice = false;
|
||||||
|
var NUMBER_OF_DICE = 2;
|
||||||
|
var dice = [];
|
||||||
|
var DIE_SIZE = 0.20;
|
||||||
|
|
||||||
|
var madeSound = true; // Set false at start of throw to look for collision
|
||||||
|
|
||||||
|
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
|
|
||||||
|
var rollSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/dice/diceRoll.wav");
|
||||||
|
|
||||||
|
var screenSize = Controller.getViewportDimensions();
|
||||||
|
var offButton = Overlays.addOverlay("image", {
|
||||||
|
x: screenSize.x - 48,
|
||||||
|
y: 96,
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
alpha: 1
|
||||||
|
});
|
||||||
|
var diceButton = Overlays.addOverlay("image", {
|
||||||
|
x: screenSize.x - 48,
|
||||||
|
y: 130,
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
imageURL: HIFI_PUBLIC_BUCKET + "images/die.png",
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
alpha: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
var GRAVITY = -3.5;
|
||||||
|
var LIFETIME = 300;
|
||||||
|
function shootDice(position, velocity) {
|
||||||
|
for (var i = 0; i < NUMBER_OF_DICE; i++) {
|
||||||
|
dice.push(Entities.addEntity(
|
||||||
|
{ type: "Model",
|
||||||
|
modelURL: HIFI_PUBLIC_BUCKET + "models/props/Dice/goldDie.fbx",
|
||||||
|
position: position,
|
||||||
|
velocity: velocity,
|
||||||
|
rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360),
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||||
|
collisionsWillMove: true
|
||||||
|
}));
|
||||||
|
position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation()))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteDice() {
|
||||||
|
while(dice.length > 0) {
|
||||||
|
Entities.deleteEntity(dice.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||||
|
if (!madeSound) {
|
||||||
|
// Is it one of our dice?
|
||||||
|
for (var i = 0; i < dice.length; i++) {
|
||||||
|
if (!dice[i].isKnownID) {
|
||||||
|
dice[i] = Entities.identifyEntity(dice[i]);
|
||||||
|
}
|
||||||
|
if ((entity1.id == dice[i].id) || (entity2.id == dice[i].id)) {
|
||||||
|
madeSound = true;
|
||||||
|
Audio.playSound(rollSound, { position: collision.contactPoint });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
var clickedText = false;
|
||||||
|
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||||
|
if (clickedOverlay == offButton) {
|
||||||
|
deleteDice();
|
||||||
|
} else if (clickedOverlay == diceButton) {
|
||||||
|
var HOW_HARD = 2.0;
|
||||||
|
var position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||||
|
var velocity = Vec3.multiply(HOW_HARD, Quat.getFront(Camera.getOrientation()));
|
||||||
|
shootDice(position, velocity);
|
||||||
|
madeSound = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scriptEnding() {
|
||||||
|
deleteDice();
|
||||||
|
Overlays.deleteOverlay(offButton);
|
||||||
|
Overlays.deleteOverlay(diceButton);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||||
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
|
@ -60,6 +60,7 @@ selectionManager.addEventListener(function() {
|
||||||
propertiesTool.setVisible(true);
|
propertiesTool.setVisible(true);
|
||||||
entityListTool.setVisible(true);
|
entityListTool.setVisible(true);
|
||||||
gridTool.setVisible(true);
|
gridTool.setVisible(true);
|
||||||
|
Window.setFocus();
|
||||||
hasShownPropertiesTool = true;
|
hasShownPropertiesTool = true;
|
||||||
}
|
}
|
||||||
if (!selectionManager.hasSelection()) {
|
if (!selectionManager.hasSelection()) {
|
||||||
|
@ -534,7 +535,7 @@ function mousePressEvent(event) {
|
||||||
if (result !== null) {
|
if (result !== null) {
|
||||||
var currentProperties = Entities.getEntityProperties(result.entityID);
|
var currentProperties = Entities.getEntityProperties(result.entityID);
|
||||||
cameraManager.enable();
|
cameraManager.enable();
|
||||||
cameraManager.focus(currentProperties.position, null, Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
cameraManager.focus(currentProperties.position, null, true);
|
||||||
cameraManager.mousePressEvent(event);
|
cameraManager.mousePressEvent(event);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -670,19 +671,19 @@ function mouseClickEvent(event) {
|
||||||
orientation = MyAvatar.orientation;
|
orientation = MyAvatar.orientation;
|
||||||
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
|
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
|
||||||
|
|
||||||
if (!event.isShifted) {
|
|
||||||
selectionManager.clearSelections();
|
|
||||||
}
|
|
||||||
|
|
||||||
var toggle = event.isShifted;
|
if (!event.isShifted) {
|
||||||
selectionManager.addEntity(foundEntity, toggle);
|
selectionManager.setSelections([foundEntity]);
|
||||||
|
} else {
|
||||||
|
selectionManager.addEntity(foundEntity, true);
|
||||||
|
}
|
||||||
|
|
||||||
print("Model selected: " + foundEntity.id);
|
print("Model selected: " + foundEntity.id);
|
||||||
selectionDisplay.select(selectedEntityID, event);
|
selectionDisplay.select(selectedEntityID, event);
|
||||||
|
|
||||||
cameraManager.focus(selectionManager.worldPosition,
|
cameraManager.focus(selectionManager.worldPosition,
|
||||||
selectionManager.worldDimensions,
|
selectionManager.worldDimensions,
|
||||||
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -820,10 +821,8 @@ function handeMenuEvent(menuItem) {
|
||||||
} else if (menuItem == "Import Models") {
|
} else if (menuItem == "Import Models") {
|
||||||
modelImporter.doImport();
|
modelImporter.doImport();
|
||||||
} else if (menuItem == "Entity List...") {
|
} else if (menuItem == "Entity List...") {
|
||||||
if (isActive) {
|
|
||||||
entityListTool.toggleVisible();
|
entityListTool.toggleVisible();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
tooltip.show(false);
|
tooltip.show(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -559,13 +559,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="property">
|
<div class="property">
|
||||||
<div class="label">Mass</div>
|
|
||||||
<div class="value">
|
|
||||||
<input type='number' id="property-mass"></input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="label">Density</div>
|
<div class="label">Density</div>
|
||||||
<div>
|
<div>
|
||||||
<input type='number' id="property-density"></input>
|
<input type='number' id="property-density"></input>
|
||||||
|
|
121
examples/planets.js
Normal file
121
examples/planets.js
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
//
|
||||||
|
// planets.js
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on January 26, 2015
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Some planets are created in front of you. A physical object shot or thrown between them will move
|
||||||
|
// correctly.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var MAX_RANGE = 75.0;
|
||||||
|
var MAX_TRANSLATION = MAX_RANGE / 20.0;
|
||||||
|
|
||||||
|
var LIFETIME = 600;
|
||||||
|
var DAMPING = 0.0;
|
||||||
|
var G = 3.0;
|
||||||
|
|
||||||
|
// In this section, setup where you want your 'Planets' that will exert gravity on the
|
||||||
|
// smaller test particles. Use the first one for the simplest 'planets around sun' simulation.
|
||||||
|
// Add additional planets to make things a lot more complicated!
|
||||||
|
|
||||||
|
var planetTypes = [];
|
||||||
|
planetTypes.push({ radius: 15, red: 0, green: 0, blue: 255, x: 0.0, y:0, z: 0.0 });
|
||||||
|
//planetTypes.push({ radius: 10, red: 0, green: 255, blue: 0, x: 0.60, y:0, z: 0.60 });
|
||||||
|
//planetTypes.push({ radius: 10, red: 0, green: 0, blue: 255, x: 0.75, y:0, z: 0.75 });
|
||||||
|
//planetTypes.push({ radius: 5, red: 255, green: 0, blue: 0, x: 0.25, y:0, z: 0.25 });
|
||||||
|
//planetTypes.push({ radius: 5, red: 0, green: 255, blue: 255, x: 0, y:0, z: 0 });
|
||||||
|
|
||||||
|
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation())));
|
||||||
|
|
||||||
|
var NUM_INITIAL_PARTICLES = 200;
|
||||||
|
var PARTICLE_MIN_SIZE = 0.50;
|
||||||
|
var PARTICLE_MAX_SIZE = 1.50;
|
||||||
|
var INITIAL_VELOCITY = 5.0;
|
||||||
|
|
||||||
|
var planets = [];
|
||||||
|
var particles = [];
|
||||||
|
|
||||||
|
// Create planets that will extert gravity on test particles
|
||||||
|
for (var i = 0; i < planetTypes.length; i++) {
|
||||||
|
var rotationalVelocity = 10 + Math.random() * 60;
|
||||||
|
var position = { x: planetTypes[i].x, y: planetTypes[i].y, z: planetTypes[i].z };
|
||||||
|
position = Vec3.multiply(MAX_RANGE / 2, position);
|
||||||
|
position = Vec3.sum(center, position);
|
||||||
|
|
||||||
|
planets.push(Entities.addEntity(
|
||||||
|
{ type: "Sphere",
|
||||||
|
position: position,
|
||||||
|
dimensions: { x: planetTypes[i].radius, y: planetTypes[i].radius, z: planetTypes[i].radius },
|
||||||
|
color: { red: planetTypes[i].red, green: planetTypes[i].green, blue: planetTypes[i].blue },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
angularVelocity: { x: 0, y: rotationalVelocity, z: 0 },
|
||||||
|
angularDamping: 0.0,
|
||||||
|
ignoreCollisions: false,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
collisionsWillMove: false }));
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.setTimeout(createParticles, 1000);
|
||||||
|
|
||||||
|
function createParticles() {
|
||||||
|
// Create initial test particles that will move according to gravity from the planets
|
||||||
|
for (var i = 0; i < NUM_INITIAL_PARTICLES; i++) {
|
||||||
|
var radius = PARTICLE_MIN_SIZE + Math.random() * PARTICLE_MAX_SIZE;
|
||||||
|
var gray = Math.random() * 155;
|
||||||
|
var whichPlanet = Math.floor(Math.random() * planets.length);
|
||||||
|
var position = { x: (Math.random() - 0.5) * MAX_RANGE, y: (Math.random() - 0.5) * MAX_TRANSLATION, z: (Math.random() - 0.5) * MAX_RANGE };
|
||||||
|
var separation = Vec3.length(position);
|
||||||
|
particles.push(Entities.addEntity(
|
||||||
|
{ type: "Sphere",
|
||||||
|
position: Vec3.sum(center, position),
|
||||||
|
dimensions: { x: radius, y: radius, z: radius },
|
||||||
|
color: { red: 100 + gray, green: 100 + gray, blue: 100 + gray },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
angularVelocity: { x: 0, y: 0, z: 0 },
|
||||||
|
velocity: Vec3.multiply(INITIAL_VELOCITY * Math.sqrt(separation), Vec3.normalize(Vec3.cross(position, { x: 0, y: 1, z: 0 }))),
|
||||||
|
ignoreCollisions: false,
|
||||||
|
damping: DAMPING,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
collisionsWillMove: true }));
|
||||||
|
}
|
||||||
|
Script.update.connect(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scriptEnding() {
|
||||||
|
for (var i = 0; i < planetTypes.length; i++) {
|
||||||
|
Entities.deleteEntity(planets[i]);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < particles.length; i++) {
|
||||||
|
Entities.deleteEntity(particles[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(deltaTime) {
|
||||||
|
// Apply gravitational force from planets
|
||||||
|
for (var t = 0; t < particles.length; t++) {
|
||||||
|
var properties1 = Entities.getEntityProperties(particles[t]);
|
||||||
|
var velocity = properties1.velocity;
|
||||||
|
var vColor = Vec3.length(velocity) / 50 * 255;
|
||||||
|
var dV = { x:0, y:0, z:0 };
|
||||||
|
var mass1 = Math.pow(properties1.dimensions.x / 2.0, 3.0);
|
||||||
|
for (var p = 0; p < planets.length; p++) {
|
||||||
|
var properties2 = Entities.getEntityProperties(planets[p]);
|
||||||
|
var mass2 = Math.pow(properties2.dimensions.x / 2.0, 3.0);
|
||||||
|
var between = Vec3.subtract(properties1.position, properties2.position);
|
||||||
|
var separation = Vec3.length(between);
|
||||||
|
dV = Vec3.sum(dV, Vec3.multiply(-G * mass1 * mass2 / separation, Vec3.normalize(between)));
|
||||||
|
}
|
||||||
|
if (Math.random() < 0.1) {
|
||||||
|
Entities.editEntity(particles[t], { color: { red: vColor, green: 100, blue: (255 - vColor) }, velocity: Vec3.sum(velocity, Vec3.multiply(deltaTime, dV))});
|
||||||
|
} else {
|
||||||
|
Entities.editEntity(particles[t], { velocity: Vec3.sum(velocity, Vec3.multiply(deltaTime, dV))});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
|
@ -201,6 +201,7 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
auto lodManager = DependencyManager::set<LODManager>();
|
auto lodManager = DependencyManager::set<LODManager>();
|
||||||
auto jsConsole = DependencyManager::set<StandAloneJSConsole>();
|
auto jsConsole = DependencyManager::set<StandAloneJSConsole>();
|
||||||
auto dialogsManager = DependencyManager::set<DialogsManager>();
|
auto dialogsManager = DependencyManager::set<DialogsManager>();
|
||||||
|
auto bandwidthRecorder = DependencyManager::set<BandwidthRecorder>();
|
||||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||||
auto speechRecognizer = DependencyManager::set<SpeechRecognizer>();
|
auto speechRecognizer = DependencyManager::set<SpeechRecognizer>();
|
||||||
#endif
|
#endif
|
||||||
|
@ -241,10 +242,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
_mousePressed(false),
|
_mousePressed(false),
|
||||||
_enableProcessOctreeThread(true),
|
_enableProcessOctreeThread(true),
|
||||||
_octreeProcessor(),
|
_octreeProcessor(),
|
||||||
_inPacketsPerSecond(0),
|
|
||||||
_outPacketsPerSecond(0),
|
|
||||||
_inBytesPerSecond(0),
|
|
||||||
_outBytesPerSecond(0),
|
|
||||||
_nodeBoundsDisplay(this),
|
_nodeBoundsDisplay(this),
|
||||||
_previousScriptLocation(),
|
_previousScriptLocation(),
|
||||||
_applicationOverlay(),
|
_applicationOverlay(),
|
||||||
|
@ -435,6 +432,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
connect(this, SIGNAL(aboutToQuit()), this, SLOT(saveScripts()));
|
connect(this, SIGNAL(aboutToQuit()), this, SLOT(saveScripts()));
|
||||||
connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
|
connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
|
||||||
|
|
||||||
|
// hook up bandwidth estimator
|
||||||
|
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||||
|
connect(nodeList.data(), SIGNAL(dataSent(const quint8, const int)),
|
||||||
|
bandwidthRecorder.data(), SLOT(updateOutboundData(const quint8, const int)));
|
||||||
|
connect(nodeList.data(), SIGNAL(dataReceived(const quint8, const int)),
|
||||||
|
bandwidthRecorder.data(), SLOT(updateInboundData(const quint8, const int)));
|
||||||
|
|
||||||
// check first run...
|
// check first run...
|
||||||
bool firstRun = SettingHandles::firstRun.get();
|
bool firstRun = SettingHandles::firstRun.get();
|
||||||
if (firstRun) {
|
if (firstRun) {
|
||||||
|
@ -774,25 +778,8 @@ void Application::updateProjectionMatrix(Camera& camera, bool updateViewFrustum)
|
||||||
|
|
||||||
void Application::controlledBroadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) {
|
void Application::controlledBroadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) {
|
||||||
foreach(NodeType_t type, destinationNodeTypes) {
|
foreach(NodeType_t type, destinationNodeTypes) {
|
||||||
|
|
||||||
// Perform the broadcast for one type
|
// Perform the broadcast for one type
|
||||||
int nReceivingNodes = DependencyManager::get<NodeList>()->broadcastToNodes(packet, NodeSet() << type);
|
DependencyManager::get<NodeList>()->broadcastToNodes(packet, NodeSet() << type);
|
||||||
|
|
||||||
// Feed number of bytes to corresponding channel of the bandwidth meter, if any (done otherwise)
|
|
||||||
double bandwidth_amount = nReceivingNodes * packet.size();
|
|
||||||
switch (type) {
|
|
||||||
case NodeType::Agent:
|
|
||||||
case NodeType::AvatarMixer:
|
|
||||||
_bandwidthRecorder.avatarsChannel->output.updateValue(bandwidth_amount);
|
|
||||||
_bandwidthRecorder.totalChannel->input.updateValue(bandwidth_amount);
|
|
||||||
break;
|
|
||||||
case NodeType::EntityServer:
|
|
||||||
_bandwidthRecorder.octreeChannel->output.updateValue(bandwidth_amount);
|
|
||||||
_bandwidthRecorder.totalChannel->output.updateValue(bandwidth_amount);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1393,15 +1380,8 @@ void Application::timer() {
|
||||||
float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0f;
|
float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0f;
|
||||||
|
|
||||||
_fps = (float)_frameCount / diffTime;
|
_fps = (float)_frameCount / diffTime;
|
||||||
|
|
||||||
_inPacketsPerSecond = (float) _datagramProcessor.getInPacketCount() / diffTime;
|
|
||||||
_outPacketsPerSecond = (float) _datagramProcessor.getOutPacketCount() / diffTime;
|
|
||||||
_inBytesPerSecond = (float) _datagramProcessor.getInByteCount() / diffTime;
|
|
||||||
_outBytesPerSecond = (float) _datagramProcessor.getOutByteCount() / diffTime;
|
|
||||||
_frameCount = 0;
|
_frameCount = 0;
|
||||||
|
|
||||||
_datagramProcessor.resetCounters();
|
_datagramProcessor.resetCounters();
|
||||||
|
|
||||||
_timerStart.start();
|
_timerStart.start();
|
||||||
|
|
||||||
// ask the node list to check in with the domain server
|
// ask the node list to check in with the domain server
|
||||||
|
@ -2386,10 +2366,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
||||||
|
|
||||||
// make sure we still have an active socket
|
// make sure we still have an active socket
|
||||||
nodeList->writeUnverifiedDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
|
nodeList->writeUnverifiedDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
|
||||||
|
|
||||||
// Feed number of bytes to corresponding channel of the bandwidth meter
|
|
||||||
_bandwidthRecorder.octreeChannel->output.updateValue(packetLength);
|
|
||||||
_bandwidthRecorder.totalChannel->output.updateValue(packetLength);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3377,8 +3353,6 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::packetSent(quint64 length) {
|
void Application::packetSent(quint64 length) {
|
||||||
_bandwidthRecorder.octreeChannel->output.updateValue(length);
|
|
||||||
_bandwidthRecorder.totalChannel->output.updateValue(length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString SETTINGS_KEY = "Settings";
|
const QString SETTINGS_KEY = "Settings";
|
||||||
|
|
|
@ -202,16 +202,11 @@ public:
|
||||||
bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; }
|
bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; }
|
||||||
|
|
||||||
FaceTracker* getActiveFaceTracker();
|
FaceTracker* getActiveFaceTracker();
|
||||||
BandwidthRecorder* getBandwidthRecorder() { return &_bandwidthRecorder; }
|
|
||||||
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
||||||
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
|
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
|
||||||
Overlays& getOverlays() { return _overlays; }
|
Overlays& getOverlays() { return _overlays; }
|
||||||
|
|
||||||
float getFps() const { return _fps; }
|
float getFps() const { return _fps; }
|
||||||
float getInPacketsPerSecond() const { return _inPacketsPerSecond; }
|
|
||||||
float getOutPacketsPerSecond() const { return _outPacketsPerSecond; }
|
|
||||||
float getInBytesPerSecond() const { return _inBytesPerSecond; }
|
|
||||||
float getOutBytesPerSecond() const { return _outBytesPerSecond; }
|
|
||||||
const glm::vec3& getViewMatrixTranslation() const { return _viewMatrixTranslation; }
|
const glm::vec3& getViewMatrixTranslation() const { return _viewMatrixTranslation; }
|
||||||
void setViewMatrixTranslation(const glm::vec3& translation) { _viewMatrixTranslation = translation; }
|
void setViewMatrixTranslation(const glm::vec3& translation) { _viewMatrixTranslation = translation; }
|
||||||
|
|
||||||
|
@ -486,9 +481,6 @@ private:
|
||||||
|
|
||||||
OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
|
OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
|
||||||
|
|
||||||
BandwidthRecorder _bandwidthRecorder;
|
|
||||||
|
|
||||||
|
|
||||||
AvatarManager _avatarManager;
|
AvatarManager _avatarManager;
|
||||||
MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
|
MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
|
||||||
|
|
||||||
|
@ -537,11 +529,6 @@ private:
|
||||||
OctreePacketProcessor _octreeProcessor;
|
OctreePacketProcessor _octreeProcessor;
|
||||||
EntityEditPacketSender _entityEditSender;
|
EntityEditPacketSender _entityEditSender;
|
||||||
|
|
||||||
int _inPacketsPerSecond;
|
|
||||||
int _outPacketsPerSecond;
|
|
||||||
int _inBytesPerSecond;
|
|
||||||
int _outBytesPerSecond;
|
|
||||||
|
|
||||||
StDev _idleLoopStdev;
|
StDev _idleLoopStdev;
|
||||||
float _idleLoopMeasuredJitter;
|
float _idleLoopMeasuredJitter;
|
||||||
|
|
||||||
|
|
|
@ -768,9 +768,6 @@ void Audio::handleAudioInput() {
|
||||||
int packetBytes = currentPacketPtr - audioDataPacket;
|
int packetBytes = currentPacketPtr - audioDataPacket;
|
||||||
nodeList->writeDatagram(audioDataPacket, packetBytes, audioMixer);
|
nodeList->writeDatagram(audioDataPacket, packetBytes, audioMixer);
|
||||||
_outgoingAvatarAudioSequenceNumber++;
|
_outgoingAvatarAudioSequenceNumber++;
|
||||||
|
|
||||||
Application::getInstance()->getBandwidthRecorder()->audioChannel->output.updateValue(packetBytes);
|
|
||||||
Application::getInstance()->getBandwidthRecorder()->totalChannel->output.updateValue(packetBytes);
|
|
||||||
}
|
}
|
||||||
delete[] inputAudioSamples;
|
delete[] inputAudioSamples;
|
||||||
}
|
}
|
||||||
|
@ -828,9 +825,6 @@ void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) {
|
||||||
// Audio output must exist and be correctly set up if we're going to process received audio
|
// Audio output must exist and be correctly set up if we're going to process received audio
|
||||||
_receivedAudioStream.parseData(audioByteArray);
|
_receivedAudioStream.parseData(audioByteArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::getInstance()->getBandwidthRecorder()->audioChannel->input.updateValue(audioByteArray.size());
|
|
||||||
Application::getInstance()->getBandwidthRecorder()->totalChannel->input.updateValue(audioByteArray.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::parseAudioEnvironmentData(const QByteArray &packet) {
|
void Audio::parseAudioEnvironmentData(const QByteArray &packet) {
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
//
|
|
||||||
// BandwidthMeter.cpp
|
|
||||||
// interface/src/ui
|
|
||||||
//
|
|
||||||
// Created by Seth Alves on 2015-1-30
|
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Based on code by Tobias Schwinger
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <GeometryCache.h>
|
|
||||||
#include "BandwidthRecorder.h"
|
|
||||||
|
|
||||||
|
|
||||||
BandwidthRecorder::Channel::Channel(char const* const caption,
|
|
||||||
char const* unitCaption,
|
|
||||||
double unitScale,
|
|
||||||
unsigned colorRGBA) :
|
|
||||||
caption(caption),
|
|
||||||
unitCaption(unitCaption),
|
|
||||||
unitScale(unitScale),
|
|
||||||
colorRGBA(colorRGBA)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BandwidthRecorder::BandwidthRecorder() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BandwidthRecorder::~BandwidthRecorder() {
|
|
||||||
delete audioChannel;
|
|
||||||
delete avatarsChannel;
|
|
||||||
delete octreeChannel;
|
|
||||||
delete metavoxelsChannel;
|
|
||||||
delete totalChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BandwidthRecorder::Stream::Stream(float msToAverage) : _value(0.0f), _msToAverage(msToAverage) {
|
|
||||||
_prevTime.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BandwidthRecorder::Stream::updateValue(double amount) {
|
|
||||||
|
|
||||||
// Determine elapsed time
|
|
||||||
double dt = (double)_prevTime.nsecsElapsed() / 1000000.0; // ns to ms
|
|
||||||
|
|
||||||
// Ignore this value when timer imprecision yields dt = 0
|
|
||||||
if (dt == 0.0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_prevTime.start();
|
|
||||||
|
|
||||||
// Compute approximate average
|
|
||||||
_value = glm::mix(_value, amount / dt,
|
|
||||||
glm::clamp(dt / _msToAverage, 0.0, 1.0));
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
//
|
|
||||||
// BandwidthRecorder.h
|
|
||||||
//
|
|
||||||
// Created by Seth Alves on 2015-1-30
|
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Based on code by Tobias Schwinger
|
|
||||||
//
|
|
||||||
// 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_BandwidthRecorder_h
|
|
||||||
#define hifi_BandwidthRecorder_h
|
|
||||||
|
|
||||||
#include <QElapsedTimer>
|
|
||||||
|
|
||||||
class BandwidthRecorder {
|
|
||||||
public:
|
|
||||||
BandwidthRecorder();
|
|
||||||
~BandwidthRecorder();
|
|
||||||
|
|
||||||
// keep track of data rate in one direction
|
|
||||||
class Stream {
|
|
||||||
public:
|
|
||||||
Stream(float msToAverage = 3000.0f);
|
|
||||||
void updateValue(double amount);
|
|
||||||
double getValue() const { return _value; }
|
|
||||||
private:
|
|
||||||
double _value; // Current value.
|
|
||||||
double _msToAverage; // Milliseconds to average.
|
|
||||||
QElapsedTimer _prevTime; // Time of last feed.
|
|
||||||
};
|
|
||||||
|
|
||||||
// keep track of data rate in two directions as well as units and style to use during display
|
|
||||||
class Channel {
|
|
||||||
public:
|
|
||||||
Channel(char const* const caption, char const* unitCaption, double unitScale, unsigned colorRGBA);
|
|
||||||
Stream input;
|
|
||||||
Stream output;
|
|
||||||
char const* const caption;
|
|
||||||
char const* unitCaption;
|
|
||||||
double unitScale;
|
|
||||||
unsigned colorRGBA;
|
|
||||||
};
|
|
||||||
|
|
||||||
// create the channels we keep track of
|
|
||||||
Channel* audioChannel = new Channel("Audio", "Kbps", 8000.0 / 1024.0, 0x33cc99ff);
|
|
||||||
Channel* avatarsChannel = new Channel("Avatars", "Kbps", 8000.0 / 1024.0, 0xffef40c0);
|
|
||||||
Channel* octreeChannel = new Channel("Octree", "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0);
|
|
||||||
Channel* metavoxelsChannel = new Channel("Metavoxels", "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0);
|
|
||||||
Channel* totalChannel = new Channel("Total", "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -39,8 +39,7 @@ void DatagramProcessor::processDatagrams() {
|
||||||
|
|
||||||
while (DependencyManager::get<NodeList>()->getNodeSocket().hasPendingDatagrams()) {
|
while (DependencyManager::get<NodeList>()->getNodeSocket().hasPendingDatagrams()) {
|
||||||
incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||||
nodeList->getNodeSocket().readDatagram(incomingPacket.data(), incomingPacket.size(),
|
nodeList->readDatagram(incomingPacket, senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
|
||||||
|
|
||||||
_inPacketCount++;
|
_inPacketCount++;
|
||||||
_inByteCount += incomingPacket.size();
|
_inByteCount += incomingPacket.size();
|
||||||
|
@ -73,7 +72,6 @@ void DatagramProcessor::processDatagrams() {
|
||||||
|
|
||||||
if (audioMixer) {
|
if (audioMixer) {
|
||||||
audioMixer->setLastHeardMicrostamp(usecTimestampNow());
|
audioMixer->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
audioMixer->recordBytesReceived(incomingPacket.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -82,8 +80,6 @@ void DatagramProcessor::processDatagrams() {
|
||||||
// this will keep creatorTokenIDs to IDs mapped correctly
|
// this will keep creatorTokenIDs to IDs mapped correctly
|
||||||
EntityItemID::handleAddEntityResponse(incomingPacket);
|
EntityItemID::handleAddEntityResponse(incomingPacket);
|
||||||
application->getEntities()->getTree()->handleAddEntityResponse(incomingPacket);
|
application->getEntities()->getTree()->handleAddEntityResponse(incomingPacket);
|
||||||
application->_bandwidthRecorder.octreeChannel->input.updateValue(incomingPacket.size());
|
|
||||||
application->_bandwidthRecorder.totalChannel->input.updateValue(incomingPacket.size());
|
|
||||||
break;
|
break;
|
||||||
case PacketTypeEntityData:
|
case PacketTypeEntityData:
|
||||||
case PacketTypeEntityErase:
|
case PacketTypeEntityErase:
|
||||||
|
@ -97,8 +93,6 @@ void DatagramProcessor::processDatagrams() {
|
||||||
// add this packet to our list of octree packets and process them on the octree data processing
|
// add this packet to our list of octree packets and process them on the octree data processing
|
||||||
application->_octreeProcessor.queueReceivedPacket(matchedNode, incomingPacket);
|
application->_octreeProcessor.queueReceivedPacket(matchedNode, incomingPacket);
|
||||||
}
|
}
|
||||||
application->_bandwidthRecorder.octreeChannel->input.updateValue(incomingPacket.size());
|
|
||||||
application->_bandwidthRecorder.totalChannel->input.updateValue(incomingPacket.size());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PacketTypeMetavoxelData:
|
case PacketTypeMetavoxelData:
|
||||||
|
@ -113,15 +107,10 @@ void DatagramProcessor::processDatagrams() {
|
||||||
|
|
||||||
if (avatarMixer) {
|
if (avatarMixer) {
|
||||||
avatarMixer->setLastHeardMicrostamp(usecTimestampNow());
|
avatarMixer->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
avatarMixer->recordBytesReceived(incomingPacket.size());
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(&application->getAvatarManager(), "processAvatarMixerDatagram",
|
QMetaObject::invokeMethod(&application->getAvatarManager(), "processAvatarMixerDatagram",
|
||||||
Q_ARG(const QByteArray&, incomingPacket),
|
Q_ARG(const QByteArray&, incomingPacket),
|
||||||
Q_ARG(const QWeakPointer<Node>&, avatarMixer));
|
Q_ARG(const QWeakPointer<Node>&, avatarMixer));
|
||||||
}
|
}
|
||||||
|
|
||||||
application->_bandwidthRecorder.avatarsChannel->input.updateValue(incomingPacket.size());
|
|
||||||
application->_bandwidthRecorder.totalChannel->input.updateValue(incomingPacket.size());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PacketTypeDomainConnectionDenied: {
|
case PacketTypeDomainConnectionDenied: {
|
||||||
|
|
|
@ -899,8 +899,6 @@ int MetavoxelSystemClient::parseData(const QByteArray& packet) {
|
||||||
} else {
|
} else {
|
||||||
QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet));
|
QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet));
|
||||||
}
|
}
|
||||||
Application::getInstance()->getBandwidthRecorder()->metavoxelsChannel->input.updateValue(packet.size());
|
|
||||||
Application::getInstance()->getBandwidthRecorder()->totalChannel->input.updateValue(packet.size());
|
|
||||||
}
|
}
|
||||||
return packet.size();
|
return packet.size();
|
||||||
}
|
}
|
||||||
|
@ -1016,8 +1014,6 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) {
|
||||||
} else {
|
} else {
|
||||||
DependencyManager::get<NodeList>()->writeDatagram(data, _node);
|
DependencyManager::get<NodeList>()->writeDatagram(data, _node);
|
||||||
}
|
}
|
||||||
Application::getInstance()->getBandwidthRecorder()->metavoxelsChannel->output.updateValue(data.size());
|
|
||||||
Application::getInstance()->getBandwidthRecorder()->totalChannel->output.updateValue(data.size());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,11 @@ QScriptValue WindowScriptingInterface::hasFocus() {
|
||||||
return DependencyManager::get<GLCanvas>()->hasFocus();
|
return DependencyManager::get<GLCanvas>()->hasFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowScriptingInterface::setFocus() {
|
||||||
|
Application::getInstance()->getWindow()->activateWindow();
|
||||||
|
Application::getInstance()->getWindow()->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
void WindowScriptingInterface::setCursorVisible(bool visible) {
|
void WindowScriptingInterface::setCursorVisible(bool visible) {
|
||||||
Application::getInstance()->setCursorVisible(visible);
|
Application::getInstance()->setCursorVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ public slots:
|
||||||
void setCursorPosition(int x, int y);
|
void setCursorPosition(int x, int y);
|
||||||
void setCursorVisible(bool visible);
|
void setCursorVisible(bool visible);
|
||||||
QScriptValue hasFocus();
|
QScriptValue hasFocus();
|
||||||
|
void setFocus();
|
||||||
QScriptValue alert(const QString& message = "");
|
QScriptValue alert(const QString& message = "");
|
||||||
QScriptValue confirm(const QString& message = "");
|
QScriptValue confirm(const QString& message = "");
|
||||||
QScriptValue form(const QString& title, QScriptValue array);
|
QScriptValue form(const QString& title, QScriptValue array);
|
||||||
|
|
|
@ -904,6 +904,7 @@ void ApplicationOverlay::renderAudioMeter() {
|
||||||
void ApplicationOverlay::renderStatsAndLogs() {
|
void ApplicationOverlay::renderStatsAndLogs() {
|
||||||
|
|
||||||
Application* application = Application::getInstance();
|
Application* application = Application::getInstance();
|
||||||
|
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||||
|
|
||||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||||
const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor();
|
const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor();
|
||||||
|
@ -919,10 +920,10 @@ void ApplicationOverlay::renderStatsAndLogs() {
|
||||||
int voxelPacketsToProcess = octreePacketProcessor.packetsToProcessCount();
|
int voxelPacketsToProcess = octreePacketProcessor.packetsToProcessCount();
|
||||||
// Onscreen text about position, servers, etc
|
// Onscreen text about position, servers, etc
|
||||||
Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, application->getFps(),
|
Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, application->getFps(),
|
||||||
application->getInPacketsPerSecond(),
|
bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond(),
|
||||||
application->getOutPacketsPerSecond(),
|
bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond(),
|
||||||
application->getInBytesPerSecond(),
|
bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond(),
|
||||||
application->getOutBytesPerSecond(),
|
bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond(),
|
||||||
voxelPacketsToProcess);
|
voxelPacketsToProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,42 +21,54 @@
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
|
||||||
|
|
||||||
BandwidthDialog::ChannelDisplay::ChannelDisplay(BandwidthRecorder::Channel *ch, QFormLayout* form) {
|
BandwidthChannelDisplay::BandwidthChannelDisplay(QVector<NodeType_t> nodeTypesToFollow,
|
||||||
this->ch = ch;
|
QFormLayout* form,
|
||||||
this->label = setupLabel(form);
|
char const* const caption, char const* unitCaption,
|
||||||
}
|
const float unitScale, unsigned colorRGBA) :
|
||||||
|
_nodeTypesToFollow(nodeTypesToFollow),
|
||||||
|
_caption(caption),
|
||||||
|
_unitCaption(unitCaption),
|
||||||
|
_unitScale(unitScale),
|
||||||
|
_colorRGBA(colorRGBA)
|
||||||
|
{
|
||||||
|
_label = new QLabel();
|
||||||
|
_label->setAlignment(Qt::AlignRight);
|
||||||
|
|
||||||
|
QPalette palette = _label->palette();
|
||||||
QLabel* BandwidthDialog::ChannelDisplay::setupLabel(QFormLayout* form) {
|
unsigned rgb = colorRGBA >> 8;
|
||||||
QLabel* label = new QLabel();
|
|
||||||
|
|
||||||
label->setAlignment(Qt::AlignRight);
|
|
||||||
|
|
||||||
QPalette palette = label->palette();
|
|
||||||
unsigned rgb = ch->colorRGBA >> 8;
|
|
||||||
rgb = ((rgb & 0xfefefeu) >> 1) + ((rgb & 0xf8f8f8) >> 3);
|
rgb = ((rgb & 0xfefefeu) >> 1) + ((rgb & 0xf8f8f8) >> 3);
|
||||||
palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb));
|
palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb));
|
||||||
label->setPalette(palette);
|
_label->setPalette(palette);
|
||||||
|
|
||||||
form->addRow((std::string(" ") + ch->caption + " Bandwidth In/Out:").c_str(), label);
|
form->addRow(QString(" ") + _caption + " Bandwidth In/Out:", _label);
|
||||||
|
|
||||||
return label;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void BandwidthDialog::ChannelDisplay::setLabelText() {
|
void BandwidthChannelDisplay::bandwidthAverageUpdated() {
|
||||||
std::string strBuf =
|
float inTotal = 0.;
|
||||||
std::to_string ((int) (ch->input.getValue() * ch->unitScale)) + "/" +
|
float outTotal = 0.;
|
||||||
std::to_string ((int) (ch->output.getValue() * ch->unitScale)) + " " + ch->unitCaption;
|
|
||||||
label->setText(strBuf.c_str());
|
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||||
|
|
||||||
|
for (int i = 0; i < _nodeTypesToFollow.size(); ++i) {
|
||||||
|
inTotal += bandwidthRecorder->getAverageInputKilobitsPerSecond(_nodeTypesToFollow.at(i));
|
||||||
|
outTotal += bandwidthRecorder->getAverageOutputKilobitsPerSecond(_nodeTypesToFollow.at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
_strBuf =
|
||||||
|
QString("").setNum((int) (inTotal * _unitScale)) + "/" +
|
||||||
|
QString("").setNum((int) (outTotal * _unitScale)) + " " + _unitCaption;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BandwidthChannelDisplay::paint() {
|
||||||
|
_label->setText(_strBuf);
|
||||||
|
}
|
||||||
|
|
||||||
BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthRecorder* model) :
|
|
||||||
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint),
|
BandwidthDialog::BandwidthDialog(QWidget* parent) :
|
||||||
_model(model) {
|
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) {
|
||||||
|
|
||||||
this->setWindowTitle("Bandwidth Details");
|
this->setWindowTitle("Bandwidth Details");
|
||||||
|
|
||||||
|
@ -64,30 +76,48 @@ BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthRecorder* model) :
|
||||||
QFormLayout* form = new QFormLayout();
|
QFormLayout* form = new QFormLayout();
|
||||||
this->QDialog::setLayout(form);
|
this->QDialog::setLayout(form);
|
||||||
|
|
||||||
audioChannelDisplay = new ChannelDisplay(_model->audioChannel, form);
|
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||||
avatarsChannelDisplay = new ChannelDisplay(_model->avatarsChannel, form);
|
|
||||||
octreeChannelDisplay = new ChannelDisplay(_model->octreeChannel, form);
|
_allChannelDisplays[0] = _audioChannelDisplay =
|
||||||
metavoxelsChannelDisplay = new ChannelDisplay(_model->metavoxelsChannel, form);
|
new BandwidthChannelDisplay({NodeType::AudioMixer}, form, "Audio", "Kbps", 1.0, COLOR0);
|
||||||
totalChannelDisplay = new ChannelDisplay(_model->totalChannel, form);
|
_allChannelDisplays[1] = _avatarsChannelDisplay =
|
||||||
|
new BandwidthChannelDisplay({NodeType::Agent, NodeType::AvatarMixer}, form, "Avatars", "Kbps", 1.0, COLOR1);
|
||||||
|
_allChannelDisplays[2] = _octreeChannelDisplay =
|
||||||
|
new BandwidthChannelDisplay({NodeType::EntityServer}, form, "Octree", "Kbps", 1.0, COLOR2);
|
||||||
|
_allChannelDisplays[3] = _octreeChannelDisplay =
|
||||||
|
new BandwidthChannelDisplay({NodeType::DomainServer}, form, "Domain", "Kbps", 1.0, COLOR2);
|
||||||
|
_allChannelDisplays[4] = _metavoxelsChannelDisplay =
|
||||||
|
new BandwidthChannelDisplay({NodeType::MetavoxelServer, NodeType::EnvironmentServer}, form, "Metavoxels", "Kbps", 1.0, COLOR2);
|
||||||
|
_allChannelDisplays[5] = _otherChannelDisplay =
|
||||||
|
new BandwidthChannelDisplay({NodeType::Unassigned}, form, "Other", "Kbps", 1.0, COLOR2);
|
||||||
|
_allChannelDisplays[6] = _totalChannelDisplay =
|
||||||
|
new BandwidthChannelDisplay({NodeType::DomainServer, NodeType::EntityServer, NodeType::MetavoxelServer,
|
||||||
|
NodeType::EnvironmentServer, NodeType::AudioMixer, NodeType::Agent,
|
||||||
|
NodeType::AvatarMixer, NodeType::Unassigned},
|
||||||
|
form, "Total", "Kbps", 1.0, COLOR2);
|
||||||
|
|
||||||
|
connect(averageUpdateTimer, SIGNAL(timeout()), this, SLOT(updateTimerTimeout()));
|
||||||
|
averageUpdateTimer->start(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BandwidthDialog::~BandwidthDialog() {
|
BandwidthDialog::~BandwidthDialog() {
|
||||||
delete audioChannelDisplay;
|
for (unsigned int i = 0; i < _CHANNELCOUNT; i++) {
|
||||||
delete avatarsChannelDisplay;
|
delete _allChannelDisplays[i];
|
||||||
delete octreeChannelDisplay;
|
}
|
||||||
delete metavoxelsChannelDisplay;
|
}
|
||||||
delete totalChannelDisplay;
|
|
||||||
|
|
||||||
|
void BandwidthDialog::updateTimerTimeout() {
|
||||||
|
for (unsigned int i = 0; i < _CHANNELCOUNT; i++) {
|
||||||
|
_allChannelDisplays[i]->bandwidthAverageUpdated();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BandwidthDialog::paintEvent(QPaintEvent* event) {
|
void BandwidthDialog::paintEvent(QPaintEvent* event) {
|
||||||
audioChannelDisplay->setLabelText();
|
for (unsigned int i=0; i<_CHANNELCOUNT; i++)
|
||||||
avatarsChannelDisplay->setLabelText();
|
_allChannelDisplays[i]->paint();
|
||||||
octreeChannelDisplay->setLabelText();
|
|
||||||
metavoxelsChannelDisplay->setLabelText();
|
|
||||||
totalChannelDisplay->setLabelText();
|
|
||||||
|
|
||||||
this->QDialog::paintEvent(event);
|
this->QDialog::paintEvent(event);
|
||||||
this->setFixedSize(this->width(), this->height());
|
this->setFixedSize(this->width(), this->height());
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,36 +15,61 @@
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "Node.h"
|
||||||
#include "BandwidthRecorder.h"
|
#include "BandwidthRecorder.h"
|
||||||
|
|
||||||
|
|
||||||
|
const unsigned int COLOR0 = 0x33cc99ff;
|
||||||
|
const unsigned int COLOR1 = 0xffef40c0;
|
||||||
|
const unsigned int COLOR2 = 0xd0d0d0a0;
|
||||||
|
|
||||||
|
|
||||||
|
class BandwidthChannelDisplay : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
BandwidthChannelDisplay(QVector<NodeType_t> nodeTypesToFollow,
|
||||||
|
QFormLayout* form,
|
||||||
|
char const* const caption, char const* unitCaption, float unitScale, unsigned colorRGBA);
|
||||||
|
void paint();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVector<NodeType_t> _nodeTypesToFollow;
|
||||||
|
QLabel* _label;
|
||||||
|
QString _strBuf;
|
||||||
|
char const* const _caption;
|
||||||
|
char const* _unitCaption;
|
||||||
|
float const _unitScale;
|
||||||
|
unsigned _colorRGBA;
|
||||||
|
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void bandwidthAverageUpdated();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class BandwidthDialog : public QDialog {
|
class BandwidthDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
// Sets up the UI based on the configuration of the BandwidthRecorder
|
BandwidthDialog(QWidget* parent);
|
||||||
BandwidthDialog(QWidget* parent, BandwidthRecorder* model);
|
|
||||||
~BandwidthDialog();
|
~BandwidthDialog();
|
||||||
|
|
||||||
class ChannelDisplay {
|
void paintEvent(QPaintEvent*);
|
||||||
public:
|
|
||||||
ChannelDisplay(BandwidthRecorder::Channel *ch, QFormLayout* form);
|
|
||||||
QLabel* setupLabel(QFormLayout* form);
|
|
||||||
void setLabelText();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BandwidthRecorder::Channel *ch;
|
BandwidthChannelDisplay* _audioChannelDisplay;
|
||||||
|
BandwidthChannelDisplay* _avatarsChannelDisplay;
|
||||||
|
BandwidthChannelDisplay* _octreeChannelDisplay;
|
||||||
|
BandwidthChannelDisplay* _domainChannelDisplay;
|
||||||
|
BandwidthChannelDisplay* _metavoxelsChannelDisplay;
|
||||||
|
BandwidthChannelDisplay* _otherChannelDisplay;
|
||||||
|
BandwidthChannelDisplay* _totalChannelDisplay; // sums of all the other channels
|
||||||
|
|
||||||
QLabel* label;
|
static const unsigned int _CHANNELCOUNT = 7;
|
||||||
};
|
BandwidthChannelDisplay* _allChannelDisplays[_CHANNELCOUNT];
|
||||||
|
|
||||||
ChannelDisplay* audioChannelDisplay;
|
|
||||||
ChannelDisplay* avatarsChannelDisplay;
|
|
||||||
ChannelDisplay* octreeChannelDisplay;
|
|
||||||
ChannelDisplay* metavoxelsChannelDisplay;
|
|
||||||
|
|
||||||
// sums of all the other channels
|
|
||||||
ChannelDisplay* totalChannelDisplay;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
@ -53,15 +78,17 @@ signals:
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void reject();
|
void reject();
|
||||||
|
void updateTimerTimeout();
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent*);
|
|
||||||
|
|
||||||
// Emits a 'closed' signal when this dialog is closed.
|
// Emits a 'closed' signal when this dialog is closed.
|
||||||
void closeEvent(QCloseEvent*);
|
void closeEvent(QCloseEvent*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BandwidthRecorder* _model;
|
QTimer* averageUpdateTimer = new QTimer(this);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_BandwidthDialog_h
|
#endif // hifi_BandwidthDialog_h
|
||||||
|
|
|
@ -102,7 +102,7 @@ void DialogsManager::editAnimations() {
|
||||||
|
|
||||||
void DialogsManager::bandwidthDetails() {
|
void DialogsManager::bandwidthDetails() {
|
||||||
if (! _bandwidthDialog) {
|
if (! _bandwidthDialog) {
|
||||||
_bandwidthDialog = new BandwidthDialog(qApp->getWindow(), qApp->getBandwidthRecorder());
|
_bandwidthDialog = new BandwidthDialog(qApp->getWindow());
|
||||||
connect(_bandwidthDialog, SIGNAL(closed()), _bandwidthDialog, SLOT(deleteLater()));
|
connect(_bandwidthDialog, SIGNAL(closed()), _bandwidthDialog, SLOT(deleteLater()));
|
||||||
|
|
||||||
if (_hmdToolsDialog) {
|
if (_hmdToolsDialog) {
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
|
||||||
#include "Stats.h"
|
#include "Stats.h"
|
||||||
|
#include "BandwidthRecorder.h"
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
|
@ -201,8 +202,8 @@ void Stats::display(
|
||||||
float fps,
|
float fps,
|
||||||
int inPacketsPerSecond,
|
int inPacketsPerSecond,
|
||||||
int outPacketsPerSecond,
|
int outPacketsPerSecond,
|
||||||
int inBytesPerSecond,
|
int inKbitsPerSecond,
|
||||||
int outBytesPerSecond,
|
int outKbitsPerSecond,
|
||||||
int voxelPacketsToProcess)
|
int voxelPacketsToProcess)
|
||||||
{
|
{
|
||||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||||
|
@ -216,6 +217,8 @@ void Stats::display(
|
||||||
QLocale locale(QLocale::English);
|
QLocale locale(QLocale::English);
|
||||||
std::stringstream octreeStats;
|
std::stringstream octreeStats;
|
||||||
|
|
||||||
|
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||||
|
|
||||||
if (_lastHorizontalOffset != horizontalOffset) {
|
if (_lastHorizontalOffset != horizontalOffset) {
|
||||||
resetWidth(glCanvas->width(), horizontalOffset);
|
resetWidth(glCanvas->width(), horizontalOffset);
|
||||||
_lastHorizontalOffset = horizontalOffset;
|
_lastHorizontalOffset = horizontalOffset;
|
||||||
|
@ -312,12 +315,17 @@ void Stats::display(
|
||||||
verticalOffset = 0;
|
verticalOffset = 0;
|
||||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + 1;
|
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + 1;
|
||||||
|
|
||||||
|
if (columnOneWidth == _generalStatsWidth) {
|
||||||
|
drawBackground(backgroundColor, horizontalOffset, 0, _bandwidthStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||||
|
}
|
||||||
|
horizontalOffset += 5;
|
||||||
|
|
||||||
char packetsPerSecondString[30];
|
char packetsPerSecondString[30];
|
||||||
sprintf(packetsPerSecondString, "Packets In/Out: %d/%d", inPacketsPerSecond, outPacketsPerSecond);
|
sprintf(packetsPerSecondString, "Packets In/Out: %d/%d", inPacketsPerSecond, outPacketsPerSecond);
|
||||||
char averageMegabitsPerSecond[30];
|
char averageMegabitsPerSecond[30];
|
||||||
sprintf(averageMegabitsPerSecond, "Mbps In/Out: %3.2f/%3.2f",
|
sprintf(averageMegabitsPerSecond, "Mbps In/Out: %3.2f/%3.2f",
|
||||||
(float)inBytesPerSecond * 8.0f / 1000000.0f,
|
(float)inKbitsPerSecond * 1.0f / 1000.0f,
|
||||||
(float)outBytesPerSecond * 8.0f / 1000000.0f);
|
(float)outKbitsPerSecond * 1.0f / 1000.0f);
|
||||||
|
|
||||||
verticalOffset += STATS_PELS_PER_LINE;
|
verticalOffset += STATS_PELS_PER_LINE;
|
||||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, packetsPerSecondString, color);
|
drawText(horizontalOffset, verticalOffset, scale, rotation, font, packetsPerSecondString, color);
|
||||||
|
@ -440,8 +448,10 @@ void Stats::display(
|
||||||
SharedNodePointer avatarMixer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AvatarMixer);
|
SharedNodePointer avatarMixer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AvatarMixer);
|
||||||
if (avatarMixer) {
|
if (avatarMixer) {
|
||||||
sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps",
|
sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps",
|
||||||
roundf(avatarMixer->getAverageKilobitsPerSecond()),
|
roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +
|
||||||
roundf(avatarMixer->getAveragePacketsPerSecond()));
|
bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer)),
|
||||||
|
roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +
|
||||||
|
bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
|
||||||
} else {
|
} else {
|
||||||
sprintf(avatarMixerStats, "No Avatar Mixer");
|
sprintf(avatarMixerStats, "No Avatar Mixer");
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset);
|
void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset);
|
||||||
void resetWidth(int width, int horizontalOffset);
|
void resetWidth(int width, int horizontalOffset);
|
||||||
void display(const float* color, int horizontalOffset, float fps, int inPacketsPerSecond, int outPacketsPerSecond,
|
void display(const float* color, int horizontalOffset, float fps, int inPacketsPerSecond, int outPacketsPerSecond,
|
||||||
int inBytesPerSecond, int outBytesPerSecond, int voxelPacketsToProcess);
|
int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess);
|
||||||
bool includeTimingRecord(const QString& name);
|
bool includeTimingRecord(const QString& name);
|
||||||
|
|
||||||
Q_INVOKABLE void setMetavoxelStats(int internal, int leaves, int sendProgress,
|
Q_INVOKABLE void setMetavoxelStats(int internal, int leaves, int sendProgress,
|
||||||
|
|
|
@ -9,15 +9,12 @@
|
||||||
// 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
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <NetworkAccessManager.h>
|
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
#include "BillboardOverlay.h"
|
#include "BillboardOverlay.h"
|
||||||
|
|
||||||
BillboardOverlay::BillboardOverlay() :
|
BillboardOverlay::BillboardOverlay() :
|
||||||
_newTextureNeeded(true),
|
_fromImage(),
|
||||||
_fromImage(-1,-1,-1,-1),
|
|
||||||
_scale(1.0f),
|
_scale(1.0f),
|
||||||
_isFacingAvatar(true)
|
_isFacingAvatar(true)
|
||||||
{
|
{
|
||||||
|
@ -27,10 +24,7 @@ BillboardOverlay::BillboardOverlay() :
|
||||||
BillboardOverlay::BillboardOverlay(const BillboardOverlay* billboardOverlay) :
|
BillboardOverlay::BillboardOverlay(const BillboardOverlay* billboardOverlay) :
|
||||||
Base3DOverlay(billboardOverlay),
|
Base3DOverlay(billboardOverlay),
|
||||||
_url(billboardOverlay->_url),
|
_url(billboardOverlay->_url),
|
||||||
_billboard(billboardOverlay->_billboard),
|
_texture(billboardOverlay->_texture),
|
||||||
_size(),
|
|
||||||
_billboardTexture(),
|
|
||||||
_newTextureNeeded(true),
|
|
||||||
_fromImage(billboardOverlay->_fromImage),
|
_fromImage(billboardOverlay->_fromImage),
|
||||||
_scale(billboardOverlay->_scale),
|
_scale(billboardOverlay->_scale),
|
||||||
_isFacingAvatar(billboardOverlay->_isFacingAvatar)
|
_isFacingAvatar(billboardOverlay->_isFacingAvatar)
|
||||||
|
@ -38,41 +32,23 @@ BillboardOverlay::BillboardOverlay(const BillboardOverlay* billboardOverlay) :
|
||||||
}
|
}
|
||||||
|
|
||||||
void BillboardOverlay::render(RenderArgs* args) {
|
void BillboardOverlay::render(RenderArgs* args) {
|
||||||
if (!_visible || !_isLoaded) {
|
if (!_isLoaded) {
|
||||||
|
_isLoaded = true;
|
||||||
|
_texture = DependencyManager::get<TextureCache>()->getTexture(_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_visible || !_texture->isLoaded()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_billboard.isEmpty()) {
|
|
||||||
if (_newTextureNeeded && _billboardTexture) {
|
|
||||||
_billboardTexture.reset();
|
|
||||||
}
|
|
||||||
if (!_billboardTexture) {
|
|
||||||
QImage image = QImage::fromData(_billboard);
|
|
||||||
if (image.format() != QImage::Format_ARGB32) {
|
|
||||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
|
||||||
}
|
|
||||||
_size = image.size();
|
|
||||||
if (_fromImage.x() == -1) {
|
|
||||||
_fromImage.setRect(0, 0, _size.width(), _size.height());
|
|
||||||
}
|
|
||||||
_billboardTexture.reset(new Texture());
|
|
||||||
_newTextureNeeded = false;
|
|
||||||
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _size.width(), _size.height(), 0,
|
|
||||||
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glEnable(GL_ALPHA_TEST);
|
glEnable(GL_ALPHA_TEST);
|
||||||
glAlphaFunc(GL_GREATER, 0.5f);
|
glAlphaFunc(GL_GREATER, 0.5f);
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _texture->getID());
|
||||||
|
|
||||||
glPushMatrix(); {
|
glPushMatrix(); {
|
||||||
glTranslatef(_position.x, _position.y, _position.z);
|
glTranslatef(_position.x, _position.y, _position.z);
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
|
@ -87,26 +63,42 @@ void BillboardOverlay::render(RenderArgs* args) {
|
||||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||||
glScalef(_scale, _scale, _scale);
|
glScalef(_scale, _scale, _scale);
|
||||||
|
|
||||||
if (_billboardTexture) {
|
|
||||||
float maxSize = glm::max(_fromImage.width(), _fromImage.height());
|
|
||||||
float x = _fromImage.width() / (2.0f * maxSize);
|
|
||||||
float y = -_fromImage.height() / (2.0f * maxSize);
|
|
||||||
|
|
||||||
const float MAX_COLOR = 255.0f;
|
const float MAX_COLOR = 255.0f;
|
||||||
xColor color = getColor();
|
xColor color = getColor();
|
||||||
float alpha = getAlpha();
|
float alpha = getAlpha();
|
||||||
|
|
||||||
|
float imageWidth = _texture->getWidth();
|
||||||
|
float imageHeight = _texture->getHeight();
|
||||||
|
|
||||||
|
QRect fromImage;
|
||||||
|
if (_fromImage.isNull()) {
|
||||||
|
fromImage.setX(0);
|
||||||
|
fromImage.setY(0);
|
||||||
|
fromImage.setWidth(imageWidth);
|
||||||
|
fromImage.setHeight(imageHeight);
|
||||||
|
} else {
|
||||||
|
float scaleX = imageWidth / _texture->getOriginalWidth();
|
||||||
|
float scaleY = imageHeight / _texture->getOriginalHeight();
|
||||||
|
|
||||||
|
fromImage.setX(scaleX * _fromImage.x());
|
||||||
|
fromImage.setY(scaleY * _fromImage.y());
|
||||||
|
fromImage.setWidth(scaleX * _fromImage.width());
|
||||||
|
fromImage.setHeight(scaleY * _fromImage.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
float maxSize = glm::max(fromImage.width(), fromImage.height());
|
||||||
|
float x = fromImage.width() / (2.0f * maxSize);
|
||||||
|
float y = -fromImage.height() / (2.0f * maxSize);
|
||||||
|
|
||||||
glm::vec2 topLeft(-x, -y);
|
glm::vec2 topLeft(-x, -y);
|
||||||
glm::vec2 bottomRight(x, y);
|
glm::vec2 bottomRight(x, y);
|
||||||
glm::vec2 texCoordTopLeft((float)_fromImage.x() / (float)_size.width(),
|
glm::vec2 texCoordTopLeft(fromImage.x() / imageWidth, fromImage.y() / imageHeight);
|
||||||
(float)_fromImage.y() / (float)_size.height());
|
glm::vec2 texCoordBottomRight((fromImage.x() + fromImage.width()) / imageWidth,
|
||||||
glm::vec2 texCoordBottomRight(((float)_fromImage.x() + (float)_fromImage.width()) / (float)_size.width(),
|
(fromImage.y() + fromImage.height()) / imageHeight);
|
||||||
((float)_fromImage.y() + (float)_fromImage.height()) / _size.height());
|
|
||||||
|
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||||
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha));
|
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha));
|
||||||
|
|
||||||
}
|
|
||||||
} glPopMatrix();
|
} glPopMatrix();
|
||||||
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
@ -129,6 +121,9 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
||||||
|
|
||||||
QScriptValue subImageBounds = properties.property("subImage");
|
QScriptValue subImageBounds = properties.property("subImage");
|
||||||
if (subImageBounds.isValid()) {
|
if (subImageBounds.isValid()) {
|
||||||
|
if (subImageBounds.isNull()) {
|
||||||
|
_fromImage = QRect();
|
||||||
|
} else {
|
||||||
QRect oldSubImageRect = _fromImage;
|
QRect oldSubImageRect = _fromImage;
|
||||||
QRect subImageRect = _fromImage;
|
QRect subImageRect = _fromImage;
|
||||||
if (subImageBounds.property("x").isValid()) {
|
if (subImageBounds.property("x").isValid()) {
|
||||||
|
@ -153,6 +148,7 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
||||||
}
|
}
|
||||||
setClipFromSource(subImageRect);
|
setClipFromSource(subImageRect);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QScriptValue scaleValue = properties.property("scale");
|
QScriptValue scaleValue = properties.property("scale");
|
||||||
if (scaleValue.isValid()) {
|
if (scaleValue.isValid()) {
|
||||||
|
@ -188,35 +184,20 @@ void BillboardOverlay::setURL(const QString& url) {
|
||||||
|
|
||||||
void BillboardOverlay::setBillboardURL(const QString& url) {
|
void BillboardOverlay::setBillboardURL(const QString& url) {
|
||||||
_url = url;
|
_url = url;
|
||||||
QUrl actualURL = url;
|
|
||||||
|
|
||||||
_isLoaded = false;
|
_isLoaded = false;
|
||||||
|
|
||||||
// clear the billboard if previously set
|
|
||||||
_billboard.clear();
|
|
||||||
_newTextureNeeded = true;
|
|
||||||
|
|
||||||
QNetworkRequest request(actualURL);
|
|
||||||
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
|
||||||
QNetworkReply* reply = NetworkAccessManager::getInstance().get(request);
|
|
||||||
connect(reply, &QNetworkReply::finished, this, &BillboardOverlay::replyFinished);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BillboardOverlay::replyFinished() {
|
|
||||||
// replace our byte array with the downloaded data
|
|
||||||
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
|
||||||
_billboard = reply->readAll();
|
|
||||||
_isLoaded = true;
|
|
||||||
reply->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
float& distance, BoxFace& face) {
|
float& distance, BoxFace& face) {
|
||||||
|
|
||||||
if (_billboardTexture) {
|
if (_texture) {
|
||||||
float maxSize = glm::max(_fromImage.width(), _fromImage.height());
|
bool isNull = _fromImage.isNull();
|
||||||
float x = _fromImage.width() / (2.0f * maxSize);
|
float width = isNull ? _texture->getWidth() : _fromImage.width();
|
||||||
float y = -_fromImage.height() / (2.0f * maxSize);
|
float height = isNull ? _texture->getHeight() : _fromImage.height();
|
||||||
|
|
||||||
|
float maxSize = glm::max(width, height);
|
||||||
|
float x = width / (2.0f * maxSize);
|
||||||
|
float y = -height / (2.0f * maxSize);
|
||||||
float maxDimension = glm::max(x,y);
|
float maxDimension = glm::max(x,y);
|
||||||
float scaledDimension = maxDimension * _scale;
|
float scaledDimension = maxDimension * _scale;
|
||||||
glm::vec3 corner = getCenter() - glm::vec3(scaledDimension, scaledDimension, scaledDimension) ;
|
glm::vec3 corner = getCenter() - glm::vec3(scaledDimension, scaledDimension, scaledDimension) ;
|
||||||
|
|
|
@ -40,17 +40,11 @@ public:
|
||||||
|
|
||||||
virtual BillboardOverlay* createClone() const;
|
virtual BillboardOverlay* createClone() const;
|
||||||
|
|
||||||
private slots:
|
|
||||||
void replyFinished();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setBillboardURL(const QString& url);
|
void setBillboardURL(const QString& url);
|
||||||
|
|
||||||
QString _url;
|
QString _url;
|
||||||
QByteArray _billboard;
|
NetworkTexturePointer _texture;
|
||||||
QSize _size;
|
|
||||||
QScopedPointer<Texture> _billboardTexture;
|
|
||||||
bool _newTextureNeeded;
|
|
||||||
|
|
||||||
QRect _fromImage; // where from in the image to sample
|
QRect _fromImage; // where from in the image to sample
|
||||||
|
|
||||||
|
|
|
@ -70,8 +70,8 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
|
||||||
|
|
||||||
// for our overlay, is solid means we draw a solid "filled" rectangle otherwise we just draw a border line...
|
// for our overlay, is solid means we draw a solid "filled" rectangle otherwise we just draw a border line...
|
||||||
if (getIsSolid()) {
|
if (getIsSolid()) {
|
||||||
glm::vec3 topLeft(-halfDimensions.x, 0.0f, -halfDimensions.y);
|
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||||
glm::vec3 bottomRight(halfDimensions.x, 0.0f, halfDimensions.y);
|
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, rectangleColor);
|
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, rectangleColor);
|
||||||
} else {
|
} else {
|
||||||
if (getIsDashedLine()) {
|
if (getIsDashedLine()) {
|
||||||
|
|
|
@ -148,7 +148,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat rotation = getRotation();
|
glm::quat rotation = getRotation();
|
||||||
if (needsToCallUpdate() && _model->isActive()) {
|
bool movingOrAnimating = isMoving() || isAnimatingSomething();
|
||||||
|
if ((movingOrAnimating || _needsInitialSimulation) && _model->isActive()) {
|
||||||
_model->setScaleToFit(true, dimensions);
|
_model->setScaleToFit(true, dimensions);
|
||||||
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
|
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
|
||||||
_model->setRotation(rotation);
|
_model->setRotation(rotation);
|
||||||
|
@ -168,7 +169,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
PerformanceTimer perfTimer("model->render");
|
PerformanceTimer perfTimer("model->render");
|
||||||
// filter out if not needed to render
|
// filter out if not needed to render
|
||||||
if (args && (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE)) {
|
if (args && (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE)) {
|
||||||
if (isMoving() || isAnimatingSomething()) {
|
if (movingOrAnimating) {
|
||||||
_model->renderInScene(alpha, args);
|
_model->renderInScene(alpha, args);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -245,6 +245,21 @@ bool ModelEntityItem::needsToCallUpdate() const {
|
||||||
return isAnimatingSomething() ? true : EntityItem::needsToCallUpdate();
|
return isAnimatingSomething() ? true : EntityItem::needsToCallUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelEntityItem::computeShapeInfo(ShapeInfo& info) const {
|
||||||
|
// HACK: Default first first approximation is to boxify the entity... but only if it is small enough.
|
||||||
|
// The limit here is chosen to something that most avatars could not comfortably fit inside
|
||||||
|
// to prevent houses from getting boxified... we don't want the things inside houses to
|
||||||
|
// collide with a house as if it were a giant solid block.
|
||||||
|
const float MAX_SIZE_FOR_BOXIFICATION_HACK = 3.0f;
|
||||||
|
float diagonal = glm::length(getDimensionsInMeters());
|
||||||
|
if (diagonal < MAX_SIZE_FOR_BOXIFICATION_HACK) {
|
||||||
|
glm::vec3 halfExtents = 0.5f * getDimensionsInMeters();
|
||||||
|
info.setBox(halfExtents);
|
||||||
|
} else {
|
||||||
|
info.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ModelEntityItem::update(const quint64& now) {
|
void ModelEntityItem::update(const quint64& now) {
|
||||||
// only advance the frame index if we're playing
|
// only advance the frame index if we're playing
|
||||||
if (getAnimationIsPlaying()) {
|
if (getAnimationIsPlaying()) {
|
||||||
|
|
|
@ -46,6 +46,7 @@ public:
|
||||||
|
|
||||||
virtual void update(const quint64& now);
|
virtual void update(const quint64& now);
|
||||||
virtual bool needsToCallUpdate() const;
|
virtual bool needsToCallUpdate() const;
|
||||||
|
void computeShapeInfo(ShapeInfo& info) const;
|
||||||
virtual void debugDump() const;
|
virtual void debugDump() const;
|
||||||
|
|
||||||
|
|
||||||
|
|
190
libraries/networking/src/BandwidthRecorder.cpp
Normal file
190
libraries/networking/src/BandwidthRecorder.cpp
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
//
|
||||||
|
// BandwidthMeter.cpp
|
||||||
|
// interface/src/ui
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2015-1-30
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Based on code by Tobias Schwinger
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include "BandwidthRecorder.h"
|
||||||
|
|
||||||
|
|
||||||
|
BandwidthRecorder::Channel::Channel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() {
|
||||||
|
float delt = _input.getEventDeltaAverage();
|
||||||
|
if (delt > 0.0f) {
|
||||||
|
return (1.0 / delt);
|
||||||
|
}
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() {
|
||||||
|
float delt = _input.getEventDeltaAverage();
|
||||||
|
if (delt > 0.0f) {
|
||||||
|
return (1.0 / _output.getEventDeltaAverage());
|
||||||
|
}
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::Channel::getAverageInputKilobitsPerSecond() {
|
||||||
|
return (_input.getAverageSampleValuePerSecond() * (8.0f / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::Channel::getAverageOutputKilobitsPerSecond() {
|
||||||
|
return (_output.getAverageSampleValuePerSecond() * (8.0f / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BandwidthRecorder::Channel::updateInputAverage(const float sample) {
|
||||||
|
_input.updateAverage(sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BandwidthRecorder::Channel::updateOutputAverage(const float sample) {
|
||||||
|
_output.updateAverage(sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
BandwidthRecorder::BandwidthRecorder() {
|
||||||
|
for (uint i=0; i<CHANNEL_COUNT; i++) {
|
||||||
|
_channels[ i ] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BandwidthRecorder::~BandwidthRecorder() {
|
||||||
|
for (uint i=0; i<CHANNEL_COUNT; i++) {
|
||||||
|
delete _channels[ i ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BandwidthRecorder::updateInboundData(const quint8 channelType, const int sample) {
|
||||||
|
if (! _channels[channelType]) {
|
||||||
|
_channels[channelType] = new Channel();
|
||||||
|
}
|
||||||
|
_channels[channelType]->updateInputAverage(sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BandwidthRecorder::updateOutboundData(const quint8 channelType, const int sample) {
|
||||||
|
if (! _channels[channelType]) {
|
||||||
|
_channels[channelType] = new Channel();
|
||||||
|
}
|
||||||
|
_channels[channelType]->updateOutputAverage(sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getAverageInputPacketsPerSecond(const quint8 channelType) {
|
||||||
|
if (! _channels[channelType]) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
return _channels[channelType]->getAverageInputPacketsPerSecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getAverageOutputPacketsPerSecond(const quint8 channelType) {
|
||||||
|
if (! _channels[channelType]) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
return _channels[channelType]->getAverageOutputPacketsPerSecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getAverageInputKilobitsPerSecond(const quint8 channelType) {
|
||||||
|
if (! _channels[channelType]) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
return _channels[channelType]->getAverageInputKilobitsPerSecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getAverageOutputKilobitsPerSecond(const quint8 channelType) {
|
||||||
|
if (! _channels[channelType]) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
return _channels[channelType]->getAverageOutputKilobitsPerSecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getTotalAverageInputPacketsPerSecond() {
|
||||||
|
float result = 0.0f;
|
||||||
|
for (uint i=0; i<CHANNEL_COUNT; i++) {
|
||||||
|
if (_channels[i]) {
|
||||||
|
result += _channels[i]->getAverageInputPacketsPerSecond();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getTotalAverageOutputPacketsPerSecond() {
|
||||||
|
float result = 0.0f;
|
||||||
|
for (uint i=0; i<CHANNEL_COUNT; i++) {
|
||||||
|
if (_channels[i]) {
|
||||||
|
result += _channels[i]->getAverageOutputPacketsPerSecond();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getTotalAverageInputKilobitsPerSecond(){
|
||||||
|
float result = 0.0f;
|
||||||
|
for (uint i=0; i<CHANNEL_COUNT; i++) {
|
||||||
|
if (_channels[i]) {
|
||||||
|
result += _channels[i]->getAverageInputKilobitsPerSecond();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getTotalAverageOutputKilobitsPerSecond(){
|
||||||
|
float result = 0.0f;
|
||||||
|
for (uint i=0; i<CHANNEL_COUNT; i++) {
|
||||||
|
if (_channels[i]) {
|
||||||
|
result += _channels[i]->getAverageOutputKilobitsPerSecond();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getCachedTotalAverageInputPacketsPerSecond() {
|
||||||
|
static qint64 lastCalculated = 0;
|
||||||
|
static float cachedValue = 0.0f;
|
||||||
|
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
if (now - lastCalculated > 1000.0f) {
|
||||||
|
lastCalculated = now;
|
||||||
|
cachedValue = getTotalAverageInputPacketsPerSecond();
|
||||||
|
}
|
||||||
|
return cachedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getCachedTotalAverageOutputPacketsPerSecond() {
|
||||||
|
static qint64 lastCalculated = 0;
|
||||||
|
static float cachedValue = 0.0f;
|
||||||
|
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
if (now - lastCalculated > 1000.0f) {
|
||||||
|
lastCalculated = now;
|
||||||
|
cachedValue = getTotalAverageOutputPacketsPerSecond();
|
||||||
|
}
|
||||||
|
return cachedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getCachedTotalAverageInputKilobitsPerSecond() {
|
||||||
|
static qint64 lastCalculated = 0;
|
||||||
|
static float cachedValue = 0.0f;
|
||||||
|
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
if (now - lastCalculated > 1000.0f) {
|
||||||
|
lastCalculated = now;
|
||||||
|
cachedValue = getTotalAverageInputKilobitsPerSecond();
|
||||||
|
}
|
||||||
|
return cachedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BandwidthRecorder::getCachedTotalAverageOutputKilobitsPerSecond() {
|
||||||
|
static qint64 lastCalculated = 0;
|
||||||
|
static float cachedValue = 0.0f;
|
||||||
|
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
if (now - lastCalculated > 1000.0f) {
|
||||||
|
lastCalculated = now;
|
||||||
|
cachedValue = getTotalAverageOutputKilobitsPerSecond();
|
||||||
|
}
|
||||||
|
return cachedValue;
|
||||||
|
}
|
77
libraries/networking/src/BandwidthRecorder.h
Normal file
77
libraries/networking/src/BandwidthRecorder.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
//
|
||||||
|
// BandwidthRecorder.h
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2015-1-30
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Based on code by Tobias Schwinger
|
||||||
|
//
|
||||||
|
// 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_BandwidthRecorder_h
|
||||||
|
#define hifi_BandwidthRecorder_h
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <QTimer>
|
||||||
|
#include "DependencyManager.h"
|
||||||
|
#include "Node.h"
|
||||||
|
#include "SimpleMovingAverage.h"
|
||||||
|
|
||||||
|
|
||||||
|
class BandwidthRecorder : public QObject, public Dependency {
|
||||||
|
Q_OBJECT
|
||||||
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
|
public:
|
||||||
|
BandwidthRecorder();
|
||||||
|
~BandwidthRecorder();
|
||||||
|
|
||||||
|
// keep track of data rate in two directions as well as units and style to use during display
|
||||||
|
class Channel {
|
||||||
|
public:
|
||||||
|
Channel();
|
||||||
|
float getAverageInputPacketsPerSecond();
|
||||||
|
float getAverageOutputPacketsPerSecond();
|
||||||
|
float getAverageInputKilobitsPerSecond();
|
||||||
|
float getAverageOutputKilobitsPerSecond();
|
||||||
|
|
||||||
|
void updateInputAverage(const float sample);
|
||||||
|
void updateOutputAverage(const float sample);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SimpleMovingAverage _input = SimpleMovingAverage();
|
||||||
|
SimpleMovingAverage _output = SimpleMovingAverage();
|
||||||
|
};
|
||||||
|
|
||||||
|
float getAverageInputPacketsPerSecond(const quint8 channelType);
|
||||||
|
float getAverageOutputPacketsPerSecond(const quint8 channelType);
|
||||||
|
float getAverageInputKilobitsPerSecond(const quint8 channelType);
|
||||||
|
float getAverageOutputKilobitsPerSecond(const quint8 channelType);
|
||||||
|
|
||||||
|
float getTotalAverageInputPacketsPerSecond();
|
||||||
|
float getTotalAverageOutputPacketsPerSecond();
|
||||||
|
float getTotalAverageInputKilobitsPerSecond();
|
||||||
|
float getTotalAverageOutputKilobitsPerSecond();
|
||||||
|
|
||||||
|
float getCachedTotalAverageInputPacketsPerSecond();
|
||||||
|
float getCachedTotalAverageOutputPacketsPerSecond();
|
||||||
|
float getCachedTotalAverageInputKilobitsPerSecond();
|
||||||
|
float getCachedTotalAverageOutputKilobitsPerSecond();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
// one for each possible Node type
|
||||||
|
static const unsigned int CHANNEL_COUNT = 256;
|
||||||
|
Channel* _channels[CHANNEL_COUNT];
|
||||||
|
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateInboundData(const quint8 channelType, const int bytes);
|
||||||
|
void updateOutboundData(const quint8 channelType, const int bytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -47,8 +47,6 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
||||||
_localSockAddr(),
|
_localSockAddr(),
|
||||||
_publicSockAddr(),
|
_publicSockAddr(),
|
||||||
_stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT),
|
_stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT),
|
||||||
_numCollectedPackets(0),
|
|
||||||
_numCollectedBytes(0),
|
|
||||||
_packetStatTimer()
|
_packetStatTimer()
|
||||||
{
|
{
|
||||||
static bool firstCall = true;
|
static bool firstCall = true;
|
||||||
|
@ -210,6 +208,21 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// qint64 LimitedNodeList::readDatagram(char* data, qint64 maxSize, QHostAddress* address = 0, quint16 * port = 0) {
|
||||||
|
|
||||||
|
qint64 LimitedNodeList::readDatagram(QByteArray& incomingPacket, QHostAddress* address = 0, quint16 * port = 0) {
|
||||||
|
qint64 result = getNodeSocket().readDatagram(incomingPacket.data(), incomingPacket.size(), address, port);
|
||||||
|
|
||||||
|
SharedNodePointer sendingNode = sendingNodeForPacket(incomingPacket);
|
||||||
|
if (sendingNode) {
|
||||||
|
emit dataReceived(sendingNode->getType(), incomingPacket.size());
|
||||||
|
} else {
|
||||||
|
emit dataReceived(NodeType::Unassigned, incomingPacket.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr,
|
qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr,
|
||||||
const QUuid& connectionSecret) {
|
const QUuid& connectionSecret) {
|
||||||
QByteArray datagramCopy = datagram;
|
QByteArray datagramCopy = datagram;
|
||||||
|
@ -219,6 +232,7 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSock
|
||||||
replaceHashInPacketGivenConnectionUUID(datagramCopy, connectionSecret);
|
replaceHashInPacketGivenConnectionUUID(datagramCopy, connectionSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX can BandwidthRecorder be used for this?
|
||||||
// stat collection for packets
|
// stat collection for packets
|
||||||
++_numCollectedPackets;
|
++_numCollectedPackets;
|
||||||
_numCollectedBytes += datagram.size();
|
_numCollectedBytes += datagram.size();
|
||||||
|
@ -233,10 +247,11 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSock
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
|
qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram,
|
||||||
|
const SharedNodePointer& destinationNode,
|
||||||
const HifiSockAddr& overridenSockAddr) {
|
const HifiSockAddr& overridenSockAddr) {
|
||||||
if (destinationNode) {
|
if (destinationNode) {
|
||||||
// if we don't have an ovveriden address, assume they want to send to the node's active socket
|
// if we don't have an overridden address, assume they want to send to the node's active socket
|
||||||
const HifiSockAddr* destinationSockAddr = &overridenSockAddr;
|
const HifiSockAddr* destinationSockAddr = &overridenSockAddr;
|
||||||
if (overridenSockAddr.isNull()) {
|
if (overridenSockAddr.isNull()) {
|
||||||
if (destinationNode->getActiveSocket()) {
|
if (destinationNode->getActiveSocket()) {
|
||||||
|
@ -248,6 +263,8 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const SharedNo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit dataSent(destinationNode->getType(), datagram.size());
|
||||||
|
|
||||||
return writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret());
|
return writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +322,6 @@ int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& match
|
||||||
QMutexLocker locker(&matchingNode->getMutex());
|
QMutexLocker locker(&matchingNode->getMutex());
|
||||||
|
|
||||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
matchingNode->recordBytesReceived(packet.size());
|
|
||||||
|
|
||||||
if (!matchingNode->getLinkedData() && linkedDataCreateCallback) {
|
if (!matchingNode->getLinkedData() && linkedDataCreateCallback) {
|
||||||
linkedDataCreateCallback(matchingNode.data());
|
linkedDataCreateCallback(matchingNode.data());
|
||||||
|
|
|
@ -83,6 +83,8 @@ public:
|
||||||
|
|
||||||
bool packetVersionAndHashMatch(const QByteArray& packet);
|
bool packetVersionAndHashMatch(const QByteArray& packet);
|
||||||
|
|
||||||
|
qint64 readDatagram(QByteArray& incomingPacket, QHostAddress* address, quint16 * port);
|
||||||
|
|
||||||
qint64 writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
|
qint64 writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
|
||||||
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
|
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
|
||||||
|
|
||||||
|
@ -181,6 +183,9 @@ signals:
|
||||||
void localSockAddrChanged(const HifiSockAddr& localSockAddr);
|
void localSockAddrChanged(const HifiSockAddr& localSockAddr);
|
||||||
void publicSockAddrChanged(const HifiSockAddr& publicSockAddr);
|
void publicSockAddrChanged(const HifiSockAddr& publicSockAddr);
|
||||||
|
|
||||||
|
void dataSent(const quint8 channel_type, const int bytes);
|
||||||
|
void dataReceived(const quint8 channel_type, const int bytes);
|
||||||
|
|
||||||
void packetVersionMismatch();
|
void packetVersionMismatch();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -203,8 +208,11 @@ protected:
|
||||||
HifiSockAddr _localSockAddr;
|
HifiSockAddr _localSockAddr;
|
||||||
HifiSockAddr _publicSockAddr;
|
HifiSockAddr _publicSockAddr;
|
||||||
HifiSockAddr _stunSockAddr;
|
HifiSockAddr _stunSockAddr;
|
||||||
|
|
||||||
|
// XXX can BandwidthRecorder be used for this?
|
||||||
int _numCollectedPackets;
|
int _numCollectedPackets;
|
||||||
int _numCollectedBytes;
|
int _numCollectedBytes;
|
||||||
|
|
||||||
QElapsedTimer _packetStatTimer;
|
QElapsedTimer _packetStatTimer;
|
||||||
|
|
||||||
template<typename IteratorLambda>
|
template<typename IteratorLambda>
|
||||||
|
|
|
@ -47,7 +47,6 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket,
|
||||||
_activeSocket(NULL),
|
_activeSocket(NULL),
|
||||||
_symmetricSocket(),
|
_symmetricSocket(),
|
||||||
_connectionSecret(),
|
_connectionSecret(),
|
||||||
_bytesReceivedMovingAverage(NULL),
|
|
||||||
_linkedData(NULL),
|
_linkedData(NULL),
|
||||||
_isAlive(true),
|
_isAlive(true),
|
||||||
_pingMs(-1), // "Uninitialized"
|
_pingMs(-1), // "Uninitialized"
|
||||||
|
@ -60,31 +59,6 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket,
|
||||||
|
|
||||||
Node::~Node() {
|
Node::~Node() {
|
||||||
delete _linkedData;
|
delete _linkedData;
|
||||||
delete _bytesReceivedMovingAverage;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Node::recordBytesReceived(int bytesReceived) {
|
|
||||||
if (!_bytesReceivedMovingAverage) {
|
|
||||||
_bytesReceivedMovingAverage = new SimpleMovingAverage(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
_bytesReceivedMovingAverage->updateAverage((float) bytesReceived);
|
|
||||||
}
|
|
||||||
|
|
||||||
float Node::getAveragePacketsPerSecond() {
|
|
||||||
if (_bytesReceivedMovingAverage) {
|
|
||||||
return (1 / _bytesReceivedMovingAverage->getEventDeltaAverage());
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float Node::getAverageKilobitsPerSecond() {
|
|
||||||
if (_bytesReceivedMovingAverage) {
|
|
||||||
return (_bytesReceivedMovingAverage->getAverageSampleValuePerSecond() * (8.0f / 1000));
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::updateClockSkewUsec(int clockSkewSample) {
|
void Node::updateClockSkewUsec(int clockSkewSample) {
|
||||||
|
|
|
@ -63,10 +63,6 @@ public:
|
||||||
bool isAlive() const { return _isAlive; }
|
bool isAlive() const { return _isAlive; }
|
||||||
void setAlive(bool isAlive) { _isAlive = isAlive; }
|
void setAlive(bool isAlive) { _isAlive = isAlive; }
|
||||||
|
|
||||||
void recordBytesReceived(int bytesReceived);
|
|
||||||
float getAverageKilobitsPerSecond();
|
|
||||||
float getAveragePacketsPerSecond();
|
|
||||||
|
|
||||||
int getPingMs() const { return _pingMs; }
|
int getPingMs() const { return _pingMs; }
|
||||||
void setPingMs(int pingMs) { _pingMs = pingMs; }
|
void setPingMs(int pingMs) { _pingMs = pingMs; }
|
||||||
|
|
||||||
|
@ -99,7 +95,6 @@ private:
|
||||||
HifiSockAddr _symmetricSocket;
|
HifiSockAddr _symmetricSocket;
|
||||||
|
|
||||||
QUuid _connectionSecret;
|
QUuid _connectionSecret;
|
||||||
SimpleMovingAverage* _bytesReceivedMovingAverage;
|
|
||||||
NodeData* _linkedData;
|
NodeData* _linkedData;
|
||||||
bool _isAlive;
|
bool _isAlive;
|
||||||
int _pingMs;
|
int _pingMs;
|
||||||
|
|
|
@ -83,6 +83,7 @@ void ThreadedAssignment::addPacketStatsAndSendStatsPacket(QJsonObject &statsObje
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
float packetsPerSecond, bytesPerSecond;
|
float packetsPerSecond, bytesPerSecond;
|
||||||
|
// XXX can BandwidthRecorder be used for this?
|
||||||
nodeList->getPacketStats(packetsPerSecond, bytesPerSecond);
|
nodeList->getPacketStats(packetsPerSecond, bytesPerSecond);
|
||||||
nodeList->resetPacketStats();
|
nodeList->resetPacketStats();
|
||||||
|
|
||||||
|
|
14
tools/refresh-tags.sh
Executable file
14
tools/refresh-tags.sh
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
rm -f TAGS
|
||||||
|
|
||||||
|
find . -name *.h -print | while read I
|
||||||
|
do
|
||||||
|
etags --append "$I"
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
find . -name *.cpp -print | grep -v 'moc_' | while read I
|
||||||
|
do
|
||||||
|
etags --append "$I"
|
||||||
|
done
|
Loading…
Reference in a new issue