mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
introduces bandwidth meter / dialog
This commit is contained in:
parent
517ff0f3cf
commit
290c20bfc7
11 changed files with 527 additions and 23 deletions
|
@ -70,7 +70,7 @@ include(${QT_USE_FILE})
|
|||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}")
|
||||
|
||||
# run qt moc on qt-enabled headers
|
||||
qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h src/Webcam.h)
|
||||
qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h src/Webcam.h src/ui/BandwidthDialog.h)
|
||||
|
||||
# create the executable, make it a bundle on OS X
|
||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS})
|
||||
|
|
|
@ -131,6 +131,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
QApplication(argc, argv),
|
||||
_window(new QMainWindow(desktop())),
|
||||
_glWidget(new GLCanvas()),
|
||||
_bandwidthDialog(NULL),
|
||||
_displayLevels(false),
|
||||
_frameCount(0),
|
||||
_fps(120.0f),
|
||||
|
@ -423,11 +424,30 @@ void Application::resizeGL(int width, int height) {
|
|||
glLoadIdentity();
|
||||
}
|
||||
|
||||
static void sendVoxelServerAddScene() {
|
||||
void Application::broadcastToAgents(unsigned char* data, size_t bytes, const char type) {
|
||||
|
||||
int n = AgentList::getInstance()->broadcastToAgents(data, bytes, &type, 1);
|
||||
|
||||
unsigned channel;
|
||||
switch (type) {
|
||||
case AGENT_TYPE_AVATAR:
|
||||
case AGENT_TYPE_AVATAR_MIXER:
|
||||
channel = 1;
|
||||
break;
|
||||
case AGENT_TYPE_VOXEL_SERVER:
|
||||
channel = 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
getInstance()->_bandwidthMeter.outputStream(channel).updateValue(n * bytes);
|
||||
}
|
||||
|
||||
void Application::sendVoxelServerAddScene() {
|
||||
char message[100];
|
||||
sprintf(message,"%c%s",'Z',"add scene");
|
||||
int messageSize = strlen(message) + 1;
|
||||
AgentList::getInstance()->broadcastToAgents((unsigned char*)message, messageSize, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
broadcastToAgents((unsigned char*)message, messageSize, AGENT_TYPE_VOXEL_SERVER);
|
||||
}
|
||||
|
||||
void Application::keyPressEvent(QKeyEvent* event) {
|
||||
|
@ -833,7 +853,7 @@ void Application::terminate() {
|
|||
}
|
||||
}
|
||||
|
||||
static void sendAvatarVoxelURLMessage(const QUrl& url) {
|
||||
void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
|
||||
uint16_t ownerID = AgentList::getInstance()->getOwnerID();
|
||||
|
||||
if (ownerID == UNKNOWN_AGENT_ID) {
|
||||
|
@ -844,10 +864,10 @@ static void sendAvatarVoxelURLMessage(const QUrl& url) {
|
|||
message.append((const char*)&ownerID, sizeof(ownerID));
|
||||
message.append(url.toEncoded());
|
||||
|
||||
AgentList::getInstance()->broadcastToAgents((unsigned char*)message.data(), message.size(), &AGENT_TYPE_AVATAR_MIXER, 1);
|
||||
broadcastToAgents((unsigned char*)message.data(), message.size(), AGENT_TYPE_AVATAR_MIXER);
|
||||
}
|
||||
|
||||
static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes) {
|
||||
void Application::processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes) {
|
||||
// skip the header
|
||||
packetData++;
|
||||
dataBytes--;
|
||||
|
@ -872,6 +892,24 @@ static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataB
|
|||
QMetaObject::invokeMethod(avatar->getVoxels(), "setVoxelURL", Q_ARG(QUrl, url));
|
||||
}
|
||||
|
||||
void Application::bandwidthDetails() {
|
||||
|
||||
if (! _bandwidthDialog) {
|
||||
_bandwidthDialog = new BandwidthDialog(_glWidget, getBandwidthMeter());
|
||||
_bandwidthDialog->show();
|
||||
}
|
||||
_bandwidthDialog->raise();
|
||||
|
||||
connect(_bandwidthDialog, SIGNAL(closed()), SLOT(bandwidthDetailsClosed()));
|
||||
}
|
||||
|
||||
void Application::bandwidthDetailsClosed() {
|
||||
|
||||
QDialog* dlg = _bandwidthDialog;
|
||||
_bandwidthDialog = NULL;
|
||||
delete dlg;
|
||||
}
|
||||
|
||||
void Application::editPreferences() {
|
||||
QDialog dialog(_glWidget);
|
||||
dialog.setWindowTitle("Interface Preferences");
|
||||
|
@ -1024,12 +1062,12 @@ void Application::updateVoxelModeActions() {
|
|||
}
|
||||
}
|
||||
|
||||
static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
|
||||
void Application::sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
|
||||
unsigned char* bufferOut;
|
||||
int sizeOut;
|
||||
|
||||
if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){
|
||||
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
Application::broadcastToAgents(bufferOut, sizeOut, AGENT_TYPE_VOXEL_SERVER);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
}
|
||||
|
@ -1104,7 +1142,7 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
|
|||
|
||||
// if we have room don't have room in the buffer, then send the previously generated message first
|
||||
if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) {
|
||||
AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
broadcastToAgents(args->messageBuffer, args->bufferInUse, AGENT_TYPE_VOXEL_SERVER);
|
||||
args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // reset
|
||||
}
|
||||
|
||||
|
@ -1168,7 +1206,7 @@ void Application::importVoxels() {
|
|||
|
||||
// If we have voxels left in the packet, then send the packet
|
||||
if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) {
|
||||
AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
broadcastToAgents(args.messageBuffer, args.bufferInUse, AGENT_TYPE_VOXEL_SERVER);
|
||||
}
|
||||
|
||||
if (calculatedOctCode) {
|
||||
|
@ -1220,7 +1258,7 @@ void Application::pasteVoxels() {
|
|||
|
||||
// If we have voxels left in the packet, then send the packet
|
||||
if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) {
|
||||
AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
broadcastToAgents(args.messageBuffer, args.bufferInUse, AGENT_TYPE_VOXEL_SERVER);
|
||||
}
|
||||
|
||||
if (calculatedOctCode) {
|
||||
|
@ -1290,7 +1328,9 @@ void Application::initMenu() {
|
|||
(_logOn = toolsMenu->addAction("Log"))->setCheckable(true);
|
||||
_logOn->setChecked(false);
|
||||
_logOn->setShortcut(Qt::CTRL | Qt::Key_L);
|
||||
|
||||
toolsMenu->addAction("Bandwidth Details", this, SLOT(bandwidthDetails()));
|
||||
|
||||
|
||||
QMenu* voxelMenu = menuBar->addMenu("Voxels");
|
||||
_voxelModeActions = new QActionGroup(this);
|
||||
_voxelModeActions->setExclusive(false); // exclusivity implies one is always checked
|
||||
|
@ -1643,7 +1683,12 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update bandwidth dialog, if any
|
||||
if (_bandwidthDialog) {
|
||||
_bandwidthDialog->update();
|
||||
}
|
||||
|
||||
// Update audio stats for procedural sounds
|
||||
#ifndef _WIN32
|
||||
_audio.setLastAcceleration(_myAvatar.getThrust());
|
||||
|
@ -1727,8 +1772,8 @@ void Application::updateAvatar(float deltaTime) {
|
|||
|
||||
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
|
||||
|
||||
const char broadcastReceivers[2] = {AGENT_TYPE_VOXEL_SERVER, AGENT_TYPE_AVATAR_MIXER};
|
||||
AgentList::getInstance()->broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, broadcastReceivers, sizeof(broadcastReceivers));
|
||||
broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, AGENT_TYPE_VOXEL_SERVER);
|
||||
broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, AGENT_TYPE_AVATAR_MIXER);
|
||||
|
||||
// once in a while, send my voxel url
|
||||
const float AVATAR_VOXEL_URL_SEND_INTERVAL = 1.0f; // seconds
|
||||
|
@ -2116,6 +2161,8 @@ void Application::displayOverlay() {
|
|||
glPointSize(1.0f);
|
||||
|
||||
if (_renderStatsOn->isChecked()) { displayStats(); }
|
||||
|
||||
_bandwidthMeter.render(_glWidget->width() - 400, 40, 380, 42 * BandwidthMeter::N_CHANNELS);
|
||||
if (_logOn->isChecked()) { LogDisplay::instance.render(_glWidget->width(), _glWidget->height()); }
|
||||
|
||||
// Show chat entry field
|
||||
|
@ -2612,6 +2659,7 @@ void* Application::networkReceive(void* args) {
|
|||
AgentList::getInstance()->processBulkAgentData(&senderAddress,
|
||||
app->_incomingPacket,
|
||||
bytesReceived);
|
||||
getInstance()->_bandwidthMeter.inputStream(1).updateValue(bytesReceived);
|
||||
break;
|
||||
case PACKET_HEADER_AVATAR_VOXEL_URL:
|
||||
processAvatarVoxelURLMessage(app->_incomingPacket, bytesReceived);
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
|
||||
#include <AgentList.h>
|
||||
|
||||
#include "BandwidthMeter.h"
|
||||
#include "ui/BandwidthDialog.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "Audio.h"
|
||||
#endif
|
||||
|
@ -31,6 +34,7 @@
|
|||
#include "Stars.h"
|
||||
#include "ViewFrustum.h"
|
||||
#include "VoxelSystem.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "Webcam.h"
|
||||
#include "ui/ChatEntry.h"
|
||||
|
||||
|
@ -77,6 +81,7 @@ public:
|
|||
QSettings* getSettings() { return _settings; }
|
||||
Environment* getEnvironment() { return &_environment; }
|
||||
Webcam* getWebcam() { return &_webcam; }
|
||||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||
bool shouldEchoAudio() { return _echoAudioMode->isChecked(); }
|
||||
|
||||
QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; }
|
||||
|
@ -86,8 +91,10 @@ private slots:
|
|||
void timer();
|
||||
void idle();
|
||||
void terminate();
|
||||
|
||||
|
||||
void bandwidthDetails();
|
||||
void editPreferences();
|
||||
void bandwidthDetailsClosed();
|
||||
|
||||
void pair();
|
||||
|
||||
|
@ -133,7 +140,12 @@ private slots:
|
|||
void runTests();
|
||||
private:
|
||||
|
||||
static void broadcastToAgents(unsigned char* data, size_t bytes, const char type);
|
||||
static void sendVoxelServerAddScene();
|
||||
static bool sendVoxelsOperation(VoxelNode* node, void* extraData);
|
||||
static void sendAvatarVoxelURLMessage(const QUrl& url);
|
||||
static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes);
|
||||
static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail);
|
||||
|
||||
void initMenu();
|
||||
void updateFrustumRenderModeAction();
|
||||
|
@ -210,6 +222,9 @@ private:
|
|||
QAction* _frustumRenderModeAction;
|
||||
QAction* _settingsAutosave; // Whether settings are saved automatically
|
||||
|
||||
BandwidthMeter _bandwidthMeter;
|
||||
BandwidthDialog* _bandwidthDialog;
|
||||
|
||||
SerialInterface _serialHeadSensor;
|
||||
QNetworkAccessManager* _networkAccessManager;
|
||||
QSettings* _settings;
|
||||
|
@ -224,7 +239,7 @@ private:
|
|||
timeval _timerStart, _timerEnd;
|
||||
timeval _lastTimeIdle;
|
||||
bool _justStarted;
|
||||
|
||||
|
||||
Stars _stars;
|
||||
|
||||
VoxelSystem _voxels;
|
||||
|
|
|
@ -143,10 +143,12 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
|
|||
|
||||
// copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet
|
||||
memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
||||
|
||||
agentList->getAgentSocket()->send(audioMixer->getActiveSocket(),
|
||||
dataPacket,
|
||||
BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
||||
|
||||
interface->getBandwidthMeter()->outputStream(0)
|
||||
.updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -423,9 +425,12 @@ void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBy
|
|||
if (_packetsReceivedThisPlayback == 1) {
|
||||
gettimeofday(&_firstPlaybackTime, NULL);
|
||||
}
|
||||
|
||||
|
||||
_ringBuffer.parseData((unsigned char*) receivedData, PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER));
|
||||
|
||||
|
||||
Application::getInstance()->getBandwidthMeter()->inputStream(0)
|
||||
.updateValue(PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER));
|
||||
|
||||
_lastReceiveTime = currentReceiveTime;
|
||||
}
|
||||
|
||||
|
|
217
interface/src/BandwidthMeter.cpp
Normal file
217
interface/src/BandwidthMeter.cpp
Normal file
|
@ -0,0 +1,217 @@
|
|||
//
|
||||
// BandwidthMeter.h
|
||||
// interface
|
||||
//
|
||||
// Created by Tobias Schwinger on 6/20/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "BandwidthMeter.h"
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
|
||||
// --- Configuration
|
||||
|
||||
// Layout:
|
||||
//
|
||||
// +--- unit label width (e)
|
||||
// | +-- unit label horiz. spacing (f)
|
||||
// V V
|
||||
// | | |
|
||||
// +--------+ \ \ Channel
|
||||
// Unit +-------+ | Total channel height (a) / height (d)
|
||||
// | / ] Channel spacing (b)
|
||||
// +----+
|
||||
// Unit +------+
|
||||
// |
|
||||
// ...
|
||||
//
|
||||
|
||||
namespace { // .cpp-local
|
||||
|
||||
float const CHANNEL_SPACING = 0.125f; // (b) fractional in respect to total channel height
|
||||
float const STREAM_SPACING = 0.0625f; // (c) fractional in respect to total channel height
|
||||
float const LABEL_CHAR_WIDTH = 0.30f; // (e) fractional in respect to total channel height
|
||||
float const LABEL_HORIZ_SPACING = 0.25f; // (f) fractional in respect to total channel height
|
||||
float const LABEL_VERT_PADDING = 0.035f; // fractional in respect to total channel height / 2
|
||||
|
||||
unsigned const FRAME_COLOR = 0xe0e0e0b0;
|
||||
unsigned const INDICATOR_COLOR = 0xc0c0c0b0;
|
||||
unsigned const VALUE_COLOR = 0xa0a0a0e0;
|
||||
float const INDICATOR_BASE = 10.0f;
|
||||
float const INDICATOR_LOG_BASE = log(INDICATOR_BASE);
|
||||
}
|
||||
|
||||
BandwidthMeter::ChannelInfo BandwidthMeter::_DEFAULT_CHANNELS[] = {
|
||||
{ "Audio" , "Mbps", 1024.0 * 1024.0, 2.5, 0x40ff40d0 },
|
||||
{ "Avatars" , "KBps", 1.0 * 1024.0, 20.0, 0xffef40c0 },
|
||||
{ "Voxels" , "Mbps", 1024.0 * 1024.0, 0.5, 0xd0d0d0a0 }
|
||||
};
|
||||
|
||||
// ---
|
||||
|
||||
BandwidthMeter::BandwidthMeter() :
|
||||
_textRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT) {
|
||||
|
||||
memcpy(_channels, _DEFAULT_CHANNELS, sizeof(_DEFAULT_CHANNELS));
|
||||
}
|
||||
|
||||
BandwidthMeter::Stream::Stream(float secondsToAverage) :
|
||||
_value(0.0f),
|
||||
_secsToAverage(secondsToAverage) {
|
||||
|
||||
gettimeofday(& _prevTime, NULL);
|
||||
}
|
||||
|
||||
void BandwidthMeter::Stream::updateValue(double amount) {
|
||||
|
||||
// Determine elapsed time
|
||||
timeval now;
|
||||
gettimeofday(& now, NULL);
|
||||
double dt = diffclock(& _prevTime, & now) / 1000.0;
|
||||
memcpy(& _prevTime, & now, sizeof(timeval));
|
||||
|
||||
// Compute approximate average
|
||||
_value = glm::mix(_value, amount / dt,
|
||||
glm::clamp(dt / _secsToAverage, 0.0, 1.0));
|
||||
}
|
||||
|
||||
static void setColorRGBA(unsigned c) {
|
||||
|
||||
glColor4ub(GLubyte( c >> 24),
|
||||
GLubyte((c >> 16) & 0xff),
|
||||
GLubyte((c >> 8) & 0xff),
|
||||
GLubyte( c & 0xff));
|
||||
}
|
||||
|
||||
static void renderBox(float w, float h) {
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(0.0f, 0.0f);
|
||||
glVertex2f(w, 0.0f);
|
||||
glVertex2f(w, h);
|
||||
glVertex2f(0.0f, h);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void BandwidthMeter::render(int x, int y, unsigned w, unsigned h) {
|
||||
|
||||
float channelTotalHeight = float(h) / N_CHANNELS;
|
||||
float channelSpacing = CHANNEL_SPACING * channelTotalHeight;
|
||||
float channelHeight = channelTotalHeight - channelSpacing;
|
||||
float streamSpacing = STREAM_SPACING * channelTotalHeight;
|
||||
float streamHeight = (channelHeight - streamSpacing) * 0.5;
|
||||
|
||||
QFontMetrics const& fontMetrics = _textRenderer.metrics();
|
||||
int fontDescent = fontMetrics.descent();
|
||||
int labelRenderWidthCaption = 0;
|
||||
int labelRenderWidthUnit = 0;
|
||||
for (int i = 0; i < N_CHANNELS; ++i) {
|
||||
labelRenderWidthCaption = glm::max(labelRenderWidthCaption, fontMetrics.width(_channels[i].caption));
|
||||
labelRenderWidthUnit = glm::max(labelRenderWidthUnit, fontMetrics.width(_channels[i].unitCaption));
|
||||
}
|
||||
int labelRenderWidth = glm::max(labelRenderWidthCaption, labelRenderWidthUnit);
|
||||
int labelRenderHeight = fontMetrics.lineSpacing();
|
||||
float labelCharWSpaces = float(labelRenderWidth) / float(fontMetrics.width("M"));
|
||||
float labelWidth = channelTotalHeight * LABEL_CHAR_WIDTH * labelCharWSpaces;
|
||||
float labelHeight = channelTotalHeight * (1.0f - LABEL_VERT_PADDING);
|
||||
float labelTextHeight = labelHeight * 0.5f;
|
||||
|
||||
float labelScaleX = labelWidth / float(labelRenderWidth);
|
||||
float labelScaleY = labelTextHeight / float(labelRenderHeight);
|
||||
float labelHorizSpacing = channelTotalHeight * LABEL_HORIZ_SPACING;
|
||||
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
int xMin = x + int(labelWidth + labelHorizSpacing);
|
||||
|
||||
// Render vertical lines for the frame
|
||||
setColorRGBA(FRAME_COLOR);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2i(xMin - 1, y);
|
||||
glVertex2i(xMin - 1, y + h);
|
||||
glVertex2i(x + w - 1, y);
|
||||
glVertex2i(x + w - 1, y + h);
|
||||
glEnd();
|
||||
|
||||
// Set coordinate center to right edge of bars / top
|
||||
glTranslatef(float(xMin), float(y) + channelSpacing * 0.5f, 0.0f);
|
||||
|
||||
// Determine maximum horizontal length for bars
|
||||
float xMax = float(w) - labelWidth - labelHorizSpacing;
|
||||
|
||||
char fmtBuf[64];
|
||||
|
||||
for (int i = 0; i < N_CHANNELS; ++i) {
|
||||
// ...each channel
|
||||
|
||||
ChannelInfo& c = channelInfo(i);
|
||||
float scaleStep = powf(INDICATOR_BASE, ceil(logf(c.unitsMax) / INDICATOR_LOG_BASE) - 1.0f);
|
||||
|
||||
float unitsIn = inputStream(i).getValue() / c.unitScale;
|
||||
if (unitsIn > c.unitsMax) {
|
||||
c.unitsMax += scaleStep;
|
||||
}
|
||||
float barPosIn = xMax * fmin(unitsIn / c.unitsMax, 1.0f);
|
||||
float unitsOut = outputStream(i).getValue() / c.unitScale;
|
||||
float barPosOut = xMax * fmin(unitsOut / c.unitsMax, 1.0f);
|
||||
|
||||
// Render scale indicators
|
||||
setColorRGBA(INDICATOR_COLOR);
|
||||
for (float meas = scaleStep; meas < c.unitsMax - 0.01f; meas += scaleStep) {
|
||||
float pixX = xMax * meas / c.unitsMax;
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(pixX, 0);
|
||||
glVertex2f(pixX, channelHeight);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// Render captions
|
||||
setColorRGBA(c.colorRGBA);
|
||||
glPushMatrix();
|
||||
glTranslatef(-labelHorizSpacing, channelHeight * 0.5f, 0.0f);
|
||||
glScalef(labelScaleX, labelScaleY, 1.0f);
|
||||
_textRenderer.draw(-labelRenderWidth, -fontDescent, c.caption);
|
||||
_textRenderer.draw(-fontMetrics.width(c.unitCaption), labelRenderHeight - fontDescent, c.unitCaption);
|
||||
glPopMatrix();
|
||||
|
||||
// Render input bar
|
||||
renderBox(barPosIn, streamHeight);
|
||||
|
||||
// Render output value
|
||||
glPushMatrix();
|
||||
setColorRGBA(VALUE_COLOR);
|
||||
glTranslatef(0.0f, streamHeight, 0.0f);
|
||||
glScalef(labelScaleX, labelScaleY, 1.0f);
|
||||
|
||||
sprintf(fmtBuf, "%0.2f in", unitsIn);
|
||||
_textRenderer.draw(glm::max(int(barPosIn) - fontMetrics.width(fmtBuf), 0), -fontDescent, fmtBuf);
|
||||
glPopMatrix();
|
||||
|
||||
// Advance to next stream
|
||||
glTranslatef(0.0f, streamHeight + streamSpacing, 0.0f);
|
||||
|
||||
// Render output bar
|
||||
setColorRGBA(c.colorRGBA);
|
||||
renderBox(barPosOut, streamHeight);
|
||||
|
||||
// Render output value
|
||||
glPushMatrix();
|
||||
setColorRGBA(VALUE_COLOR);
|
||||
glTranslatef(0.0f, streamHeight, 0.0f);
|
||||
glScalef(labelScaleX, labelScaleY, 1.0f);
|
||||
|
||||
sprintf(fmtBuf, "%0.2f out", unitsOut);
|
||||
_textRenderer.draw(glm::max(int(barPosOut) - fontMetrics.width(fmtBuf), 0), -fontDescent, fmtBuf);
|
||||
glPopMatrix();
|
||||
|
||||
// Advance to next channel
|
||||
glTranslatef(0.0f, streamHeight + channelSpacing, 0.0f);
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
72
interface/src/BandwidthMeter.h
Normal file
72
interface/src/BandwidthMeter.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// BandwidthMeter.h
|
||||
// interface
|
||||
//
|
||||
// Created by Tobias Schwinger on 6/20/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__BandwidthMeter__
|
||||
#define __interface__BandwidthMeter__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "ui/TextRenderer.h"
|
||||
|
||||
|
||||
class BandwidthMeter {
|
||||
|
||||
public:
|
||||
|
||||
BandwidthMeter();
|
||||
|
||||
void render(int x, int y, unsigned w, unsigned h);
|
||||
|
||||
// Number of channels / streams.
|
||||
static size_t const N_CHANNELS = 3;
|
||||
static size_t const N_STREAMS = N_CHANNELS * 2;
|
||||
|
||||
// Meta information held for a communication channel (bidirectional).
|
||||
struct ChannelInfo {
|
||||
|
||||
char const* caption;
|
||||
char const* unitCaption;
|
||||
double unitScale;
|
||||
double unitsMax;
|
||||
unsigned colorRGBA;
|
||||
};
|
||||
|
||||
// Representation of a data stream (unidirectional; input or output).
|
||||
class Stream {
|
||||
|
||||
public:
|
||||
|
||||
Stream(float secondsToAverage = 3.0f);
|
||||
void updateValue(double amount);
|
||||
double getValue() const { return _value; }
|
||||
|
||||
private:
|
||||
double _value; // Current value.
|
||||
timeval _prevTime; // Time of last feed.
|
||||
float _secsToAverage; // Seconds to average.
|
||||
};
|
||||
|
||||
// Data model accessors
|
||||
Stream& inputStream(unsigned channelIndex) { return _streams[channelIndex * 2]; }
|
||||
Stream const& inputStream(unsigned channelIndex) const { return _streams[channelIndex * 2]; }
|
||||
Stream& outputStream(unsigned channelIndex) { return _streams[channelIndex * 2 + 1]; }
|
||||
Stream const& outputStream(unsigned channelIndex) const { return _streams[channelIndex * 2 + 1]; }
|
||||
ChannelInfo& channelInfo(unsigned index) { return _channels[index]; }
|
||||
ChannelInfo const& channelInfo(unsigned index) const { return _channels[index]; }
|
||||
|
||||
private:
|
||||
TextRenderer _textRenderer;
|
||||
ChannelInfo _channels[N_CHANNELS];
|
||||
Stream _streams[N_STREAMS];
|
||||
|
||||
static ChannelInfo _DEFAULT_CHANNELS[];
|
||||
static Stream _DEFAULT_STREAMS[];
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__BandwidthMeter__) */
|
||||
|
|
@ -160,7 +160,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
setupNewVoxelsForDrawing();
|
||||
|
||||
pthread_mutex_unlock(&_treeLock);
|
||||
|
||||
|
||||
Application::getInstance()->getBandwidthMeter()->inputStream(2).updateValue(numBytes);
|
||||
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
|
|
91
interface/src/ui/BandwidthDialog.cpp
Normal file
91
interface/src/ui/BandwidthDialog.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
|
||||
#include "ui/BandwidthDialog.h"
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) :
|
||||
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint),
|
||||
_model(model) {
|
||||
|
||||
char strBuf[64];
|
||||
|
||||
this->setWindowTitle("Bandwidth Details");
|
||||
|
||||
// Create layouter
|
||||
QFormLayout* form = new QFormLayout();
|
||||
this->QDialog::setLayout(form);
|
||||
|
||||
// Setup labels
|
||||
for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) {
|
||||
int chIdx = i / 2;
|
||||
bool input = i % 2 == 0;
|
||||
BandwidthMeter::ChannelInfo& ch = _model->channelInfo(chIdx);
|
||||
QLabel* label = _labels[i] = new QLabel();
|
||||
snprintf(strBuf, sizeof(strBuf), "%s %s Bandwidth:", input ? "Input" : "Output", ch.caption);
|
||||
form->addRow(strBuf, label);
|
||||
}
|
||||
|
||||
// Setup spinners
|
||||
for (int i = 0; i < BandwidthMeter::N_CHANNELS; ++i) {
|
||||
|
||||
BandwidthMeter::ChannelInfo& ch = _model->channelInfo(i);
|
||||
QDoubleSpinBox* spinner = _spinners[i] = new QDoubleSpinBox();
|
||||
spinner->setDecimals(3);
|
||||
spinner->setMinimum(0.001);
|
||||
spinner->setMaximum(1000.0);
|
||||
spinner->setSuffix(ch.unitCaption);
|
||||
snprintf(strBuf, sizeof(strBuf), "Maximum of %s Bandwidth Meter:", ch.caption);
|
||||
form->addRow(strBuf, spinner);
|
||||
connect(spinner, SIGNAL(valueChanged(double)), SLOT(applySettings(double)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BandwidthDialog::paintEvent(QPaintEvent* event) {
|
||||
|
||||
// Update labels
|
||||
char strBuf[64];
|
||||
for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) {
|
||||
int chIdx = i / 2;
|
||||
bool input = i % 2 == 0;
|
||||
BandwidthMeter::ChannelInfo& ch = _model->channelInfo(chIdx);
|
||||
BandwidthMeter::Stream& s = input ? _model->inputStream(chIdx) : _model->outputStream(chIdx);
|
||||
QLabel* label = _labels[i];
|
||||
snprintf(strBuf, sizeof(strBuf), "%010.6f%s", s.getValue() / ch.unitScale, ch.unitCaption);
|
||||
label->setText(strBuf);
|
||||
}
|
||||
// Update spinners (only when the value has been changed)
|
||||
for (int i = 0; i < BandwidthMeter::N_CHANNELS; ++i) {
|
||||
BandwidthMeter::ChannelInfo& ch = _model->channelInfo(i);
|
||||
if (_spinners[i]->value() != double(ch.unitsMax)) {
|
||||
_spinners[i]->setValue(ch.unitsMax);
|
||||
}
|
||||
}
|
||||
|
||||
this->QDialog::paintEvent(event);
|
||||
this->setFixedSize(this->width(), this->height());
|
||||
}
|
||||
|
||||
void BandwidthDialog::closeEvent(QCloseEvent* event) {
|
||||
|
||||
this->QDialog::closeEvent(event);
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void BandwidthDialog::applySettings(double value) {
|
||||
|
||||
// Update model from spinner value (only the one that's been changed)
|
||||
for (int i = 0; i < BandwidthMeter::N_CHANNELS; ++i) {
|
||||
float v = _spinners[i]->value();
|
||||
if (v == float(value)) {
|
||||
BandwidthMeter::ChannelInfo& ch = _model->channelInfo(i);
|
||||
if (ch.unitsMax != v) {
|
||||
ch.unitsMax = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
51
interface/src/ui/BandwidthDialog.h
Normal file
51
interface/src/ui/BandwidthDialog.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// BandwidthDialog.h
|
||||
// interface
|
||||
//
|
||||
// Created by Tobias Schwinger on 6/21/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__BandwidthDialog__
|
||||
#define __hifi__BandwidthDialog__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QDoubleSpinBox>
|
||||
|
||||
#include "BandwidthMeter.h"
|
||||
|
||||
|
||||
class BandwidthDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
// Sets up the UI based on the configuration of the BandwidthMeter
|
||||
BandwidthDialog(QWidget* parent, BandwidthMeter* model);
|
||||
|
||||
signals:
|
||||
|
||||
void closed();
|
||||
|
||||
protected:
|
||||
|
||||
// State <- data model held by BandwidthMeter
|
||||
void paintEvent(QPaintEvent*);
|
||||
|
||||
// Emits a 'closed' signal when this dialog is closed.
|
||||
void closeEvent(QCloseEvent*);
|
||||
|
||||
private slots:
|
||||
|
||||
// State -> data model held by BandwidthMeter
|
||||
void applySettings(double);
|
||||
|
||||
private:
|
||||
BandwidthMeter* _model;
|
||||
QLabel* _labels[BandwidthMeter::N_STREAMS];
|
||||
QDoubleSpinBox* _spinners[BandwidthMeter::N_CHANNELS];
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__BandwidthDialog__) */
|
||||
|
|
@ -336,14 +336,17 @@ void AgentList::addAgentToList(Agent* newAgent) {
|
|||
Agent::printLog(*newAgent);
|
||||
}
|
||||
|
||||
void AgentList::broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes) {
|
||||
unsigned AgentList::broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes) {
|
||||
unsigned n = 0;
|
||||
for(AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||
// only send to the AgentTypes we are asked to send to.
|
||||
if (agent->getActiveSocket() != NULL && memchr(agentTypes, agent->getType(), numAgentTypes)) {
|
||||
// we know which socket is good for this agent, send there
|
||||
_agentSocket.send(agent->getActiveSocket(), broadcastData, dataBytes);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void AgentList::handlePingReply(sockaddr *agentAddress) {
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
int updateAgentWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
|
||||
int updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes);
|
||||
|
||||
void broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes);
|
||||
unsigned broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes);
|
||||
|
||||
Agent* soloAgentOfType(char agentType);
|
||||
|
||||
|
|
Loading…
Reference in a new issue