diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 48722a0058..285a395c07 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -98,6 +98,8 @@ const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; const QString CHECK_VERSION_URL = "http://highfidelity.io/latestVersion.xml"; const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion"; +const int STATS_PELS_PER_LINE = 20; + void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) { QString messageWithNewLine = message + "\n"; fprintf(stdout, "%s", messageWithNewLine.toLocal8Bit().constData()); @@ -151,7 +153,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _swatch(NULL), _pasteMode(false), _logger(new FileLogger()), - _persistThread(NULL) + _persistThread(NULL), + _statsExpanded(false) { _applicationStartupTime = startup_time; @@ -250,6 +253,10 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : restoreSizeAndPosition(); loadScripts(); + + QFontDatabase fontDatabase; + fontDatabase.addApplicationFont("resources/styles/Inconsolata.otf"); + _window->setVisible(true); _glWidget->setFocusPolicy(Qt::StrongFocus); _glWidget->setFocus(); @@ -1260,6 +1267,9 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { _mouseY = event->y(); _mousePressed = false; checkBandwidthMeterClick(); + if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { + checkStatsClick(); + } _pieMenu.mouseReleaseEvent(_mouseX, _mouseY); } @@ -2977,9 +2987,11 @@ void Application::displayOverlay() { } if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { + displayStatsBackground(0x33333399, 0, _glWidget->height() - 68, 296, 68); _audio.render(_glWidget->width(), _glWidget->height()); if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) { - _audioScope.render(45, _glWidget->height() - 200); + int oscilloscopeTop = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) ? 130 : 25; + _audioScope.render(25, oscilloscopeTop); } } @@ -3034,17 +3046,9 @@ void Application::displayOverlay() { displayStats(); // Bandwidth meter if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) { + displayStatsBackground(0x33333399, _glWidget->width() - 296, _glWidget->height() - 68, 296, 68); _bandwidthMeter.render(_glWidget->width(), _glWidget->height()); } - // Stats at upper right of screen about who domain server is telling us about - glPointSize(1.0f); - char nodes[100]; - - int totalAvatars = _avatarManager.size(); - int totalServers = NodeList::getInstance()->size(); - - sprintf(nodes, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars); - drawtext(_glWidget->width() - 150, 20, 0.10f, 0, 1.0f, 0, nodes, 1, 0, 0); } // testing rendering coverage map @@ -3066,8 +3070,12 @@ void Application::displayOverlay() { char frameTimer[10]; uint64_t mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5); sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000)); - drawtext(_glWidget->width() - 100, _glWidget->height() - 20, 0.30f, 0, 1.0f, 0, frameTimer, 0, 0, 0); - drawtext(_glWidget->width() - 102, _glWidget->height() - 22, 0.30f, 0, 1.0f, 0, frameTimer, 1, 1, 1); + int timerBottom = + (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && + Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) + ? 80 : 20; + drawtext(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 0, 1.0f, 0, frameTimer, 0, 0, 0); + drawtext(_glWidget->width() - 102, _glWidget->height() - timerBottom - 2, 0.30f, 0, 1.0f, 0, frameTimer, 1, 1, 1); } _palette.render(_glWidget->width(), _glWidget->height()); @@ -3125,15 +3133,73 @@ void Application::displayOverlay() { glPopMatrix(); } +// translucent background box that makes stats more readable +void Application::displayStatsBackground(unsigned int rgba, int x, int y, int width, int height) { + glBegin(GL_QUADS); + glColor4f(((rgba >> 24) & 0xff) / 255.0f, + ((rgba >> 16) & 0xff) / 255.0f, + ((rgba >> 8) & 0xff) / 255.0f, + (rgba & 0xff) / 255.0f); + glVertex3f(x, y, 0); + glVertex3f(x + width, y, 0); + glVertex3f(x + width, y + height, 0); + glVertex3f(x , y + height, 0); + glEnd(); + glColor4f(1, 1, 1, 1); +} +// display expanded or contracted stats void Application::displayStats() { - int statsVerticalOffset = 8; - const int PELS_PER_LINE = 15; - char stats[200]; - statsVerticalOffset += PELS_PER_LINE; - sprintf(stats, "%3.0f FPS, %d Pkts/sec, %3.2f Mbps ", - _fps, _packetsPerSecond, (float)_bytesPerSecond * 8.f / 1000000.f); - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, stats); + unsigned int backgroundColor = 0x33333399; + int verticalOffset = 0, horizontalOffset = 0, lines = 0; + bool mirrorEnabled = Menu::getInstance()->isOptionChecked(MenuOption::Mirror); + + QLocale locale(QLocale::English); + std::stringstream voxelStats; + + glPointSize(1.0f); + + int totalAvatars = 0, totalServers = 0; + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + node->getType() == NODE_TYPE_AGENT ? totalAvatars++ : totalServers++; + } + + if (mirrorEnabled) { + horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; + } + + lines = _statsExpanded ? 5 : 3; + displayStatsBackground(backgroundColor, horizontalOffset, 0, 165, lines * STATS_PELS_PER_LINE + 10); + horizontalOffset += 5; + + char serverNodes[30]; + sprintf(serverNodes, "Servers: %d", totalServers); + char avatarNodes[30]; + sprintf(avatarNodes, "Avatars: %d", totalAvatars); + char framesPerSecond[30]; + sprintf(framesPerSecond, "Framerate: %3.0f FPS", _fps); + + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0f, 2, serverNodes, .93f, .93f, .93f); + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0f, 2, avatarNodes, .93f, .93f, .93f); + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, framesPerSecond, .93f, .93f, .93f); + + if (_statsExpanded) { + char packetsPerSecond[30]; + sprintf(packetsPerSecond, "Pkts/sec: %d", _packetsPerSecond); + char averageMegabitsPerSecond[30]; + sprintf(averageMegabitsPerSecond, "Avg Mbps: %3.2f", (float)_bytesPerSecond * 8.f / 1000000.f); + + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, packetsPerSecond, .93f, .93f, .93f); + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, averageMegabitsPerSecond, .93f, .93f, .93f); + } + + verticalOffset = 0; + horizontalOffset += 161; if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0; @@ -3145,7 +3211,6 @@ void Application::displayStats() { pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : 0; pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : 0; - // Now handle voxel servers, since there could be more than one, we average their ping times unsigned long totalPingVoxel = 0; int voxelServerCount = 0; @@ -3164,35 +3229,115 @@ void Application::displayStats() { pingVoxel = totalPingVoxel/voxelServerCount; } - char pingStats[200]; - statsVerticalOffset += PELS_PER_LINE; - sprintf(pingStats, "Ping audio/avatar/voxel: %d / %d / %d avg %d max ", pingAudio, pingAvatar, pingVoxel, pingVoxelMax); - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, pingStats); + lines = _statsExpanded ? 4 : 3; + displayStatsBackground(backgroundColor, horizontalOffset, 0, 175, lines * STATS_PELS_PER_LINE + 10); + horizontalOffset += 5; + + char audioPing[30]; + sprintf(audioPing, "Audio ping: %d", pingAudio); + char avatarPing[30]; + sprintf(avatarPing, "Avatar ping: %d", pingAvatar); + char voxelAvgPing[30]; + sprintf(voxelAvgPing, "Voxel avg ping: %d", pingVoxel); + + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, audioPing, .93f, .93f, .93f); + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, avatarPing, .93f, .93f, .93f); + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, voxelAvgPing, .93f, .93f, .93f); + + if (_statsExpanded) { + char voxelMaxPing[30]; + sprintf(voxelMaxPing, "Voxel max ping: %d", pingVoxelMax); + + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, voxelMaxPing, .93f, .93f, .93f); + } + + verticalOffset = 0; + horizontalOffset += 171; } - char avatarStats[200]; - statsVerticalOffset += PELS_PER_LINE; glm::vec3 avatarPos = _myAvatar.getPosition(); - sprintf(avatarStats, "Avatar: pos %.3f, %.3f, %.3f, vel %.1f, yaw = %.2f", avatarPos.x, avatarPos.y, avatarPos.z, glm::length(_myAvatar.getVelocity()), _myAvatar.getBodyYaw()); - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarStats); - SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); - char avatarMixerStats[200]; - if (avatarMixer) { - sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps", - roundf(avatarMixer->getAverageKilobitsPerSecond()), - roundf(avatarMixer->getAveragePacketsPerSecond())); + lines = _statsExpanded ? 4 : 3; + displayStatsBackground(backgroundColor, horizontalOffset, 0, _glWidget->width() - (mirrorEnabled ? 301 : 411) - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); + horizontalOffset += 5; + + char avatarPosition[200]; + if (mirrorEnabled) { + // shorthand formatting + sprintf(avatarPosition, "Pos: %.0f,%.0f,%.0f", avatarPos.x, avatarPos.y, avatarPos.z); } else { - sprintf(avatarMixerStats, "No Avatar Mixer"); + // longhand way + sprintf(avatarPosition, "Position: %.3f, %.3f, %.3f", avatarPos.x, avatarPos.y, avatarPos.z); + } + char avatarVelocity[30]; + sprintf(avatarVelocity, "Velocity: %.1f", glm::length(_myAvatar.getVelocity())); + char avatarBodyYaw[30]; + sprintf(avatarBodyYaw, "Yaw: %.2f", _myAvatar.getBodyYaw()); + char avatarMixerStats[200]; + + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, avatarPosition, .93f, .93f, .93f); + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, avatarVelocity, .93f, .93f, .93f); + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, avatarBodyYaw, .93f, .93f, .93f); + + if (_statsExpanded) { + SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); + if (avatarMixer) { + sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps", + roundf(avatarMixer->getAverageKilobitsPerSecond()), + roundf(avatarMixer->getAveragePacketsPerSecond())); + } else { + sprintf(avatarMixerStats, "No Avatar Mixer"); + } + + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, avatarMixerStats, .93f, .93f, .93f); } - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarMixerStats); + verticalOffset = 0; + horizontalOffset = _glWidget->width() - (mirrorEnabled ? 300 : 410); - // Used for formatting voxel stats details - statsVerticalOffset += PELS_PER_LINE; // skip a line for voxels - QLocale locale(QLocale::English); - std::stringstream voxelStats; + lines = _statsExpanded ? 11 : 3; + displayStatsBackground(backgroundColor, horizontalOffset, 0, _glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); + horizontalOffset += 5; + + if (_statsExpanded) { + // Local Voxel Memory Usage + voxelStats.str(""); + voxelStats << "Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.f << "MB"; + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, (char*)voxelStats.str().c_str(), .93f, .93f, .93f); + + voxelStats.str(""); + voxelStats << + "Geometry RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB / " << + "VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB"; + if (_voxels.hasVoxelMemoryUsageGPU()) { + voxelStats << " / GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB"; + } + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, (char*)voxelStats.str().c_str(), .93f, .93f, .93f); + + // Voxel Rendering + voxelStats.str(""); + voxelStats.precision(4); + voxelStats << "Voxel Rendering Slots Max: " << _voxels.getMaxVoxels() / 1000.f << "K"; + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, (char*)voxelStats.str().c_str(), .93f, .93f, .93f); + } + + voxelStats.str(""); + voxelStats.precision(4); + voxelStats << "Drawn: " << _voxels.getVoxelsWritten() / 1000.f << "K " << + "Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K "; + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, (char*)voxelStats.str().c_str(), .93f, .93f, .93f); // iterate all the current voxel stats, and list their sending modes, and total voxel counts std::stringstream sendingMode(""); @@ -3206,93 +3351,50 @@ void Application::displayStats() { //const QUuid& uuid = i->first; VoxelSceneStats& stats = i->second; serverCount++; - if (serverCount > 1) { - sendingMode << ","; - } - if (stats.isMoving()) { - sendingMode << "M"; - movingServerCount++; - } else { - sendingMode << "S"; + if (_statsExpanded) { + if (serverCount > 1) { + sendingMode << ","; + } + if (stats.isMoving()) { + sendingMode << "M"; + movingServerCount++; + } else { + sendingMode << "S"; + } } // calculate server node totals totalNodes += stats.getTotalElements(); - totalInternal += stats.getTotalInternal(); - totalLeaves += stats.getTotalLeaves(); + if (_statsExpanded) { + totalInternal += stats.getTotalInternal(); + totalLeaves += stats.getTotalLeaves(); + } } - if (serverCount == 0) { - sendingMode << "---"; + if (_statsExpanded) { + if (serverCount == 0) { + sendingMode << "---"; + } + sendingMode << "] " << serverCount << " servers"; + if (movingServerCount > 0) { + sendingMode << " "; + } else { + sendingMode << " "; + } + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, (char*)sendingMode.str().c_str(), .93f, .93f, .93f); } - sendingMode << "] " << serverCount << " servers"; - if (movingServerCount > 0) { - sendingMode << " "; - } else { - sendingMode << " "; - } - - QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); - QString serversInternalString = locale.toString((uint)totalInternal); - QString serversLeavesString = locale.toString((uint)totalLeaves); - - // Server Voxels - voxelStats.str(""); - voxelStats << - "Server Voxels Total: " << serversTotalString.toLocal8Bit().constData() << " / " << - "Internal: " << serversInternalString.toLocal8Bit().constData() << " / " << - "Leaves: " << serversLeavesString.toLocal8Bit().constData() << ""; - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - - unsigned long localTotal = VoxelTreeElement::getNodeCount(); - unsigned long localInternal = VoxelTreeElement::getInternalNodeCount(); - unsigned long localLeaves = VoxelTreeElement::getLeafNodeCount(); - QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); - QString localInternalString = locale.toString((uint)localInternal); - QString localLeavesString = locale.toString((uint)localLeaves); - - // Local Voxels - voxelStats.str(""); - voxelStats << - "Local Voxels Total: " << localTotalString.toLocal8Bit().constData() << " / " << - "Internal: " << localInternalString.toLocal8Bit().constData() << " / " << - "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - - // Local Voxel Memory Usage - voxelStats.str(""); - voxelStats << - "Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.f << "MB " - "Geometry RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB " << - "VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB "; - if (_voxels.hasVoxelMemoryUsageGPU()) { - voxelStats << "GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB "; - } - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - - // Voxel Rendering - voxelStats.str(""); - voxelStats.precision(4); - voxelStats << "Voxel Rendering Slots " << - "Max: " << _voxels.getMaxVoxels() / 1000.f << "K " << - "Drawn: " << _voxels.getVoxelsWritten() / 1000.f << "K " << - "Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K "; - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - - // draw Sending mode AFTER server node stats - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)sendingMode.str().c_str()); // Incoming packets - voxelStats.str(""); int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount(); - QString packetsString = locale.toString((int)voxelPacketsToProcess); - QString maxString = locale.toString((int)_recentMaxPackets); - voxelStats << "Voxel Packets to Process: " << packetsString.toLocal8Bit().constData() - << " [Recent Max: " << maxString.toLocal8Bit().constData() << "]"; + if (_statsExpanded) { + voxelStats.str(""); + QString packetsString = locale.toString((int)voxelPacketsToProcess); + QString maxString = locale.toString((int)_recentMaxPackets); + voxelStats << "Voxel Packets to Process: " << packetsString.toLocal8Bit().constData() + << " [Recent Max: " << maxString.toLocal8Bit().constData() << "]"; + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, (char*)voxelStats.str().c_str(), .93f, .93f, .93f); + } if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { _recentMaxPackets = 0; @@ -3305,8 +3407,109 @@ void Application::displayStats() { _recentMaxPackets = voxelPacketsToProcess; } } - statsVerticalOffset += PELS_PER_LINE; - drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); + + verticalOffset += (_statsExpanded ? STATS_PELS_PER_LINE : 0); + + QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); + + // Server Voxels + voxelStats.str(""); + voxelStats << "Server voxels: " << serversTotalString.toLocal8Bit().constData(); + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, (char*)voxelStats.str().c_str(), .93f, .93f, .93f); + + if (_statsExpanded) { + QString serversInternalString = locale.toString((uint)totalInternal); + QString serversLeavesString = locale.toString((uint)totalLeaves); + + voxelStats.str(""); + voxelStats << + "Internal: " << serversInternalString.toLocal8Bit().constData() << " " << + "Leaves: " << serversLeavesString.toLocal8Bit().constData() << ""; + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, (char*)voxelStats.str().c_str(), .93f, .93f, .93f); + } + + unsigned long localTotal = VoxelTreeElement::getNodeCount(); + QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); + + // Local Voxels + voxelStats.str(""); + voxelStats << "Local voxels: " << localTotalString.toLocal8Bit().constData(); + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, (char*)voxelStats.str().c_str(), .93f, .93f, .93f); + + if (_statsExpanded) { + unsigned long localInternal = VoxelTreeElement::getInternalNodeCount(); + unsigned long localLeaves = VoxelTreeElement::getLeafNodeCount(); + QString localInternalString = locale.toString((uint)localInternal); + QString localLeavesString = locale.toString((uint)localLeaves); + + voxelStats.str(""); + voxelStats << + "Internal: " << localInternalString.toLocal8Bit().constData() << " " << + "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; + verticalOffset += STATS_PELS_PER_LINE; + drawtext(horizontalOffset, verticalOffset, 0.10f, 0, 1.0, 2, (char*)voxelStats.str().c_str(), .93f, .93f, .93f); + } +} + +// called on mouse click release +// check for clicks over stats in order to expand or contract them +void Application::checkStatsClick() { + if (0 != glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY)))) { + // not worried about dragging on stats + return; + } + + int statsHeight = 0, statsWidth = 0, statsX = 0, statsY = 0, lines = 0; + + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + statsX += MIRROR_VIEW_WIDTH; + } + + // top-left stats click + lines = _statsExpanded ? 5 : 3; + statsHeight = lines * STATS_PELS_PER_LINE + 10; + statsWidth = 165; + if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) { + toggleStatsExpanded(); + return; + } + + // ping stats click + lines = _statsExpanded ? 4 : 3; + statsX += statsWidth; + statsHeight = lines * STATS_PELS_PER_LINE + 10; + statsWidth = 175; + if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) { + toggleStatsExpanded(); + return; + } + + // top-center stats panel click + lines = _statsExpanded ? 4 : 3; + statsX += statsWidth; + statsHeight = lines * STATS_PELS_PER_LINE + 10; + statsWidth = _glWidget->width() - 411 - statsX; + if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) { + toggleStatsExpanded(); + return; + } + + // top-right stats click + lines = _statsExpanded ? 11 : 3; + statsX = _glWidget->width() - 410; + statsHeight = lines * STATS_PELS_PER_LINE + 10; + statsWidth = _glWidget->width() - statsX; + if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) { + toggleStatsExpanded(); + return; + } +} + +void Application::toggleStatsExpanded() { + _statsExpanded = !_statsExpanded; } void Application::renderThrustAtVoxel(const glm::vec3& thrust) { diff --git a/interface/src/Application.h b/interface/src/Application.h index defe4dc8aa..c3404b4035 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -306,7 +306,11 @@ private: void updateShadowMap(); void displayOverlay(); + void displayStatsBackground(unsigned int rgba, int x, int y, int width, int height); void displayStats(); + void checkStatsClick(); + void toggleStatsExpanded(); + void renderAvatars(bool forceRenderHead, bool selfAvatarOnly = false); void renderViewFrustum(ViewFrustum& viewFrustum); void checkBandwidthMeterClick(); @@ -327,6 +331,7 @@ private: QMainWindow* _window; QGLWidget* _glWidget; + bool _statsExpanded; BandwidthMeter _bandwidthMeter; QThread* _nodeThread; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 47ab8b0aba..ea6bc80712 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -40,8 +40,9 @@ static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_ // Mute icon configration static const int ICON_SIZE = 24; -static const int ICON_LEFT = 20; -static const int BOTTOM_PADDING = 110; +static const int ICON_LEFT = 0; +static const int ICON_TOP = 115; +static const int ICON_TOP_MIRROR = 220; Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* parent) : AbstractAudioInterface(parent), @@ -548,13 +549,13 @@ void Audio::render(int screenWidth, int screenHeight) { if (_audioInput) { glLineWidth(2.0); glBegin(GL_LINES); - glColor3f(1,1,1); + glColor3f(.93f, .93f, .93f); int startX = 20.0; int currentX = startX; - int topY = screenHeight - 40; - int bottomY = screenHeight - 20; - float frameWidth = 20.0; + int topY = screenHeight - 45; + int bottomY = screenHeight - 25; + float frameWidth = 23.0; float halfY = topY + ((bottomY - topY) / 2.0); // draw the lines for the base of the ring buffer @@ -583,9 +584,9 @@ void Audio::render(int screenWidth, int screenHeight) { float msLeftForAudioOutput = (secondsLeftForAudioOutput + secondsLeftForRingBuffer) * 1000; if (_numFramesDisplayStarve == 0) { - glColor3f(0, 1, 0); + glColor3f(0, .8f, .4f); } else { - glColor3f(0.5 + (_numFramesDisplayStarve / 20.0f), 0, 0); + glColor3f(0.5 + (_numFramesDisplayStarve / 20.0f), .2f, .4f); _numFramesDisplayStarve--; } @@ -596,44 +597,44 @@ void Audio::render(int screenWidth, int screenHeight) { } glBegin(GL_QUADS); - glVertex2f(startX, topY + 2); - glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth, topY + 2); - glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth, bottomY - 2); - glVertex2f(startX, bottomY - 2); + glVertex2f(startX + 1, topY + 2); + glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth + 1, topY + 2); + glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth + 1, bottomY - 2); + glVertex2f(startX + 1, bottomY - 2); glEnd(); // Show a yellow bar with the averaged msecs latency you are hearing (from time of packet receipt) - glColor3f(1,1,0); + glColor3f(1, .8f, 0); glBegin(GL_QUADS); - glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth - 2, topY - 2); - glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth + 2, topY - 2); - glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth + 2, bottomY + 2); - glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth - 2, bottomY + 2); + glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth - 1, topY - 2); + glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth + 3, topY - 2); + glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth + 3, bottomY + 2); + glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth - 1, bottomY + 2); glEnd(); char out[40]; sprintf(out, "%3.0f\n", _averagedLatency); - drawtext(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth - 10, topY - 9, 0.10f, 0, 1, 0, out, 1,1,0); + drawtext(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth - 10, topY - 9, 0.10f, 0, 1, 2, out, 1, .8f, 0); // Show a red bar with the 'start' point of one frame plus the jitter buffer - glColor3f(1, 0, 0); + glColor3f(1, .2f, .4f); int jitterBufferPels = (1.f + (float)getJitterBufferSamples() / (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL) * frameWidth; sprintf(out, "%.0f\n", getJitterBufferSamples() / SAMPLE_RATE * 1000.f); - drawtext(startX + jitterBufferPels - 5, topY - 9, 0.10f, 0, 1, 0, out, 1, 0, 0); + drawtext(startX + jitterBufferPels - 5, topY - 9, 0.10f, 0, 1, 2, out, 1, .2f, .4f); sprintf(out, "j %.1f\n", _measuredJitter); if (Menu::getInstance()->getAudioJitterBufferSamples() == 0) { - drawtext(startX + jitterBufferPels - 5, bottomY + 12, 0.10f, 0, 1, 0, out, 1, 0, 0); + drawtext(startX + jitterBufferPels - 5, bottomY + 12, 0.10f, 0, 1, 2, out, 1, .2f, .4f); } else { - drawtext(startX, bottomY + 12, 0.10f, 0, 1, 0, out, 1, 0, 0); + drawtext(startX, bottomY + 12, 0.10f, 0, 1, 2, out, 1, .2f, .4f); } glBegin(GL_QUADS); - glVertex2f(startX + jitterBufferPels - 2, topY - 2); - glVertex2f(startX + jitterBufferPels + 2, topY - 2); - glVertex2f(startX + jitterBufferPels + 2, bottomY + 2); - glVertex2f(startX + jitterBufferPels - 2, bottomY + 2); + glVertex2f(startX + jitterBufferPels - 1, topY - 2); + glVertex2f(startX + jitterBufferPels + 3, topY - 2); + glVertex2f(startX + jitterBufferPels + 3, bottomY + 2); + glVertex2f(startX + jitterBufferPels - 1, bottomY + 2); glEnd(); } @@ -739,11 +740,13 @@ void Audio::handleAudioByteArray(const QByteArray& audioByteArray) { void Audio::renderToolIcon(int screenHeight) { - _iconBounds = QRect(ICON_LEFT, screenHeight - BOTTOM_PADDING, ICON_SIZE, ICON_SIZE); + int iconTop = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) ? ICON_TOP_MIRROR : ICON_TOP; + + _iconBounds = QRect(ICON_LEFT, iconTop, ICON_SIZE, ICON_SIZE); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, _micTextureId); - glColor3f(1, 1, 1); + glColor3f(.93f, .93f, .93f); glBegin(GL_QUADS); glTexCoord2f(1, 1); diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index 94fb06a496..d8081e186f 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -14,21 +14,21 @@ namespace { // .cpp-local int const AREA_WIDTH = -280; // 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 const AREA_HEIGHT = -40; // Height of the area used. Aligned to the bottom when negative. + int const BORDER_DISTANCE_HORIZ = -10; // Distance to edge of screen (use negative value when width is negative). + int const BORDER_DISTANCE_VERT = -15; // 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_TEXT = 0xedededff; // ^ ^ ^ ^ ^ ^ unsigned const COLOR_FRAME = 0xe0e0e0b0; // | | | unsigned const COLOR_INDICATOR = 0xc0c0c0b0; // | - char const* CAPTION_IN = "IN"; - char const* CAPTION_OUT = "OUT"; + 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 @@ -38,13 +38,13 @@ namespace { // .cpp-local } BandwidthMeter::ChannelInfo BandwidthMeter::_CHANNELS[] = { - { "Audio" , "Kbps", 8000.0 / 1024.0, 0x40ff40d0 }, + { "Audio" , "Kbps", 8000.0 / 1024.0, 0x33cc99ff }, { "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), + _textRenderer(INCONSOLATA_FONT_FAMILY, -1, QFont::Bold, false), _scaleMaxIndex(INITIAL_SCALE_MAXIMUM_INDEX) { _channels = static_cast( malloc(sizeof(_CHANNELS)) ); diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index ffee4c7879..a2e518b2d7 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -373,9 +373,18 @@ const glm::vec3 randVector() { } static TextRenderer* textRenderer(int mono) { - static TextRenderer* monoRenderer = new TextRenderer(MONO_FONT_FAMILY); - static TextRenderer* proportionalRenderer = new TextRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT); - return mono ? monoRenderer : proportionalRenderer; + static TextRenderer* monoRenderer = new TextRenderer(MONO_FONT_FAMILY); + static TextRenderer* proportionalRenderer = new TextRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT); + static TextRenderer* inconsolataRenderer = new TextRenderer(INCONSOLATA_FONT_FAMILY, -1, QFont::Bold, false); + switch (mono) { + case 1: + return monoRenderer; + case 2: + return inconsolataRenderer; + case 0: + default: + return proportionalRenderer; + } } int widthText(float scale, int mono, char const* string) { diff --git a/interface/src/Util.h b/interface/src/Util.h index 19509f8254..2a812120f0 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -25,6 +25,9 @@ // the standard mono font family #define MONO_FONT_FAMILY "Courier" +// the Inconsolata font family +#define INCONSOLATA_FONT_FAMILY "Inconsolata" + void eulerToOrthonormals(glm::vec3 * angles, glm::vec3 * fwd, glm::vec3 * left, glm::vec3 * up); float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos);