From 5fe59acb87996447bafba976488cc7511f5fa3d0 Mon Sep 17 00:00:00 2001 From: Lucas Crisman Date: Fri, 21 Mar 2014 14:10:00 -0300 Subject: [PATCH 01/13] Stats variable width for panels --- interface/src/Application.cpp | 424 ++---------------------------- interface/src/Application.h | 8 - interface/src/ui/Stats.cpp | 468 ++++++++++++++++++++++++++++++++++ interface/src/ui/Stats.h | 40 +++ 4 files changed, 525 insertions(+), 415 deletions(-) create mode 100644 interface/src/ui/Stats.cpp create mode 100644 interface/src/ui/Stats.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 030e3bc6fd..01e68e92d9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -76,6 +76,7 @@ #include "ui/TextRenderer.h" #include "InfoView.h" #include "ui/Snapshot.h" +#include "ui/Stats.h" using namespace std; @@ -105,8 +106,6 @@ const float MIRROR_FIELD_OF_VIEW = 30.0f; 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; - const QString CUSTOM_URL_SCHEME = "hifi:"; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { @@ -132,7 +131,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : QApplication(argc, argv), _window(new QMainWindow(desktop())), _glWidget(new GLCanvas()), - _statsExpanded(false), _nodeThread(new QThread(this)), _datagramProcessor(), _frameCount(0), @@ -162,8 +160,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _voxelHideShowThread(&_voxels), _packetsPerSecond(0), _bytesPerSecond(0), - _recentMaxPackets(0), - _resetRecentMaxPacketsSoon(true), _logger(new FileLogger(this)) { // read the ApplicationInfo.ini file for Name/Version/Domain information @@ -594,6 +590,8 @@ void Application::resizeGL(int width, int height) { updateProjectionMatrix(); glLoadIdentity(); + + Stats::getInstance()->resetWidthOnResizeGL(width); } void Application::updateProjectionMatrix() { @@ -1053,8 +1051,12 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { _mousePressed = false; checkBandwidthMeterClick(); if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { - checkStatsClick(); - } + int horizontalOffset = 0; + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + horizontalOffset = MIRROR_VIEW_WIDTH; + } + Stats::getInstance()->checkClick(_mouseX, _mouseY, _mouseDragStartedX, _mouseDragStartedY, horizontalOffset); + } } } } @@ -2486,11 +2488,17 @@ void Application::displayOverlay() { glPointSize(1.0f); if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { + int horizontalOffset = 0; + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + // mirror is enabled, let's set horizontal offset to give stats some margin + horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; + } + int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount(); // Onscreen text about position, servers, etc - displayStats(); + Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, _fps, _packetsPerSecond, _bytesPerSecond, voxelPacketsToProcess); // Bandwidth meter if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) { - displayStatsBackground(0x33333399, _glWidget->width() - 296, _glWidget->height() - 68, 296, 68); + Stats::drawBackground(0x33333399, _glWidget->width() - 296, _glWidget->height() - 68, 296, 68); _bandwidthMeter.render(_glWidget->width(), _glWidget->height()); } } @@ -2512,404 +2520,6 @@ 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() { - 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); - - // we need to take one avatar out so we don't include ourselves - int totalAvatars = _avatarManager.size() - 1; - int totalServers = NodeList::getInstance()->size(); - - 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.f, 2.f, serverNodes, WHITE_TEXT); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarNodes, WHITE_TEXT); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, framesPerSecond, WHITE_TEXT); - - if (_statsExpanded) { - char packetsPerSecond[30]; - sprintf(packetsPerSecond, "Pkts/sec: %d", _packetsPerSecond); - char averageMegabitsPerSecond[30]; - sprintf(averageMegabitsPerSecond, "Mbps: %3.2f", (float)_bytesPerSecond * 8.f / 1000000.f); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, packetsPerSecond, WHITE_TEXT); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, averageMegabitsPerSecond, WHITE_TEXT); - } - - verticalOffset = 0; - horizontalOffset += 161; - - if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { - int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0; - - NodeList* nodeList = NodeList::getInstance(); - SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); - SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer); - - 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; - - foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { - if (node->getType() == NodeType::VoxelServer) { - totalPingVoxel += node->getPingMs(); - voxelServerCount++; - if (pingVoxelMax < node->getPingMs()) { - pingVoxelMax = node->getPingMs(); - } - } - } - - if (voxelServerCount) { - pingVoxel = totalPingVoxel/voxelServerCount; - } - - lines = _statsExpanded ? 4 : 3; - displayStatsBackground(backgroundColor, horizontalOffset, 0, 175, lines * STATS_PELS_PER_LINE + 10); - horizontalOffset += 5; - - char audioJitter[30]; - sprintf(audioJitter, - "Buffer msecs %.1f", - (float) (_audio.getNetworkBufferLengthSamplesPerChannel() + (float) _audio.getJitterBufferSamples()) / - (float)_audio.getNetworkSampleRate() * 1000.f); - drawText(30, _glWidget->height() - 22, 0.10f, 0.f, 2.f, audioJitter, WHITE_TEXT); - - - 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.f, 2.f, audioPing, WHITE_TEXT); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPing, WHITE_TEXT); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelAvgPing, WHITE_TEXT); - - if (_statsExpanded) { - char voxelMaxPing[30]; - sprintf(voxelMaxPing, "Voxel max ping: %d", pingVoxelMax); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelMaxPing, WHITE_TEXT); - } - - verticalOffset = 0; - horizontalOffset += 171; - } - - glm::vec3 avatarPos = _myAvatar->getPosition(); - - 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 { - // longhand way - sprintf(avatarPosition, "Position: %.1f, %.1f, %.1f", avatarPos.x, avatarPos.y, avatarPos.z); - } - char avatarVelocity[30]; - sprintf(avatarVelocity, "Velocity: %.1f", glm::length(_myAvatar->getVelocity())); - char avatarBodyYaw[30]; - sprintf(avatarBodyYaw, "Yaw: %.1f", _myAvatar->getBodyYaw()); - char avatarMixerStats[200]; - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPosition, WHITE_TEXT); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarVelocity, WHITE_TEXT); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarBodyYaw, WHITE_TEXT); - - if (_statsExpanded) { - SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AvatarMixer); - 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.f, 2.f, avatarMixerStats, WHITE_TEXT); - } - - verticalOffset = 0; - horizontalOffset = _glWidget->width() - (mirrorEnabled ? 300 : 410); - - 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.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); - - 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.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); - - // 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.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); - } - - 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.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); - - // iterate all the current voxel stats, and list their sending modes, and total voxel counts - std::stringstream sendingMode(""); - sendingMode << "Octree Sending Mode: ["; - int serverCount = 0; - int movingServerCount = 0; - unsigned long totalNodes = 0; - unsigned long totalInternal = 0; - unsigned long totalLeaves = 0; - for(NodeToOctreeSceneStatsIterator i = _octreeServerSceneStats.begin(); i != _octreeServerSceneStats.end(); i++) { - //const QUuid& uuid = i->first; - OctreeSceneStats& stats = i->second; - serverCount++; - if (_statsExpanded) { - if (serverCount > 1) { - sendingMode << ","; - } - if (stats.isMoving()) { - sendingMode << "M"; - movingServerCount++; - } else { - sendingMode << "S"; - } - } - - // calculate server node totals - totalNodes += stats.getTotalElements(); - if (_statsExpanded) { - totalInternal += stats.getTotalInternal(); - totalLeaves += stats.getTotalLeaves(); - } - } - 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.f, 2.f, (char*)sendingMode.str().c_str(), WHITE_TEXT); - } - - // Incoming packets - int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount(); - if (_statsExpanded) { - voxelStats.str(""); - QString packetsString = locale.toString((int)voxelPacketsToProcess); - QString maxString = locale.toString((int)_recentMaxPackets); - voxelStats << "Voxel Packets to Process: " << qPrintable(packetsString) - << " [Recent Max: " << qPrintable(maxString) << "]"; - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); - } - - if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { - _recentMaxPackets = 0; - _resetRecentMaxPacketsSoon = false; - } - if (voxelPacketsToProcess == 0) { - _resetRecentMaxPacketsSoon = true; - } else { - if (voxelPacketsToProcess > _recentMaxPackets) { - _recentMaxPackets = voxelPacketsToProcess; - } - } - - verticalOffset += (_statsExpanded ? STATS_PELS_PER_LINE : 0); - - QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); - - // Server Voxels - voxelStats.str(""); - voxelStats << "Server voxels: " << qPrintable(serversTotalString); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); - - if (_statsExpanded) { - QString serversInternalString = locale.toString((uint)totalInternal); - QString serversLeavesString = locale.toString((uint)totalLeaves); - - voxelStats.str(""); - voxelStats << - "Internal: " << qPrintable(serversInternalString) << " " << - "Leaves: " << qPrintable(serversLeavesString) << ""; - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); - } - - unsigned long localTotal = VoxelTreeElement::getNodeCount(); - QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); - - // Local Voxels - voxelStats.str(""); - voxelStats << "Local voxels: " << qPrintable(localTotalString); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); - - 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: " << qPrintable(localInternalString) << " " << - "Leaves: " << qPrintable(localLeavesString) << ""; - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT); - } - - // LOD Details - if (_statsExpanded) { - voxelStats.str(""); - QString displayLODDetails = Menu::getInstance()->getLODFeedbackText(); - voxelStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed()); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); - } -} - -// 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; -} - glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { float horizontalScale = _glWidget->width() / 2.0f; float verticalScale = _glWidget->height() / 2.0f; diff --git a/interface/src/Application.h b/interface/src/Application.h index 28060113a9..8e65a660b8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -321,10 +321,6 @@ 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 renderRearViewMirror(const QRect& region, bool billboard = false); void renderViewFrustum(ViewFrustum& viewFrustum); @@ -345,7 +341,6 @@ private: QMainWindow* _window; GLCanvas* _glWidget; // our GLCanvas has a couple extra features - bool _statsExpanded; BandwidthMeter _bandwidthMeter; QThread* _nodeThread; @@ -456,9 +451,6 @@ private: int _packetsPerSecond; int _bytesPerSecond; - int _recentMaxPackets; // recent max incoming voxel packets to process - bool _resetRecentMaxPacketsSoon; - StDev _idleLoopStdev; float _idleLoopMeasuredJitter; diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp new file mode 100644 index 0000000000..9f87371c4c --- /dev/null +++ b/interface/src/ui/Stats.cpp @@ -0,0 +1,468 @@ +// +// Stats.cpp +// interface +// +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved +// + +#include + +#include + +#include +#include +#include +#include + +#include "Stats.h" +#include "InterfaceConfig.h" +#include "Menu.h" +#include "Util.h" + +const int STATS_PELS_PER_LINE = 20; + +const int STATS_GENERAL_MIN_WIDTH = 165; +const int STATS_PING_MIN_WIDTH = 190; +const int STATS_GEO_MIN_WIDTH = 240; +const int STATS_VOXEL_MIN_WIDTH = 410; + +Stats* Stats::getInstance() { + static Stats stats; + return &stats; +} + +Stats::Stats(): + _expanded(false), + _recentMaxPackets(0), + _resetRecentMaxPacketsSoon(true), + _generalStatsWidth(STATS_GENERAL_MIN_WIDTH), + _pingStatsWidth(STATS_PING_MIN_WIDTH), + _geoStatsWidth(STATS_GEO_MIN_WIDTH), + _voxelStatsWidth(STATS_VOXEL_MIN_WIDTH) +{ + // no constructor behavior yet, only members initialization +} + +void Stats::toggleExpanded() { + _expanded = !_expanded; +} + +// called on mouse click release +// check for clicks over stats in order to expand or contract them +void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset) { + QGLWidget* glWidget = Application::getInstance()->getGLWidget(); + + 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; + + statsX = horizontalOffset; + + // top-left stats click + lines = _expanded ? 5 : 3; + statsHeight = lines * STATS_PELS_PER_LINE + 10; + if (mouseX > statsX && mouseX < statsX + _generalStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { + toggleExpanded(); + return; + } + statsX += _generalStatsWidth; + + // ping stats click + lines = _expanded ? 4 : 3; + statsHeight = lines * STATS_PELS_PER_LINE + 10; + if (mouseX > statsX && mouseX < statsX + _pingStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { + toggleExpanded(); + return; + } + statsX += _pingStatsWidth; + + // top-center stats panel click + lines = _expanded ? 4 : 3; + statsHeight = lines * STATS_PELS_PER_LINE + 10; + if (mouseX > statsX && mouseX < statsX + _geoStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { + toggleExpanded(); + return; + } + statsX += _geoStatsWidth; + + // top-right stats click + lines = _expanded ? 11 : 3; + statsHeight = lines * STATS_PELS_PER_LINE + 10; + statsWidth = glWidget->width() - statsX; + if (mouseX > statsX && mouseX < statsX + statsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { + toggleExpanded(); + return; + } +} + +void Stats::resetWidthOnResizeGL(int width) { + QGLWidget* glWidget = Application::getInstance()->getGLWidget(); + int extraSpace = glWidget->width() + - STATS_GENERAL_MIN_WIDTH + - STATS_PING_MIN_WIDTH + - STATS_GEO_MIN_WIDTH + - STATS_VOXEL_MIN_WIDTH + - 3; + + _generalStatsWidth = STATS_GENERAL_MIN_WIDTH; + _pingStatsWidth = STATS_PING_MIN_WIDTH; + _geoStatsWidth = STATS_GEO_MIN_WIDTH; + _voxelStatsWidth = STATS_VOXEL_MIN_WIDTH; + + if (extraSpace > 4) { + _generalStatsWidth += (int) extraSpace / 4; + _pingStatsWidth += (int) extraSpace / 4; + _geoStatsWidth += (int) extraSpace / 4; + _voxelStatsWidth += glWidget->width() - (_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3); + } +} + + +// translucent background box that makes stats more readable +void Stats::drawBackground(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 Stats::display( + const float* color, + int horizontalOffset, + float fps, + int packetsPerSecond, + int bytesPerSecond, + int voxelPacketsToProcess) +{ + QGLWidget* glWidget = Application::getInstance()->getGLWidget(); + + unsigned int backgroundColor = 0x33333399; + int verticalOffset = 0, lines = 0; + + QLocale locale(QLocale::English); + std::stringstream voxelStats; + + glPointSize(1.0f); + + // we need to take one avatar out so we don't include ourselves + int totalAvatars = Application::getInstance()->getAvatarManager().size() - 1; + int totalServers = NodeList::getInstance()->size(); + + lines = _expanded ? 5 : 3; + drawBackground(backgroundColor, horizontalOffset, 0, _generalStatsWidth, 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.f, 2.f, serverNodes, color); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarNodes, color); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, framesPerSecond, color); + + if (_expanded) { + char packetsPerSecondString[30]; + sprintf(packetsPerSecondString, "Pkts/sec: %d", packetsPerSecond); + char averageMegabitsPerSecond[30]; + sprintf(averageMegabitsPerSecond, "Mbps: %3.2f", (float)bytesPerSecond * 8.f / 1000000.f); + + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, packetsPerSecondString, color); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, averageMegabitsPerSecond, color); + } + + verticalOffset = 0; + horizontalOffset = _generalStatsWidth +1; + + if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { + int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0; + + NodeList* nodeList = NodeList::getInstance(); + SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); + SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer); + + 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; + + foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { + if (node->getType() == NodeType::VoxelServer) { + totalPingVoxel += node->getPingMs(); + voxelServerCount++; + if (pingVoxelMax < node->getPingMs()) { + pingVoxelMax = node->getPingMs(); + } + } + } + + if (voxelServerCount) { + pingVoxel = totalPingVoxel/voxelServerCount; + } + + lines = _expanded ? 4 : 3; + drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10); + horizontalOffset += 5; + + Audio* audio = Application::getInstance()->getAudio(); + + char audioJitter[30]; + sprintf(audioJitter, + "Buffer msecs %.1f", + (float) (audio->getNetworkBufferLengthSamplesPerChannel() + (float) audio->getJitterBufferSamples()) / + (float) audio->getNetworkSampleRate() * 1000.f); + drawText(30, glWidget->height() - 22, 0.10f, 0.f, 2.f, audioJitter, color); + + + 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.f, 2.f, audioPing, color); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPing, color); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelAvgPing, color); + + if (_expanded) { + char voxelMaxPing[30]; + sprintf(voxelMaxPing, "Voxel max ping: %d", pingVoxelMax); + + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelMaxPing, color); + } + + verticalOffset = 0; + horizontalOffset = _generalStatsWidth + _pingStatsWidth + 2; + } + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + glm::vec3 avatarPos = myAvatar->getPosition(); + + lines = _expanded ? 4 : 3; + drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10); + horizontalOffset += 5; + + char avatarPosition[200]; + sprintf(avatarPosition, "Position: %.1f, %.1f, %.1f", avatarPos.x, avatarPos.y, avatarPos.z); + char avatarVelocity[30]; + sprintf(avatarVelocity, "Velocity: %.1f", glm::length(myAvatar->getVelocity())); + char avatarBodyYaw[30]; + sprintf(avatarBodyYaw, "Yaw: %.1f", myAvatar->getBodyYaw()); + char avatarMixerStats[200]; + + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPosition, color); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarVelocity, color); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarBodyYaw, color); + + if (_expanded) { + SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AvatarMixer); + 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.f, 2.f, avatarMixerStats, color); + } + + verticalOffset = 0; + horizontalOffset = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3; + + VoxelSystem* voxels = Application::getInstance()->getVoxels(); + + lines = _expanded ? 11 : 3; + drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); + horizontalOffset += 5; + + if (_expanded) { + // 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.f, 2.f, (char*)voxelStats.str().c_str(), color); + + 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.f, 2.f, (char*)voxelStats.str().c_str(), color); + + // 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.f, 2.f, (char*)voxelStats.str().c_str(), color); + } + + 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.f, 2.f, (char*)voxelStats.str().c_str(), color); + + // iterate all the current voxel stats, and list their sending modes, and total voxel counts + std::stringstream sendingMode(""); + sendingMode << "Octree Sending Mode: ["; + int serverCount = 0; + int movingServerCount = 0; + unsigned long totalNodes = 0; + unsigned long totalInternal = 0; + unsigned long totalLeaves = 0; + NodeToOctreeSceneStats* octreeServerSceneStats = Application::getInstance()->getOcteeSceneStats(); + for(NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) { + //const QUuid& uuid = i->first; + OctreeSceneStats& stats = i->second; + serverCount++; + if (_expanded) { + if (serverCount > 1) { + sendingMode << ","; + } + if (stats.isMoving()) { + sendingMode << "M"; + movingServerCount++; + } else { + sendingMode << "S"; + } + } + + // calculate server node totals + totalNodes += stats.getTotalElements(); + if (_expanded) { + totalInternal += stats.getTotalInternal(); + totalLeaves += stats.getTotalLeaves(); + } + } + if (_expanded) { + if (serverCount == 0) { + sendingMode << "---"; + } + sendingMode << "] " << serverCount << " servers"; + if (movingServerCount > 0) { + sendingMode << " "; + } else { + sendingMode << " "; + } + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)sendingMode.str().c_str(), color); + } + + // Incoming packets + if (_expanded) { + voxelStats.str(""); + QString packetsString = locale.toString((int)voxelPacketsToProcess); + QString maxString = locale.toString((int)_recentMaxPackets); + voxelStats << "Voxel Packets to Process: " << qPrintable(packetsString) + << " [Recent Max: " << qPrintable(maxString) << "]"; + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color); + } + + if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { + _recentMaxPackets = 0; + _resetRecentMaxPacketsSoon = false; + } + if (voxelPacketsToProcess == 0) { + _resetRecentMaxPacketsSoon = true; + } else { + if (voxelPacketsToProcess > _recentMaxPackets) { + _recentMaxPackets = voxelPacketsToProcess; + } + } + + verticalOffset += (_expanded ? STATS_PELS_PER_LINE : 0); + + QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); + + // Server Voxels + voxelStats.str(""); + voxelStats << "Server voxels: " << qPrintable(serversTotalString); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color); + + if (_expanded) { + QString serversInternalString = locale.toString((uint)totalInternal); + QString serversLeavesString = locale.toString((uint)totalLeaves); + + voxelStats.str(""); + voxelStats << + "Internal: " << qPrintable(serversInternalString) << " " << + "Leaves: " << qPrintable(serversLeavesString) << ""; + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color); + } + + unsigned long localTotal = VoxelTreeElement::getNodeCount(); + QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); + + // Local Voxels + voxelStats.str(""); + voxelStats << "Local voxels: " << qPrintable(localTotalString); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color); + + if (_expanded) { + 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: " << qPrintable(localInternalString) << " " << + "Leaves: " << qPrintable(localLeavesString) << ""; + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), color); + } + + // LOD Details + if (_expanded) { + voxelStats.str(""); + QString displayLODDetails = Menu::getInstance()->getLODFeedbackText(); + voxelStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed()); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color); + } +} diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h new file mode 100644 index 0000000000..aeb981a0c6 --- /dev/null +++ b/interface/src/ui/Stats.h @@ -0,0 +1,40 @@ +// +// Stats.h +// interface +// +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include + +#include + +//#include "Menu.h" + +class Stats: public QObject { + Q_OBJECT + +public: + static Stats* getInstance(); + + Stats(); + + static void drawBackground(unsigned int rgba, int x, int y, int width, int height); + + void toggleExpanded(); + void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset); + void resetWidthOnResizeGL(int width); + void display(const float* color, int horizontalOffset, float fps, int packetsPerSecond, int bytesPerSecond, int voxelPacketsToProcess); +private: + static Stats* _sharedInstance; + + bool _expanded; + + int _recentMaxPackets; // recent max incoming voxel packets to process + bool _resetRecentMaxPacketsSoon; + + int _generalStatsWidth; + int _pingStatsWidth; + int _geoStatsWidth; + int _voxelStatsWidth; +}; \ No newline at end of file From e545c2ac6565bcd754e3afd7c170f087ed3454cd Mon Sep 17 00:00:00 2001 From: Lucas Crisman Date: Mon, 24 Mar 2014 14:57:40 -0300 Subject: [PATCH 02/13] Stats tweaks: fonts adjustments --- interface/src/Application.cpp | 8 ++++- interface/src/ui/Stats.cpp | 58 +++++++++++++++++++++++------------ interface/src/ui/Stats.h | 7 +++-- 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 01e68e92d9..5fd6e7366a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -591,7 +591,13 @@ void Application::resizeGL(int width, int height) { updateProjectionMatrix(); glLoadIdentity(); - Stats::getInstance()->resetWidthOnResizeGL(width); + // update Stats width + int horizontalOffset = 0; + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + // mirror is enabled, let's set horizontal offset to give stats some margin + horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; + } + Stats::getInstance()->resetWidth(width, horizontalOffset); } void Application::updateProjectionMatrix() { diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 9f87371c4c..305b5fad57 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -2,6 +2,7 @@ // Stats.cpp // interface // +// Created by Lucas Crisman on 22/03/14. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved // @@ -38,9 +39,11 @@ Stats::Stats(): _generalStatsWidth(STATS_GENERAL_MIN_WIDTH), _pingStatsWidth(STATS_PING_MIN_WIDTH), _geoStatsWidth(STATS_GEO_MIN_WIDTH), - _voxelStatsWidth(STATS_VOXEL_MIN_WIDTH) + _voxelStatsWidth(STATS_VOXEL_MIN_WIDTH), + _lastHorizontalOffset(0) { - // no constructor behavior yet, only members initialization + QGLWidget* glWidget = Application::getInstance()->getGLWidget(); + resetWidth(glWidget->width(), 0); } void Stats::toggleExpanded() { @@ -75,15 +78,17 @@ void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseD statsX += _generalStatsWidth; // ping stats click - lines = _expanded ? 4 : 3; - statsHeight = lines * STATS_PELS_PER_LINE + 10; - if (mouseX > statsX && mouseX < statsX + _pingStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { - toggleExpanded(); - return; + if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { + lines = _expanded ? 4 : 3; + statsHeight = lines * STATS_PELS_PER_LINE + 10; + if (mouseX > statsX && mouseX < statsX + _pingStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { + toggleExpanded(); + return; + } + statsX += _pingStatsWidth; } - statsX += _pingStatsWidth; - // top-center stats panel click + // geo stats panel click lines = _expanded ? 4 : 3; statsHeight = lines * STATS_PELS_PER_LINE + 10; if (mouseX > statsX && mouseX < statsX + _geoStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { @@ -102,24 +107,32 @@ void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseD } } -void Stats::resetWidthOnResizeGL(int width) { +void Stats::resetWidth(int width, int horizontalOffset) { QGLWidget* glWidget = Application::getInstance()->getGLWidget(); - int extraSpace = glWidget->width() + int extraSpace = glWidget->width() - horizontalOffset -2 - STATS_GENERAL_MIN_WIDTH - - STATS_PING_MIN_WIDTH + - (Menu::getInstance()->isOptionChecked(MenuOption::TestPing) ? STATS_PING_MIN_WIDTH -1 : 0) - STATS_GEO_MIN_WIDTH - - STATS_VOXEL_MIN_WIDTH - - 3; + - STATS_VOXEL_MIN_WIDTH; + + int panels = 4; _generalStatsWidth = STATS_GENERAL_MIN_WIDTH; - _pingStatsWidth = STATS_PING_MIN_WIDTH; + if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { + _pingStatsWidth = STATS_PING_MIN_WIDTH; + } else { + _pingStatsWidth = 0; + panels = 3; + } _geoStatsWidth = STATS_GEO_MIN_WIDTH; _voxelStatsWidth = STATS_VOXEL_MIN_WIDTH; - if (extraSpace > 4) { - _generalStatsWidth += (int) extraSpace / 4; - _pingStatsWidth += (int) extraSpace / 4; - _geoStatsWidth += (int) extraSpace / 4; + if (extraSpace > panels) { + _generalStatsWidth += (int) extraSpace / panels; + if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { + _pingStatsWidth += (int) extraSpace / panels; + } + _geoStatsWidth += (int) extraSpace / panels; _voxelStatsWidth += glWidget->width() - (_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3); } } @@ -157,6 +170,11 @@ void Stats::display( QLocale locale(QLocale::English); std::stringstream voxelStats; + if (_lastHorizontalOffset != horizontalOffset) { + resetWidth(glWidget->width(), horizontalOffset); + _lastHorizontalOffset = horizontalOffset; + } + glPointSize(1.0f); // we need to take one avatar out so we don't include ourselves @@ -307,7 +325,7 @@ void Stats::display( VoxelSystem* voxels = Application::getInstance()->getVoxels(); - lines = _expanded ? 11 : 3; + lines = _expanded ? 12 : 3; drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index aeb981a0c6..7920c35953 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -2,6 +2,7 @@ // Stats.h // interface // +// Created by Lucas Crisman on 22/03/14. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // @@ -9,8 +10,6 @@ #include -//#include "Menu.h" - class Stats: public QObject { Q_OBJECT @@ -23,7 +22,7 @@ public: void toggleExpanded(); void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset); - void resetWidthOnResizeGL(int width); + void resetWidth(int width, int horizontalOffset); void display(const float* color, int horizontalOffset, float fps, int packetsPerSecond, int bytesPerSecond, int voxelPacketsToProcess); private: static Stats* _sharedInstance; @@ -37,4 +36,6 @@ private: int _pingStatsWidth; int _geoStatsWidth; int _voxelStatsWidth; + + int _lastHorizontalOffset; }; \ No newline at end of file From 9af1ddb37a55802620237a0bdcf974dc62a988a5 Mon Sep 17 00:00:00 2001 From: Lucas Crisman Date: Mon, 24 Mar 2014 15:27:17 -0300 Subject: [PATCH 03/13] Stats: fix for stats panels positioning when mirror is enabled --- interface/src/ui/Stats.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 305b5fad57..1722732e76 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -212,7 +212,7 @@ void Stats::display( } verticalOffset = 0; - horizontalOffset = _generalStatsWidth +1; + horizontalOffset = _lastHorizontalOffset + _generalStatsWidth +1; if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0; @@ -281,7 +281,7 @@ void Stats::display( } verticalOffset = 0; - horizontalOffset = _generalStatsWidth + _pingStatsWidth + 2; + horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + 2; } MyAvatar* myAvatar = Application::getInstance()->getAvatar(); @@ -321,7 +321,7 @@ void Stats::display( } verticalOffset = 0; - horizontalOffset = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3; + horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3; VoxelSystem* voxels = Application::getInstance()->getVoxels(); From 52df77b4b560005aece460c907058fc055ac054b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Apr 2014 16:25:35 -0700 Subject: [PATCH 04/13] Final work on models metadata support --- interface/src/ui/ModelsBrowser.cpp | 114 +++++++++++++++++------- interface/src/ui/ModelsBrowser.h | 14 ++- libraries/shared/src/FileDownloader.cpp | 45 ---------- libraries/shared/src/FileDownloader.h | 41 --------- 4 files changed, 87 insertions(+), 127 deletions(-) delete mode 100644 libraries/shared/src/FileDownloader.cpp delete mode 100644 libraries/shared/src/FileDownloader.h diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 15f1e9111e..e128d047ef 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -8,11 +8,10 @@ #include #include -#include #include #include #include -#include +#include #include #include @@ -33,27 +32,39 @@ static const QString KEY_NAME = "Key"; static const QString LOADING_MSG = "Loading..."; static const QString ERROR_MSG = "Error loading files"; +static const QString DO_NOT_MODIFY_TAG = "DoNotModify"; + enum ModelMetaData { NAME, - CREATOR, - UPLOAD_DATE, TYPE, GENDER, + CREATOR, + UPLOAD_DATE, MODEL_METADATA_COUNT }; static const QString propertiesNames[MODEL_METADATA_COUNT] = { "Name", - "Creator", - "Upload Date", "Type", - "Gender" + "Gender", + "Creator", + "Last Modified" +}; +static const QString propertiesIds[MODEL_METADATA_COUNT] = { + DO_NOT_MODIFY_TAG, + "Type", + "Gender", + "x-amz-request-id", + "Last-Modified" }; ModelsBrowser::ModelsBrowser(ModelType modelsType, QWidget* parent) : QWidget(parent), _handler(new ModelHandler(modelsType)) { + connect(_handler, SIGNAL(doneDownloading()), SLOT(resizeView())); + connect(_handler, SIGNAL(updated()), SLOT(resizeView())); + // Connect handler _handler->connect(this, SIGNAL(startDownloading()), SLOT(download())); _handler->connect(_handler, SIGNAL(doneDownloading()), SLOT(update())); @@ -106,6 +117,12 @@ void ModelsBrowser::applyFilter(const QString &filter) { _handler->unlockModel(); } +void ModelsBrowser::resizeView() { + for (int i = 0; i < MODEL_METADATA_COUNT; ++i) { + _view.resizeColumnToContents(i); + } +} + void ModelsBrowser::browse() { QDialog dialog; dialog.setWindowTitle("Browse models"); @@ -145,8 +162,6 @@ ModelHandler::ModelHandler(ModelType modelsType, QWidget* parent) : _initiateExit(false), _type(modelsType) { - connect(&_downloader, SIGNAL(done(QNetworkReply::NetworkError)), SLOT(downloadFinished())); - // set headers data QStringList headerData; for (int i = 0; i < MODEL_METADATA_COUNT; ++i) { @@ -156,9 +171,6 @@ ModelHandler::ModelHandler(ModelType modelsType, QWidget* parent) : } void ModelHandler::download() { - // Query models list - queryNewFiles(); - _lock.lockForWrite(); if (_initiateExit) { _lock.unlock(); @@ -169,10 +181,25 @@ void ModelHandler::download() { loadingItem->setEnabled(false); _model.appendRow(loadingItem); _lock.unlock(); + + // Query models list + queryNewFiles(); } void ModelHandler::update() { - // Will be implemented in my next PR + _lock.lockForWrite(); + if (_initiateExit) { + _lock.unlock(); + return; + } + for (int i = 0; i < _model.rowCount(); ++i) { + QUrl url(_model.item(i,0)->data(Qt::UserRole).toString()); + QNetworkAccessManager* accessManager = new QNetworkAccessManager(this); + QNetworkRequest request(url); + accessManager->head(request); + connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*))); + } + _lock.unlock(); } void ModelHandler::exit() { @@ -180,7 +207,6 @@ void ModelHandler::exit() { _initiateExit = true; // Disconnect everything - _downloader.disconnect(); disconnect(); thread()->disconnect(); @@ -191,12 +217,16 @@ void ModelHandler::exit() { _lock.unlock(); } -void ModelHandler::downloadFinished() { - if (_downloader.getData().startsWith("readAll(); + + if (!data.isEmpty()) { + parseXML(data); } else { - qDebug() << _downloader.getData(); + parseHeaders(reply); } + reply->deleteLater(); + sender()->deleteLater(); } void ModelHandler::queryNewFiles(QString marker) { @@ -219,7 +249,11 @@ void ModelHandler::queryNewFiles(QString marker) { // Download url.setQuery(query); - _downloader.download(url); + QNetworkAccessManager* accessManager = new QNetworkAccessManager(this); + QNetworkRequest request(url); + accessManager->get(request); + connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*))); + } bool ModelHandler::parseXML(QByteArray xmlFile) { @@ -266,18 +300,9 @@ bool ModelHandler::parseXML(QByteArray xmlFile) { QList model; model << new QStandardItem(QFileInfo(xml.text().toString()).baseName()); model.first()->setData(PUBLIC_URL + "/" + xml.text().toString(), Qt::UserRole); - - // Rand properties for now (Will be taken out in the next PR) - static QString creator[] = {"Ryan", "Philip", "Andzrej"}; - static QString type[] = {"human", "beast", "pet", "elfe"}; - static QString gender[] = {"male", "female", "none"}; - model << new QStandardItem(creator[randIntInRange(0, 2)]); - model << new QStandardItem(QDate(randIntInRange(2013, 2014), - randIntInRange(1, 12), - randIntInRange(1, 30)).toString()); - model << new QStandardItem(type[randIntInRange(0, 3)]); - model << new QStandardItem(gender[randIntInRange(0, 2)]); - //////////////////////////////////////////////////////////// + for (int i = 1; i < MODEL_METADATA_COUNT; ++i) { + model << new QStandardItem(); + } _model.appendRow(model); } @@ -312,9 +337,32 @@ bool ModelHandler::parseXML(QByteArray xmlFile) { _lock.unlock(); if (!truncated) { - qDebug() << "Emitting..."; emit doneDownloading(); } return true; -} \ No newline at end of file +} + +bool ModelHandler::parseHeaders(QNetworkReply* reply) { + _lock.lockForWrite(); + + QList items = _model.findItems(QFileInfo(reply->url().toString()).baseName()); + if (items.isEmpty() || items.first()->text() == DO_NOT_MODIFY_TAG) { + return false; + } + + for (int i = 0; i < MODEL_METADATA_COUNT; ++i) { + for (int k = 1; k < reply->rawHeaderPairs().count(); ++k) { + QString key = reply->rawHeaderPairs().at(k).first.data(); + QString item = reply->rawHeaderPairs().at(k).second.data(); + if (key == propertiesIds[i]) { + _model.item(_model.indexFromItem(items.first()).row(), i)->setText(item); + } + } + } + _lock.unlock(); + + emit updated(); + return true; +} + diff --git a/interface/src/ui/ModelsBrowser.h b/interface/src/ui/ModelsBrowser.h index 9bc239ba18..30320de1c1 100644 --- a/interface/src/ui/ModelsBrowser.h +++ b/interface/src/ui/ModelsBrowser.h @@ -9,13 +9,10 @@ #ifndef __hifi__ModelsBrowser__ #define __hifi__ModelsBrowser__ -#include -#include -#include -#include #include +#include +#include -#include "FileDownloader.h" enum ModelType { Head, @@ -33,7 +30,7 @@ public: signals: void doneDownloading(); - void doneUpdating(); + void updated(); public slots: void download(); @@ -41,17 +38,17 @@ public slots: void exit(); private slots: - void downloadFinished(); + void downloadFinished(QNetworkReply* reply); private: bool _initiateExit; ModelType _type; - FileDownloader _downloader; QReadWriteLock _lock; QStandardItemModel _model; void queryNewFiles(QString marker = QString()); bool parseXML(QByteArray xmlFile); + bool parseHeaders(QNetworkReply* reply); }; @@ -71,6 +68,7 @@ public slots: private slots: void applyFilter(const QString& filter); + void resizeView(); private: ModelHandler* _handler; diff --git a/libraries/shared/src/FileDownloader.cpp b/libraries/shared/src/FileDownloader.cpp deleted file mode 100644 index 8b13b129fe..0000000000 --- a/libraries/shared/src/FileDownloader.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// -// FileDownloader.cpp -// hifi -// -// Created by Clement Brisset on 3/14/14. -// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. -// -// - -#include -#include -#include -#include - -#include "FileDownloader.h" - -FileDownloader::FileDownloader(QObject* parent) : QObject(parent) { - connect(&_networkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(processReply(QNetworkReply*))); -} - -void FileDownloader::download(const QUrl& dataURL, QNetworkAccessManager::Operation operation) { - QNetworkRequest request(dataURL); - - _downloadedData.clear(); - switch (operation) { - case QNetworkAccessManager::GetOperation: - _networkAccessManager.get(request); - break; - case QNetworkAccessManager::HeadOperation: - _networkAccessManager.head(request); - break; - default: - emit done(QNetworkReply::ProtocolInvalidOperationError); - break; - } -} - -void FileDownloader::processReply(QNetworkReply *reply) { - if (reply->error() == QNetworkReply::NoError) { - _downloadedData = reply->readAll(); - } - - reply->deleteLater(); - emit done(reply->error()); -} \ No newline at end of file diff --git a/libraries/shared/src/FileDownloader.h b/libraries/shared/src/FileDownloader.h deleted file mode 100644 index ad1351a575..0000000000 --- a/libraries/shared/src/FileDownloader.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// FileDownloader.h -// hifi -// -// Created by Clement Brisset on 3/14/14. -// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. -// -// - -#ifndef __hifi__FileDownloader__ -#define __hifi__FileDownloader__ - -#include -#include -#include -#include - -class FileDownloader : public QObject { - Q_OBJECT - -public: - FileDownloader(QObject* parent = NULL); - QByteArray getData() const { return _downloadedData; } - - -signals: - void done(QNetworkReply::NetworkError error); - -public slots: - void download(const QUrl& dataURL, QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation); - -private slots: - void processReply(QNetworkReply* reply); - -private: - QNetworkAccessManager _networkAccessManager; - QByteArray _downloadedData; -}; - - -#endif /* defined(__hifi__FileDownloader__) */ From cf20c448a3100ab1ca51bbee858b4f15d7d70d6f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Apr 2014 16:46:03 -0700 Subject: [PATCH 05/13] Few tweaks before PR --- interface/src/ui/ModelsBrowser.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index e128d047ef..276fdd24c1 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -54,7 +54,7 @@ static const QString propertiesIds[MODEL_METADATA_COUNT] = { DO_NOT_MODIFY_TAG, "Type", "Gender", - "x-amz-request-id", + "Creator", "Last-Modified" }; @@ -97,7 +97,7 @@ void ModelsBrowser::applyFilter(const QString &filter) { for (int k = 0; k < filters.count(); ++k) { match = false; for (int j = 0; j < MODEL_METADATA_COUNT; ++j) { - if (model->item(i, j)->text().contains(filters.at(k))) { + if (model->item(i, j)->text().contains(filters.at(k), Qt::CaseInsensitive)) { match = true; break; } @@ -359,6 +359,22 @@ bool ModelHandler::parseHeaders(QNetworkReply* reply) { _model.item(_model.indexFromItem(items.first()).row(), i)->setText(item); } } + + // Rand properties for now (Will be taken out when we have real metadata on the server) + if (_model.item(_model.indexFromItem(items.first()).row(), i)->text().isEmpty()) { + if (i == CREATOR) { + static QString creator[] = {"Ryan", "Philip", "Andzrej", "Phteven", "Brad"}; + _model.item(_model.indexFromItem(items.first()).row(), i)->setText(creator[randIntInRange(0, 4)]); + } else if (i == TYPE) { + static QString type[] = {"human", "beast", "pet", "elfe"}; + _model.item(_model.indexFromItem(items.first()).row(), i)->setText(type[randIntInRange(0, 3)]); + } else if (i == GENDER) { + static QString gender[] = {"male", "female", "none"}; + _model.item(_model.indexFromItem(items.first()).row(), i)->setText(gender[randIntInRange(0, 2)]); + } + } + //////////////////////////////////////////////////////////// + } _lock.unlock(); From c2f0545d96c3af7fc1c1f047a3b42d66d0a58826 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Apr 2014 17:12:11 -0700 Subject: [PATCH 06/13] Setup for actual metadata --- interface/src/ui/ModelsBrowser.cpp | 37 ++++++++++-------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 276fdd24c1..616aba3881 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -36,26 +36,29 @@ static const QString DO_NOT_MODIFY_TAG = "DoNotModify"; enum ModelMetaData { NAME, - TYPE, - GENDER, CREATOR, - UPLOAD_DATE, + DATE_ADDED, + TOTAL_SIZE, + POLY_NUM, + TAGS, MODEL_METADATA_COUNT }; static const QString propertiesNames[MODEL_METADATA_COUNT] = { "Name", - "Type", - "Gender", "Creator", - "Last Modified" + "Date Added", + "Total Size", + "Poly#", + "Tags" }; static const QString propertiesIds[MODEL_METADATA_COUNT] = { DO_NOT_MODIFY_TAG, - "Type", - "Gender", "Creator", - "Last-Modified" + "Date-Added", + "Total-Size", + "Poly-Num", + "Tags" }; ModelsBrowser::ModelsBrowser(ModelType modelsType, QWidget* parent) : @@ -359,22 +362,6 @@ bool ModelHandler::parseHeaders(QNetworkReply* reply) { _model.item(_model.indexFromItem(items.first()).row(), i)->setText(item); } } - - // Rand properties for now (Will be taken out when we have real metadata on the server) - if (_model.item(_model.indexFromItem(items.first()).row(), i)->text().isEmpty()) { - if (i == CREATOR) { - static QString creator[] = {"Ryan", "Philip", "Andzrej", "Phteven", "Brad"}; - _model.item(_model.indexFromItem(items.first()).row(), i)->setText(creator[randIntInRange(0, 4)]); - } else if (i == TYPE) { - static QString type[] = {"human", "beast", "pet", "elfe"}; - _model.item(_model.indexFromItem(items.first()).row(), i)->setText(type[randIntInRange(0, 3)]); - } else if (i == GENDER) { - static QString gender[] = {"male", "female", "none"}; - _model.item(_model.indexFromItem(items.first()).row(), i)->setText(gender[randIntInRange(0, 2)]); - } - } - //////////////////////////////////////////////////////////// - } _lock.unlock(); From d15e12da771ea0f2728783d71e163302d1a0fc70 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Apr 2014 12:25:50 -0700 Subject: [PATCH 07/13] Changed FstReader categories to place models in the right dirs --- libraries/shared/src/FstReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index 14cff957b1..fa71679dd2 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -157,9 +157,9 @@ bool FstReader::zip() { textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" " name=\"model_category\""); if (_isHead) { - textPart.setBody("head"); + textPart.setBody("heads"); } else { - textPart.setBody("skeleton"); + textPart.setBody("skeletons"); } _dataMultiPart->append(textPart); From 3bb6d9b3b33caa7fb28665fdce2992d7518daa74 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Apr 2014 16:07:25 -0700 Subject: [PATCH 08/13] Added call back to model upload. --- libraries/shared/src/FstReader.cpp | 24 ++++++++++++++++++++++-- libraries/shared/src/FstReader.h | 7 +++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index fa71679dd2..4a299fd757 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -172,14 +172,34 @@ bool FstReader::send() { return false; } - AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart); + JSONCallbackParameters callbackParams; + callbackParams.jsonCallbackReceiver = this; + callbackParams.jsonCallbackMethod = "uploadSuccess"; + callbackParams.errorCallbackReceiver = this; + callbackParams.errorCallbackMethod = "uploadFailed"; + + AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, callbackParams, QByteArray(), _dataMultiPart); _zipDir = NULL; _dataMultiPart = NULL; - qDebug() << "Model sent."; return true; } +void FstReader::uploadSuccess(const QJsonObject& jsonResponse) { + qDebug() << "Model sent with success to the data server."; + qDebug() << "It might take a few minute for it to appear in your model browser."; + deleteLater(); +} + +void FstReader::uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString) { + QMessageBox::warning(NULL, + QString("ModelUploader::uploadFailed()"), + QString("Model could not be sent to the data server."), + QMessageBox::Ok); + qDebug() << "Model upload failed (" << errorCode << "): " << errorString; + deleteLater(); +} + bool FstReader::addTextures(const QFileInfo& texdir) { QStringList filter; filter << "*.png" << "*.tif" << "*.jpg" << "*.jpeg"; diff --git a/libraries/shared/src/FstReader.h b/libraries/shared/src/FstReader.h index 6d1cac01c4..2ccf21a3b0 100644 --- a/libraries/shared/src/FstReader.h +++ b/libraries/shared/src/FstReader.h @@ -12,8 +12,11 @@ class TemporaryDir; class QHttpMultiPart; +class QFileInfo; class FstReader : public QObject { + Q_OBJECT + public: FstReader(bool isHead); ~FstReader(); @@ -21,6 +24,10 @@ public: bool zip(); bool send(); +private slots: + void uploadSuccess(const QJsonObject& jsonResponse); + void uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString); + private: TemporaryDir* _zipDir; int _lodCount; From 9166dea02eadb04a2810d28c2b7771dd99f494e7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Apr 2014 16:16:58 -0700 Subject: [PATCH 09/13] Changed FstReader name to ModelUploader --- interface/src/Application.cpp | 8 +++---- .../src/{FstReader.cpp => ModelUploader.cpp} | 22 +++++++++---------- .../src/{FstReader.h => ModelUploader.h} | 14 ++++++------ 3 files changed, 22 insertions(+), 22 deletions(-) rename libraries/shared/src/{FstReader.cpp => ModelUploader.cpp} (94%) rename libraries/shared/src/{FstReader.h => ModelUploader.h} (78%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 18a3a228d6..83eab37318 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include "Application.h" #include "InterfaceVersion.h" @@ -3244,9 +3244,9 @@ void Application::toggleRunningScriptsWidget() } void Application::uploadFST(bool isHead) { - FstReader reader(isHead); - if (reader.zip()) { - reader.send(); + ModelUploader* uploader = new ModelUploader(isHead); + if (uploader->zip()) { + uploader->send(); } } diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/ModelUploader.cpp similarity index 94% rename from libraries/shared/src/FstReader.cpp rename to libraries/shared/src/ModelUploader.cpp index 4a299fd757..aeeb3f642e 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/ModelUploader.cpp @@ -1,5 +1,5 @@ // -// FstReader.cpp +// ModelUploader.cpp // hifi // // Created by Clément Brisset on 3/4/14. @@ -18,7 +18,7 @@ #include #include "AccountManager.h" -#include "FstReader.h" +#include "ModelUploader.h" static const QString NAME_FIELD = "name"; @@ -38,7 +38,7 @@ public: } }; -FstReader::FstReader(bool isHead) : +ModelUploader::ModelUploader(bool isHead) : _zipDir(new TemporaryDir()), _lodCount(-1), _texturesCount(-1), @@ -51,11 +51,11 @@ FstReader::FstReader(bool isHead) : } -FstReader::~FstReader() { +ModelUploader::~ModelUploader() { delete _dataMultiPart; } -bool FstReader::zip() { +bool ModelUploader::zip() { // File Dialog QString filename = QFileDialog::getOpenFileName(NULL, "Select your .fst file ...", @@ -167,7 +167,7 @@ bool FstReader::zip() { return true; } -bool FstReader::send() { +bool ModelUploader::send() { if (!_readyToSend) { return false; } @@ -185,13 +185,13 @@ bool FstReader::send() { return true; } -void FstReader::uploadSuccess(const QJsonObject& jsonResponse) { +void ModelUploader::uploadSuccess(const QJsonObject& jsonResponse) { qDebug() << "Model sent with success to the data server."; qDebug() << "It might take a few minute for it to appear in your model browser."; deleteLater(); } -void FstReader::uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString) { +void ModelUploader::uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString) { QMessageBox::warning(NULL, QString("ModelUploader::uploadFailed()"), QString("Model could not be sent to the data server."), @@ -200,7 +200,7 @@ void FstReader::uploadFailed(QNetworkReply::NetworkError errorCode, const QStrin deleteLater(); } -bool FstReader::addTextures(const QFileInfo& texdir) { +bool ModelUploader::addTextures(const QFileInfo& texdir) { QStringList filter; filter << "*.png" << "*.tif" << "*.jpg" << "*.jpeg"; @@ -229,7 +229,7 @@ bool FstReader::addTextures(const QFileInfo& texdir) { return true; } -bool FstReader::compressFile(const QString &inFileName, const QString &outFileName) { +bool ModelUploader::compressFile(const QString &inFileName, const QString &outFileName) { QFile inFile(inFileName); inFile.open(QIODevice::ReadOnly); QByteArray buffer = inFile.readAll(); @@ -253,7 +253,7 @@ bool FstReader::compressFile(const QString &inFileName, const QString &outFileNa } -bool FstReader::addPart(const QString &path, const QString& name) { +bool ModelUploader::addPart(const QString &path, const QString& name) { QFile* file = new QFile(path); if (!file->open(QIODevice::ReadOnly)) { QMessageBox::warning(NULL, diff --git a/libraries/shared/src/FstReader.h b/libraries/shared/src/ModelUploader.h similarity index 78% rename from libraries/shared/src/FstReader.h rename to libraries/shared/src/ModelUploader.h index 2ccf21a3b0..f127008f44 100644 --- a/libraries/shared/src/FstReader.h +++ b/libraries/shared/src/ModelUploader.h @@ -1,5 +1,5 @@ // -// FstReader.h +// ModelUploader.h // hifi // // Created by Clément Brisset on 3/4/14. @@ -7,19 +7,19 @@ // // -#ifndef __hifi__FstReader__ -#define __hifi__FstReader__ +#ifndef __hifi__ModelUploader__ +#define __hifi__ModelUploader__ class TemporaryDir; class QHttpMultiPart; class QFileInfo; -class FstReader : public QObject { +class ModelUploader : public QObject { Q_OBJECT public: - FstReader(bool isHead); - ~FstReader(); + ModelUploader(bool isHead); + ~ModelUploader(); bool zip(); bool send(); @@ -44,4 +44,4 @@ private: bool addPart(const QString& path, const QString& name); }; -#endif /* defined(__hifi__FstReader__) */ +#endif /* defined(__hifi__ModelUploader__) */ From ba4ccc22efa19e7d5e296e03b3ddce47b3bdf9c0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Apr 2014 16:16:58 -0700 Subject: [PATCH 10/13] Changed FstReader name to ModelUploader --- interface/src/Application.cpp | 8 +++---- .../src/{FstReader.cpp => ModelUploader.cpp} | 23 ++++++++++--------- .../src/{FstReader.h => ModelUploader.h} | 14 +++++------ 3 files changed, 23 insertions(+), 22 deletions(-) rename libraries/shared/src/{FstReader.cpp => ModelUploader.cpp} (94%) rename libraries/shared/src/{FstReader.h => ModelUploader.h} (78%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 18a3a228d6..83eab37318 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include "Application.h" #include "InterfaceVersion.h" @@ -3244,9 +3244,9 @@ void Application::toggleRunningScriptsWidget() } void Application::uploadFST(bool isHead) { - FstReader reader(isHead); - if (reader.zip()) { - reader.send(); + ModelUploader* uploader = new ModelUploader(isHead); + if (uploader->zip()) { + uploader->send(); } } diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/ModelUploader.cpp similarity index 94% rename from libraries/shared/src/FstReader.cpp rename to libraries/shared/src/ModelUploader.cpp index 4a299fd757..71514c8b0f 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/ModelUploader.cpp @@ -1,5 +1,5 @@ // -// FstReader.cpp +// ModelUploader.cpp // hifi // // Created by Clément Brisset on 3/4/14. @@ -18,7 +18,7 @@ #include #include "AccountManager.h" -#include "FstReader.h" +#include "ModelUploader.h" static const QString NAME_FIELD = "name"; @@ -38,7 +38,7 @@ public: } }; -FstReader::FstReader(bool isHead) : +ModelUploader::ModelUploader(bool isHead) : _zipDir(new TemporaryDir()), _lodCount(-1), _texturesCount(-1), @@ -51,11 +51,11 @@ FstReader::FstReader(bool isHead) : } -FstReader::~FstReader() { +ModelUploader::~ModelUploader() { delete _dataMultiPart; } -bool FstReader::zip() { +bool ModelUploader::zip() { // File Dialog QString filename = QFileDialog::getOpenFileName(NULL, "Select your .fst file ...", @@ -167,7 +167,7 @@ bool FstReader::zip() { return true; } -bool FstReader::send() { +bool ModelUploader::send() { if (!_readyToSend) { return false; } @@ -181,17 +181,18 @@ bool FstReader::send() { AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, callbackParams, QByteArray(), _dataMultiPart); _zipDir = NULL; _dataMultiPart = NULL; + qDebug() << "Sending model..."; return true; } -void FstReader::uploadSuccess(const QJsonObject& jsonResponse) { +void ModelUploader::uploadSuccess(const QJsonObject& jsonResponse) { qDebug() << "Model sent with success to the data server."; qDebug() << "It might take a few minute for it to appear in your model browser."; deleteLater(); } -void FstReader::uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString) { +void ModelUploader::uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString) { QMessageBox::warning(NULL, QString("ModelUploader::uploadFailed()"), QString("Model could not be sent to the data server."), @@ -200,7 +201,7 @@ void FstReader::uploadFailed(QNetworkReply::NetworkError errorCode, const QStrin deleteLater(); } -bool FstReader::addTextures(const QFileInfo& texdir) { +bool ModelUploader::addTextures(const QFileInfo& texdir) { QStringList filter; filter << "*.png" << "*.tif" << "*.jpg" << "*.jpeg"; @@ -229,7 +230,7 @@ bool FstReader::addTextures(const QFileInfo& texdir) { return true; } -bool FstReader::compressFile(const QString &inFileName, const QString &outFileName) { +bool ModelUploader::compressFile(const QString &inFileName, const QString &outFileName) { QFile inFile(inFileName); inFile.open(QIODevice::ReadOnly); QByteArray buffer = inFile.readAll(); @@ -253,7 +254,7 @@ bool FstReader::compressFile(const QString &inFileName, const QString &outFileNa } -bool FstReader::addPart(const QString &path, const QString& name) { +bool ModelUploader::addPart(const QString &path, const QString& name) { QFile* file = new QFile(path); if (!file->open(QIODevice::ReadOnly)) { QMessageBox::warning(NULL, diff --git a/libraries/shared/src/FstReader.h b/libraries/shared/src/ModelUploader.h similarity index 78% rename from libraries/shared/src/FstReader.h rename to libraries/shared/src/ModelUploader.h index 2ccf21a3b0..f127008f44 100644 --- a/libraries/shared/src/FstReader.h +++ b/libraries/shared/src/ModelUploader.h @@ -1,5 +1,5 @@ // -// FstReader.h +// ModelUploader.h // hifi // // Created by Clément Brisset on 3/4/14. @@ -7,19 +7,19 @@ // // -#ifndef __hifi__FstReader__ -#define __hifi__FstReader__ +#ifndef __hifi__ModelUploader__ +#define __hifi__ModelUploader__ class TemporaryDir; class QHttpMultiPart; class QFileInfo; -class FstReader : public QObject { +class ModelUploader : public QObject { Q_OBJECT public: - FstReader(bool isHead); - ~FstReader(); + ModelUploader(bool isHead); + ~ModelUploader(); bool zip(); bool send(); @@ -44,4 +44,4 @@ private: bool addPart(const QString& path, const QString& name); }; -#endif /* defined(__hifi__FstReader__) */ +#endif /* defined(__hifi__ModelUploader__) */ From 3a125db1f8241999e0457141a1fe14c728eb688d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Apr 2014 14:31:30 -0700 Subject: [PATCH 11/13] Increase the rate at which we increase detail and put a limit on the LOD multiplier so that it never takes more than about five seconds to return to default detail. Also, since there seems to be a weird issue where OS X throttles the frame rate to 30 fps (independent of our own throttling), use that as the lower adjustment range. --- interface/src/Menu.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5530c57281..5deb9474cf 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1260,20 +1260,22 @@ void Menu::autoAdjustLOD(float currentFPS) { quint64 now = usecTimestampNow(); + const float ADJUST_AVATAR_LOD_DOWN_FPS = 30.0f; const quint64 ADJUST_AVATAR_LOD_DOWN_DELAY = 1000 * 1000; - if (_fastFPSAverage.getAverage() < ADJUST_LOD_DOWN_FPS) { + if (_fastFPSAverage.getAverage() < ADJUST_AVATAR_LOD_DOWN_FPS) { if (now - _lastAvatarDetailDrop > ADJUST_AVATAR_LOD_DOWN_DELAY) { // attempt to lower the detail in proportion to the fps difference - float targetFps = (ADJUST_LOD_DOWN_FPS + ADJUST_LOD_UP_FPS) * 0.5f; + float targetFps = (ADJUST_AVATAR_LOD_DOWN_FPS + ADJUST_LOD_UP_FPS) * 0.5f; float averageFps = _fastFPSAverage.getAverage(); const float MAXIMUM_MULTIPLIER_SCALE = 2.0f; - _avatarLODDistanceMultiplier *= (averageFps < EPSILON) ? MAXIMUM_MULTIPLIER_SCALE : - qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps); + const float MAXIMUM_DISTANCE_MULTIPLIER = 15.0f; + _avatarLODDistanceMultiplier = qMin(MAXIMUM_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier * + (averageFps < EPSILON ? MAXIMUM_MULTIPLIER_SCALE : qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps))); _lastAvatarDetailDrop = now; } } else if (_fastFPSAverage.getAverage() > ADJUST_LOD_UP_FPS) { // let the detail level creep slowly upwards - const float DISTANCE_DECREASE_RATE = 0.02f; + const float DISTANCE_DECREASE_RATE = 0.05f; const float MINIMUM_DISTANCE_MULTIPLIER = 0.1f; _avatarLODDistanceMultiplier = qMax(MINIMUM_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE); From 01c42c741c57ecd01c51238ab3996228a45d2e0c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 4 Apr 2014 14:46:54 -0700 Subject: [PATCH 12/13] fix #2567 thrust + oculus doesn't change body rot --- interface/src/Application.cpp | 2 +- interface/src/avatar/Head.cpp | 4 ++++ interface/src/avatar/MyAvatar.cpp | 28 +--------------------------- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 83eab37318..d54cceb245 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -510,7 +510,7 @@ void Application::paintGL() { _myCamera.setDistance(0.0f); _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); - _myCamera.setTargetRotation(_myAvatar->getHead()->getOrientation()); + _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index ffa0975ccb..8a25c14574 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -14,6 +14,7 @@ #include "Head.h" #include "Menu.h" #include "Util.h" +#include "devices/OculusManager.h" using namespace std; @@ -198,6 +199,9 @@ glm::quat Head::getFinalOrientation() const { } glm::quat Head::getCameraOrientation () const { + if (OculusManager::isConnected()) { + return getOrientation(); + } Avatar* owningAvatar = static_cast(_owningAvatar); return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, 0.f, 0.0f))); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9dcfaa09ba..1ff93794c5 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -169,9 +169,6 @@ void MyAvatar::simulate(float deltaTime) { // Collect thrust forces from keyboard and devices updateThrust(deltaTime); - // copy velocity so we can use it later for acceleration - glm::vec3 oldVelocity = getVelocity(); - // calculate speed _speed = glm::length(_velocity); @@ -231,29 +228,6 @@ void MyAvatar::simulate(float deltaTime) { // update the euler angles setOrientation(orientation); - // Compute instantaneous acceleration - float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime; - const float OCULUS_ACCELERATION_PULL_THRESHOLD = 1.0f; - const int OCULUS_YAW_OFFSET_THRESHOLD = 10; - - if (!Application::getInstance()->getFaceshift()->isActive() && OculusManager::isConnected() && - fabsf(forwardAcceleration) > OCULUS_ACCELERATION_PULL_THRESHOLD && - fabs(getHead()->getBaseYaw()) > OCULUS_YAW_OFFSET_THRESHOLD) { - - // if we're wearing the oculus - // and this acceleration is above the pull threshold - // and the head yaw if off the body by more than OCULUS_YAW_OFFSET_THRESHOLD - - // match the body yaw to the oculus yaw - _bodyYaw = getAbsoluteHeadYaw(); - - // set the head yaw to zero for this draw - getHead()->setBaseYaw(0); - - // correct the oculus yaw offset - OculusManager::updateYawOffset(); - } - const float WALKING_SPEED_THRESHOLD = 0.2f; // use speed and angular velocity to determine walking vs. standing if (_speed + fabs(_bodyYawDelta) > WALKING_SPEED_THRESHOLD) { @@ -308,7 +282,7 @@ void MyAvatar::simulate(float deltaTime) { head->simulate(deltaTime, true); // Zero thrust out now that we've added it to velocity in this frame - _thrust = glm::vec3(0, 0, 0); + _thrust = glm::vec3(0.f); // now that we're done stepping the avatar forward in time, compute new collisions if (_collisionFlags != 0) { From 403ad5e984a8365353fe3b1a3371846fdcf7d0fb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 4 Apr 2014 15:18:12 -0700 Subject: [PATCH 13/13] removing a warning about hidden virtual override --- interface/src/avatar/FaceModel.cpp | 2 +- interface/src/avatar/FaceModel.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index b0ef947f65..e81e1da117 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -18,7 +18,7 @@ FaceModel::FaceModel(Head* owningHead) : { } -void FaceModel::simulate(float deltaTime) { +void FaceModel::simulate(float deltaTime, bool fullUpdate) { updateGeometry(); Avatar* owningAvatar = static_cast(_owningHead->_owningAvatar); glm::vec3 neckPosition; diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index acf2d2baf4..d675495e6b 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -21,7 +21,7 @@ public: FaceModel(Head* owningHead); - void simulate(float deltaTime); + virtual void simulate(float deltaTime, bool fullUpdate = true); protected: