mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 14:37:46 +02:00
commit
6a3833359e
12 changed files with 560 additions and 25 deletions
|
@ -74,7 +74,7 @@ add_subdirectory(external/fervor/)
|
||||||
include_directories(external/fervor/)
|
include_directories(external/fervor/)
|
||||||
|
|
||||||
# run qt moc on qt-enabled headers
|
# 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
|
# create the executable, make it a bundle on OS X
|
||||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS})
|
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS})
|
||||||
|
|
|
@ -70,6 +70,8 @@ using namespace std;
|
||||||
static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
|
static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
|
||||||
static char STAR_CACHE_FILE[] = "cachedStars.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
|
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)
|
// (will be overwritten if avatar data file is found)
|
||||||
|
|
||||||
|
@ -160,6 +162,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
QApplication(argc, argv),
|
QApplication(argc, argv),
|
||||||
_window(new QMainWindow(desktop())),
|
_window(new QMainWindow(desktop())),
|
||||||
_glWidget(new GLCanvas()),
|
_glWidget(new GLCanvas()),
|
||||||
|
_bandwidthDialog(NULL),
|
||||||
_displayLevels(false),
|
_displayLevels(false),
|
||||||
_frameCount(0),
|
_frameCount(0),
|
||||||
_fps(120.0f),
|
_fps(120.0f),
|
||||||
|
@ -478,11 +481,30 @@ void Application::resizeGL(int width, int height) {
|
||||||
glLoadIdentity();
|
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);
|
||||||
|
|
||||||
|
BandwidthMeter::ChannelIndex channel;
|
||||||
|
switch (type) {
|
||||||
|
case AGENT_TYPE_AVATAR:
|
||||||
|
case AGENT_TYPE_AVATAR_MIXER:
|
||||||
|
channel = BandwidthMeter::AVATARS;
|
||||||
|
break;
|
||||||
|
case AGENT_TYPE_VOXEL_SERVER:
|
||||||
|
channel = BandwidthMeter::VOXELS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getInstance()->_bandwidthMeter.outputStream(channel).updateValue(n * bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::sendVoxelServerAddScene() {
|
||||||
char message[100];
|
char message[100];
|
||||||
sprintf(message,"%c%s",'Z',"add scene");
|
sprintf(message,"%c%s",'Z',"add scene");
|
||||||
int messageSize = strlen(message) + 1;
|
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) {
|
void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
|
@ -800,6 +822,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
_mouseX = event->x();
|
_mouseX = event->x();
|
||||||
_mouseY = event->y();
|
_mouseY = event->y();
|
||||||
_mousePressed = false;
|
_mousePressed = false;
|
||||||
|
checkBandwidthMeterClick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -940,7 +963,7 @@ void Application::terminate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sendAvatarVoxelURLMessage(const QUrl& url) {
|
void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
|
||||||
uint16_t ownerID = AgentList::getInstance()->getOwnerID();
|
uint16_t ownerID = AgentList::getInstance()->getOwnerID();
|
||||||
|
|
||||||
if (ownerID == UNKNOWN_AGENT_ID) {
|
if (ownerID == UNKNOWN_AGENT_ID) {
|
||||||
|
@ -951,10 +974,10 @@ static void sendAvatarVoxelURLMessage(const QUrl& url) {
|
||||||
message.append((const char*)&ownerID, sizeof(ownerID));
|
message.append((const char*)&ownerID, sizeof(ownerID));
|
||||||
message.append(url.toEncoded());
|
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
|
// skip the header
|
||||||
packetData++;
|
packetData++;
|
||||||
dataBytes--;
|
dataBytes--;
|
||||||
|
@ -979,6 +1002,37 @@ static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataB
|
||||||
QMetaObject::invokeMethod(avatar->getVoxels(), "setVoxelURL", Q_ARG(QUrl, url));
|
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))) <= 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
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::bandwidthDetailsClosed() {
|
||||||
|
|
||||||
|
QDialog* dlg = _bandwidthDialog;
|
||||||
|
_bandwidthDialog = NULL;
|
||||||
|
delete dlg;
|
||||||
|
}
|
||||||
|
|
||||||
void Application::editPreferences() {
|
void Application::editPreferences() {
|
||||||
QDialog dialog(_glWidget);
|
QDialog dialog(_glWidget);
|
||||||
dialog.setWindowTitle("Interface Preferences");
|
dialog.setWindowTitle("Interface Preferences");
|
||||||
|
@ -1139,12 +1193,12 @@ void Application::updateVoxelModeActions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
|
void Application::sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
|
||||||
unsigned char* bufferOut;
|
unsigned char* bufferOut;
|
||||||
int sizeOut;
|
int sizeOut;
|
||||||
|
|
||||||
if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, 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;
|
delete[] bufferOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1219,7 +1273,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 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) {
|
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
|
args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // reset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1283,7 +1337,7 @@ void Application::importVoxels() {
|
||||||
|
|
||||||
// If we have voxels left in the packet, then send the packet
|
// 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))) {
|
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) {
|
if (calculatedOctCode) {
|
||||||
|
@ -1335,7 +1389,7 @@ void Application::pasteVoxels() {
|
||||||
|
|
||||||
// If we have voxels left in the packet, then send the packet
|
// 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))) {
|
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) {
|
if (calculatedOctCode) {
|
||||||
|
@ -1412,7 +1466,11 @@ void Application::initMenu() {
|
||||||
(_logOn = toolsMenu->addAction("Log"))->setCheckable(true);
|
(_logOn = toolsMenu->addAction("Log"))->setCheckable(true);
|
||||||
_logOn->setChecked(false);
|
_logOn->setChecked(false);
|
||||||
_logOn->setShortcut(Qt::CTRL | Qt::Key_L);
|
_logOn->setShortcut(Qt::CTRL | Qt::Key_L);
|
||||||
|
(_bandwidthDisplayOn = toolsMenu->addAction("Bandwidth Display"))->setCheckable(true);
|
||||||
|
_bandwidthDisplayOn->setChecked(true);
|
||||||
|
toolsMenu->addAction("Bandwidth Details", this, SLOT(bandwidthDetails()));
|
||||||
|
|
||||||
|
|
||||||
QMenu* voxelMenu = menuBar->addMenu("Voxels");
|
QMenu* voxelMenu = menuBar->addMenu("Voxels");
|
||||||
_voxelModeActions = new QActionGroup(this);
|
_voxelModeActions = new QActionGroup(this);
|
||||||
_voxelModeActions->setExclusive(false); // exclusivity implies one is always checked
|
_voxelModeActions->setExclusive(false); // exclusivity implies one is always checked
|
||||||
|
@ -1792,7 +1850,12 @@ void Application::update(float deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update bandwidth dialog, if any
|
||||||
|
if (_bandwidthDialog) {
|
||||||
|
_bandwidthDialog->update();
|
||||||
|
}
|
||||||
|
|
||||||
// Update audio stats for procedural sounds
|
// Update audio stats for procedural sounds
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
_audio.setLastAcceleration(_myAvatar.getThrust());
|
_audio.setLastAcceleration(_myAvatar.getThrust());
|
||||||
|
@ -1875,8 +1938,8 @@ void Application::updateAvatar(float deltaTime) {
|
||||||
|
|
||||||
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
|
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
|
||||||
|
|
||||||
const char broadcastReceivers[2] = {AGENT_TYPE_VOXEL_SERVER, AGENT_TYPE_AVATAR_MIXER};
|
broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, AGENT_TYPE_VOXEL_SERVER);
|
||||||
AgentList::getInstance()->broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, broadcastReceivers, sizeof(broadcastReceivers));
|
broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, AGENT_TYPE_AVATAR_MIXER);
|
||||||
|
|
||||||
// once in a while, send my voxel url
|
// once in a while, send my voxel url
|
||||||
const float AVATAR_VOXEL_URL_SEND_INTERVAL = 1.0f; // seconds
|
const float AVATAR_VOXEL_URL_SEND_INTERVAL = 1.0f; // seconds
|
||||||
|
@ -2264,6 +2327,9 @@ void Application::displayOverlay() {
|
||||||
glPointSize(1.0f);
|
glPointSize(1.0f);
|
||||||
|
|
||||||
if (_renderStatsOn->isChecked()) { displayStats(); }
|
if (_renderStatsOn->isChecked()) { displayStats(); }
|
||||||
|
|
||||||
|
if (_bandwidthDisplayOn->isChecked()) { _bandwidthMeter.render(_glWidget->width(), _glWidget->height()); }
|
||||||
|
|
||||||
if (_logOn->isChecked()) { LogDisplay::instance.render(_glWidget->width(), _glWidget->height()); }
|
if (_logOn->isChecked()) { LogDisplay::instance.render(_glWidget->width(), _glWidget->height()); }
|
||||||
|
|
||||||
// Show chat entry field
|
// Show chat entry field
|
||||||
|
@ -2779,6 +2845,7 @@ void* Application::networkReceive(void* args) {
|
||||||
AgentList::getInstance()->processBulkAgentData(&senderAddress,
|
AgentList::getInstance()->processBulkAgentData(&senderAddress,
|
||||||
app->_incomingPacket,
|
app->_incomingPacket,
|
||||||
bytesReceived);
|
bytesReceived);
|
||||||
|
getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived);
|
||||||
break;
|
break;
|
||||||
case PACKET_HEADER_AVATAR_VOXEL_URL:
|
case PACKET_HEADER_AVATAR_VOXEL_URL:
|
||||||
processAvatarVoxelURLMessage(app->_incomingPacket, bytesReceived);
|
processAvatarVoxelURLMessage(app->_incomingPacket, bytesReceived);
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
|
|
||||||
#include <AgentList.h>
|
#include <AgentList.h>
|
||||||
|
|
||||||
|
#include "BandwidthMeter.h"
|
||||||
|
#include "ui/BandwidthDialog.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include "Audio.h"
|
#include "Audio.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,6 +35,7 @@
|
||||||
#include "Stars.h"
|
#include "Stars.h"
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
#include "VoxelSystem.h"
|
#include "VoxelSystem.h"
|
||||||
|
#include "PacketHeaders.h"
|
||||||
#include "Webcam.h"
|
#include "Webcam.h"
|
||||||
#include "renderer/GeometryCache.h"
|
#include "renderer/GeometryCache.h"
|
||||||
#include "ui/ChatEntry.h"
|
#include "ui/ChatEntry.h"
|
||||||
|
@ -84,6 +88,7 @@ public:
|
||||||
Environment* getEnvironment() { return &_environment; }
|
Environment* getEnvironment() { return &_environment; }
|
||||||
SerialInterface* getSerialHeadSensor() { return &_serialHeadSensor; }
|
SerialInterface* getSerialHeadSensor() { return &_serialHeadSensor; }
|
||||||
Webcam* getWebcam() { return &_webcam; }
|
Webcam* getWebcam() { return &_webcam; }
|
||||||
|
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||||
bool shouldEchoAudio() { return _echoAudioMode->isChecked(); }
|
bool shouldEchoAudio() { return _echoAudioMode->isChecked(); }
|
||||||
bool shouldLowPassFilter() { return _shouldLowPassFilter->isChecked(); }
|
bool shouldLowPassFilter() { return _shouldLowPassFilter->isChecked(); }
|
||||||
|
|
||||||
|
@ -97,8 +102,10 @@ private slots:
|
||||||
void timer();
|
void timer();
|
||||||
void idle();
|
void idle();
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
|
void bandwidthDetails();
|
||||||
void editPreferences();
|
void editPreferences();
|
||||||
|
void bandwidthDetailsClosed();
|
||||||
|
|
||||||
void pair();
|
void pair();
|
||||||
|
|
||||||
|
@ -145,7 +152,12 @@ private slots:
|
||||||
void runTests();
|
void runTests();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
static void broadcastToAgents(unsigned char* data, size_t bytes, const char type);
|
||||||
|
static void sendVoxelServerAddScene();
|
||||||
static bool sendVoxelsOperation(VoxelNode* node, void* extraData);
|
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 initMenu();
|
||||||
void updateFrustumRenderModeAction();
|
void updateFrustumRenderModeAction();
|
||||||
|
@ -161,7 +173,9 @@ private:
|
||||||
void displayOverlay();
|
void displayOverlay();
|
||||||
void displayStats();
|
void displayStats();
|
||||||
void renderViewFrustum(ViewFrustum& viewFrustum);
|
void renderViewFrustum(ViewFrustum& viewFrustum);
|
||||||
|
|
||||||
|
void checkBandwidthMeterClick();
|
||||||
|
|
||||||
void setupPaintingVoxel();
|
void setupPaintingVoxel();
|
||||||
void shiftPaintingColor();
|
void shiftPaintingColor();
|
||||||
void maybeEditVoxelUnderCursor();
|
void maybeEditVoxelUnderCursor();
|
||||||
|
@ -212,6 +226,7 @@ private:
|
||||||
QAction* _manualFirstPerson; // Whether to force first-person mode
|
QAction* _manualFirstPerson; // Whether to force first-person mode
|
||||||
QAction* _manualThirdPerson; // Whether to force third-person mode
|
QAction* _manualThirdPerson; // Whether to force third-person mode
|
||||||
QAction* _logOn; // Whether to show on-screen log
|
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
|
QActionGroup* _voxelModeActions; // The group of voxel edit mode actions
|
||||||
QAction* _addVoxelMode; // Whether add voxel mode is enabled
|
QAction* _addVoxelMode; // Whether add voxel mode is enabled
|
||||||
QAction* _deleteVoxelMode; // Whether delete voxel mode is enabled
|
QAction* _deleteVoxelMode; // Whether delete voxel mode is enabled
|
||||||
|
@ -226,6 +241,9 @@ private:
|
||||||
QAction* _frustumRenderModeAction;
|
QAction* _frustumRenderModeAction;
|
||||||
QAction* _settingsAutosave; // Whether settings are saved automatically
|
QAction* _settingsAutosave; // Whether settings are saved automatically
|
||||||
|
|
||||||
|
BandwidthMeter _bandwidthMeter;
|
||||||
|
BandwidthDialog* _bandwidthDialog;
|
||||||
|
|
||||||
SerialInterface _serialHeadSensor;
|
SerialInterface _serialHeadSensor;
|
||||||
QNetworkAccessManager* _networkAccessManager;
|
QNetworkAccessManager* _networkAccessManager;
|
||||||
QSettings* _settings;
|
QSettings* _settings;
|
||||||
|
@ -240,7 +258,7 @@ private:
|
||||||
timeval _timerStart, _timerEnd;
|
timeval _timerStart, _timerEnd;
|
||||||
timeval _lastTimeIdle;
|
timeval _lastTimeIdle;
|
||||||
bool _justStarted;
|
bool _justStarted;
|
||||||
|
|
||||||
Stars _stars;
|
Stars _stars;
|
||||||
|
|
||||||
VoxelSystem _voxels;
|
VoxelSystem _voxels;
|
||||||
|
|
|
@ -120,10 +120,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
|
// copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet
|
||||||
memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
||||||
|
|
||||||
agentList->getAgentSocket()->send(audioMixer->getActiveSocket(),
|
agentList->getAgentSocket()->send(audioMixer->getActiveSocket(),
|
||||||
dataPacket,
|
dataPacket,
|
||||||
BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
||||||
|
|
||||||
|
interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO)
|
||||||
|
.updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -335,13 +337,20 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
|
||||||
// Manually initialize the portaudio stream to ask for minimum latency
|
// Manually initialize the portaudio stream to ask for minimum latency
|
||||||
PaStreamParameters inputParameters, outputParameters;
|
PaStreamParameters inputParameters, outputParameters;
|
||||||
|
|
||||||
inputParameters.device = Pa_GetDefaultInputDevice();
|
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.channelCount = 2; // Stereo input
|
||||||
inputParameters.sampleFormat = (paInt16 | paNonInterleaved);
|
inputParameters.sampleFormat = (paInt16 | paNonInterleaved);
|
||||||
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
|
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
|
||||||
inputParameters.hostApiSpecificStreamInfo = NULL;
|
inputParameters.hostApiSpecificStreamInfo = NULL;
|
||||||
|
|
||||||
outputParameters.device = Pa_GetDefaultOutputDevice();
|
|
||||||
outputParameters.channelCount = 2; // Stereo output
|
outputParameters.channelCount = 2; // Stereo output
|
||||||
outputParameters.sampleFormat = (paInt16 | paNonInterleaved);
|
outputParameters.sampleFormat = (paInt16 | paNonInterleaved);
|
||||||
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
|
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
|
||||||
|
@ -438,7 +447,10 @@ void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBy
|
||||||
//printf("Got audio packet %d\n", _packetsReceivedThisPlayback);
|
//printf("Got audio packet %d\n", _packetsReceivedThisPlayback);
|
||||||
|
|
||||||
_ringBuffer.parseData((unsigned char*) receivedData, PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER));
|
_ringBuffer.parseData((unsigned char*) receivedData, PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER));
|
||||||
|
|
||||||
|
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO)
|
||||||
|
.updateValue(PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER));
|
||||||
|
|
||||||
_lastReceiveTime = currentReceiveTime;
|
_lastReceiveTime = currentReceiveTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
230
interface/src/BandwidthMeter.cpp
Normal file
230
interface/src/BandwidthMeter.cpp
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
//
|
||||||
|
// 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"
|
||||||
|
|
||||||
|
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 = 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }
|
||||||
|
};
|
||||||
|
|
||||||
|
BandwidthMeter::BandwidthMeter() :
|
||||||
|
_textRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT),
|
||||||
|
_scaleMaxIndex(INITIAL_SCALE_MAXIMUM_INDEX) {
|
||||||
|
|
||||||
|
_channels = static_cast<ChannelInfo*>( malloc(sizeof(_CHANNELS)) );
|
||||||
|
memcpy(_channels, _CHANNELS, sizeof(_CHANNELS));
|
||||||
|
}
|
||||||
|
|
||||||
|
BandwidthMeter::~BandwidthMeter() {
|
||||||
|
|
||||||
|
free(_channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
BandwidthMeter::Stream::Stream(float msToAverage) :
|
||||||
|
_value(0.0f),
|
||||||
|
_msToAverage(msToAverage) {
|
||||||
|
|
||||||
|
gettimeofday(& _prevTime, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BandwidthMeter::Stream::updateValue(double amount) {
|
||||||
|
|
||||||
|
// Determine elapsed time
|
||||||
|
timeval now;
|
||||||
|
gettimeofday(& now, NULL);
|
||||||
|
double dt = diffclock(& _prevTime, & now);
|
||||||
|
memcpy(& _prevTime, & now, sizeof(timeval));
|
||||||
|
|
||||||
|
// Compute approximate average
|
||||||
|
_value = glm::mix(_value, amount / dt,
|
||||||
|
glm::clamp(dt / _msToAverage, 0.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BandwidthMeter::setColorRGBA(unsigned c) {
|
||||||
|
|
||||||
|
glColor4ub(GLubyte( c >> 24),
|
||||||
|
GLubyte((c >> 16) & 0xff),
|
||||||
|
GLubyte((c >> 8) & 0xff),
|
||||||
|
GLubyte( c & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BandwidthMeter::renderBox(int x, int y, int w, int h) {
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
for (int i = 0; i < N_CHANNELS; ++i) {
|
||||||
|
|
||||||
|
totalIn += inputStream(ChannelIndex(i)).getValue();
|
||||||
|
totalOut += outputStream(ChannelIndex(i)).getValue();
|
||||||
|
}
|
||||||
|
totalIn *= UNIT_SCALE;
|
||||||
|
totalOut *= UNIT_SCALE;
|
||||||
|
float totalMax = glm::max(totalIn, totalOut);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Render 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);
|
||||||
|
|
||||||
|
// Render vertical lines for the frame
|
||||||
|
setColorRGBA(COLOR_FRAME);
|
||||||
|
renderVerticalLine(0, 0, h);
|
||||||
|
renderVerticalLine(barWidth, 0, h);
|
||||||
|
|
||||||
|
// Adjust scale
|
||||||
|
int steps;
|
||||||
|
double step, scaleMax;
|
||||||
|
bool commit = false;
|
||||||
|
do {
|
||||||
|
steps = (_scaleMaxIndex % 9) + 2;
|
||||||
|
step = pow(10.0, (_scaleMaxIndex / 9) - 10);
|
||||||
|
scaleMax = step * steps;
|
||||||
|
if (commit) {
|
||||||
|
// printLog("Bandwidth meter scale: %d\n", _scaleMaxIndex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (totalMax < scaleMax * 0.5) {
|
||||||
|
_scaleMaxIndex = glm::max(0, _scaleMaxIndex-1);
|
||||||
|
commit = true;
|
||||||
|
} else if (totalMax > scaleMax) {
|
||||||
|
_scaleMaxIndex += 1;
|
||||||
|
commit = true;
|
||||||
|
}
|
||||||
|
} while (commit);
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
|
||||||
|
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(chIdx).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_TEXT);
|
||||||
|
sprintf(fmtBuf, "%0.2f", totalIn);
|
||||||
|
_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) - PADDING_HORIZ_VALUE,
|
||||||
|
PADDING_HORIZ_VALUE),
|
||||||
|
textYlowerLine, fmtBuf);
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
83
interface/src/BandwidthMeter.h
Normal file
83
interface/src/BandwidthMeter.h
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
//
|
||||||
|
// 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();
|
||||||
|
~BandwidthMeter();
|
||||||
|
|
||||||
|
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;
|
||||||
|
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* const caption;
|
||||||
|
char const* unitCaption;
|
||||||
|
double unitScale;
|
||||||
|
unsigned colorRGBA;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Representation of a data stream (unidirectional; input or output).
|
||||||
|
class Stream {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Stream(float msToAverage = 3000.0f);
|
||||||
|
void updateValue(double amount);
|
||||||
|
double getValue() const { return _value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
double _value; // Current value.
|
||||||
|
double _msToAverage; // Milliseconds to average.
|
||||||
|
timeval _prevTime; // Time of last feed.
|
||||||
|
};
|
||||||
|
|
||||||
|
// Data model accessors
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
static ChannelInfo _CHANNELS[];
|
||||||
|
|
||||||
|
TextRenderer _textRenderer;
|
||||||
|
ChannelInfo* _channels;
|
||||||
|
Stream _streams[N_STREAMS];
|
||||||
|
int _scaleMaxIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__interface__BandwidthMeter__) */
|
||||||
|
|
|
@ -160,7 +160,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
setupNewVoxelsForDrawing();
|
setupNewVoxelsForDrawing();
|
||||||
|
|
||||||
pthread_mutex_unlock(&_treeLock);
|
pthread_mutex_unlock(&_treeLock);
|
||||||
|
|
||||||
|
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::VOXELS).updateValue(numBytes);
|
||||||
|
|
||||||
return numBytes;
|
return numBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
72
interface/src/ui/BandwidthDialog.cpp
Normal file
72
interface/src/ui/BandwidthDialog.cpp
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
#include "ui/BandwidthDialog.h"
|
||||||
|
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
|
||||||
|
#include <QPalette>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
#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) {
|
||||||
|
bool input = i % 2 == 0;
|
||||||
|
BandwidthMeter::ChannelInfo& ch = _model->channelInfo(BandwidthMeter::ChannelIndex(i / 2));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BandwidthDialog::paintEvent(QPaintEvent* event) {
|
||||||
|
|
||||||
|
// Update labels
|
||||||
|
char strBuf[64];
|
||||||
|
for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) {
|
||||||
|
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);
|
||||||
|
QLabel* label = _labels[i];
|
||||||
|
snprintf(strBuf, sizeof(strBuf), "%0.2f %s", s.getValue() * ch.unitScale, ch.unitCaption);
|
||||||
|
label->setText(strBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->QDialog::paintEvent(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);
|
||||||
|
emit closed();
|
||||||
|
}
|
||||||
|
|
47
interface/src/ui/BandwidthDialog.h
Normal file
47
interface/src/ui/BandwidthDialog.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//
|
||||||
|
// 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 "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();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void reject();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// State <- data model held by BandwidthMeter
|
||||||
|
void paintEvent(QPaintEvent*);
|
||||||
|
|
||||||
|
// Emits a 'closed' signal when this dialog is closed.
|
||||||
|
void closeEvent(QCloseEvent*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BandwidthMeter* _model;
|
||||||
|
QLabel* _labels[BandwidthMeter::N_STREAMS];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__interface__BandwidthDialog__) */
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtx/quaternion.hpp>
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
#include <glm/gtx/component_wise.hpp>
|
||||||
|
|
||||||
#include <UDPSocket.h>
|
#include <UDPSocket.h>
|
||||||
|
|
||||||
|
|
|
@ -350,14 +350,17 @@ void AgentList::addAgentToList(Agent* newAgent) {
|
||||||
Agent::printLog(*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++) {
|
for(AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||||
// only send to the AgentTypes we are asked to send to.
|
// only send to the AgentTypes we are asked to send to.
|
||||||
if (agent->getActiveSocket() != NULL && memchr(agentTypes, agent->getType(), numAgentTypes)) {
|
if (agent->getActiveSocket() != NULL && memchr(agentTypes, agent->getType(), numAgentTypes)) {
|
||||||
// we know which socket is good for this agent, send there
|
// we know which socket is good for this agent, send there
|
||||||
_agentSocket.send(agent->getActiveSocket(), broadcastData, dataBytes);
|
_agentSocket.send(agent->getActiveSocket(), broadcastData, dataBytes);
|
||||||
|
++n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AgentList::handlePingReply(sockaddr *agentAddress) {
|
void AgentList::handlePingReply(sockaddr *agentAddress) {
|
||||||
|
|
|
@ -82,7 +82,7 @@ public:
|
||||||
int updateAgentWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
|
int updateAgentWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
|
||||||
int updateAgentWithData(Agent *agent, unsigned char *packetData, int 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);
|
Agent* soloAgentOfType(char agentType);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue