diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 751583960e..ef69771607 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -241,6 +241,9 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int truePacketsSent = 0; int trueBytesSent = 0; int packetsSentThisInterval = 0; + bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) && nodeData->getViewFrustumJustStoppedChanging()) + || nodeData->hasLodChanged(); + bool somethingToSend = true; // assume we have something // FOR NOW... node tells us if it wants to receive only view frustum deltas @@ -365,10 +368,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue << " Wasted:" << _totalWastedBytes; } - // start tracking our stats - bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) - && nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged(); - // If we're starting a full scene, then definitely we want to empty the nodeBag if (isFullScene) { nodeData->nodeBag.deleteAll(); @@ -382,6 +381,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue } ::startSceneSleepTime = _usleepTime; + // start tracking our stats nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getOctree()->getRoot(), _myServer->getJurisdiction()); // This is the start of "resending" the scene. @@ -432,10 +432,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - - bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) && - nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged(); - EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, wantOcclusionCulling, coverageMap, boundaryLevelAdjust, voxelSizeScale, diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index e5979c561f..a425052970 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -544,8 +544,16 @@ void DomainServer::readAvailableDatagrams() { // construct the requested assignment from the packet data Assignment requestAssignment(receivedPacket); - qDebug() << "Received a request for assignment type" << requestAssignment.getType() - << "from" << senderSockAddr; + // Suppress these for Assignment::AgentType to once per 5 seconds + static quint64 lastNoisyMessage = usecTimestampNow(); + quint64 timeNow = usecTimestampNow(); + const quint64 NOISY_TIME_ELAPSED = 5 * USECS_PER_SECOND; + bool noisyMessage = false; + if (requestAssignment.getType() != Assignment::AgentType || (timeNow - lastNoisyMessage) > NOISY_TIME_ELAPSED) { + qDebug() << "Received a request for assignment type" << requestAssignment.getType() + << "from" << senderSockAddr; + noisyMessage = true; + } SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); @@ -562,8 +570,15 @@ void DomainServer::readAvailableDatagrams() { nodeList->getNodeSocket().writeDatagram(assignmentPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); } else { - qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType() - << "from" << senderSockAddr; + if (requestAssignment.getType() != Assignment::AgentType || (timeNow - lastNoisyMessage) > NOISY_TIME_ELAPSED) { + qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType() + << "from" << senderSockAddr; + noisyMessage = true; + } + } + + if (noisyMessage) { + lastNoisyMessage = timeNow; } } } diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 4aa920945b..72299befa4 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -28,19 +28,19 @@ ChatWindow - + Chat - + Connecting to XMPP... - + online now: @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 96069b7fcd..8091e58545 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -143,6 +143,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _importSucceded(false), _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), _wantToKillLocalVoxels(false), + _viewFrustum(), + _lastQueriedViewFrustum(), + _lastQueriedTime(usecTimestampNow()), _audioScope(256, 200, true), _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), _mouseX(0), @@ -1900,8 +1903,19 @@ void Application::updateMyAvatar(float deltaTime) { loadViewFrustum(_myCamera, _viewFrustum); // Update my voxel servers with my current voxel query... - queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); - queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions); + quint64 now = usecTimestampNow(); + quint64 sinceLastQuery = now - _lastQueriedTime; + const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; + bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY; + bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum); + + // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it + if (queryIsDue || viewIsDifferentEnough) { + _lastQueriedTime = now; + queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); + queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions); + _lastQueriedViewFrustum = _viewFrustum; + } } void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) { @@ -2750,8 +2764,8 @@ void Application::displayStats() { 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() << "]"; + 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); } @@ -2774,7 +2788,7 @@ void Application::displayStats() { // Server Voxels voxelStats.str(""); - voxelStats << "Server voxels: " << serversTotalString.toLocal8Bit().constData(); + 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); @@ -2784,8 +2798,8 @@ void Application::displayStats() { voxelStats.str(""); voxelStats << - "Internal: " << serversInternalString.toLocal8Bit().constData() << " " << - "Leaves: " << serversLeavesString.toLocal8Bit().constData() << ""; + "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); } @@ -2795,7 +2809,7 @@ void Application::displayStats() { // Local Voxels voxelStats.str(""); - voxelStats << "Local voxels: " << localTotalString.toLocal8Bit().constData(); + 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); @@ -2807,8 +2821,17 @@ void Application::displayStats() { voxelStats.str(""); voxelStats << - "Internal: " << localInternalString.toLocal8Bit().constData() << " " << - "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; + "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); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 124b95f73a..a84a455cb2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -381,6 +381,8 @@ private: MetavoxelSystem _metavoxels; ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. + ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels, particles) + quint64 _lastQueriedTime; Oscilloscope _audioScope; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 21c470c0cf..f73da0400a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1091,6 +1091,40 @@ void Menu::octreeStatsDetailsClosed() { } } +QString Menu::getLODFeedbackText() { + // determine granularity feedback + int boundaryLevelAdjust = getBoundaryLevelAdjust(); + QString granularityFeedback; + + switch (boundaryLevelAdjust) { + case 0: { + granularityFeedback = QString("at standard granularity."); + } break; + case 1: { + granularityFeedback = QString("at half of standard granularity."); + } break; + case 2: { + granularityFeedback = QString("at a third of standard granularity."); + } break; + default: { + granularityFeedback = QString("at 1/%1th of standard granularity.").arg(boundaryLevelAdjust + 1); + } break; + } + + // distance feedback + float voxelSizeScale = getVoxelSizeScale(); + float relativeToDefault = voxelSizeScale / DEFAULT_OCTREE_SIZE_SCALE; + QString result; + if (relativeToDefault > 1.01) { + result = QString("%1 further %2").arg(relativeToDefault,8,'f',2).arg(granularityFeedback); + } else if (relativeToDefault > 0.99) { + result = QString("the default distance %1").arg(granularityFeedback); + } else { + result = QString("%1 of default %2").arg(relativeToDefault,8,'f',3).arg(granularityFeedback); + } + return result; +} + void Menu::autoAdjustLOD(float currentFPS) { // NOTE: our first ~100 samples at app startup are completely all over the place, and we don't // really want to count them in our average, so we will ignore the real frame rates and stuff diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 380fe2d3b7..00ef51178a 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -84,6 +84,7 @@ public: void handleViewFrustumOffsetKeyModifier(int key); // User Tweakable LOD Items + QString getLODFeedbackText(); void autoAdjustLOD(float currentFPS); void setVoxelSizeScale(float sizeScale); float getVoxelSizeScale() const { return _voxelSizeScale; } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 6cd7523a14..b7e3d675a5 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -109,9 +109,6 @@ void Avatar::simulate(float deltaTime) { _shouldRenderBillboard = true; } - // copy velocity so we can use it later for acceleration - glm::vec3 oldVelocity = getVelocity(); - getHand()->simulate(deltaTime, false); _skeletonModel.setLODDistance(getLODDistance()); @@ -192,7 +189,7 @@ void Avatar::render(bool forShadowMap) { { // glow when moving in the distance - const float GLOW_DISTANCE = 5.0f; + const float GLOW_DISTANCE = 20.0f; Glower glower(_moving && lengthToTarget > GLOW_DISTANCE && !forShadowMap ? 1.0f : 0.0f); // render body diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 4699b360f6..f405358710 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -146,7 +146,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin // rotate palm according to average finger direction float directionLength = glm::length(direction); - const int MIN_ROTATION_FINGERS = 3; + const unsigned int MIN_ROTATION_FINGERS = 3; if (directionLength > EPSILON && palm.getNumFingers() >= MIN_ROTATION_FINGERS) { applyRotationDelta(jointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction), false); getJointRotation(jointIndex, palmRotation, true); diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 287aa4e5f6..0482dbf84c 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -60,7 +60,7 @@ void SixenseManager::update(float deltaTime) { // Either find a palm matching the sixense controller, or make a new one PalmData* palm; bool foundHand = false; - for (int j = 0; j < hand->getNumPalms(); j++) { + for (size_t j = 0; j < hand->getNumPalms(); j++) { if (hand->getPalms()[j].getSixenseID() == data.controller_index) { palm = &(hand->getPalms()[j]); foundHand = true; @@ -128,7 +128,7 @@ void SixenseManager::update(float deltaTime) { } // if the controllers haven't been moved in a while, disable - const int MOVEMENT_DISABLE_DURATION = 30 * 1000 * 1000; + const unsigned int MOVEMENT_DISABLE_DURATION = 30 * 1000 * 1000; if (usecTimestampNow() - _lastMovement > MOVEMENT_DISABLE_DURATION) { for (vector::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) { it->setActive(false); diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index cda14dc807..8bf5583a02 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -66,7 +66,7 @@ template QVariant readBinaryArray(QDataStream& in) { in >> compressedLength; QVector values; - const int DEFLATE_ENCODING = 1; + const unsigned int DEFLATE_ENCODING = 1; if (encoding == DEFLATE_ENCODING) { // preface encoded data with uncompressed length QByteArray compressed(sizeof(quint32) + compressedLength, 0); @@ -163,7 +163,7 @@ FBXNode parseBinaryFBXNode(QDataStream& in) { in >> nameLength; FBXNode node; - const int MIN_VALID_OFFSET = 40; + const unsigned int MIN_VALID_OFFSET = 40; if (endOffset < MIN_VALID_OFFSET || nameLength == 0) { // use a null name to indicate a null node return node; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index f657ef01d7..21fdc80858 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -328,6 +328,8 @@ bool Model::render(float alpha) { glDisable(GL_COLOR_MATERIAL); + glEnable(GL_CULL_FACE); + // render opaque meshes with alpha testing glEnable(GL_ALPHA_TEST); @@ -339,8 +341,6 @@ bool Model::render(float alpha) { // render translucent meshes afterwards, with back face culling - glEnable(GL_CULL_FACE); - renderMeshes(alpha, true); glDisable(GL_CULL_FACE); diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 2fd3d4f9cb..5fc5d56430 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -184,11 +184,8 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { } QLabel* userLabel = new QLabel(getParticipantName(message.from())); - QFont font = userLabel->font(); - font.setBold(true); - userLabel->setFont(font); userLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - userLabel->setStyleSheet("padding: 2px;"); + userLabel->setStyleSheet("padding: 2px; font-weight: bold"); userLabel->setAlignment(Qt::AlignTop); QLabel* messageLabel = new QLabel(message.body().replace(regexLinks, "\\1")); diff --git a/interface/src/ui/LodToolsDialog.cpp b/interface/src/ui/LodToolsDialog.cpp index 4cf4a29bf1..564669757c 100644 --- a/interface/src/ui/LodToolsDialog.cpp +++ b/interface/src/ui/LodToolsDialog.cpp @@ -68,7 +68,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : const unsigned redish = 0xfff00000; palette.setColor(QPalette::WindowText, QColor::fromRgb(redish)); _feedback->setPalette(palette); - _feedback->setText(getFeedbackText()); + _feedback->setText(Menu::getInstance()->getLODFeedbackText()); const int FEEDBACK_WIDTH = 350; _feedback->setFixedWidth(FEEDBACK_WIDTH); form->addRow("You can see... ", _feedback); @@ -81,40 +81,6 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : this->QDialog::setLayout(form); } -QString LodToolsDialog::getFeedbackText() { - // determine granularity feedback - int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); - QString granularityFeedback; - - switch (boundaryLevelAdjust) { - case 0: { - granularityFeedback = QString("at standard granularity."); - } break; - case 1: { - granularityFeedback = QString("at half of standard granularity."); - } break; - case 2: { - granularityFeedback = QString("at a third of standard granularity."); - } break; - default: { - granularityFeedback = QString("at 1/%1th of standard granularity.").arg(boundaryLevelAdjust + 1); - } break; - } - - // distance feedback - float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale(); - float relativeToDefault = voxelSizeScale / DEFAULT_OCTREE_SIZE_SCALE; - QString result; - if (relativeToDefault > 1.01) { - result = QString("%1 further %2").arg(relativeToDefault,8,'f',2).arg(granularityFeedback); - } else if (relativeToDefault > 0.99) { - result = QString("the default distance %1").arg(granularityFeedback); - } else { - result = QString("%1 of default %2").arg(relativeToDefault,8,'f',3).arg(granularityFeedback); - } - return result; -} - LodToolsDialog::~LodToolsDialog() { delete _feedback; delete _lodSize; @@ -124,19 +90,19 @@ LodToolsDialog::~LodToolsDialog() { void LodToolsDialog::reloadSliders() { _lodSize->setValue(Menu::getInstance()->getVoxelSizeScale() / TREE_SCALE); _boundaryLevelAdjust->setValue(Menu::getInstance()->getBoundaryLevelAdjust()); - _feedback->setText(getFeedbackText()); + _feedback->setText(Menu::getInstance()->getLODFeedbackText()); } void LodToolsDialog::sizeScaleValueChanged(int value) { float realValue = value * TREE_SCALE; Menu::getInstance()->setVoxelSizeScale(realValue); - _feedback->setText(getFeedbackText()); + _feedback->setText(Menu::getInstance()->getLODFeedbackText()); } void LodToolsDialog::boundaryLevelValueChanged(int value) { Menu::getInstance()->setBoundaryLevelAdjust(value); - _feedback->setText(getFeedbackText()); + _feedback->setText(Menu::getInstance()->getLODFeedbackText()); } void LodToolsDialog::resetClicked(bool checked) { diff --git a/interface/src/ui/LodToolsDialog.h b/interface/src/ui/LodToolsDialog.h index ee96cffd7e..98a5fce5f8 100644 --- a/interface/src/ui/LodToolsDialog.h +++ b/interface/src/ui/LodToolsDialog.h @@ -36,8 +36,6 @@ protected: void closeEvent(QCloseEvent*); private: - QString getFeedbackText(); - QSlider* _lodSize; QSlider* _boundaryLevelAdjust; QLabel* _feedback; diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index b1842e0619..eed8a7b6f3 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -387,7 +387,7 @@ void BoxSetTool::render() { glm::quat rotation = _editor->getGridRotation(); glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); glm::quat inverseRotation = glm::inverse(rotation); glm::vec3 rayOrigin = inverseRotation * Application::getInstance()->getMouseRayOrigin(); diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index 974964da04..daf5a68587 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -157,9 +157,9 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { statsValue.str(""); statsValue << - "Total: " << localTotalString.toLocal8Bit().constData() << " / " << - "Internal: " << localInternalString.toLocal8Bit().constData() << " / " << - "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; + "Total: " << qPrintable(localTotalString) << " / " << + "Internal: " << qPrintable(localInternalString) << " / " << + "Leaves: " << qPrintable(localLeavesString) << ""; label->setText(statsValue.str().c_str()); // iterate all the current voxel stats, and list their sending modes, total their voxels, etc... @@ -212,9 +212,9 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { label = _labels[_serverVoxels]; statsValue.str(""); statsValue << - "Total: " << serversTotalString.toLocal8Bit().constData() << " / " << - "Internal: " << serversInternalString.toLocal8Bit().constData() << " / " << - "Leaves: " << serversLeavesString.toLocal8Bit().constData() << ""; + "Total: " << qPrintable(serversTotalString) << " / " << + "Internal: " << qPrintable(serversInternalString) << " / " << + "Leaves: " << qPrintable(serversLeavesString) << ""; label->setText(statsValue.str().c_str()); showAllOctreeServers(); @@ -290,7 +290,7 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); serverBounds.scale(TREE_SCALE); serverDetails << " jurisdiction: " - << rootCodeHex.toLocal8Bit().constData() + << qPrintable(rootCodeHex) << " [" << rootDetails.x << ", " << rootDetails.y << ", " @@ -315,13 +315,25 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser const unsigned long USECS_PER_MSEC = 1000; float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; + float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; + float lastFullPackets = stats.getLastFullTotalPackets(); + float lastFullPPS = lastFullPackets; + if (lastFullSendInSeconds > 0) { + lastFullPPS = lastFullPackets / lastFullSendInSeconds; + } QString lastFullEncodeString = locale.toString(lastFullEncode); QString lastFullSendString = locale.toString(lastFullSend); + QString lastFullPacketsString = locale.toString(lastFullPackets); + QString lastFullBytesString = locale.toString((uint)stats.getLastFullTotalBytes()); + QString lastFullPPSString = locale.toString(lastFullPPS); extraDetails << "
" << "Last Full Scene... " << - "Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " << - "Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms "; + "Encode: " << qPrintable(lastFullEncodeString) << " ms " << + "Send: " << qPrintable(lastFullSendString) << " ms " << + "Packets: " << qPrintable(lastFullPacketsString) << " " << + "Bytes: " << qPrintable(lastFullBytesString) << " " << + "Rate: " << qPrintable(lastFullPPSString) << " PPS"; for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); @@ -334,42 +346,51 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser QString internalString = locale.toString((uint)stats.getTotalInternal()); QString leavesString = locale.toString((uint)stats.getTotalLeaves()); - serverDetails << "
" << "Node UUID: " << - nodeUUID.toString().toLocal8Bit().constData() << " "; + serverDetails << "
" << "Node UUID: " << qPrintable(nodeUUID.toString()) << " "; serverDetails << "
" << "Voxels: " << - totalString.toLocal8Bit().constData() << " total " << - internalString.toLocal8Bit().constData() << " internal " << - leavesString.toLocal8Bit().constData() << " leaves "; + qPrintable(totalString) << " total " << + qPrintable(internalString) << " internal " << + qPrintable(leavesString) << " leaves "; QString incomingPacketsString = locale.toString((uint)stats.getIncomingPackets()); QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes()); QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes()); QString incomingOutOfOrderString = locale.toString((uint)stats.getIncomingOutOfOrder()); + QString incomingLateString = locale.toString((uint)stats.getIncomingLate()); + QString incomingReallyLateString = locale.toString((uint)stats.getIncomingReallyLate()); + QString incomingEarlyString = locale.toString((uint)stats.getIncomingEarly()); QString incomingLikelyLostString = locale.toString((uint)stats.getIncomingLikelyLost()); + QString incomingRecovered = locale.toString((uint)stats.getIncomingRecovered()); + QString incomingDuplicateString = locale.toString((uint)stats.getIncomingPossibleDuplicate()); int clockSkewInMS = node->getClockSkewUsec() / (int)USECS_PER_MSEC; QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage()); QString incomingPingTimeString = locale.toString(node->getPingMs()); QString incomingClockSkewString = locale.toString(clockSkewInMS); - serverDetails << "
" << "Incoming Packets: " << - incomingPacketsString.toLocal8Bit().constData() << - " Out of Order: " << incomingOutOfOrderString.toLocal8Bit().constData() << - " Likely Lost: " << incomingLikelyLostString.toLocal8Bit().constData(); + serverDetails << "
" << "Incoming Packets: " << qPrintable(incomingPacketsString) << + "/ Lost: " << qPrintable(incomingLikelyLostString) << + "/ Recovered: " << qPrintable(incomingRecovered); + + serverDetails << "
" << " Out of Order: " << qPrintable(incomingOutOfOrderString) << + "/ Early: " << qPrintable(incomingEarlyString) << + "/ Late: " << qPrintable(incomingLateString) << + "/ Really Late: " << qPrintable(incomingReallyLateString) << + "/ Duplicate: " << qPrintable(incomingDuplicateString); serverDetails << "
" << - " Average Flight Time: " << incomingFlightTimeString.toLocal8Bit().constData() << " msecs"; + " Average Flight Time: " << qPrintable(incomingFlightTimeString) << " msecs"; serverDetails << "
" << - " Average Ping Time: " << incomingPingTimeString.toLocal8Bit().constData() << " msecs"; + " Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs"; serverDetails << "
" << - " Average Clock Skew: " << incomingClockSkewString.toLocal8Bit().constData() << " msecs"; - + " Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs"; + serverDetails << "
" << "Incoming" << - " Bytes: " << incomingBytesString.toLocal8Bit().constData() << - " Wasted Bytes: " << incomingWastedBytesString.toLocal8Bit().constData(); + " Bytes: " << qPrintable(incomingBytesString) << + " Wasted Bytes: " << qPrintable(incomingWastedBytesString); serverDetails << extraDetails.str(); if (_extraServerDetails[serverCount-1] == MORE) { diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 199d9b42e3..18c9b3814a 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -67,7 +67,7 @@ - margin-top: 12px; + margin-top: 12px; font-family: Helvetica, Arial, sans-serif; Qt::ScrollBarAlwaysOff @@ -121,6 +121,9 @@ 0 + + font-family: Helvetica, Arial, sans-serif; + Qt::ScrollBarAlwaysOff diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 9ec37acd80..ccb6d3970e 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -155,27 +155,27 @@ Attribute::Attribute(const QString& name) : Attribute::~Attribute() { } -void Attribute::read(MetavoxelData& data, MetavoxelStreamState& state) { +void Attribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state) { data.createRoot(state.attribute)->read(state); } -void Attribute::write(const MetavoxelNode& root, MetavoxelStreamState& state) { +void Attribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) { root.write(state); } -void Attribute::readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) { +void Attribute::readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) { data.createRoot(state.attribute)->readDelta(reference, state); } -void Attribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) { +void Attribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) { root.writeDelta(reference, state); } -void Attribute::readSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { +void Attribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { data.getRoot(state.attribute)->readSubdivision(state); } -void Attribute::writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { +void Attribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { root.writeSubdivision(state); } @@ -327,7 +327,7 @@ SpannerSetAttribute::SpannerSetAttribute(const QString& name, const QMetaObject* SharedObjectSetAttribute(name, metaObject) { } -void SpannerSetAttribute::read(MetavoxelData& data, MetavoxelStreamState& state) { +void SpannerSetAttribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state) { forever { SharedObjectPointer object; state.stream >> object; @@ -338,13 +338,14 @@ void SpannerSetAttribute::read(MetavoxelData& data, MetavoxelStreamState& state) } } -void SpannerSetAttribute::write(const MetavoxelNode& root, MetavoxelStreamState& state) { +void SpannerSetAttribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) { Spanner::incrementVisit(); root.writeSpanners(state); state.stream << SharedObjectPointer(); } -void SpannerSetAttribute::readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) { +void SpannerSetAttribute::readMetavoxelDelta(MetavoxelData& data, + const MetavoxelNode& reference, MetavoxelStreamState& state) { forever { SharedObjectPointer object; state.stream >> object; @@ -355,13 +356,14 @@ void SpannerSetAttribute::readDelta(MetavoxelData& data, const MetavoxelNode& re } } -void SpannerSetAttribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) { +void SpannerSetAttribute::writeMetavoxelDelta(const MetavoxelNode& root, + const MetavoxelNode& reference, MetavoxelStreamState& state) { Spanner::incrementVisit(); root.writeSpannerDelta(reference, state); state.stream << SharedObjectPointer(); } -void SpannerSetAttribute::readSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { +void SpannerSetAttribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { forever { SharedObjectPointer object; state.stream >> object; @@ -372,7 +374,7 @@ void SpannerSetAttribute::readSubdivision(MetavoxelData& data, MetavoxelStreamSt } } -void SpannerSetAttribute::writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { +void SpannerSetAttribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { Spanner::incrementVisit(); root.writeSpannerSubdivision(state); state.stream << SharedObjectPointer(); diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 3405f90315..b6a415bef7 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -177,14 +177,14 @@ public: virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { read(in, value, isLeaf); } virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { write(out, value, isLeaf); } - virtual void read(MetavoxelData& data, MetavoxelStreamState& state); - virtual void write(const MetavoxelNode& root, MetavoxelStreamState& state); + virtual void readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state); + virtual void writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state); - virtual void readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state); - virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state); + virtual void readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state); + virtual void writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state); - virtual void readSubdivision(MetavoxelData& data, MetavoxelStreamState& state); - virtual void writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state); + virtual void readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state); + virtual void writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state); virtual bool equal(void* first, void* second) const = 0; @@ -265,7 +265,7 @@ template inline bool SimpleInlineAttribute::merge(vo /// Provides appropriate averaging for RGBA values. class QRgbAttribute : public InlineAttribute { Q_OBJECT - Q_PROPERTY(int defaultValue MEMBER _defaultValue) + Q_PROPERTY(uint defaultValue MEMBER _defaultValue) public: @@ -355,14 +355,14 @@ public: Q_INVOKABLE SpannerSetAttribute(const QString& name = QString(), const QMetaObject* metaObject = &SharedObject::staticMetaObject); - virtual void read(MetavoxelData& data, MetavoxelStreamState& state); - virtual void write(const MetavoxelNode& root, MetavoxelStreamState& state); + virtual void readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state); + virtual void writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state); - virtual void readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state); - virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state); + virtual void readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state); + virtual void writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state); - virtual void readSubdivision(MetavoxelData& data, MetavoxelStreamState& state); - virtual void writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state); + virtual void readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state); + virtual void writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state); }; #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 0af44eaae6..f80ef3aa28 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -23,6 +23,7 @@ REGISTER_SIMPLE_TYPE_STREAMER(bool) REGISTER_SIMPLE_TYPE_STREAMER(int) +REGISTER_SIMPLE_TYPE_STREAMER(uint) REGISTER_SIMPLE_TYPE_STREAMER(float) REGISTER_SIMPLE_TYPE_STREAMER(QByteArray) REGISTER_SIMPLE_TYPE_STREAMER(QColor) @@ -238,6 +239,17 @@ Bitstream& Bitstream::operator>>(int& value) { return *this; } +Bitstream& Bitstream::operator<<(uint value) { + return write(&value, 32); +} + +Bitstream& Bitstream::operator>>(uint& value) { + quint32 sizedValue; + read(&sizedValue, 32); + value = sizedValue; + return *this; +} + Bitstream& Bitstream::operator<<(float value) { return write(&value, 32); } diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 297d265d97..ca26509d60 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -254,6 +254,9 @@ public: Bitstream& operator<<(int value); Bitstream& operator>>(int& value); + Bitstream& operator<<(uint value); + Bitstream& operator>>(uint& value); + Bitstream& operator<<(float value); Bitstream& operator>>(float& value); diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 8a6b0bc16a..08cd62f30d 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -228,7 +228,7 @@ public: Spanner* getSpanner() const { return _spanner; } float getDistance() const { return _distance; } - virtual bool visit(Spanner* spanner, float distance); + virtual bool visitSpanner(Spanner* spanner, float distance); private: @@ -243,7 +243,7 @@ FirstRaySpannerIntersectionVisitor::FirstRaySpannerIntersectionVisitor( _spanner(NULL) { } -bool FirstRaySpannerIntersectionVisitor::visit(Spanner* spanner, float distance) { +bool FirstRaySpannerIntersectionVisitor::visitSpanner(Spanner* spanner, float distance) { _spanner = spanner; _distance = distance; return false; @@ -312,7 +312,7 @@ void MetavoxelData::read(Bitstream& in, const MetavoxelLOD& lod) { break; } MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, lod }; - attribute->read(*this, state); + attribute->readMetavoxelRoot(*this, state); } } @@ -321,7 +321,7 @@ void MetavoxelData::write(Bitstream& out, const MetavoxelLOD& lod) const { for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { out << it.key(); MetavoxelStreamState state = { getMinimum(), _size, it.key(), out, lod, lod }; - it.key()->write(*it.value(), state); + it.key()->writeMetavoxelRoot(*it.value(), state); } out << AttributePointer(); } @@ -360,13 +360,13 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD in >> changed; if (changed) { oldRoot->incrementReferenceCount(); - attribute->readDelta(*this, *oldRoot, state); + attribute->readMetavoxelDelta(*this, *oldRoot, state); oldRoot->decrementReferenceCount(attribute); } else { - attribute->readSubdivision(*this, state); + attribute->readMetavoxelSubdivision(*this, state); } } else { - attribute->read(*this, state); + attribute->readMetavoxelRoot(*this, state); } } @@ -415,13 +415,13 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, const MetavoxelLO if (referenceRoot) { if (it.value() == referenceRoot) { out << false; - it.key()->writeSubdivision(*it.value(), state); + it.key()->writeMetavoxelSubdivision(*it.value(), state); } else { out << true; - it.key()->writeDelta(*it.value(), *referenceRoot, state); + it.key()->writeMetavoxelDelta(*it.value(), *referenceRoot, state); } } else { - it.key()->write(*it.value(), state); + it.key()->writeMetavoxelRoot(*it.value(), state); } } } @@ -938,7 +938,7 @@ int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { } qStableSort(spannerDistances); foreach (const SpannerDistance& spannerDistance, spannerDistances) { - if (!visit(spannerDistance.spanner, spannerDistance.distance)) { + if (!visitSpanner(spannerDistance.spanner, spannerDistance.distance)) { return SHORT_CIRCUIT; } } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index ab50bacff9..9d642f8f34 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -302,7 +302,7 @@ public: /// Visits a spanner that the ray intersects. /// \return true to continue, false to short-circuit the tour - virtual bool visit(Spanner* spanner, float distance) = 0; + virtual bool visitSpanner(Spanner* spanner, float distance) = 0; virtual void prepare(); virtual int visit(MetavoxelInfo& info, float distance); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index f85ed7f487..4c8ed8c9f6 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -15,8 +15,6 @@ #include #include // to load voxels from file -#include - #include #include "CoverageMap.h" diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 794884334f..e42fe17df0 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -18,20 +18,32 @@ #include "OctreeSceneStats.h" +const uint16_t MAX_MISSING_SEQUENCE = 100; /// how many items in our _missingSequenceNumbers before we start to prune them +const uint16_t MAX_MISSING_SEQUENCE_OLD_AGE = 1000; /// age we allow items in _missingSequenceNumbers to be before pruning + + const int samples = 100; OctreeSceneStats::OctreeSceneStats() : _isReadyToSend(false), _isStarted(false), _lastFullElapsed(0), + _lastFullTotalEncodeTime(0), + _lastFullTotalPackets(0), + _lastFullTotalBytes(0), + _elapsedAverage(samples), _bitsPerOctreeAverage(samples), - _lastFullTotalEncodeTime(0), _incomingPacket(0), _incomingBytes(0), _incomingWastedBytes(0), _incomingLastSequence(0), - _incomingOutOfOrder(0), _incomingLikelyLost(0), + _incomingRecovered(0), + _incomingEarly(0), + _incomingLate(0), + _incomingReallyLate(0), + _incomingPossibleDuplicate(0), + _missingSequenceNumbers(), _incomingFlightTimeAverage(samples), _jurisdictionRoot(NULL) { @@ -53,8 +65,10 @@ OctreeSceneStats& OctreeSceneStats::operator=(const OctreeSceneStats& other) { void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) { _totalEncodeTime = other._totalEncodeTime; _elapsed = other._elapsed; - _lastFullTotalEncodeTime = other._lastFullTotalEncodeTime; _lastFullElapsed = other._lastFullElapsed; + _lastFullTotalEncodeTime = other._lastFullTotalEncodeTime; + _lastFullTotalPackets = other._lastFullTotalPackets; + _lastFullTotalBytes = other._lastFullTotalBytes; _encodeStart = other._encodeStart; _packets = other._packets; @@ -134,8 +148,14 @@ void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) { _incomingBytes = other._incomingBytes; _incomingWastedBytes = other._incomingWastedBytes; _incomingLastSequence = other._incomingLastSequence; - _incomingOutOfOrder = other._incomingOutOfOrder; _incomingLikelyLost = other._incomingLikelyLost; + _incomingRecovered = other._incomingRecovered; + _incomingEarly = other._incomingEarly; + _incomingLate = other._incomingLate; + _incomingReallyLate = other._incomingReallyLate; + _incomingPossibleDuplicate = other._incomingPossibleDuplicate; + + _missingSequenceNumbers = other._missingSequenceNumbers; } @@ -493,12 +513,6 @@ int OctreeSceneStats::unpackFromMessage(const unsigned char* sourceBuffer, int a memcpy(&_isFullScene, sourceBuffer, sizeof(_isFullScene)); sourceBuffer += sizeof(_isFullScene); - - if (_isFullScene) { - _lastFullElapsed = _elapsed; - _lastFullTotalEncodeTime = _totalEncodeTime; - } - memcpy(&_isMoving, sourceBuffer, sizeof(_isMoving)); sourceBuffer += sizeof(_isMoving); memcpy(&_packets, sourceBuffer, sizeof(_packets)); @@ -506,6 +520,13 @@ int OctreeSceneStats::unpackFromMessage(const unsigned char* sourceBuffer, int a memcpy(&_bytes, sourceBuffer, sizeof(_bytes)); sourceBuffer += sizeof(_bytes); + if (_isFullScene) { + _lastFullElapsed = _elapsed; + _lastFullTotalEncodeTime = _totalEncodeTime; + _lastFullTotalPackets = _packets; + _lastFullTotalBytes = _bytes; + } + memcpy(&_totalInternal, sourceBuffer, sizeof(_totalInternal)); sourceBuffer += sizeof(_totalInternal); memcpy(&_totalLeaves, sourceBuffer, sizeof(_totalLeaves)); @@ -823,18 +844,95 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, float flightTimeMsecs = flightTime / USECS_PER_MSEC; _incomingFlightTimeAverage.updateAverage(flightTimeMsecs); + // track out of order and possibly lost packets... + const bool wantExtraDebugging = false; + if (sequence == _incomingLastSequence) { + if (wantExtraDebugging) { + qDebug() << "last packet duplicate got:" << sequence << "_incomingLastSequence:" << _incomingLastSequence; + } + } else { + OCTREE_PACKET_SEQUENCE expected = _incomingLastSequence+1; + if (sequence != expected) { + if (wantExtraDebugging) { + qDebug() << "out of order... got:" << sequence << "expected:" << expected; + } + + // if the sequence is less than our expected, then this might be a packet + // that was delayed and so we should find it in our lostSequence list + if (sequence < expected) { + if (wantExtraDebugging) { + qDebug() << "this packet is later than expected..."; + } + if (sequence < std::max(0, (expected - MAX_MISSING_SEQUENCE_OLD_AGE))) { + _incomingReallyLate++; + } else { + _incomingLate++; + } + + if (_missingSequenceNumbers.contains(sequence)) { + if (wantExtraDebugging) { + qDebug() << "found it in _missingSequenceNumbers"; + } + _missingSequenceNumbers.remove(sequence); + _incomingLikelyLost--; + _incomingRecovered++; + } else { + // if we're still in our pruning window, and we didn't find it in our missing list, + // than this is really unexpected and can probably only happen if the packet was a + // duplicate + if (sequence >= std::max(0, (expected - MAX_MISSING_SEQUENCE_OLD_AGE))) { + if (wantExtraDebugging) { + qDebug() << "sequence:" << sequence << "WAS NOT found in _missingSequenceNumbers, and not that old... (expected - MAX_MISSING_SEQUENCE_OLD_AGE):" << (expected - MAX_MISSING_SEQUENCE_OLD_AGE); + } + _incomingPossibleDuplicate++; + } + } + } + + if (sequence > expected) { + if (wantExtraDebugging) { + qDebug() << "this packet is earlier than expected..."; + } + _incomingEarly++; + + // hmm... so, we either didn't get some packets, or this guy came early... + unsigned int missing = sequence - expected; + if (wantExtraDebugging) { + qDebug() << ">>>>>>>> missing gap=" << missing; + } + _incomingLikelyLost += missing; + for(unsigned int missingSequence = expected; missingSequence < sequence; missingSequence++) { + _missingSequenceNumbers << missingSequence; + } + } + } + } + + // only bump the last sequence if it was greater than our previous last sequence, this will keep us from + // accidentally going backwards when an out of order (recovered) packet comes in + if (sequence > _incomingLastSequence) { + _incomingLastSequence = sequence; + } - // detect out of order packets - if (sequence < _incomingLastSequence) { - _incomingOutOfOrder++; + // do some garbage collecting on our _missingSequenceNumbers + if (_missingSequenceNumbers.size() > MAX_MISSING_SEQUENCE) { + if (wantExtraDebugging) { + qDebug() << "too many _missingSequenceNumbers:" << _missingSequenceNumbers.size(); + } + foreach(unsigned int missingItem, _missingSequenceNumbers) { + if (wantExtraDebugging) { + qDebug() << "checking item:" << missingItem << "is it in need of pruning?"; + qDebug() << "(_incomingLastSequence - MAX_MISSING_SEQUENCE_OLD_AGE):" + << (_incomingLastSequence - MAX_MISSING_SEQUENCE_OLD_AGE); + } + if (missingItem <= std::max(0, (_incomingLastSequence - MAX_MISSING_SEQUENCE_OLD_AGE))) { + if (wantExtraDebugging) { + qDebug() << "pruning really old missing sequence:" << missingItem; + } + _missingSequenceNumbers.remove(missingItem); + } + } } - - // detect likely lost packets - OCTREE_PACKET_SEQUENCE expected = _incomingLastSequence+1; - if (sequence > expected) { - _incomingLikelyLost++; - } - - _incomingLastSequence = sequence; + } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index e106f53589..2b39b3434c 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -150,8 +150,10 @@ public: unsigned long getTotalEncodeTime() const { return _totalEncodeTime; } unsigned long getElapsedTime() const { return _elapsed; } - unsigned long getLastFullTotalEncodeTime() const { return _lastFullTotalEncodeTime; } unsigned long getLastFullElapsedTime() const { return _lastFullElapsed; } + unsigned long getLastFullTotalEncodeTime() const { return _lastFullTotalEncodeTime; } + unsigned int getLastFullTotalPackets() const { return _lastFullTotalPackets; } + unsigned long getLastFullTotalBytes() const { return _lastFullTotalBytes; } // Used in client implementations to track individual octree packets void trackIncomingOctreePacket(const QByteArray& packet, bool wasStatsPacket, int nodeClockSkewUsec); @@ -159,8 +161,13 @@ public: unsigned int getIncomingPackets() const { return _incomingPacket; } unsigned long getIncomingBytes() const { return _incomingBytes; } unsigned long getIncomingWastedBytes() const { return _incomingWastedBytes; } - unsigned int getIncomingOutOfOrder() const { return _incomingOutOfOrder; } + unsigned int getIncomingOutOfOrder() const { return _incomingLate + _incomingEarly; } unsigned int getIncomingLikelyLost() const { return _incomingLikelyLost; } + unsigned int getIncomingRecovered() const { return _incomingRecovered; } + unsigned int getIncomingEarly() const { return _incomingEarly; } + unsigned int getIncomingLate() const { return _incomingLate; } + unsigned int getIncomingReallyLate() const { return _incomingReallyLate; } + unsigned int getIncomingPossibleDuplicate() const { return _incomingPossibleDuplicate; } float getIncomingFlightTimeAverage() { return _incomingFlightTimeAverage.getAverage(); } private: @@ -176,13 +183,16 @@ private: quint64 _start; quint64 _end; quint64 _elapsed; + quint64 _lastFullElapsed; + quint64 _lastFullTotalEncodeTime; + unsigned int _lastFullTotalPackets; + unsigned long _lastFullTotalBytes; SimpleMovingAverage _elapsedAverage; SimpleMovingAverage _bitsPerOctreeAverage; quint64 _totalEncodeTime; - quint64 _lastFullTotalEncodeTime; quint64 _encodeStart; // scene octree related data @@ -251,9 +261,15 @@ private: unsigned int _incomingPacket; unsigned long _incomingBytes; unsigned long _incomingWastedBytes; - unsigned int _incomingLastSequence; - unsigned int _incomingOutOfOrder; - unsigned int _incomingLikelyLost; + + uint16_t _incomingLastSequence; /// last incoming sequence number + unsigned int _incomingLikelyLost; /// count of packets likely lost, may be off by _incomingReallyLate count + unsigned int _incomingRecovered; /// packets that were late, and we had in our missing list, we consider recovered + unsigned int _incomingEarly; /// out of order earlier than expected + unsigned int _incomingLate; /// out of order later than expected + unsigned int _incomingReallyLate; /// out of order and later than MAX_MISSING_SEQUENCE_OLD_AGE late + unsigned int _incomingPossibleDuplicate; /// out of order possibly a duplicate + QSet _missingSequenceNumbers; SimpleMovingAverage _incomingFlightTimeAverage; // features related items diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 4c756c2257..5c48244a39 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -8,8 +8,6 @@ #include -#include - #include #include #include