overte/interface/src/BandwidthMeter.cpp

215 lines
7.1 KiB
C++

//
// 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.28f; // (e) fractional in respect to total channel height
float const LABEL_HORIZ_SPACING = 0.25f; // (f) fractional in respect to total channel height
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" , "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 }
};
// ---
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 = (channelHeight - streamSpacing) * 0.5f;
float labelScaleX = labelWidth / float(labelRenderWidth);
float labelScaleY = labelHeight / 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 / 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);
}
glPopMatrix();
}