From 290c20bfc757e1fba3da7cb70ab01f1b5c452845 Mon Sep 17 00:00:00 2001 From: tosh Date: Sat, 22 Jun 2013 04:22:10 +0200 Subject: [PATCH 01/12] introduces bandwidth meter / dialog --- interface/CMakeLists.txt | 2 +- interface/src/Application.cpp | 76 ++++++++-- interface/src/Application.h | 19 ++- interface/src/Audio.cpp | 11 +- interface/src/BandwidthMeter.cpp | 217 +++++++++++++++++++++++++++ interface/src/BandwidthMeter.h | 72 +++++++++ interface/src/VoxelSystem.cpp | 4 +- interface/src/ui/BandwidthDialog.cpp | 91 +++++++++++ interface/src/ui/BandwidthDialog.h | 51 +++++++ libraries/shared/src/AgentList.cpp | 5 +- libraries/shared/src/AgentList.h | 2 +- 11 files changed, 527 insertions(+), 23 deletions(-) create mode 100644 interface/src/BandwidthMeter.cpp create mode 100644 interface/src/BandwidthMeter.h create mode 100644 interface/src/ui/BandwidthDialog.cpp create mode 100644 interface/src/ui/BandwidthDialog.h diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 148e6819be..6f90a67f28 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -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}) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6954339cee..728bea8b04 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -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); diff --git a/interface/src/Application.h b/interface/src/Application.h index 54fdf1c347..b666bb06a0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -20,6 +20,9 @@ #include +#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; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 533b6e9e3b..fd44b930ac 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -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; } diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp new file mode 100644 index 0000000000..d044fe5e37 --- /dev/null +++ b/interface/src/BandwidthMeter.cpp @@ -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(); +} + + diff --git a/interface/src/BandwidthMeter.h b/interface/src/BandwidthMeter.h new file mode 100644 index 0000000000..3da26d680a --- /dev/null +++ b/interface/src/BandwidthMeter.h @@ -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 + +#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__) */ + diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 69edf376ee..5de9b89594 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -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; } diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp new file mode 100644 index 0000000000..fcbab5816b --- /dev/null +++ b/interface/src/ui/BandwidthDialog.cpp @@ -0,0 +1,91 @@ + +#include "ui/BandwidthDialog.h" + +#include +#include + +#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; + } + } + } +} + diff --git a/interface/src/ui/BandwidthDialog.h b/interface/src/ui/BandwidthDialog.h new file mode 100644 index 0000000000..e2d12cc976 --- /dev/null +++ b/interface/src/ui/BandwidthDialog.h @@ -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 + +#include +#include + +#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__) */ + diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 7a4803586e..4b112c5477 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -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) { diff --git a/libraries/shared/src/AgentList.h b/libraries/shared/src/AgentList.h index 1b51913928..b50b3fbff7 100644 --- a/libraries/shared/src/AgentList.h +++ b/libraries/shared/src/AgentList.h @@ -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); From 4f692aeb5662a417c8222e3511d88ab6c985787b Mon Sep 17 00:00:00 2001 From: tosh Date: Sat, 22 Jun 2013 05:07:01 +0200 Subject: [PATCH 02/12] improves bandwidth meter layout / simplifies & fixes rendering --- interface/src/Application.cpp | 2 +- interface/src/BandwidthMeter.cpp | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 728bea8b04..ed2f37cfc9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2162,7 +2162,7 @@ void Application::displayOverlay() { if (_renderStatsOn->isChecked()) { displayStats(); } - _bandwidthMeter.render(_glWidget->width() - 400, 40, 380, 42 * BandwidthMeter::N_CHANNELS); + _bandwidthMeter.render(_glWidget->width() - 400, 40, 380, 32 * BandwidthMeter::N_CHANNELS); if (_logOn->isChecked()) { LogDisplay::instance.render(_glWidget->width(), _glWidget->height()); } // Show chat entry field diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index d044fe5e37..48a7a3b3b0 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -33,9 +33,8 @@ 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_CHAR_WIDTH = 0.28f; // (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; @@ -45,9 +44,9 @@ namespace { // .cpp-local } 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 } + { "Audio" , "Kbps", 1.0 * 1024.0, 80.5, 0x40ff40d0 }, + { "Avatars" , "KBps", 1.0 * 1024.0, 20.0, 0xffef40c0 }, + { "Voxels" , "Mbps", 1024.0 * 1024.0, 0.5, 0xd0d0d0a0 } }; // --- @@ -115,11 +114,10 @@ void BandwidthMeter::render(int x, int y, unsigned w, unsigned h) { 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 labelHeight = (channelHeight - streamSpacing) * 0.5f; float labelScaleX = labelWidth / float(labelRenderWidth); - float labelScaleY = labelTextHeight / float(labelRenderHeight); + float labelScaleY = labelHeight / float(labelRenderHeight); float labelHorizSpacing = channelTotalHeight * LABEL_HORIZ_SPACING; @@ -187,7 +185,7 @@ void BandwidthMeter::render(int x, int y, unsigned w, unsigned h) { glScalef(labelScaleX, labelScaleY, 1.0f); sprintf(fmtBuf, "%0.2f in", unitsIn); - _textRenderer.draw(glm::max(int(barPosIn) - fontMetrics.width(fmtBuf), 0), -fontDescent, fmtBuf); + _textRenderer.draw(glm::max(int(barPosIn / labelScaleX) - fontMetrics.width(fmtBuf), 0), -fontDescent, fmtBuf); glPopMatrix(); // Advance to next stream @@ -204,7 +202,7 @@ void BandwidthMeter::render(int x, int y, unsigned w, unsigned h) { glScalef(labelScaleX, labelScaleY, 1.0f); sprintf(fmtBuf, "%0.2f out", unitsOut); - _textRenderer.draw(glm::max(int(barPosOut) - fontMetrics.width(fmtBuf), 0), -fontDescent, fmtBuf); + _textRenderer.draw(glm::max(int(barPosOut / labelScaleX) - fontMetrics.width(fmtBuf), 0), -fontDescent, fmtBuf); glPopMatrix(); // Advance to next channel From 09962737dd8a67ebaeae6ab946f290db9463a132 Mon Sep 17 00:00:00 2001 From: tosh Date: Sat, 22 Jun 2013 05:21:15 +0200 Subject: [PATCH 03/12] tightens bounding issues for bandwidth meter's scale indicators --- interface/src/BandwidthMeter.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index 48a7a3b3b0..39526d206c 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -44,7 +44,7 @@ namespace { // .cpp-local } BandwidthMeter::ChannelInfo BandwidthMeter::_DEFAULT_CHANNELS[] = { - { "Audio" , "Kbps", 1.0 * 1024.0, 80.5, 0x40ff40d0 }, + { "Audio" , "Kbps", 1.0 * 1024.0, 85.0, 0x40ff40d0 }, { "Avatars" , "KBps", 1.0 * 1024.0, 20.0, 0xffef40c0 }, { "Voxels" , "Mbps", 1024.0 * 1024.0, 0.5, 0xd0d0d0a0 } }; @@ -158,11 +158,12 @@ void BandwidthMeter::render(int x, int y, unsigned w, unsigned h) { // Render scale indicators setColorRGBA(INDICATOR_COLOR); - for (float meas = scaleStep; meas < c.unitsMax - 0.01f; meas += scaleStep) { - float pixX = xMax * meas / c.unitsMax; + for (int j = int((c.unitsMax + scaleStep - 1) / scaleStep); --j > 0;) { + float xPix = xMax * float(j) * scaleStep / c.unitsMax; + glBegin(GL_LINES); - glVertex2f(pixX, 0); - glVertex2f(pixX, channelHeight); + glVertex2f(xPix, 0); + glVertex2f(xPix, channelHeight); glEnd(); } From c88642bac2b5e7203afa5e81ad7b76444c1f293b Mon Sep 17 00:00:00 2001 From: tosh Date: Sat, 29 Jun 2013 15:58:25 +0200 Subject: [PATCH 04/12] keeps audio from crashing when sound device is unavailable --- interface/src/Audio.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index b3b5d0f099..b60f060e5d 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -338,12 +338,19 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : PaStreamParameters inputParameters, outputParameters; inputParameters.device = Pa_GetDefaultInputDevice(); + outputParameters.device = Pa_GetDefaultOutputDevice(); + + if (inputParameters.device == -1 || outputParameters.device == -1) { + printLog("Audio: Missing device.\n"); + outputPortAudioError(Pa_Terminate()); + return; + } + inputParameters.channelCount = 2; // Stereo input inputParameters.sampleFormat = (paInt16 | paNonInterleaved); inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency; inputParameters.hostApiSpecificStreamInfo = NULL; - outputParameters.device = Pa_GetDefaultOutputDevice(); outputParameters.channelCount = 2; // Stereo output outputParameters.sampleFormat = (paInt16 | paNonInterleaved); outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; From 46f8136f2e090ecad5218ed4686b7c446a3cf859 Mon Sep 17 00:00:00 2001 From: tosh Date: Sat, 29 Jun 2013 20:30:12 +0200 Subject: [PATCH 05/12] combined bandwidth display at automatic scale --- interface/src/Application.cpp | 2 +- interface/src/BandwidthMeter.cpp | 271 +++++++++++++-------------- interface/src/BandwidthMeter.h | 15 +- interface/src/ui/BandwidthDialog.cpp | 38 +--- interface/src/ui/BandwidthDialog.h | 8 - 5 files changed, 146 insertions(+), 188 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0dd2a520fb..e9022935a6 100755 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2291,7 +2291,7 @@ void Application::displayOverlay() { if (_renderStatsOn->isChecked()) { displayStats(); } - _bandwidthMeter.render(_glWidget->width() - 400, 40, 380, 32 * BandwidthMeter::N_CHANNELS); + _bandwidthMeter.render(_glWidget->width() - 400, 40, 380, 32); if (_logOn->isChecked()) { LogDisplay::instance.render(_glWidget->width(), _glWidget->height()); } // Show chat entry field diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index 39526d206c..f99fe4d486 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -12,54 +12,44 @@ #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.28f; // (e) fractional in respect to total channel height - float const LABEL_HORIZ_SPACING = 0.25f; // (f) fractional in respect to total channel height + char const* CAPTION_IN = "IN"; + char const* CAPTION_OUT = "OUT"; + char const* CAPTION_UNIT = "Mbps"; - 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); + int SPACING_RIGHT_CAPTION_IN_OUT = 4; + int SPACING_LEFT_CAPTION_UNIT = 6; + + int SPACING_VERT_BARS = 2; + + + unsigned const COLOR_CAPTIONS = 0xa0a0a0e0; + unsigned const COLOR_FRAME = 0xe0e0e0b0; + unsigned const COLOR_INDICATOR = 0xc0c0c0b0; + + double const UNIT_SCALE = 1000.0 / (1024.0 * 1024.0); // bytes/ms -> Mbps + int const FRAMES_SHRINK = 20; } BandwidthMeter::ChannelInfo BandwidthMeter::_DEFAULT_CHANNELS[] = { - { "Audio" , "Kbps", 1.0 * 1024.0, 85.0, 0x40ff40d0 }, - { "Avatars" , "KBps", 1.0 * 1024.0, 20.0, 0xffef40c0 }, - { "Voxels" , "Mbps", 1024.0 * 1024.0, 0.5, 0xd0d0d0a0 } + { "Audio" , "Kbps", 1000.0 / 1024.0, 0x40ff40d0 }, + { "Avatars" , "Kbps", 1000.0 / 1024.0, 0xffef40c0 }, + { "Voxels" , "Kbps", 1000.0 / 1024.0, 0xd0d0d0a0 } }; // --- BandwidthMeter::BandwidthMeter() : - _textRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT) { + _textRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT), + _scaleMax(50), _framesTillShrink(0) { memcpy(_channels, _DEFAULT_CHANNELS, sizeof(_DEFAULT_CHANNELS)); } -BandwidthMeter::Stream::Stream(float secondsToAverage) : +BandwidthMeter::Stream::Stream(float msToAverage) : _value(0.0f), - _secsToAverage(secondsToAverage) { + _msToAverage(msToAverage) { gettimeofday(& _prevTime, NULL); } @@ -69,15 +59,15 @@ void BandwidthMeter::Stream::updateValue(double amount) { // Determine elapsed time timeval now; gettimeofday(& now, NULL); - double dt = diffclock(& _prevTime, & now) / 1000.0; + double dt = diffclock(& _prevTime, & now); memcpy(& _prevTime, & now, sizeof(timeval)); // Compute approximate average _value = glm::mix(_value, amount / dt, - glm::clamp(dt / _secsToAverage, 0.0, 1.0)); + glm::clamp(dt / _msToAverage, 0.0, 1.0)); } -static void setColorRGBA(unsigned c) { +void BandwidthMeter::setColorRGBA(unsigned c) { glColor4ub(GLubyte( c >> 24), GLubyte((c >> 16) & 0xff), @@ -85,131 +75,136 @@ static void setColorRGBA(unsigned c) { GLubyte( c & 0xff)); } -static void renderBox(float w, float h) { +void BandwidthMeter::renderBox(int x, int y, int w, int h) { + glBegin(GL_QUADS); - glVertex2f(0.0f, 0.0f); - glVertex2f(w, 0.0f); - glVertex2f(w, h); - glVertex2f(0.0f, h); + glVertex2i(x, y); + glVertex2i(x + w, y); + glVertex2i(x + w, y + h); + glVertex2i(x, y + h); glEnd(); } +void BandwidthMeter::renderVerticalLine(int x, int y, int h) { + + glBegin(GL_LINES); + glVertex2i(x, y); + glVertex2i(x, y + h); + glEnd(); +} + +inline int BandwidthMeter::centered(int subject, int object) { + return (object - subject) / 2; +} + 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; + // Determine total + float totalIn = 0.0f, totalOut = 0.0f; 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)); + + totalIn += inputStream(i).getValue(); + totalOut += outputStream(i).getValue(); } - 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 = (channelHeight - streamSpacing) * 0.5f; + totalIn *= UNIT_SCALE; + totalOut *= UNIT_SCALE; + float totalMax = glm::max(totalIn, totalOut); + //printLog("totalMax = %f\n", totalMax); - float labelScaleX = labelWidth / float(labelRenderWidth); - float labelScaleY = labelHeight / float(labelRenderHeight); - float labelHorizSpacing = channelTotalHeight * LABEL_HORIZ_SPACING; + // Get font / caption metrics + QFontMetrics const& fontMetrics = _textRenderer.metrics(); + int fontDescent = fontMetrics.descent(); + int labelWidthIn = fontMetrics.width(CAPTION_IN); + int labelWidthOut = fontMetrics.width(CAPTION_OUT); + int labelWidthInOut = glm::max(labelWidthIn, labelWidthOut); + int labelHeight = fontMetrics.ascent() + fontDescent; + int labelWidthUnit = fontMetrics.width(CAPTION_UNIT); + int labelsWidth = labelWidthInOut + SPACING_RIGHT_CAPTION_IN_OUT + SPACING_LEFT_CAPTION_UNIT + labelWidthUnit; + // Calculate coordinates and dimensions + int barX = x + labelWidthInOut + SPACING_RIGHT_CAPTION_IN_OUT; + int barWidth = w - labelsWidth; + int barHeight = (h - SPACING_VERT_BARS) / 2; + int textYcenteredLine = h - centered(labelHeight, h) - fontDescent; + int textYupperLine = barHeight - centered(labelHeight, barHeight) - fontDescent; + int textYlowerLine = h - centered(labelHeight, barHeight) - fontDescent; + // Center of coordinate system -> upper left of bar glPushMatrix(); + glTranslatef(float(barX), float(y), 0.0f); - int xMin = x + int(labelWidth + labelHorizSpacing); + // Render captions + setColorRGBA(COLOR_CAPTIONS); + _textRenderer.draw(barWidth + SPACING_LEFT_CAPTION_UNIT, textYcenteredLine, CAPTION_UNIT); + _textRenderer.draw(-labelWidthIn - SPACING_RIGHT_CAPTION_IN_OUT, textYupperLine, CAPTION_IN); + _textRenderer.draw(-labelWidthOut - SPACING_RIGHT_CAPTION_IN_OUT, textYlowerLine, CAPTION_OUT); // 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(); + setColorRGBA(COLOR_FRAME); + renderVerticalLine(0, 0, h); + renderVerticalLine(barWidth, 0, h); - // 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; + // Adjust scale + int steps; + double step, scaleMax; + bool commit = false; + do { + steps = (_scaleMax % 9) + 2; + step = pow(10.0, (_scaleMax / 9) - 10); + scaleMax = step * steps; + if (commit) { + printLog("Bandwidth meter scale: %d\n", _scaleMax); + break; } - 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); + if (totalMax < scaleMax * 0.5) { + if (--_framesTillShrink < 0) { + _scaleMax = glm::max(0, _scaleMax-1); + commit = true; + } + } else { + _framesTillShrink = FRAMES_SHRINK; - // Render scale indicators - setColorRGBA(INDICATOR_COLOR); - for (int j = int((c.unitsMax + scaleStep - 1) / scaleStep); --j > 0;) { - float xPix = xMax * float(j) * scaleStep / c.unitsMax; - - glBegin(GL_LINES); - glVertex2f(xPix, 0); - glVertex2f(xPix, channelHeight); - glEnd(); + if (totalMax > scaleMax) { + _scaleMax += 1; + commit = true; + } } + } while (commit); - // 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 / labelScaleX) - 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 / labelScaleX) - fontMetrics.width(fmtBuf), 0), -fontDescent, fmtBuf); - glPopMatrix(); - - // Advance to next channel - glTranslatef(0.0f, streamHeight + channelSpacing, 0.0f); + // Render scale indicators + setColorRGBA(COLOR_INDICATOR); + for (int j = int((scaleMax + step - 0.000001) / step); --j > 0;) { + renderVerticalLine(int(barWidth * j * step / scaleMax), 0, h); } + // Render bars + int xIn = 0, xOut = 0; + for (int i = 0; i < N_CHANNELS; ++i) { + + int wIn = int(barWidth * inputStream(i).getValue() * UNIT_SCALE / scaleMax); + int wOut = int(barWidth * outputStream(i).getValue() * UNIT_SCALE / scaleMax); + + setColorRGBA(channelInfo(i).colorRGBA); + + if (wIn > 0) { + renderBox(xIn, 0, wIn, barHeight); + } + xIn += wIn; + + if (wOut > 0) { + renderBox(xOut, h - barHeight, wOut, barHeight); + } + xOut += wOut; + } + + // Render numbers + char fmtBuf[8]; + setColorRGBA(COLOR_CAPTIONS); + sprintf(fmtBuf, "%0.2f", totalIn); + _textRenderer.draw(glm::max(xIn - fontMetrics.width(fmtBuf), 0), textYupperLine, fmtBuf); + sprintf(fmtBuf, "%0.2f", totalOut); + _textRenderer.draw(glm::max(xOut - fontMetrics.width(fmtBuf), 0), textYlowerLine, fmtBuf); + glPopMatrix(); } diff --git a/interface/src/BandwidthMeter.h b/interface/src/BandwidthMeter.h index 3da26d680a..9a2996f412 100644 --- a/interface/src/BandwidthMeter.h +++ b/interface/src/BandwidthMeter.h @@ -32,7 +32,6 @@ public: char const* caption; char const* unitCaption; double unitScale; - double unitsMax; unsigned colorRGBA; }; @@ -41,14 +40,14 @@ public: public: - Stream(float secondsToAverage = 3.0f); + Stream(float msToAverage = 3000.0f); void updateValue(double amount); double getValue() const { return _value; } private: double _value; // Current value. + double _msToAverage; // Milliseconds to average. timeval _prevTime; // Time of last feed. - float _secsToAverage; // Seconds to average. }; // Data model accessors @@ -60,12 +59,20 @@ public: ChannelInfo const& channelInfo(unsigned index) const { return _channels[index]; } private: + static void setColorRGBA(unsigned c); + static void renderBox(int x, int y, int w, int h); + static void renderVerticalLine(int x, int y, int h); + + static inline int centered(int subject, int object); + TextRenderer _textRenderer; ChannelInfo _channels[N_CHANNELS]; Stream _streams[N_STREAMS]; + int _scaleMax; + int _framesTillShrink; + static ChannelInfo _DEFAULT_CHANNELS[]; - static Stream _DEFAULT_STREAMS[]; }; #endif /* defined(__interface__BandwidthMeter__) */ diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp index fcbab5816b..300788e004 100644 --- a/interface/src/ui/BandwidthDialog.cpp +++ b/interface/src/ui/BandwidthDialog.cpp @@ -27,21 +27,6 @@ BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) : 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) { @@ -54,16 +39,9 @@ void BandwidthDialog::paintEvent(QPaintEvent* event) { 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); + snprintf(strBuf, sizeof(strBuf), "%010.5f%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()); @@ -75,17 +53,3 @@ void BandwidthDialog::closeEvent(QCloseEvent* 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; - } - } - } -} - diff --git a/interface/src/ui/BandwidthDialog.h b/interface/src/ui/BandwidthDialog.h index e2d12cc976..d88c0de34a 100644 --- a/interface/src/ui/BandwidthDialog.h +++ b/interface/src/ui/BandwidthDialog.h @@ -10,9 +10,7 @@ #define __hifi__BandwidthDialog__ #include - #include -#include #include "BandwidthMeter.h" @@ -36,15 +34,9 @@ protected: // 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__) */ From 435b958671e8e6918391bbff44ea1d76aebc24ad Mon Sep 17 00:00:00 2001 From: tosh Date: Sat, 29 Jun 2013 20:52:07 +0200 Subject: [PATCH 06/12] polishes bandwidth meter --- interface/src/BandwidthMeter.cpp | 33 ++++++++++++-------------------- interface/src/BandwidthMeter.h | 9 ++++----- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index f99fe4d486..2d5aed37b9 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -18,18 +18,18 @@ namespace { // .cpp-local char const* CAPTION_OUT = "OUT"; char const* CAPTION_UNIT = "Mbps"; + double const UNIT_SCALE = 1000.0 / (1024.0 * 1024.0); // Bytes/ms -> Mbps + int const INITIAL_SCALE_MAXIMUM_INDEX = 250; // / 9: exponent, % 9: mantissa - 2, 0 o--o 2 * 10^-10 + int SPACING_RIGHT_CAPTION_IN_OUT = 4; int SPACING_LEFT_CAPTION_UNIT = 6; int SPACING_VERT_BARS = 2; - unsigned const COLOR_CAPTIONS = 0xa0a0a0e0; unsigned const COLOR_FRAME = 0xe0e0e0b0; unsigned const COLOR_INDICATOR = 0xc0c0c0b0; - double const UNIT_SCALE = 1000.0 / (1024.0 * 1024.0); // bytes/ms -> Mbps - int const FRAMES_SHRINK = 20; } BandwidthMeter::ChannelInfo BandwidthMeter::_DEFAULT_CHANNELS[] = { @@ -38,11 +38,9 @@ BandwidthMeter::ChannelInfo BandwidthMeter::_DEFAULT_CHANNELS[] = { { "Voxels" , "Kbps", 1000.0 / 1024.0, 0xd0d0d0a0 } }; -// --- - BandwidthMeter::BandwidthMeter() : _textRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT), - _scaleMax(50), _framesTillShrink(0) { + _scaleMaxIndex(INITIAL_SCALE_MAXIMUM_INDEX) { memcpy(_channels, _DEFAULT_CHANNELS, sizeof(_DEFAULT_CHANNELS)); } @@ -109,7 +107,6 @@ void BandwidthMeter::render(int x, int y, unsigned w, unsigned h) { totalIn *= UNIT_SCALE; totalOut *= UNIT_SCALE; float totalMax = glm::max(totalIn, totalOut); - //printLog("totalMax = %f\n", totalMax); // Get font / caption metrics QFontMetrics const& fontMetrics = _textRenderer.metrics(); @@ -149,25 +146,19 @@ void BandwidthMeter::render(int x, int y, unsigned w, unsigned h) { double step, scaleMax; bool commit = false; do { - steps = (_scaleMax % 9) + 2; - step = pow(10.0, (_scaleMax / 9) - 10); + steps = (_scaleMaxIndex % 9) + 2; + step = pow(10.0, (_scaleMaxIndex / 9) - 10); scaleMax = step * steps; if (commit) { - printLog("Bandwidth meter scale: %d\n", _scaleMax); +// printLog("Bandwidth meter scale: %d\n", _scaleMaxIndex); break; } if (totalMax < scaleMax * 0.5) { - if (--_framesTillShrink < 0) { - _scaleMax = glm::max(0, _scaleMax-1); - commit = true; - } - } else { - _framesTillShrink = FRAMES_SHRINK; - - if (totalMax > scaleMax) { - _scaleMax += 1; - commit = true; - } + _scaleMaxIndex = glm::max(0, _scaleMaxIndex-1); + commit = true; + } else if (totalMax > scaleMax) { + _scaleMaxIndex += 1; + commit = true; } } while (commit); diff --git a/interface/src/BandwidthMeter.h b/interface/src/BandwidthMeter.h index 9a2996f412..3294e6e0e7 100644 --- a/interface/src/BandwidthMeter.h +++ b/interface/src/BandwidthMeter.h @@ -65,14 +65,13 @@ private: static inline int centered(int subject, int object); + + static ChannelInfo _DEFAULT_CHANNELS[]; + TextRenderer _textRenderer; ChannelInfo _channels[N_CHANNELS]; Stream _streams[N_STREAMS]; - - int _scaleMax; - int _framesTillShrink; - - static ChannelInfo _DEFAULT_CHANNELS[]; + int _scaleMaxIndex; }; #endif /* defined(__interface__BandwidthMeter__) */ From f1e5a563472bce96af2648bec744a26015c160db Mon Sep 17 00:00:00 2001 From: tosh Date: Sun, 30 Jun 2013 17:08:01 +0200 Subject: [PATCH 07/12] adds code to show bandwidth details upon click and adds a checkbox to the menu to set visibility of the bandwidth bars --- interface/src/Application.cpp | 23 ++++++++++++++++++++--- interface/src/Application.h | 5 ++++- interface/src/BandwidthMeter.cpp | 20 +++++++++++++++++++- interface/src/BandwidthMeter.h | 3 ++- libraries/audio/src/AudioInjector.h | 1 + 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e9022935a6..df84abe4c7 100755 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -801,6 +801,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { _mouseX = event->x(); _mouseY = event->y(); _mousePressed = false; + checkBandwidthMeterClick(); } } } @@ -980,15 +981,28 @@ void Application::processAvatarVoxelURLMessage(unsigned char *packetData, size_t QMetaObject::invokeMethod(avatar->getVoxels(), "setVoxelURL", Q_ARG(QUrl, url)); } +void Application::checkBandwidthMeterClick() { + // ... to be called upon button release + + if (_bandwidthDisplayOn->isChecked() && + glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY))) <= 6 && + _bandwidthMeter.isWithinArea(_mouseX, _mouseY, _glWidget->width(), _glWidget->height())) { + + // The bandwidth meter is visible, the click didn't get dragged too far and + // we actually hit the bandwidth meter + bandwidthDetails(); + } +} + void Application::bandwidthDetails() { if (! _bandwidthDialog) { _bandwidthDialog = new BandwidthDialog(_glWidget, getBandwidthMeter()); + connect(_bandwidthDialog, SIGNAL(closed()), SLOT(bandwidthDetailsClosed())); + _bandwidthDialog->show(); } _bandwidthDialog->raise(); - - connect(_bandwidthDialog, SIGNAL(closed()), SLOT(bandwidthDetailsClosed())); } void Application::bandwidthDetailsClosed() { @@ -1431,6 +1445,8 @@ void Application::initMenu() { (_logOn = toolsMenu->addAction("Log"))->setCheckable(true); _logOn->setChecked(false); _logOn->setShortcut(Qt::CTRL | Qt::Key_L); + (_bandwidthDisplayOn = toolsMenu->addAction("Bandwidth Display"))->setCheckable(true); + _bandwidthDisplayOn->setChecked(true); toolsMenu->addAction("Bandwidth Details", this, SLOT(bandwidthDetails())); @@ -2291,7 +2307,8 @@ void Application::displayOverlay() { if (_renderStatsOn->isChecked()) { displayStats(); } - _bandwidthMeter.render(_glWidget->width() - 400, 40, 380, 32); + if (_bandwidthDisplayOn->isChecked()) { _bandwidthMeter.render(_glWidget->width(), _glWidget->height()); } + if (_logOn->isChecked()) { LogDisplay::instance.render(_glWidget->width(), _glWidget->height()); } // Show chat entry field diff --git a/interface/src/Application.h b/interface/src/Application.h index 77520d0e85..be95f81c15 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -173,7 +173,9 @@ private: void displayOverlay(); void displayStats(); void renderViewFrustum(ViewFrustum& viewFrustum); - + + void checkBandwidthMeterClick(); + void setupPaintingVoxel(); void shiftPaintingColor(); void maybeEditVoxelUnderCursor(); @@ -224,6 +226,7 @@ private: QAction* _manualFirstPerson; // Whether to force first-person mode QAction* _manualThirdPerson; // Whether to force third-person mode QAction* _logOn; // Whether to show on-screen log + QAction* _bandwidthDisplayOn; // Whether to show on-screen bandwidth bars QActionGroup* _voxelModeActions; // The group of voxel edit mode actions QAction* _addVoxelMode; // Whether add voxel mode is enabled QAction* _deleteVoxelMode; // Whether delete voxel mode is enabled diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index 2d5aed37b9..c2a5b581c2 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -14,6 +14,11 @@ namespace { // .cpp-local + int const AREA_WIDTH = -400; // Width of the area used. Aligned to the right when negative. + int const AREA_HEIGHT = 32; // Height of the area used. Aligned to the bottom when negative. + int const BORDER_DISTANCE_HORIZ = -20; // Distance to edge of screen (use negative value when width is negative). + int const BORDER_DISTANCE_VERT = 20; // Distance to edge of screen (use negative value when height is negative). + char const* CAPTION_IN = "IN"; char const* CAPTION_OUT = "OUT"; char const* CAPTION_UNIT = "Mbps"; @@ -95,7 +100,20 @@ inline int BandwidthMeter::centered(int subject, int object) { return (object - subject) / 2; } -void BandwidthMeter::render(int x, int y, unsigned w, unsigned h) { +bool BandwidthMeter::isWithinArea(int x, int y, int screenWidth, int screenHeight) { + + int minX = BORDER_DISTANCE_HORIZ + (AREA_WIDTH >= 0 ? 0 : screenWidth + AREA_WIDTH); + int minY = BORDER_DISTANCE_VERT + (AREA_HEIGHT >= 0 ? 0 : screenHeight + AREA_HEIGHT); + + return x >= minX && x < minX + glm::abs(AREA_WIDTH) && + y >= minY && y < minY + glm::abs(AREA_HEIGHT); +} + +void BandwidthMeter::render(int screenWidth, int screenHeight) { + + int x = BORDER_DISTANCE_HORIZ + (AREA_WIDTH >= 0 ? 0 : screenWidth + AREA_WIDTH); + int y = BORDER_DISTANCE_VERT + (AREA_HEIGHT >= 0 ? 0 : screenHeight + AREA_HEIGHT); + int w = glm::abs(AREA_WIDTH), h = glm::abs(AREA_HEIGHT); // Determine total float totalIn = 0.0f, totalOut = 0.0f; diff --git a/interface/src/BandwidthMeter.h b/interface/src/BandwidthMeter.h index 3294e6e0e7..d3641a21f0 100644 --- a/interface/src/BandwidthMeter.h +++ b/interface/src/BandwidthMeter.h @@ -20,7 +20,8 @@ public: BandwidthMeter(); - void render(int x, int y, unsigned w, unsigned h); + void render(int screenWidth, int screenHeight); + bool isWithinArea(int x, int y, int screenWidth, int screenHeight); // Number of channels / streams. static size_t const N_CHANNELS = 3; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index efe52bdf57..29ff920317 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -11,6 +11,7 @@ #include #include +#include #include From fdf9f10e8211f78af51273b2174dd265388dd07b Mon Sep 17 00:00:00 2001 From: tosh Date: Sun, 30 Jun 2013 17:32:44 +0200 Subject: [PATCH 08/12] increases height of bandwidth meters by 8 pixels --- interface/src/BandwidthMeter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index c2a5b581c2..69a80c19e8 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -15,7 +15,7 @@ namespace { // .cpp-local int const AREA_WIDTH = -400; // Width of the area used. Aligned to the right when negative. - int const AREA_HEIGHT = 32; // Height of the area used. Aligned to the bottom when negative. + int const AREA_HEIGHT = 40; // Height of the area used. Aligned to the bottom when negative. int const BORDER_DISTANCE_HORIZ = -20; // Distance to edge of screen (use negative value when width is negative). int const BORDER_DISTANCE_VERT = 20; // Distance to edge of screen (use negative value when height is negative). From 98589adef50d5a05735ccc203c1020755a953f28 Mon Sep 17 00:00:00 2001 From: tosh Date: Mon, 1 Jul 2013 10:28:17 +0200 Subject: [PATCH 09/12] Bandwidth meter: Bytes -> bits, number formatting (colors, digits, aligment) on dialog --- interface/src/BandwidthMeter.cpp | 8 ++++---- interface/src/ui/BandwidthDialog.cpp | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index 69a80c19e8..01e708866e 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -23,7 +23,7 @@ namespace { // .cpp-local char const* CAPTION_OUT = "OUT"; char const* CAPTION_UNIT = "Mbps"; - double const UNIT_SCALE = 1000.0 / (1024.0 * 1024.0); // Bytes/ms -> Mbps + double const UNIT_SCALE = 8000.0 / (1024.0 * 1024.0); // Bytes/ms -> Mbps int const INITIAL_SCALE_MAXIMUM_INDEX = 250; // / 9: exponent, % 9: mantissa - 2, 0 o--o 2 * 10^-10 int SPACING_RIGHT_CAPTION_IN_OUT = 4; @@ -38,9 +38,9 @@ namespace { // .cpp-local } BandwidthMeter::ChannelInfo BandwidthMeter::_DEFAULT_CHANNELS[] = { - { "Audio" , "Kbps", 1000.0 / 1024.0, 0x40ff40d0 }, - { "Avatars" , "Kbps", 1000.0 / 1024.0, 0xffef40c0 }, - { "Voxels" , "Kbps", 1000.0 / 1024.0, 0xd0d0d0a0 } + { "Audio" , "Kbps", 8000.0 / 1024.0, 0x40ff40d0 }, + { "Avatars" , "Kbps", 8000.0 / 1024.0, 0xffef40c0 }, + { "Voxels" , "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0 } }; BandwidthMeter::BandwidthMeter() : diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp index 300788e004..f2e6ca2377 100644 --- a/interface/src/ui/BandwidthDialog.cpp +++ b/interface/src/ui/BandwidthDialog.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include + #include "Log.h" BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) : @@ -23,8 +26,17 @@ BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) : 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); + QLabel* label = _labels[i] = new QLabel(); + label->setAlignment(Qt::AlignRight); + + // Set foreground color to 62.5% brightness of the meter (otherwise will be hard to read on the bright background) + QPalette palette = label->palette(); + unsigned rgb = ch.colorRGBA >> 8; + rgb = ((rgb & 0xfefefeu) >> 1) + ((rgb & 0xf8f8f8) >> 3); + palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb)); + label->setPalette(palette); + + snprintf(strBuf, sizeof(strBuf), " %s %s Bandwidth:", input ? "Input" : "Output", ch.caption); form->addRow(strBuf, label); } } @@ -39,7 +51,7 @@ void BandwidthDialog::paintEvent(QPaintEvent* event) { 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.5f%s", s.getValue() * ch.unitScale, ch.unitCaption); + snprintf(strBuf, sizeof(strBuf), "%0.2f %s", s.getValue() * ch.unitScale, ch.unitCaption); label->setText(strBuf); } From 3f62edd68e1633248c2c3d79289f18ded463b0d5 Mon Sep 17 00:00:00 2001 From: tosh Date: Mon, 1 Jul 2013 10:53:49 +0200 Subject: [PATCH 10/12] makes bandwidth details dialog properly close (and reopen) on ESC key --- interface/src/ui/BandwidthDialog.cpp | 6 ++++++ interface/src/ui/BandwidthDialog.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp index f2e6ca2377..7879816d7c 100644 --- a/interface/src/ui/BandwidthDialog.cpp +++ b/interface/src/ui/BandwidthDialog.cpp @@ -59,6 +59,12 @@ void BandwidthDialog::paintEvent(QPaintEvent* event) { this->setFixedSize(this->width(), this->height()); } +void BandwidthDialog::reject() { + + // Just regularly close upon ESC + this->QDialog::close(); +} + void BandwidthDialog::closeEvent(QCloseEvent* event) { this->QDialog::closeEvent(event); diff --git a/interface/src/ui/BandwidthDialog.h b/interface/src/ui/BandwidthDialog.h index d88c0de34a..636e91dce9 100644 --- a/interface/src/ui/BandwidthDialog.h +++ b/interface/src/ui/BandwidthDialog.h @@ -26,6 +26,10 @@ signals: void closed(); +public slots: + + void reject(); + protected: // State <- data model held by BandwidthMeter From 7ebd912788071cd45afc7d454cd2c91351b3db41 Mon Sep 17 00:00:00 2001 From: tosh Date: Mon, 1 Jul 2013 23:38:00 +0200 Subject: [PATCH 11/12] improves defaults and inline documentation of bandwidth meter layout constants --- interface/src/BandwidthMeter.cpp | 33 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index 01e708866e..f7905cade7 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -17,24 +17,23 @@ namespace { // .cpp-local int const AREA_WIDTH = -400; // Width of the area used. Aligned to the right when negative. int const AREA_HEIGHT = 40; // Height of the area used. Aligned to the bottom when negative. int const BORDER_DISTANCE_HORIZ = -20; // Distance to edge of screen (use negative value when width is negative). - int const BORDER_DISTANCE_VERT = 20; // Distance to edge of screen (use negative value when height is negative). + int const BORDER_DISTANCE_VERT = 40; // Distance to edge of screen (use negative value when height is negative). + int SPACING_VERT_BARS = 2; // Vertical distance between input and output bar + int SPACING_RIGHT_CAPTION_IN_OUT = 4; // IN/OUT <--> |######## : | + int SPACING_LEFT_CAPTION_UNIT = 4; // |######## : | <--> UNIT + int PADDING_HORIZ_VALUE = 2; // |<-->X.XX<:-># | + + unsigned const COLOR_TEXT = 0xe0e0e0e0; // ^ ^ ^ ^ ^ ^ + unsigned const COLOR_FRAME = 0xe0e0e0b0; // | | | + unsigned const COLOR_INDICATOR = 0xc0c0c0b0; // | + char const* CAPTION_IN = "IN"; char const* CAPTION_OUT = "OUT"; char const* CAPTION_UNIT = "Mbps"; double const UNIT_SCALE = 8000.0 / (1024.0 * 1024.0); // Bytes/ms -> Mbps int const INITIAL_SCALE_MAXIMUM_INDEX = 250; // / 9: exponent, % 9: mantissa - 2, 0 o--o 2 * 10^-10 - - int SPACING_RIGHT_CAPTION_IN_OUT = 4; - int SPACING_LEFT_CAPTION_UNIT = 6; - - int SPACING_VERT_BARS = 2; - - unsigned const COLOR_CAPTIONS = 0xa0a0a0e0; - unsigned const COLOR_FRAME = 0xe0e0e0b0; - unsigned const COLOR_INDICATOR = 0xc0c0c0b0; - } BandwidthMeter::ChannelInfo BandwidthMeter::_DEFAULT_CHANNELS[] = { @@ -149,7 +148,7 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) { glTranslatef(float(barX), float(y), 0.0f); // Render captions - setColorRGBA(COLOR_CAPTIONS); + setColorRGBA(COLOR_TEXT); _textRenderer.draw(barWidth + SPACING_LEFT_CAPTION_UNIT, textYcenteredLine, CAPTION_UNIT); _textRenderer.draw(-labelWidthIn - SPACING_RIGHT_CAPTION_IN_OUT, textYupperLine, CAPTION_IN); _textRenderer.draw(-labelWidthOut - SPACING_RIGHT_CAPTION_IN_OUT, textYlowerLine, CAPTION_OUT); @@ -208,11 +207,15 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) { // Render numbers char fmtBuf[8]; - setColorRGBA(COLOR_CAPTIONS); + setColorRGBA(COLOR_TEXT); sprintf(fmtBuf, "%0.2f", totalIn); - _textRenderer.draw(glm::max(xIn - fontMetrics.width(fmtBuf), 0), textYupperLine, fmtBuf); + _textRenderer.draw(glm::max(xIn - fontMetrics.width(fmtBuf) - PADDING_HORIZ_VALUE, + PADDING_HORIZ_VALUE), + textYupperLine, fmtBuf); sprintf(fmtBuf, "%0.2f", totalOut); - _textRenderer.draw(glm::max(xOut - fontMetrics.width(fmtBuf), 0), textYlowerLine, fmtBuf); + _textRenderer.draw(glm::max(xOut - fontMetrics.width(fmtBuf) - PADDING_HORIZ_VALUE, + PADDING_HORIZ_VALUE), + textYlowerLine, fmtBuf); glPopMatrix(); } From f062319c2b8fd4b81628541c496ac9bf74db8252 Mon Sep 17 00:00:00 2001 From: tosh Date: Tue, 2 Jul 2013 03:53:49 +0200 Subject: [PATCH 12/12] introduces named constants for bandwidth meter channel indices / max. drag length --- interface/src/Application.cpp | 12 +++++++----- interface/src/Audio.cpp | 4 ++-- interface/src/BandwidthMeter.cpp | 21 ++++++++++++++------- interface/src/BandwidthMeter.h | 28 ++++++++++++++++------------ interface/src/VoxelSystem.cpp | 2 +- interface/src/ui/BandwidthDialog.cpp | 5 ++--- 6 files changed, 42 insertions(+), 30 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index de6618f831..fb63fe2daf 100755 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -70,6 +70,8 @@ using namespace std; static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; static char STAR_CACHE_FILE[] = "cachedStars.txt"; +static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored + const glm::vec3 START_LOCATION(4.f, 0.f, 5.f); // Where one's own agent begins in the world // (will be overwritten if avatar data file is found) @@ -483,14 +485,14 @@ void Application::broadcastToAgents(unsigned char* data, size_t bytes, const cha int n = AgentList::getInstance()->broadcastToAgents(data, bytes, &type, 1); - unsigned channel; + BandwidthMeter::ChannelIndex channel; switch (type) { case AGENT_TYPE_AVATAR: case AGENT_TYPE_AVATAR_MIXER: - channel = 1; + channel = BandwidthMeter::AVATARS; break; case AGENT_TYPE_VOXEL_SERVER: - channel = 2; + channel = BandwidthMeter::VOXELS; break; default: return; @@ -1004,7 +1006,7 @@ void Application::checkBandwidthMeterClick() { // ... to be called upon button release if (_bandwidthDisplayOn->isChecked() && - glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY))) <= 6 && + glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY))) <= BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH && _bandwidthMeter.isWithinArea(_mouseX, _mouseY, _glWidget->width(), _glWidget->height())) { // The bandwidth meter is visible, the click didn't get dragged too far and @@ -2843,7 +2845,7 @@ void* Application::networkReceive(void* args) { AgentList::getInstance()->processBulkAgentData(&senderAddress, app->_incomingPacket, bytesReceived); - getInstance()->_bandwidthMeter.inputStream(1).updateValue(bytesReceived); + getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived); break; case PACKET_HEADER_AVATAR_VOXEL_URL: processAvatarVoxelURLMessage(app->_incomingPacket, bytesReceived); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index b60f060e5d..cfc4f6de19 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -124,7 +124,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o dataPacket, BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); - interface->getBandwidthMeter()->outputStream(0) + interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO) .updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); } @@ -448,7 +448,7 @@ void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBy _ringBuffer.parseData((unsigned char*) receivedData, PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER)); - Application::getInstance()->getBandwidthMeter()->inputStream(0) + Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO) .updateValue(PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER)); _lastReceiveTime = currentReceiveTime; diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index f7905cade7..ba89864807 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -36,7 +36,7 @@ namespace { // .cpp-local int const INITIAL_SCALE_MAXIMUM_INDEX = 250; // / 9: exponent, % 9: mantissa - 2, 0 o--o 2 * 10^-10 } -BandwidthMeter::ChannelInfo BandwidthMeter::_DEFAULT_CHANNELS[] = { +BandwidthMeter::ChannelInfo BandwidthMeter::_CHANNELS[] = { { "Audio" , "Kbps", 8000.0 / 1024.0, 0x40ff40d0 }, { "Avatars" , "Kbps", 8000.0 / 1024.0, 0xffef40c0 }, { "Voxels" , "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0 } @@ -46,7 +46,13 @@ BandwidthMeter::BandwidthMeter() : _textRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT), _scaleMaxIndex(INITIAL_SCALE_MAXIMUM_INDEX) { - memcpy(_channels, _DEFAULT_CHANNELS, sizeof(_DEFAULT_CHANNELS)); + _channels = static_cast( malloc(sizeof(_CHANNELS)) ); + memcpy(_channels, _CHANNELS, sizeof(_CHANNELS)); +} + +BandwidthMeter::~BandwidthMeter() { + + free(_channels); } BandwidthMeter::Stream::Stream(float msToAverage) : @@ -118,8 +124,8 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) { float totalIn = 0.0f, totalOut = 0.0f; for (int i = 0; i < N_CHANNELS; ++i) { - totalIn += inputStream(i).getValue(); - totalOut += outputStream(i).getValue(); + totalIn += inputStream(ChannelIndex(i)).getValue(); + totalOut += outputStream(ChannelIndex(i)).getValue(); } totalIn *= UNIT_SCALE; totalOut *= UNIT_SCALE; @@ -189,10 +195,11 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) { int xIn = 0, xOut = 0; for (int i = 0; i < N_CHANNELS; ++i) { - int wIn = int(barWidth * inputStream(i).getValue() * UNIT_SCALE / scaleMax); - int wOut = int(barWidth * outputStream(i).getValue() * UNIT_SCALE / scaleMax); + ChannelIndex chIdx = ChannelIndex(i); + int wIn = int(barWidth * inputStream(chIdx).getValue() * UNIT_SCALE / scaleMax); + int wOut = int(barWidth * outputStream(chIdx).getValue() * UNIT_SCALE / scaleMax); - setColorRGBA(channelInfo(i).colorRGBA); + setColorRGBA(channelInfo(chIdx).colorRGBA); if (wIn > 0) { renderBox(xIn, 0, wIn, barHeight); diff --git a/interface/src/BandwidthMeter.h b/interface/src/BandwidthMeter.h index d3641a21f0..0221306ed7 100644 --- a/interface/src/BandwidthMeter.h +++ b/interface/src/BandwidthMeter.h @@ -19,6 +19,7 @@ class BandwidthMeter { public: BandwidthMeter(); + ~BandwidthMeter(); void render(int screenWidth, int screenHeight); bool isWithinArea(int x, int y, int screenWidth, int screenHeight); @@ -27,13 +28,16 @@ public: static size_t const N_CHANNELS = 3; static size_t const N_STREAMS = N_CHANNELS * 2; + // Channel usage. + enum ChannelIndex { AUDIO, AVATARS, VOXELS }; + // Meta information held for a communication channel (bidirectional). struct ChannelInfo { - char const* caption; - char const* unitCaption; - double unitScale; - unsigned colorRGBA; + char const* const caption; + char const* unitCaption; + double unitScale; + unsigned colorRGBA; }; // Representation of a data stream (unidirectional; input or output). @@ -52,12 +56,12 @@ public: }; // 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]; } + Stream& inputStream(ChannelIndex i) { return _streams[i * 2]; } + Stream const& inputStream(ChannelIndex i) const { return _streams[i * 2]; } + Stream& outputStream(ChannelIndex i) { return _streams[i * 2 + 1]; } + Stream const& outputStream(ChannelIndex i) const { return _streams[i * 2 + 1]; } + ChannelInfo& channelInfo(ChannelIndex i) { return _channels[i]; } + ChannelInfo const& channelInfo(ChannelIndex i) const { return _channels[i]; } private: static void setColorRGBA(unsigned c); @@ -67,10 +71,10 @@ private: static inline int centered(int subject, int object); - static ChannelInfo _DEFAULT_CHANNELS[]; + static ChannelInfo _CHANNELS[]; TextRenderer _textRenderer; - ChannelInfo _channels[N_CHANNELS]; + ChannelInfo* _channels; Stream _streams[N_STREAMS]; int _scaleMaxIndex; }; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 5de9b89594..55d7e76d62 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -161,7 +161,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { pthread_mutex_unlock(&_treeLock); - Application::getInstance()->getBandwidthMeter()->inputStream(2).updateValue(numBytes); + Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::VOXELS).updateValue(numBytes); return numBytes; } diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp index 7879816d7c..1e0e2e616e 100644 --- a/interface/src/ui/BandwidthDialog.cpp +++ b/interface/src/ui/BandwidthDialog.cpp @@ -23,9 +23,8 @@ BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) : // 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); + BandwidthMeter::ChannelInfo& ch = _model->channelInfo(BandwidthMeter::ChannelIndex(i / 2)); QLabel* label = _labels[i] = new QLabel(); label->setAlignment(Qt::AlignRight); @@ -46,7 +45,7 @@ void BandwidthDialog::paintEvent(QPaintEvent* event) { // Update labels char strBuf[64]; for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) { - int chIdx = i / 2; + BandwidthMeter::ChannelIndex chIdx = BandwidthMeter::ChannelIndex(i / 2); bool input = i % 2 == 0; BandwidthMeter::ChannelInfo& ch = _model->channelInfo(chIdx); BandwidthMeter::Stream& s = input ? _model->inputStream(chIdx) : _model->outputStream(chIdx);