From d7b1852164cf1db401393524e9c956da2818e4a0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 16 Mar 2015 15:25:44 -0700 Subject: [PATCH 01/27] Creating eachMatchingNode and using it in avatar mixer --- assignment-client/src/avatars/AvatarMixer.cpp | 44 ++++++++++++++----- libraries/networking/src/LimitedNodeList.h | 13 +++++- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 9616c8cb21..a6420c357a 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -119,12 +119,24 @@ void AvatarMixer::broadcastAvatarData() { auto nodeList = DependencyManager::get(); - AvatarMixerClientData* nodeData = NULL; - AvatarMixerClientData* otherNodeData = NULL; - - nodeList->eachNode([&](const SharedNodePointer& node) { - if (node->getLinkedData() && node->getType() == NodeType::Agent && node->getActiveSocket() - && (nodeData = reinterpret_cast(node->getLinkedData()))->getMutex().tryLock()) { + nodeList->eachMatchingNode( + [&](const SharedNodePointer& node)->bool { + if (!node->getLinkedData()) { + return false; + } + if (node->getType() != NodeType::Agent) { + return false; + } + if (!node->getActiveSocket()) { + return false; + } + return true; + }, + [&](const SharedNodePointer& node) { + AvatarMixerClientData* nodeData = reinterpret_cast(node->getLinkedData()); + if (!nodeData->getMutex().tryLock()) { + return; + } ++_sumListeners; // reset packet pointers for this node @@ -135,9 +147,21 @@ void AvatarMixer::broadcastAvatarData() { // this is an AGENT we have received head data from // send back a packet with other active node data to this node - nodeList->eachNode([&](const SharedNodePointer& otherNode) { - if (otherNode->getLinkedData() && otherNode->getUUID() != node->getUUID() - && (otherNodeData = reinterpret_cast(otherNode->getLinkedData()))->getMutex().tryLock()) { + nodeList->eachMatchingNode( + [&](const SharedNodePointer& otherNode)->bool { + if (!otherNode->getLinkedData()) { + return false; + } + if (otherNode->getUUID() == node->getUUID()) { + return false; + } + return true; + }, + [&](const SharedNodePointer& otherNode) { + AvatarMixerClientData* otherNodeData = otherNodeData = reinterpret_cast(otherNode->getLinkedData()); + if (!otherNodeData->getMutex().tryLock()) { + return; + } AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); AvatarData& otherAvatar = otherNodeData->getAvatar(); @@ -202,13 +226,11 @@ void AvatarMixer::broadcastAvatarData() { } otherNodeData->getMutex().unlock(); - } }); nodeList->writeDatagram(mixedAvatarByteArray, node); nodeData->getMutex().unlock(); - } }); _lastFrameTimestamp = QDateTime::currentMSecsSinceEpoch(); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index a071eced31..532e8ffcf4 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -151,7 +151,18 @@ public: functor(it->second); } } - + + template + void eachMatchingNode(PredLambda predicate, NodeLambda functor) { + QReadLocker readLock(&_nodeMutex); + + for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) { + if (predicate(it->second)) { + functor(it->second); + } + } + } + template void eachNodeBreakable(BreakableNodeLambda functor) { QReadLocker readLock(&_nodeMutex); From 80b5a44cc45b19614348496146f334d87bcf1d55 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 17 Mar 2015 11:49:17 -0700 Subject: [PATCH 02/27] Adding a RAII version of the mutex locker that uses tryLock instead of lock --- libraries/shared/src/TryLocker.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 libraries/shared/src/TryLocker.h diff --git a/libraries/shared/src/TryLocker.h b/libraries/shared/src/TryLocker.h new file mode 100644 index 0000000000..e434ae4372 --- /dev/null +++ b/libraries/shared/src/TryLocker.h @@ -0,0 +1,31 @@ +// +// TryLocker.h +// libraries/shared/src +// +// Created by Brad Davis on 2015/03/16. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_TryLocker_h +#define hifi_TryLocker_h + +#include + +class MutexTryLocker { + QMutex & _mutex; + bool _locked{false}; +public: + MutexTryLocker(QMutex &m) : _mutex(m) {} + ~MutexTryLocker() { if (_locked) _mutex.unlock(); } + bool tryLock() { + if (_locked) { + return true; + } + return (_locked = _mutex.tryLock()); + } +} + +#endif // hifi_UUID_h From 6415ff99f61d9004e85632631bf7f7a4d2841284 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 17 Mar 2015 12:04:04 -0700 Subject: [PATCH 03/27] Work in progress --- assignment-client/src/avatars/AvatarMixer.cpp | 131 +++++++++--------- libraries/networking/src/BandwidthRecorder.h | 1 - libraries/networking/src/LimitedNodeList.cpp | 6 +- libraries/networking/src/NetworkPeer.cpp | 37 ++++- libraries/networking/src/NetworkPeer.h | 6 + libraries/shared/src/TryLocker.h | 9 +- 6 files changed, 115 insertions(+), 75 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index a6420c357a..bd0239cdc8 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -20,9 +20,9 @@ #include #include #include +#include #include "AvatarMixerClientData.h" - #include "AvatarMixer.h" const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer"; @@ -134,7 +134,8 @@ void AvatarMixer::broadcastAvatarData() { }, [&](const SharedNodePointer& node) { AvatarMixerClientData* nodeData = reinterpret_cast(node->getLinkedData()); - if (!nodeData->getMutex().tryLock()) { + MutexTryLocker lock(nodeData->getMutex()); + if (!lock.tryLock()) { return; } ++_sumListeners; @@ -144,6 +145,7 @@ void AvatarMixer::broadcastAvatarData() { AvatarData& avatar = nodeData->getAvatar(); glm::vec3 myPosition = avatar.getPosition(); + float outputBandwidth = node->getBandwidthRecorder().getTotalAverageOutputKilobitsPerSecond(); // this is an AGENT we have received head data from // send back a packet with other active node data to this node @@ -155,82 +157,81 @@ void AvatarMixer::broadcastAvatarData() { if (otherNode->getUUID() == node->getUUID()) { return false; } + + // Check throttling value + if (!(_performanceThrottlingRatio == 0 || randFloat() < (1.0f - _performanceThrottlingRatio))) { + return; + } return true; }, [&](const SharedNodePointer& otherNode) { AvatarMixerClientData* otherNodeData = otherNodeData = reinterpret_cast(otherNode->getLinkedData()); - if (!otherNodeData->getMutex().tryLock()) { + MutexTryLocker lock(otherNodeData->getMutex()); + if (!lock.tryLock()) { return; } - - AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); AvatarData& otherAvatar = otherNodeData->getAvatar(); - glm::vec3 otherPosition = otherAvatar.getPosition(); - - float distanceToAvatar = glm::length(myPosition - otherPosition); + // Decide whether to send this avatar's data based on it's distance from us // The full rate distance is the distance at which EVERY update will be sent for this avatar // at a distance of twice the full rate distance, there will be a 50% chance of sending this avatar's update const float FULL_RATE_DISTANCE = 2.0f; - - // Decide whether to send this avatar's data based on it's distance from us - if ((_performanceThrottlingRatio == 0 || randFloat() < (1.0f - _performanceThrottlingRatio)) - && (distanceToAvatar == 0.0f || randFloat() < FULL_RATE_DISTANCE / distanceToAvatar)) { - QByteArray avatarByteArray; - avatarByteArray.append(otherNode->getUUID().toRfc4122()); - avatarByteArray.append(otherAvatar.toByteArray()); - - if (avatarByteArray.size() + mixedAvatarByteArray.size() > MAX_PACKET_SIZE) { - nodeList->writeDatagram(mixedAvatarByteArray, node); - - // reset the packet - mixedAvatarByteArray.resize(numPacketHeaderBytes); - } - - // copy the avatar into the mixedAvatarByteArray packet - mixedAvatarByteArray.append(avatarByteArray); - - // if the receiving avatar has just connected make sure we send out the mesh and billboard - // for this avatar (assuming they exist) - bool forceSend = !nodeData->checkAndSetHasReceivedFirstPackets(); - - // we will also force a send of billboard or identity packet - // if either has changed in the last frame - - if (otherNodeData->getBillboardChangeTimestamp() > 0 - && (forceSend - || otherNodeData->getBillboardChangeTimestamp() > _lastFrameTimestamp - || randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) { - QByteArray billboardPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard); - billboardPacket.append(otherNode->getUUID().toRfc4122()); - billboardPacket.append(otherNodeData->getAvatar().getBillboard()); - nodeList->writeDatagram(billboardPacket, node); - - ++_sumBillboardPackets; - } - - if (otherNodeData->getIdentityChangeTimestamp() > 0 - && (forceSend - || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp - || randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) { - - QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); - - QByteArray individualData = otherNodeData->getAvatar().identityByteArray(); - individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122()); - identityPacket.append(individualData); - - nodeList->writeDatagram(identityPacket, node); - - ++_sumIdentityPackets; - } + glm::vec3 otherPosition = otherAvatar.getPosition(); + float distanceToAvatar = glm::length(myPosition - otherPosition); + + if (!(distanceToAvatar == 0.0f || randFloat() < FULL_RATE_DISTANCE / distanceToAvatar)) { + return; + } + + QByteArray avatarByteArray; + avatarByteArray.append(otherNode->getUUID().toRfc4122()); + avatarByteArray.append(otherAvatar.toByteArray()); + + if (avatarByteArray.size() + mixedAvatarByteArray.size() > MAX_PACKET_SIZE) { + nodeList->writeDatagram(mixedAvatarByteArray, node); + + // reset the packet + mixedAvatarByteArray.resize(numPacketHeaderBytes); + } + + // copy the avatar into the mixedAvatarByteArray packet + mixedAvatarByteArray.append(avatarByteArray); + + // if the receiving avatar has just connected make sure we send out the mesh and billboard + // for this avatar (assuming they exist) + bool forceSend = !nodeData->checkAndSetHasReceivedFirstPackets(); + + // we will also force a send of billboard or identity packet + // if either has changed in the last frame + + if (otherNodeData->getBillboardChangeTimestamp() > 0 + && (forceSend + || otherNodeData->getBillboardChangeTimestamp() > _lastFrameTimestamp + || randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) { + QByteArray billboardPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard); + billboardPacket.append(otherNode->getUUID().toRfc4122()); + billboardPacket.append(otherNodeData->getAvatar().getBillboard()); + nodeList->writeDatagram(billboardPacket, node); + + ++_sumBillboardPackets; + } + + if (otherNodeData->getIdentityChangeTimestamp() > 0 + && (forceSend + || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp + || randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) { + + QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); + + QByteArray individualData = otherNodeData->getAvatar().identityByteArray(); + individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122()); + identityPacket.append(individualData); + + nodeList->writeDatagram(identityPacket, node); + + ++_sumIdentityPackets; } - - otherNodeData->getMutex().unlock(); }); - nodeList->writeDatagram(mixedAvatarByteArray, node); - - nodeData->getMutex().unlock(); }); _lastFrameTimestamp = QDateTime::currentMSecsSinceEpoch(); diff --git a/libraries/networking/src/BandwidthRecorder.h b/libraries/networking/src/BandwidthRecorder.h index c22665d2cc..f87d9d4d06 100644 --- a/libraries/networking/src/BandwidthRecorder.h +++ b/libraries/networking/src/BandwidthRecorder.h @@ -17,7 +17,6 @@ #include #include #include "DependencyManager.h" -#include "Node.h" #include "SimpleMovingAverage.h" diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 520dc650ed..98e1ed0572 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -263,8 +263,10 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, } emit dataSent(destinationNode->getType(), datagram.size()); - - return writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret()); + auto bytesWritten = writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret()); + // Keep track of per-destination-node bandwidth + destinationNode->recordBytesSent(bytesWritten); + return bytesWritten; } // didn't have a destinationNode to send to, return 0 diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index eaaf57471c..eb072a91f0 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -15,6 +15,7 @@ #include #include "NetworkPeer.h" +#include "BandwidthRecorder.h" NetworkPeer::NetworkPeer() : _uuid(), @@ -96,4 +97,38 @@ QDebug operator<<(QDebug debug, const NetworkPeer &peer) { << "- public:" << peer.getPublicSocket() << "- local:" << peer.getLocalSocket(); return debug; -} \ No newline at end of file +} + + +// FIXME this is a temporary implementation to determine if this is the right approach. +// If so, migrate the BandwidthRecorder into the NetworkPeer class +using BandwidthRecorderPtr = QSharedPointer < BandwidthRecorder > ; +static QHash PEER_BANDWIDTH; + +BandwidthRecorder & getBandwidthRecorder(const QUuid & uuid) { + if (!PEER_BANDWIDTH.count(uuid)) { + PEER_BANDWIDTH.insert(uuid, BandwidthRecorderPtr(new BandwidthRecorder())); + } + return *PEER_BANDWIDTH[uuid].data(); +} + + +void NetworkPeer::recordBytesSent(int count) { + auto & bw = getBandwidthRecorder(_uuid); + bw.updateOutboundData(0, count); +} + +void NetworkPeer::recordBytesReceived(int count) { + auto & bw = getBandwidthRecorder(_uuid); + bw.updateInboundData(0, count); +} + +float NetworkPeer::getOutboundBandwidth() { + auto & bw = getBandwidthRecorder(_uuid); + return bw.getAverageOutputKilobitsPerSecond(0); +} + +float NetworkPeer::getInboundBandwidth() { + auto & bw = getBandwidthRecorder(_uuid); + return bw.getAverageInputKilobitsPerSecond(0); +} diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index bb92c54eb8..5bf798d2c5 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -54,6 +54,12 @@ public: int getConnectionAttempts() const { return _connectionAttempts; } void incrementConnectionAttempts() { ++_connectionAttempts; } void resetConnectionAttemps() { _connectionAttempts = 0; } + + void recordBytesSent(int count); + void recordBytesReceived(int count); + + float getOutboundBandwidth(); + float getInboundBandwidth(); friend QDataStream& operator<<(QDataStream& out, const NetworkPeer& peer); friend QDataStream& operator>>(QDataStream& in, NetworkPeer& peer); diff --git a/libraries/shared/src/TryLocker.h b/libraries/shared/src/TryLocker.h index e434ae4372..c5328b3b3a 100644 --- a/libraries/shared/src/TryLocker.h +++ b/libraries/shared/src/TryLocker.h @@ -18,13 +18,10 @@ class MutexTryLocker { QMutex & _mutex; bool _locked{false}; public: - MutexTryLocker(QMutex &m) : _mutex(m) {} + MutexTryLocker(QMutex &m) : _mutex(m), _locked(m.tryLock()) {} ~MutexTryLocker() { if (_locked) _mutex.unlock(); } - bool tryLock() { - if (_locked) { - return true; - } - return (_locked = _mutex.tryLock()); + bool isLocked() { + return _locked; } } From 870f1112e4bd213b0c4a03acee70180e85bf1442 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 17 Mar 2015 16:17:44 -0700 Subject: [PATCH 04/27] Fix thrust not being applied w/ Physics + Avatar --- interface/src/avatar/MyAvatar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bdb0877cda..6dc3d820ae 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1357,6 +1357,9 @@ void MyAvatar::updatePositionWithPhysics(float deltaTime) { // rotate back into world-frame _velocity = rotation * newLocalVelocity; + + _velocity += _thrust * deltaTime; + _thrust = glm::vec3(0.0f); } void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { From a04bd09b83349e820dd6762bef3e0fa0aec69b87 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 17 Mar 2015 16:32:59 -0700 Subject: [PATCH 05/27] Set clip near distance per skeleton model if no separate head model --- interface/src/avatar/MyAvatar.cpp | 15 ++++++++++++--- interface/src/avatar/SkeletonModel.cpp | 7 ++++++- interface/src/avatar/SkeletonModel.h | 4 ++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bdb0877cda..642da60b18 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1028,7 +1028,18 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, boo if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { return; // wait until both models are loaded } - + + Camera *camera = Application::getInstance()->getCamera(); + const glm::vec3 cameraPos = camera->getPosition(); + + // Set near clip distance according to skeleton model dimensions if first person and there is no separate head model. + if (shouldRenderHead(cameraPos, renderMode) || !getHead()->getFaceModel().getURL().isEmpty()) { + camera->setNearClip(DEFAULT_NEAR_CLIP); + } else { + float clipDistance = _skeletonModel.getHeadClipDistance(); + camera->setNearClip(clipDistance); + } + // Render the body's voxels and head Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; @@ -1040,8 +1051,6 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, boo } // Render head so long as the camera isn't inside it - const Camera *camera = Application::getInstance()->getCamera(); - const glm::vec3 cameraPos = camera->getPosition(); if (shouldRenderHead(cameraPos, renderMode)) { getHead()->render(1.0f, renderFrustum, modelRenderMode, postLighting); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 4fdebd5f6f..3a61f69dee 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -37,7 +37,8 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : _defaultEyeModelPosition(glm::vec3(0.0f, 0.0f, 0.0f)), _standingFoot(NO_FOOT), _standingOffset(0.0f), - _clampedFootPosition(0.0f) + _clampedFootPosition(0.0f), + _headClipDistance(DEFAULT_NEAR_CLIP) { } @@ -78,6 +79,10 @@ void SkeletonModel::setJointStates(QVector states) { buildShapes(); } + Extents meshExtents = getMeshExtents(); + _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); + _headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP); + emit skeletonLoaded(); } diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 5427fcaf25..298d74fb7a 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -110,6 +110,8 @@ public: bool hasSkeleton(); + float getHeadClipDistance() const { return _headClipDistance; } + signals: void skeletonLoaded(); @@ -160,6 +162,8 @@ private: int _standingFoot; glm::vec3 _standingOffset; glm::vec3 _clampedFootPosition; + + float _headClipDistance; // Near clip distance to use if no separate head model }; #endif // hifi_SkeletonModel_h From 7b54443bda95a8622a7306225f82c6b47d13610c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 17 Mar 2015 16:33:20 -0700 Subject: [PATCH 06/27] Adjust clip distance as HMD head moves backwards --- interface/src/avatar/MyAvatar.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 642da60b18..8af5982b3e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1037,6 +1037,16 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, boo camera->setNearClip(DEFAULT_NEAR_CLIP); } else { float clipDistance = _skeletonModel.getHeadClipDistance(); + if (OculusManager::isConnected()) { + // If avatar is horizontally in front of camera, increase clip distance by the amount it is in front. + glm::vec3 cameraToAvatar = _position - cameraPos; + cameraToAvatar.y = 0.0f; + glm::vec3 cameraLookAt = camera->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f); + float headOffset = glm::dot(cameraLookAt, cameraToAvatar); + if (headOffset > 0) { + clipDistance += headOffset; + } + } camera->setNearClip(clipDistance); } From 648a2e3b1d13b4fdb45eb62d08ac714462328f67 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 18 Mar 2015 12:43:49 -0700 Subject: [PATCH 07/27] Set clip distance on rendering frustum rather than camera This fixes wrong clipping distance used for rendering in FPV if also have rear view mirror. --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8af5982b3e..25cb4d4c6a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1034,7 +1034,7 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, boo // Set near clip distance according to skeleton model dimensions if first person and there is no separate head model. if (shouldRenderHead(cameraPos, renderMode) || !getHead()->getFaceModel().getURL().isEmpty()) { - camera->setNearClip(DEFAULT_NEAR_CLIP); + renderFrustum->setNearClip(DEFAULT_NEAR_CLIP); } else { float clipDistance = _skeletonModel.getHeadClipDistance(); if (OculusManager::isConnected()) { @@ -1047,7 +1047,7 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, boo clipDistance += headOffset; } } - camera->setNearClip(clipDistance); + renderFrustum->setNearClip(clipDistance); } // Render the body's voxels and head From 9161cc8b837ad7469f211be471b42c0b0d84d9e5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 18 Mar 2015 13:00:09 -0700 Subject: [PATCH 08/27] attempt to handle collision models in the same way as render models --- .../src/EntityTreeRenderer.cpp | 26 +++++++++- .../src/EntityTreeRenderer.h | 5 +- .../src/RenderableModelEntityItem.cpp | 50 ++++++++++++------- .../src/RenderableModelEntityItem.h | 5 +- libraries/entities/src/EntityTree.h | 1 + libraries/render-utils/src/Model.cpp | 2 + libraries/render-utils/src/Model.h | 7 ++- 7 files changed, 68 insertions(+), 28 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index a5e75f760b..35a07353d1 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -417,6 +417,26 @@ const Model* EntityTreeRenderer::getModelForEntityItem(const EntityItem* entityI return result; } +const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(const EntityItem* entityItem) { + const FBXGeometry* result = NULL; + + if (entityItem->getType() == EntityTypes::Model) { + const RenderableModelEntityItem* constModelEntityItem = dynamic_cast(entityItem); + if (constModelEntityItem->hasCollisionModel()) { + RenderableModelEntityItem* modelEntityItem = const_cast(constModelEntityItem); + assert(modelEntityItem); // we need this!!! Why?!! + Model* model = modelEntityItem->getModel(this); + if (model) { + const QSharedPointer collisionNetworkGeometry = model->getCollisionGeometry(); + if (!collisionNetworkGeometry.isNull()) { + result = &collisionNetworkGeometry->getFBXGeometry(); + } + } + } + } + return result; +} + void EntityTreeRenderer::renderElementProxy(EntityTreeElement* entityTreeElement) { glm::vec3 elementCenter = entityTreeElement->getAACube().calcCenter(); float elementSize = entityTreeElement->getScale(); @@ -591,7 +611,7 @@ void EntityTreeRenderer::processEraseMessage(const QByteArray& dataByteArray, co static_cast(_tree)->processEraseMessage(dataByteArray, sourceNode); } -Model* EntityTreeRenderer::allocateModel(const QString& url) { +Model* EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl) { Model* model = NULL; // Make sure we only create and delete models on the thread that owns the EntityTreeRenderer if (QThread::currentThread() != thread()) { @@ -604,10 +624,11 @@ Model* EntityTreeRenderer::allocateModel(const QString& url) { model = new Model(); model->init(); model->setURL(QUrl(url)); + model->setCollisionModelURL(QUrl(collisionUrl)); return model; } -Model* EntityTreeRenderer::updateModel(Model* original, const QString& newUrl) { +Model* EntityTreeRenderer::updateModel(Model* original, const QString& newUrl, const QString& collisionUrl) { Model* model = NULL; // The caller shouldn't call us if the URL doesn't need to change. But if they @@ -636,6 +657,7 @@ Model* EntityTreeRenderer::updateModel(Model* original, const QString& newUrl) { model = new Model(); model->init(); model->setURL(QUrl(newUrl)); + model->setCollisionModelURL(QUrl(collisionUrl)); return model; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 0da85f360b..c4aa5a42d0 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -59,15 +59,16 @@ public: virtual const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem); virtual const Model* getModelForEntityItem(const EntityItem* entityItem); + virtual const FBXGeometry* getCollisionGeometryForEntity(const EntityItem* entityItem); /// clears the tree virtual void clear(); /// if a renderable entity item needs a model, we will allocate it for them - Q_INVOKABLE Model* allocateModel(const QString& url); + Q_INVOKABLE Model* allocateModel(const QString& url, const QString& collisionUrl); /// if a renderable entity item needs to update the URL of a model, we will handle that for the entity - Q_INVOKABLE Model* updateModel(Model* original, const QString& newUrl); + Q_INVOKABLE Model* updateModel(Model* original, const QString& newUrl, const QString& collisionUrl); /// if a renderable entity item is done with a model, it should return it to us void releaseModel(Model* model); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7e57323d68..7bd94df386 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -223,10 +223,10 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { // if we have a previously allocated model, but it's URL doesn't match // then we need to let our renderer update our model for us. if (_model && QUrl(getModelURL()) != _model->getURL()) { - result = _model = _myRenderer->updateModel(_model, getModelURL()); + result = _model = _myRenderer->updateModel(_model, getModelURL(), getCollisionModelURL()); _needsInitialSimulation = true; } else if (!_model) { // if we don't yet have a model, then we want our renderer to allocate one - result = _model = _myRenderer->allocateModel(getModelURL()); + result = _model = _myRenderer->allocateModel(getModelURL(), getCollisionModelURL()); _needsInitialSimulation = true; } else { // we already have the model we want... result = _model; @@ -267,36 +267,46 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori } bool RenderableModelEntityItem::isReadyToComputeShape() { - if (_collisionModelURL == "") { + + if (!_model) { + qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::isReadyToComputeShape --> no _model, false"; + return false; // hmm... + } + + if (_model->getCollisionURL().toString() == "") { + qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::isReadyToComputeShape --> no _model->_collisionUrl, true"; // no model url, so we're ready to compute a shape. return true; } - if (! _collisionNetworkGeometry.isNull() && _collisionNetworkGeometry->isLoadedWithTextures()) { - // we have a _collisionModelURL AND a _collisionNetworkGeometry AND it's fully loaded. + const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); + if (! collisionNetworkGeometry.isNull() && collisionNetworkGeometry->isLoadedWithTextures()) { + // we have a _collisionModelURL AND a collisionNetworkGeometry AND it's fully loaded. + qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::isReadyToComputeShape --> model is ready, true"; return true; } - if (_collisionNetworkGeometry.isNull()) { - // we have a _collisionModelURL but we don't yet have a _collisionNetworkGeometry. - _collisionNetworkGeometry = - DependencyManager::get()->getGeometry(_collisionModelURL, QUrl(), false, false); - - if (! _collisionNetworkGeometry.isNull() && _collisionNetworkGeometry->isLoadedWithTextures()) { - // shortcut in case it's already loaded. - return true; - } + if (collisionNetworkGeometry.isNull()) { + qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::isReadyToComputeShape --> started download, false"; + // we have a _collisionModelURL but we don't yet have a collisionNetworkGeometry. + // kick-off the download so that we'll have it at some future re-attempt. + DependencyManager::get()->getGeometry(_collisionModelURL, QUrl(), false, false); + return false; } // the model is still being downloaded. + qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::isReadyToComputeShape --> model not ready, false"; return false; } void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { - if (_collisionModelURL == "") { + if (_model->getCollisionURL().toString() == "") { + qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::computeShapeInfo --> default"; info.setParams(getShapeType(), 0.5f * getDimensions()); } else { - const FBXGeometry& fbxGeometry = _collisionNetworkGeometry->getFBXGeometry(); + qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::computeShapeInfo --> hull points"; + const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); + const FBXGeometry& fbxGeometry = collisionNetworkGeometry->getFBXGeometry(); _points.clear(); foreach (const FBXMesh& mesh, fbxGeometry.meshes) { @@ -310,9 +320,11 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ShapeType RenderableModelEntityItem::getShapeType() const { // XXX make hull an option in edit.js ? - if (_collisionModelURL != "") { - return SHAPE_TYPE_CONVEX_HULL; - } else { + if (!_model || _model->getCollisionURL().toString() == "") { + qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::getShapeType -->" << _shapeType; return _shapeType; + } else { + qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::getShapeType -->" << SHAPE_TYPE_CONVEX_HULL; + return SHAPE_TYPE_CONVEX_HULL; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 6d50a52a95..08adb3e9a6 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -30,8 +30,7 @@ public: _needsInitialSimulation(true), _needsModelReload(true), _myRenderer(NULL), - _originalTexturesRead(false), - _collisionNetworkGeometry(QSharedPointer()) { } + _originalTexturesRead(false) { } virtual ~RenderableModelEntityItem(); @@ -68,7 +67,7 @@ private: QStringList _originalTextures; bool _originalTexturesRead; - QSharedPointer _collisionNetworkGeometry; + // QSharedPointer _collisionNetworkGeometry; QVector _points; }; diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index e1521ebd50..8536e74e9a 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -31,6 +31,7 @@ class EntityItemFBXService { public: virtual const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem) = 0; virtual const Model* getModelForEntityItem(const EntityItem* entityItem) = 0; + virtual const FBXGeometry* getCollisionGeometryForEntity(const EntityItem* entityItem) = 0; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index d5e15ed2c8..5f9feaa49f 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1087,6 +1087,7 @@ int Model::getLastFreeJointIndex(int jointIndex) const { } void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bool delayLoad) { + qDebug() << "|||||||||||||| Model::setURL" << url.toString(); // don't recreate the geometry if it's the same URL if (_url == url) { return; @@ -1102,6 +1103,7 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo } void Model::setCollisionModelURL(const QUrl& url, const QUrl& fallback, bool delayLoad) { + qDebug() << "|||||||||||||| Model::setCollisionModelURL" << url.toString(); if (_collisionUrl == url) { return; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index f95c87e99f..890ea87d25 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -106,11 +106,11 @@ public: /// \param delayLoad if true, don't load the model immediately; wait until actually requested Q_INVOKABLE void setURL(const QUrl& url, const QUrl& fallback = QUrl(), bool retainCurrent = false, bool delayLoad = false); + const QUrl& getURL() const { return _url; } // Set the model to use for collisions Q_INVOKABLE void setCollisionModelURL(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); - - const QUrl& getURL() const { return _url; } + const QUrl& getCollisionURL() const { return _collisionUrl; } /// Sets the distance parameter used for LOD computations. void setLODDistance(float distance) { _lodDistance = distance; } @@ -132,6 +132,9 @@ public: /// Returns a reference to the shared geometry. const QSharedPointer& getGeometry() const { return _geometry; } + + /// Returns a reference to the shared collision geometry. + const QSharedPointer getCollisionGeometry() {return _collisionGeometry; } /// Returns the number of joint states in the model. int getJointStateCount() const { return _jointStates.size(); } From 36e0a5afc59b0f874be1bde247c2395edcf2b03b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 18 Mar 2015 13:04:27 -0700 Subject: [PATCH 09/27] cleanups --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 9 --------- .../entities-renderer/src/RenderableModelEntityItem.h | 2 -- libraries/render-utils/src/Model.cpp | 2 -- 3 files changed, 13 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7bd94df386..f0ba57021d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -269,12 +269,10 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori bool RenderableModelEntityItem::isReadyToComputeShape() { if (!_model) { - qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::isReadyToComputeShape --> no _model, false"; return false; // hmm... } if (_model->getCollisionURL().toString() == "") { - qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::isReadyToComputeShape --> no _model->_collisionUrl, true"; // no model url, so we're ready to compute a shape. return true; } @@ -282,12 +280,10 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); if (! collisionNetworkGeometry.isNull() && collisionNetworkGeometry->isLoadedWithTextures()) { // we have a _collisionModelURL AND a collisionNetworkGeometry AND it's fully loaded. - qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::isReadyToComputeShape --> model is ready, true"; return true; } if (collisionNetworkGeometry.isNull()) { - qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::isReadyToComputeShape --> started download, false"; // we have a _collisionModelURL but we don't yet have a collisionNetworkGeometry. // kick-off the download so that we'll have it at some future re-attempt. DependencyManager::get()->getGeometry(_collisionModelURL, QUrl(), false, false); @@ -295,16 +291,13 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { } // the model is still being downloaded. - qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::isReadyToComputeShape --> model not ready, false"; return false; } void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { if (_model->getCollisionURL().toString() == "") { - qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::computeShapeInfo --> default"; info.setParams(getShapeType(), 0.5f * getDimensions()); } else { - qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::computeShapeInfo --> hull points"; const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); const FBXGeometry& fbxGeometry = collisionNetworkGeometry->getFBXGeometry(); @@ -321,10 +314,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ShapeType RenderableModelEntityItem::getShapeType() const { // XXX make hull an option in edit.js ? if (!_model || _model->getCollisionURL().toString() == "") { - qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::getShapeType -->" << _shapeType; return _shapeType; } else { - qDebug() << "O#O#O#O#O#O RenderableModelEntityItem::getShapeType -->" << SHAPE_TYPE_CONVEX_HULL; return SHAPE_TYPE_CONVEX_HULL; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 08adb3e9a6..f02dd537fb 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -66,8 +66,6 @@ private: QString _currentTextures; QStringList _originalTextures; bool _originalTexturesRead; - - // QSharedPointer _collisionNetworkGeometry; QVector _points; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 5f9feaa49f..d5e15ed2c8 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1087,7 +1087,6 @@ int Model::getLastFreeJointIndex(int jointIndex) const { } void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bool delayLoad) { - qDebug() << "|||||||||||||| Model::setURL" << url.toString(); // don't recreate the geometry if it's the same URL if (_url == url) { return; @@ -1103,7 +1102,6 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo } void Model::setCollisionModelURL(const QUrl& url, const QUrl& fallback, bool delayLoad) { - qDebug() << "|||||||||||||| Model::setCollisionModelURL" << url.toString(); if (_collisionUrl == url) { return; } From 1cab14064dc0e9ae5ed9075445bf7a4938244bf2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 18 Mar 2015 13:10:53 -0700 Subject: [PATCH 10/27] remove unneeded code, quiet some debug spew --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 7 ------- libraries/physics/src/PhysicsEngine.cpp | 1 - 2 files changed, 8 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index f0ba57021d..c2a60e1f6f 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -283,13 +283,6 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { return true; } - if (collisionNetworkGeometry.isNull()) { - // we have a _collisionModelURL but we don't yet have a collisionNetworkGeometry. - // kick-off the download so that we'll have it at some future re-attempt. - DependencyManager::get()->getGeometry(_collisionModelURL, QUrl(), false, false); - return false; - } - // the model is still being downloaded. return false; } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index c7b3d60e41..3f5921a6bb 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -63,7 +63,6 @@ void PhysicsEngine::addEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { - qDebug() << "PhysicsEngine::addEntityInternal(" << entity; if (entity->isReadyToComputeShape()) { ShapeInfo shapeInfo; entity->computeShapeInfo(shapeInfo); From e2a104c38a04a782cb0608b332065b243f9f7c0f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 18 Mar 2015 14:11:02 -0700 Subject: [PATCH 11/27] unjack AvatarData locks --- libraries/physics/src/PhysicsEngine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 3f5921a6bb..b4c32805b5 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -298,6 +298,7 @@ void PhysicsEngine::stepSimulation() { _clock.reset(); float timeStep = btMin(dt, MAX_TIMESTEP); + _avatarData->lockForRead(); if (_avatarData->isPhysicsEnabled()) { // update character controller glm::quat rotation = _avatarData->getOrientation(); @@ -307,6 +308,7 @@ void PhysicsEngine::stepSimulation() { btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity()); _characterController->setVelocityForTimeInterval(walkVelocity, timeStep); } + _avatarData->unlock(); // This is step (2). int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); @@ -342,7 +344,6 @@ void PhysicsEngine::stepSimulation() { } unlock(); - _avatarData->unlock(); _entityTree->unlock(); computeCollisionEvents(); From 8e0141b8e9394bfb487b6cf61f9c44423ff00cd5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 19 Mar 2015 08:48:13 -0700 Subject: [PATCH 12/27] first cut at fst drag/drop support --- interface/src/Application.cpp | 57 ++++++++++++++++++++++++++++++++ interface/src/Application.h | 2 ++ interface/src/GLCanvas.cpp | 3 +- interface/src/ui/DataWebPage.cpp | 5 ++- 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 147162384b..9c0f30c413 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -893,6 +893,8 @@ bool Application::event(QEvent* event) { emit svoImportRequested(url.url()); } else if (url.path().toLower().endsWith(JS_EXTENSION)) { askToLoadScript(url.toString()); + //} else if (url.path().toLower().endsWith(FST_EXTENSION)) { + // askToSetAvatarUrl(url.toString()); } } return false; @@ -1487,6 +1489,9 @@ void Application::dropEvent(QDropEvent *event) { } else if (lower.endsWith(JS_EXTENSION)) { askToLoadScript(url.url()); atLeastOneFileAccepted = true; + } else if (lower.endsWith(FST_EXTENSION)) { + askToSetAvatarUrl(url.url()); + atLeastOneFileAccepted = true; } } @@ -3596,6 +3601,58 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri workerThread->start(); } +void Application::askToSetAvatarUrl(const QString& url) { + QUrl realUrl(url); + if (realUrl.isLocalFile()) { + QString message = "You can not use local files for avatar components."; + + QMessageBox msgBox; + msgBox.setText(message); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); + return; + } + + QString message = "Would you like to use this model for part of avatar:\n" + url; + QMessageBox msgBox; + + msgBox.setIcon(QMessageBox::Question); + msgBox.setWindowTitle("Set Avatar"); + msgBox.setText(message); + + QPushButton* headButton = msgBox.addButton(tr("Head"), QMessageBox::ActionRole); + QPushButton* bodyButton = msgBox.addButton(tr("Body"), QMessageBox::ActionRole); + QPushButton* bodyAndHeadButton = msgBox.addButton(tr("Body + Head"), QMessageBox::ActionRole); + QPushButton* cancelButton = msgBox.addButton(QMessageBox::Cancel); + + msgBox.exec(); + + if (msgBox.clickedButton() == headButton) { + qDebug() << "Chose to use for head: " << url; + //MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + _myAvatar->setFaceModelURL(url); + UserActivityLogger::getInstance().changedModel("head", url); + _myAvatar->sendIdentityPacket(); + } else if (msgBox.clickedButton() == bodyButton) { + qDebug() << "Chose to use for body: " << url; + //MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + _myAvatar->setSkeletonModelURL(url); + UserActivityLogger::getInstance().changedModel("skeleton", url); + _myAvatar->sendIdentityPacket(); + } else if (msgBox.clickedButton() == bodyAndHeadButton) { + qDebug() << "Chose to use for body + head: " << url; + //MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + _myAvatar->setFaceModelURL(QString()); + _myAvatar->setSkeletonModelURL(url); + UserActivityLogger::getInstance().changedModel("skeleton", url); + _myAvatar->sendIdentityPacket(); + } else { + qDebug() << "Declined to use the avatar: " << url; + } +} + + void Application::askToLoadScript(const QString& scriptFilenameOrURL) { QMessageBox::StandardButton reply; QString message = "Would you like to run this script:\n" + scriptFilenameOrURL; diff --git a/interface/src/Application.h b/interface/src/Application.h index 49fdde5fb2..3eaaeb6f6b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -96,6 +96,7 @@ static const float NODE_KILLED_BLUE = 0.0f; static const QString SNAPSHOT_EXTENSION = ".jpg"; static const QString SVO_EXTENSION = ".svo"; static const QString JS_EXTENSION = ".js"; +static const QString FST_EXTENSION = ".fst"; static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; // degrees static const float BILLBOARD_DISTANCE = 5.56f; // meters @@ -341,6 +342,7 @@ public slots: void loadDialog(); void loadScriptURLDialog(); void toggleLogDialog(); + void askToSetAvatarUrl(const QString& url); void askToLoadScript(const QString& scriptFilenameOrURL); ScriptEngine* loadScript(const QString& scriptFilename = QString(), bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false); diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index c615083335..3e39841fd4 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -171,7 +171,8 @@ void GLCanvas::dragEnterEvent(QDragEnterEvent* event) { const QMimeData* mimeData = event->mimeData(); foreach (QUrl url, mimeData->urls()) { auto lower = url.path().toLower(); - if (lower.endsWith(SNAPSHOT_EXTENSION) || lower.endsWith(SVO_EXTENSION) || lower.endsWith(JS_EXTENSION)) { + if (lower.endsWith(SNAPSHOT_EXTENSION) || lower.endsWith(SVO_EXTENSION) + || lower.endsWith(JS_EXTENSION) || lower.endsWith(FST_EXTENSION)) { event->acceptProposedAction(); break; } diff --git a/interface/src/ui/DataWebPage.cpp b/interface/src/ui/DataWebPage.cpp index c24e34fb64..2c41fad7d5 100644 --- a/interface/src/ui/DataWebPage.cpp +++ b/interface/src/ui/DataWebPage.cpp @@ -32,7 +32,6 @@ void DataWebPage::javaScriptConsoleMessage(const QString& message, int lineNumbe } bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) { - if (!request.url().toString().startsWith(HIFI_URL_SCHEME)) { if (request.url().path().toLower().endsWith(SVO_EXTENSION)) { Application::getInstance()->importSVOFromURL(request.url()); @@ -40,6 +39,10 @@ bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkReques } else if (request.url().path().toLower().endsWith(JS_EXTENSION)) { Application::getInstance()->askToLoadScript(request.url().toString()); return false; + } else if (request.url().path().toLower().endsWith(FST_EXTENSION)) { + + Application::getInstance()->askToSetAvatarUrl(request.url().toString()); + return false; } return true; } else { From 8eedab72b3b05e431dc6c0815f139ae6caa410f1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 19 Mar 2015 09:15:57 -0700 Subject: [PATCH 13/27] remove some unneeded asserts --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 35a07353d1..b005f67f5e 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -410,8 +410,6 @@ const Model* EntityTreeRenderer::getModelForEntityItem(const EntityItem* entityI if (entityItem->getType() == EntityTypes::Model) { const RenderableModelEntityItem* constModelEntityItem = dynamic_cast(entityItem); RenderableModelEntityItem* modelEntityItem = const_cast(constModelEntityItem); - assert(modelEntityItem); // we need this!!! - result = modelEntityItem->getModel(this); } return result; @@ -424,7 +422,6 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(const Entit const RenderableModelEntityItem* constModelEntityItem = dynamic_cast(entityItem); if (constModelEntityItem->hasCollisionModel()) { RenderableModelEntityItem* modelEntityItem = const_cast(constModelEntityItem); - assert(modelEntityItem); // we need this!!! Why?!! Model* model = modelEntityItem->getModel(this); if (model) { const QSharedPointer collisionNetworkGeometry = model->getCollisionGeometry(); From 72957670ba14c9130e0a3e42378bbfca18857ecb Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 19 Mar 2015 09:55:03 -0700 Subject: [PATCH 14/27] Some commentary --- assignment-client/src/avatars/AvatarMixer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index bd0239cdc8..151a9f8861 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -145,6 +145,10 @@ void AvatarMixer::broadcastAvatarData() { AvatarData& avatar = nodeData->getAvatar(); glm::vec3 myPosition = avatar.getPosition(); + // TODO use this along with the distance in the calculation of whether to send an update + // about a given otherNode to this node + // FIXME does this mean we should sort the othernodes by distance before iterating + // over them? float outputBandwidth = node->getBandwidthRecorder().getTotalAverageOutputKilobitsPerSecond(); // this is an AGENT we have received head data from From 3c41ecd09137951d19339e6dd65b83ff34b48e41 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 19 Mar 2015 11:29:41 -0700 Subject: [PATCH 15/27] cleanup accepted files implementation --- interface/src/Application.cpp | 99 ++++++++++++++++++++++++-------- interface/src/Application.h | 14 ++++- interface/src/GLCanvas.cpp | 4 +- interface/src/ui/DataWebPage.cpp | 15 ++--- 4 files changed, 93 insertions(+), 39 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9c0f30c413..01f4315142 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -873,8 +873,10 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod } } -void Application::importSVOFromURL(QUrl url) { +bool Application::importSVOFromURL(const QString& urlString) { + QUrl url(urlString); emit svoImportRequested(url.url()); + return true; // assume it's accepted } bool Application::event(QEvent* event) { @@ -887,14 +889,9 @@ bool Application::event(QEvent* event) { QUrl url = fileEvent->url(); if (!url.isEmpty()) { - if (url.scheme() == HIFI_URL_SCHEME) { - DependencyManager::get()->handleLookupString(fileEvent->url().toString()); - } else if (url.path().toLower().endsWith(SVO_EXTENSION)) { - emit svoImportRequested(url.url()); - } else if (url.path().toLower().endsWith(JS_EXTENSION)) { - askToLoadScript(url.toString()); - //} else if (url.path().toLower().endsWith(FST_EXTENSION)) { - // askToSetAvatarUrl(url.toString()); + QString urlString = url.toString(); + if (canAcceptURL(urlString)) { + return acceptURL(urlString); } } return false; @@ -1482,17 +1479,16 @@ void Application::dropEvent(QDropEvent *event) { msgBox.setStandardButtons(QMessageBox::Ok); msgBox.exec(); } - } else if (lower.endsWith(SVO_EXTENSION)) { - emit svoImportRequested(url.url()); - event->acceptProposedAction(); - atLeastOneFileAccepted = true; - } else if (lower.endsWith(JS_EXTENSION)) { - askToLoadScript(url.url()); - atLeastOneFileAccepted = true; - } else if (lower.endsWith(FST_EXTENSION)) { - askToSetAvatarUrl(url.url()); - atLeastOneFileAccepted = true; - } + } else { + QString urlString = url.toString(); + if (canAcceptURL(urlString)) { + if (acceptURL(urlString)) { + atLeastOneFileAccepted = true; + break; + } + } + + } } if (atLeastOneFileAccepted) { @@ -3601,7 +3597,61 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri workerThread->start(); } -void Application::askToSetAvatarUrl(const QString& url) { +void Application::initializeAcceptedFiles() { + if (_acceptedExtensions.size() == 0) { + qDebug() << "Application::initializeAcceptedFiles()"; + _acceptedExtensions[SVO_EXTENSION] = &Application::importSVOFromURL; + _acceptedExtensions[JS_EXTENSION] = &Application::askToLoadScript; + _acceptedExtensions[FST_EXTENSION] = &Application::askToSetAvatarUrl; + } +} + +bool Application::canAcceptURL(const QString& urlString) { + qDebug() << "Application::canAcceptURL() urlString:" << urlString; + initializeAcceptedFiles(); + + QUrl url(urlString); + if (urlString.startsWith(HIFI_URL_SCHEME)) { + return true; + } + QHashIterator i(_acceptedExtensions); + QString lowerPath = url.path().toLower(); + while (i.hasNext()) { + i.next(); + if (lowerPath.endsWith(i.key())) { + return true; + } + } + return false; +} + +bool Application::acceptURL(const QString& urlString) { + qDebug() << "Application::acceptURL() urlString:" << urlString; + initializeAcceptedFiles(); + + if (urlString.startsWith(HIFI_URL_SCHEME)) { + // this is a hifi URL - have the AddressManager handle it + QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString", + Qt::AutoConnection, Q_ARG(const QString&, urlString)); + return true; + } else { + QUrl url(urlString); + QHashIterator i(_acceptedExtensions); + QString lowerPath = url.path().toLower(); + while (i.hasNext()) { + i.next(); + if (lowerPath.endsWith(i.key())) { + AcceptURLMethod method = i.value(); + (this->*method)(urlString); + return true; + } + } + } + return false; +} + + +bool Application::askToSetAvatarUrl(const QString& url) { QUrl realUrl(url); if (realUrl.isLocalFile()) { QString message = "You can not use local files for avatar components."; @@ -3611,7 +3661,7 @@ void Application::askToSetAvatarUrl(const QString& url) { msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); - return; + return false; } QString message = "Would you like to use this model for part of avatar:\n" + url; @@ -3624,7 +3674,7 @@ void Application::askToSetAvatarUrl(const QString& url) { QPushButton* headButton = msgBox.addButton(tr("Head"), QMessageBox::ActionRole); QPushButton* bodyButton = msgBox.addButton(tr("Body"), QMessageBox::ActionRole); QPushButton* bodyAndHeadButton = msgBox.addButton(tr("Body + Head"), QMessageBox::ActionRole); - QPushButton* cancelButton = msgBox.addButton(QMessageBox::Cancel); + msgBox.addButton(QMessageBox::Cancel); msgBox.exec(); @@ -3650,10 +3700,11 @@ void Application::askToSetAvatarUrl(const QString& url) { } else { qDebug() << "Declined to use the avatar: " << url; } + return true; } -void Application::askToLoadScript(const QString& scriptFilenameOrURL) { +bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { QMessageBox::StandardButton reply; QString message = "Would you like to run this script:\n" + scriptFilenameOrURL; reply = QMessageBox::question(getWindow(), "Run Script", message, QMessageBox::Yes|QMessageBox::No); diff --git a/interface/src/Application.h b/interface/src/Application.h index 3eaaeb6f6b..6bfdc7ad3a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -128,6 +128,8 @@ class Application; #endif #define qApp (static_cast(QCoreApplication::instance())) +typedef bool (Application::* AcceptURLMethod)(const QString &); + class Application : public QApplication, public AbstractViewStateInterface, AbstractScriptingServicesInterface { Q_OBJECT @@ -222,7 +224,7 @@ public: float getFieldOfView() { return _fieldOfView.get(); } void setFieldOfView(float fov) { _fieldOfView.set(fov); } - void importSVOFromURL(QUrl url); + bool importSVOFromURL(const QString& urlString); NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; } void lockOctreeSceneStats() { _octreeSceneStatsLock.lockForRead(); } @@ -307,6 +309,10 @@ public: QString getScriptsLocation(); void setScriptsLocation(const QString& scriptsLocation); + + void initializeAcceptedFiles(); + bool canAcceptURL(const QString& url); + bool acceptURL(const QString& url); signals: @@ -342,8 +348,8 @@ public slots: void loadDialog(); void loadScriptURLDialog(); void toggleLogDialog(); - void askToSetAvatarUrl(const QString& url); - void askToLoadScript(const QString& scriptFilenameOrURL); + bool askToSetAvatarUrl(const QString& url); + bool askToLoadScript(const QString& scriptFilenameOrURL); ScriptEngine* loadScript(const QString& scriptFilename = QString(), bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false); void scriptFinished(const QString& scriptName); @@ -597,6 +603,8 @@ private: QWidget* _fullscreenMenuWidget = new QWidget(); int _menuBarHeight; + + QHash _acceptedExtensions; }; #endif // hifi_Application_h diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 3e39841fd4..304740e146 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -171,8 +171,8 @@ void GLCanvas::dragEnterEvent(QDragEnterEvent* event) { const QMimeData* mimeData = event->mimeData(); foreach (QUrl url, mimeData->urls()) { auto lower = url.path().toLower(); - if (lower.endsWith(SNAPSHOT_EXTENSION) || lower.endsWith(SVO_EXTENSION) - || lower.endsWith(JS_EXTENSION) || lower.endsWith(FST_EXTENSION)) { + auto urlString = url.toString(); + if (lower.endsWith(SNAPSHOT_EXTENSION) || Application::getInstance()->canAcceptURL(urlString)) { event->acceptProposedAction(); break; } diff --git a/interface/src/ui/DataWebPage.cpp b/interface/src/ui/DataWebPage.cpp index 2c41fad7d5..41dd1149cc 100644 --- a/interface/src/ui/DataWebPage.cpp +++ b/interface/src/ui/DataWebPage.cpp @@ -33,16 +33,11 @@ void DataWebPage::javaScriptConsoleMessage(const QString& message, int lineNumbe bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) { if (!request.url().toString().startsWith(HIFI_URL_SCHEME)) { - if (request.url().path().toLower().endsWith(SVO_EXTENSION)) { - Application::getInstance()->importSVOFromURL(request.url()); - return false; - } else if (request.url().path().toLower().endsWith(JS_EXTENSION)) { - Application::getInstance()->askToLoadScript(request.url().toString()); - return false; - } else if (request.url().path().toLower().endsWith(FST_EXTENSION)) { - - Application::getInstance()->askToSetAvatarUrl(request.url().toString()); - return false; + QString urlString = request.url().toString(); + if (Application::getInstance()->canAcceptURL(urlString)) { + if (Application::getInstance()->acceptURL(urlString)) { + return false; // we handled it, so QWebPage doesn't need to handle it + } } return true; } else { From e6cefa946c2619f44eefeaa4b79542e114a4b997 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 19 Mar 2015 11:41:03 -0700 Subject: [PATCH 16/27] more DRYing of code --- interface/src/ui/DataWebPage.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/interface/src/ui/DataWebPage.cpp b/interface/src/ui/DataWebPage.cpp index 41dd1149cc..ab27509d28 100644 --- a/interface/src/ui/DataWebPage.cpp +++ b/interface/src/ui/DataWebPage.cpp @@ -32,20 +32,13 @@ void DataWebPage::javaScriptConsoleMessage(const QString& message, int lineNumbe } bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) { - if (!request.url().toString().startsWith(HIFI_URL_SCHEME)) { - QString urlString = request.url().toString(); - if (Application::getInstance()->canAcceptURL(urlString)) { - if (Application::getInstance()->acceptURL(urlString)) { - return false; // we handled it, so QWebPage doesn't need to handle it - } + QString urlString = request.url().toString(); + if (Application::getInstance()->canAcceptURL(urlString)) { + if (Application::getInstance()->acceptURL(urlString)) { + return false; // we handled it, so QWebPage doesn't need to handle it } - return true; - } else { - // this is a hifi URL - have the AddressManager handle it - QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString", - Qt::AutoConnection, Q_ARG(const QString&, request.url().toString())); - return false; } + return true; } QString DataWebPage::userAgentForUrl(const QUrl& url) const { From 5814a141522fc5dcec7d6d6c7cebde560d632617 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 19 Mar 2015 11:42:00 -0700 Subject: [PATCH 17/27] removed dead code --- interface/src/Application.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 01f4315142..c7104e065d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3680,19 +3680,16 @@ bool Application::askToSetAvatarUrl(const QString& url) { if (msgBox.clickedButton() == headButton) { qDebug() << "Chose to use for head: " << url; - //MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); _myAvatar->setFaceModelURL(url); UserActivityLogger::getInstance().changedModel("head", url); _myAvatar->sendIdentityPacket(); } else if (msgBox.clickedButton() == bodyButton) { qDebug() << "Chose to use for body: " << url; - //MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); _myAvatar->setSkeletonModelURL(url); UserActivityLogger::getInstance().changedModel("skeleton", url); _myAvatar->sendIdentityPacket(); } else if (msgBox.clickedButton() == bodyAndHeadButton) { qDebug() << "Chose to use for body + head: " << url; - //MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); _myAvatar->setFaceModelURL(QString()); _myAvatar->setSkeletonModelURL(url); UserActivityLogger::getInstance().changedModel("skeleton", url); From c5314aceac52a4bd3fa70c745243e94b42629b69 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 19 Mar 2015 11:57:57 -0700 Subject: [PATCH 18/27] more DRYing up of code --- interface/src/Application.cpp | 61 +++++++++++++++++------------------ interface/src/Application.h | 1 + interface/src/GLCanvas.cpp | 3 +- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c7104e065d..b1528c0ef4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1452,43 +1452,16 @@ void Application::wheelEvent(QWheelEvent* event) { } void Application::dropEvent(QDropEvent *event) { - QString snapshotPath; const QMimeData *mimeData = event->mimeData(); bool atLeastOneFileAccepted = false; foreach (QUrl url, mimeData->urls()) { - auto lower = url.path().toLower(); - if (lower.endsWith(SNAPSHOT_EXTENSION)) { - snapshotPath = url.toLocalFile(); - - - SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath); - if (snapshotData) { - if (!snapshotData->getDomain().isEmpty()) { - DependencyManager::get()->getDomainHandler().setHostnameAndPort(snapshotData->getDomain()); - } - - _myAvatar->setPosition(snapshotData->getLocation()); - _myAvatar->setOrientation(snapshotData->getOrientation()); + QString urlString = url.toString(); + if (canAcceptURL(urlString)) { + if (acceptURL(urlString)) { atLeastOneFileAccepted = true; - break; // don't process further files - } else { - QMessageBox msgBox; - msgBox.setText("No location details were found in the file " - + snapshotPath + ", try dragging in an authentic Hifi snapshot."); - - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.exec(); + break; } - } else { - QString urlString = url.toString(); - if (canAcceptURL(urlString)) { - if (acceptURL(urlString)) { - atLeastOneFileAccepted = true; - break; - } - } - - } + } } if (atLeastOneFileAccepted) { @@ -1496,6 +1469,29 @@ void Application::dropEvent(QDropEvent *event) { } } +bool Application::acceptSnapshot(const QString& urlString) { + QUrl url(urlString); + QString snapshotPath = url.toLocalFile(); + + SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath); + if (snapshotData) { + if (!snapshotData->getDomain().isEmpty()) { + DependencyManager::get()->getDomainHandler().setHostnameAndPort(snapshotData->getDomain()); + } + + _myAvatar->setPosition(snapshotData->getLocation()); + _myAvatar->setOrientation(snapshotData->getOrientation()); + } else { + QMessageBox msgBox; + msgBox.setText("No location details were found in the file " + + snapshotPath + ", try dragging in an authentic Hifi snapshot."); + + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + } + return true; +} + void Application::sendPingPackets() { QByteArray pingPacket = DependencyManager::get()->constructPingPacket(); controlledBroadcastToNodes(pingPacket, NodeSet() @@ -3600,6 +3596,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri void Application::initializeAcceptedFiles() { if (_acceptedExtensions.size() == 0) { qDebug() << "Application::initializeAcceptedFiles()"; + _acceptedExtensions[SNAPSHOT_EXTENSION] = &Application::acceptSnapshot; _acceptedExtensions[SVO_EXTENSION] = &Application::importSVOFromURL; _acceptedExtensions[JS_EXTENSION] = &Application::askToLoadScript; _acceptedExtensions[FST_EXTENSION] = &Application::askToSetAvatarUrl; diff --git a/interface/src/Application.h b/interface/src/Application.h index 6bfdc7ad3a..4038b21739 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -348,6 +348,7 @@ public slots: void loadDialog(); void loadScriptURLDialog(); void toggleLogDialog(); + bool acceptSnapshot(const QString& urlString); bool askToSetAvatarUrl(const QString& url); bool askToLoadScript(const QString& scriptFilenameOrURL); ScriptEngine* loadScript(const QString& scriptFilename = QString(), bool isUserLoaded = true, diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 304740e146..b3c1db7b24 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -170,9 +170,8 @@ void GLCanvas::wheelEvent(QWheelEvent* event) { void GLCanvas::dragEnterEvent(QDragEnterEvent* event) { const QMimeData* mimeData = event->mimeData(); foreach (QUrl url, mimeData->urls()) { - auto lower = url.path().toLower(); auto urlString = url.toString(); - if (lower.endsWith(SNAPSHOT_EXTENSION) || Application::getInstance()->canAcceptURL(urlString)) { + if (Application::getInstance()->canAcceptURL(urlString)) { event->acceptProposedAction(); break; } From 26670f9e41de4c2ce197d4b4997ccb0e97b2f991 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 19 Mar 2015 12:15:12 -0700 Subject: [PATCH 19/27] remove unneeded debug --- interface/src/Application.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b1528c0ef4..ee16d11579 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3595,7 +3595,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri void Application::initializeAcceptedFiles() { if (_acceptedExtensions.size() == 0) { - qDebug() << "Application::initializeAcceptedFiles()"; _acceptedExtensions[SNAPSHOT_EXTENSION] = &Application::acceptSnapshot; _acceptedExtensions[SVO_EXTENSION] = &Application::importSVOFromURL; _acceptedExtensions[JS_EXTENSION] = &Application::askToLoadScript; @@ -3604,7 +3603,6 @@ void Application::initializeAcceptedFiles() { } bool Application::canAcceptURL(const QString& urlString) { - qDebug() << "Application::canAcceptURL() urlString:" << urlString; initializeAcceptedFiles(); QUrl url(urlString); @@ -3623,7 +3621,6 @@ bool Application::canAcceptURL(const QString& urlString) { } bool Application::acceptURL(const QString& urlString) { - qDebug() << "Application::acceptURL() urlString:" << urlString; initializeAcceptedFiles(); if (urlString.startsWith(HIFI_URL_SCHEME)) { From 24132968fe0d5692d7ed710d6288fea2f13970db Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 19 Mar 2015 12:41:44 -0700 Subject: [PATCH 20/27] oops --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ee16d11579..a3cf63ea74 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3706,6 +3706,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { } else { qDebug() << "Declined to run the script: " << scriptFilenameOrURL; } + return true; } ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUserLoaded, From 817a6130efb38cbd4223f7f871474b5213cf7fa5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 19 Mar 2015 13:01:57 -0700 Subject: [PATCH 21/27] return a reason as part of the domain server's connection-denied packet. Don't apply max-capacity check to users in the editors list --- domain-server/src/DomainServer.cpp | 157 +++++++++++++++++----------- domain-server/src/DomainServer.h | 3 +- interface/src/DatagramProcessor.cpp | 9 +- 3 files changed, 104 insertions(+), 65 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 2e3505dd4d..d504cd854b 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -612,13 +613,15 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock QByteArray usernameSignature; packetStream >> nodeInterestList >> username >> usernameSignature; - - if (!isAssignment && !shouldAllowConnectionFromNode(username, usernameSignature, senderSockAddr)) { + + QString reason; + if (!isAssignment && !shouldAllowConnectionFromNode(username, usernameSignature, senderSockAddr, reason)) { // this is an agent and we've decided we won't let them connect - send them a packet to deny connection - QByteArray usernameRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeDomainConnectionDenied); - - // send this oauth request datagram back to the client - DependencyManager::get()->writeUnverifiedDatagram(usernameRequestByteArray, senderSockAddr); + QByteArray connectionDeniedByteArray = byteArrayWithPopulatedHeader(PacketTypeDomainConnectionDenied); + QDataStream out(&connectionDeniedByteArray, QIODevice::WriteOnly | QIODevice::Append); + out << reason; + // tell client it has been refused. + DependencyManager::get()->writeUnverifiedDatagram(connectionDeniedByteArray, senderSockAddr); return; } @@ -680,9 +683,63 @@ unsigned int DomainServer::countConnectedUsers() { } +bool DomainServer::verifyUsersKey (const QString& username, + const QByteArray& usernameSignature, + QString& reasonReturn) { + // it's possible this user can be allowed to connect, but we need to check their username signature + + QByteArray publicKeyArray = _userPublicKeys.value(username); + if (!publicKeyArray.isEmpty()) { + // if we do have a public key for the user, check for a signature match + + const unsigned char* publicKeyData = reinterpret_cast(publicKeyArray.constData()); + + // first load up the public key into an RSA struct + RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, publicKeyArray.size()); + + if (rsaPublicKey) { + QByteArray decryptedArray(RSA_size(rsaPublicKey), 0); + int decryptResult = + RSA_public_decrypt(usernameSignature.size(), + reinterpret_cast(usernameSignature.constData()), + reinterpret_cast(decryptedArray.data()), + rsaPublicKey, RSA_PKCS1_PADDING); + + if (decryptResult != -1) { + if (username.toLower() == decryptedArray) { + qDebug() << "Username signature matches for" << username << "- allowing connection."; + + // free up the public key before we return + RSA_free(rsaPublicKey); + + return true; + } else { + qDebug() << "Username signature did not match for" << username << "- denying connection."; + reasonReturn = "Username signature did not match."; + } + } else { + qDebug() << "Couldn't decrypt user signature for" << username << "- denying connection."; + reasonReturn = "Couldn't decrypt user signature."; + } + + // free up the public key, we don't need it anymore + RSA_free(rsaPublicKey); + } else { + // we can't let this user in since we couldn't convert their public key to an RSA key we could use + qDebug() << "Couldn't convert data to RSA key for" << username << "- denying connection."; + reasonReturn = "Couldn't convert data to RSA key."; + } + } + + requestUserPublicKey(username); // no joy. maybe next time? + return false; +} + + bool DomainServer::shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature, - const HifiSockAddr& senderSockAddr) { + const HifiSockAddr& senderSockAddr, + QString& reasonReturn) { const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_USERS_SETTINGS_KEYPATH); @@ -693,72 +750,46 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username, || senderSockAddr.getAddress() == QHostAddress::LocalHost) { return true; } - - const QVariant* maximumUserCapacityVariant = valueForKeyPath(_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY); - unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0; - if (maximumUserCapacity > 0) { - unsigned int connectedUsers = countConnectedUsers(); - if (connectedUsers >= maximumUserCapacity) { - // too many users, deny the new connection. - qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection."; - return false; - } - qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, perhaps allowing new connection."; - } if (allowedUsers.count() > 0) { if (allowedUsers.contains(username, Qt::CaseInsensitive)) { - // it's possible this user can be allowed to connect, but we need to check their username signature - - QByteArray publicKeyArray = _userPublicKeys.value(username); - if (!publicKeyArray.isEmpty()) { - // if we do have a public key for the user, check for a signature match - - const unsigned char* publicKeyData = reinterpret_cast(publicKeyArray.constData()); - - // first load up the public key into an RSA struct - RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, publicKeyArray.size()); - - if (rsaPublicKey) { - QByteArray decryptedArray(RSA_size(rsaPublicKey), 0); - int decryptResult = RSA_public_decrypt(usernameSignature.size(), - reinterpret_cast(usernameSignature.constData()), - reinterpret_cast(decryptedArray.data()), - rsaPublicKey, RSA_PKCS1_PADDING); - - if (decryptResult != -1) { - if (username.toLower() == decryptedArray) { - qDebug() << "Username signature matches for" << username << "- allowing connection."; - - // free up the public key before we return - RSA_free(rsaPublicKey); - - return true; - } else { - qDebug() << "Username signature did not match for" << username << "- denying connection."; - } - } else { - qDebug() << "Couldn't decrypt user signature for" << username << "- denying connection."; - } - - // free up the public key, we don't need it anymore - RSA_free(rsaPublicKey); - } else { - // we can't let this user in since we couldn't convert their public key to an RSA key we could use - qDebug() << "Couldn't convert data to RSA key for" << username << "- denying connection."; - } + if (verifyUsersKey(username, usernameSignature, reasonReturn)) { + return true; } - - requestUserPublicKey(username); } else { qDebug() << "Connect request denied for user" << username << "not in allowed users list."; + reasonReturn = "User not on whitelist."; } + return false; } else { - // since we have no allowed user list, let them all in + // we have no allowed user list. + + // if this user is in the editors list, exempt them from the max-capacity check + const QVariant* allowedEditorsVariant = + valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_EDITORS_SETTINGS_KEYPATH); + QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList(); + if (allowedEditors.contains(username)) { + if (verifyUsersKey(username, usernameSignature, reasonReturn)) { + return true; + } + } + + // if we haven't reached max-capacity, let them in. + const QVariant* maximumUserCapacityVariant = valueForKeyPath(_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY); + unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0; + if (maximumUserCapacity > 0) { + unsigned int connectedUsers = countConnectedUsers(); + if (connectedUsers >= maximumUserCapacity) { + // too many users, deny the new connection. + qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection."; + reasonReturn = "Too many connected users."; + return false; + } + qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, perhaps allowing new connection."; + } + return true; } - - return false; } void DomainServer::preloadAllowedUserPublicKeys() { diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 7052cd65a8..79303ef098 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -84,8 +84,9 @@ private: void handleConnectRequest(const QByteArray& packet, const HifiSockAddr& senderSockAddr); unsigned int countConnectedUsers(); + bool verifyUsersKey (const QString& username, const QByteArray& usernameSignature, QString& reasonReturn); bool shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature, - const HifiSockAddr& senderSockAddr); + const HifiSockAddr& senderSockAddr, QString& reasonReturn); void preloadAllowedUserPublicKeys(); void requestUserPublicKey(const QString& username); diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 1e63ce6655..eafb8c3ba5 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -117,9 +118,15 @@ void DatagramProcessor::processDatagrams() { break; } case PacketTypeDomainConnectionDenied: { + int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeDomainConnectionDenied); + QDataStream packetStream(QByteArray(incomingPacket.constData() + headerSize, + incomingPacket.size() - headerSize)); + QString reason; + packetStream >> reason; + // output to the log so the user knows they got a denied connection request // and check and signal for an access token so that we can make sure they are logged in - qDebug() << "The domain-server denied a connection request."; + qDebug() << "The domain-server denied a connection request: " << reason; qDebug() << "You may need to re-log to generate a keypair so you can provide a username signature."; AccountManager::getInstance().checkAndSignalForAccessToken(); break; From baa8e9c86f89c2e1e081a2ff566d9144c1220e9e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 19 Mar 2015 13:05:30 -0700 Subject: [PATCH 22/27] remove uneeded #includes --- domain-server/src/DomainServer.cpp | 1 - interface/src/DatagramProcessor.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d504cd854b..57e133c599 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index eafb8c3ba5..475ce406bb 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -10,7 +10,6 @@ // #include -#include #include #include From 54f2774d2e5e612b7602e2f779478c06fe8f6fe0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 19 Mar 2015 15:45:11 -0700 Subject: [PATCH 23/27] Organize projects into folders for IDEs that support it --- CMakeLists.txt | 7 +++++++ cmake/macros/LinkHifiLibraries.cmake | 1 + tests/CMakeLists.txt | 1 + tools/CMakeLists.txt | 4 ++++ 4 files changed, 13 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1555321c32..296a566fa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,9 @@ if (POLICY CMP0042) cmake_policy(SET CMP0042 OLD) endif () +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMakeTargets") + project(hifi) add_definitions(-DGLM_FORCE_RADIANS) @@ -173,9 +176,13 @@ endif () # add subdirectories for all targets if (NOT ANDROID) add_subdirectory(assignment-client) + set_target_properties(assignment-client PROPERTIES FOLDER "Apps") add_subdirectory(domain-server) + set_target_properties(domain-server PROPERTIES FOLDER "Apps") add_subdirectory(ice-server) + set_target_properties(ice-server PROPERTIES FOLDER "Apps") add_subdirectory(interface) + set_target_properties(interface PROPERTIES FOLDER "Apps") add_subdirectory(tests) add_subdirectory(tools) endif () diff --git a/cmake/macros/LinkHifiLibraries.cmake b/cmake/macros/LinkHifiLibraries.cmake index ed68103c0c..ef7467e170 100644 --- a/cmake/macros/LinkHifiLibraries.cmake +++ b/cmake/macros/LinkHifiLibraries.cmake @@ -16,6 +16,7 @@ macro(LINK_HIFI_LIBRARIES) foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK}) if (NOT TARGET ${HIFI_LIBRARY}) add_subdirectory("${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}" "${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}") + set_target_properties(${HIFI_LIBRARY} PROPERTIES FOLDER "Libraries") endif () include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 862792d8ac..b6b57ca530 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,5 +4,6 @@ list(REMOVE_ITEM TEST_SUBDIRS "CMakeFiles") foreach(DIR ${TEST_SUBDIRS}) if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${DIR}") add_subdirectory(${DIR}) + set_target_properties("${DIR}-tests" PROPERTIES FOLDER "Tests") endif() endforeach() \ No newline at end of file diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 08fe8fd7f3..5c7c306a62 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,8 +1,12 @@ # add the tool directories add_subdirectory(mtc) +set_target_properties(mtc PROPERTIES FOLDER "Tools") add_subdirectory(scribe) +set_target_properties(scribe PROPERTIES FOLDER "Tools") + find_package(VHACD) if(VHACD_FOUND) add_subdirectory(vhacd) +set_target_properties(vhacd PROPERTIES FOLDER "Tools") endif() From 1db9a9ef46dab3fec64ad1a0b0fadd254bbd35e2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 19 Mar 2015 15:48:48 -0700 Subject: [PATCH 24/27] use .isEmpty on urls rather than convert them to strings and compare to empty string --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7dd059c361..d4eefc0986 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -272,7 +272,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { return false; // hmm... } - if (_model->getCollisionURL().toString() == "") { + if (_model->getCollisionURL().isEmpty()) { // no model url, so we're ready to compute a shape. return true; } @@ -288,7 +288,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { } void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { - if (_model->getCollisionURL().toString() == "") { + if (_model->getCollisionURL().isEmpty()) { info.setParams(getShapeType(), 0.5f * getDimensions()); } else { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); @@ -306,7 +306,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ShapeType RenderableModelEntityItem::getShapeType() const { // XXX make hull an option in edit.js ? - if (!_model || _model->getCollisionURL().toString() == "") { + if (!_model || _model->getCollisionURL().isEmpty()) { return _shapeType; } else { return SHAPE_TYPE_CONVEX_HULL; From bf607e4c9cc634f6c383913c7be8ae2a1d340114 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 19 Mar 2015 15:53:16 -0700 Subject: [PATCH 25/27] Fixing indentation and usage --- assignment-client/src/avatars/AvatarMixer.cpp | 8 ++++---- libraries/shared/src/TryLocker.h | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 151a9f8861..176fd51eea 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -135,7 +135,7 @@ void AvatarMixer::broadcastAvatarData() { [&](const SharedNodePointer& node) { AvatarMixerClientData* nodeData = reinterpret_cast(node->getLinkedData()); MutexTryLocker lock(nodeData->getMutex()); - if (!lock.tryLock()) { + if (!lock.isLocked()) { return; } ++_sumListeners; @@ -149,7 +149,7 @@ void AvatarMixer::broadcastAvatarData() { // about a given otherNode to this node // FIXME does this mean we should sort the othernodes by distance before iterating // over them? - float outputBandwidth = node->getBandwidthRecorder().getTotalAverageOutputKilobitsPerSecond(); + float outputBandwidth = node->getOutboundBandwidth(); // this is an AGENT we have received head data from // send back a packet with other active node data to this node @@ -164,14 +164,14 @@ void AvatarMixer::broadcastAvatarData() { // Check throttling value if (!(_performanceThrottlingRatio == 0 || randFloat() < (1.0f - _performanceThrottlingRatio))) { - return; + return false; } return true; }, [&](const SharedNodePointer& otherNode) { AvatarMixerClientData* otherNodeData = otherNodeData = reinterpret_cast(otherNode->getLinkedData()); MutexTryLocker lock(otherNodeData->getMutex()); - if (!lock.tryLock()) { + if (!lock.isLocked()) { return; } AvatarData& otherAvatar = otherNodeData->getAvatar(); diff --git a/libraries/shared/src/TryLocker.h b/libraries/shared/src/TryLocker.h index c5328b3b3a..f4b90575f1 100644 --- a/libraries/shared/src/TryLocker.h +++ b/libraries/shared/src/TryLocker.h @@ -15,14 +15,14 @@ #include class MutexTryLocker { - QMutex & _mutex; - bool _locked{false}; + QMutex & _mutex; + bool _locked{ false }; public: - MutexTryLocker(QMutex &m) : _mutex(m), _locked(m.tryLock()) {} - ~MutexTryLocker() { if (_locked) _mutex.unlock(); } - bool isLocked() { - return _locked; - } -} + MutexTryLocker(QMutex &m) : _mutex(m), _locked(m.tryLock()) {} + ~MutexTryLocker() { if (_locked) _mutex.unlock(); } + bool isLocked() { + return _locked; + } +}; -#endif // hifi_UUID_h +#endif // hifi_TryLocker_h From 599fe09e75fe6b2148ef0a14b410be1aaa3b00c2 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 19 Mar 2015 17:24:58 -0700 Subject: [PATCH 26/27] type & squish --- libraries/networking/src/NetworkPeer.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index eb072a91f0..c6026b3a23 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -102,33 +102,32 @@ QDebug operator<<(QDebug debug, const NetworkPeer &peer) { // FIXME this is a temporary implementation to determine if this is the right approach. // If so, migrate the BandwidthRecorder into the NetworkPeer class -using BandwidthRecorderPtr = QSharedPointer < BandwidthRecorder > ; +using BandwidthRecorderPtr = QSharedPointer; static QHash PEER_BANDWIDTH; -BandwidthRecorder & getBandwidthRecorder(const QUuid & uuid) { +BandwidthRecorder& getBandwidthRecorder(const QUuid & uuid) { if (!PEER_BANDWIDTH.count(uuid)) { PEER_BANDWIDTH.insert(uuid, BandwidthRecorderPtr(new BandwidthRecorder())); } return *PEER_BANDWIDTH[uuid].data(); } - void NetworkPeer::recordBytesSent(int count) { - auto & bw = getBandwidthRecorder(_uuid); + auto& bw = getBandwidthRecorder(_uuid); bw.updateOutboundData(0, count); } void NetworkPeer::recordBytesReceived(int count) { - auto & bw = getBandwidthRecorder(_uuid); + auto& bw = getBandwidthRecorder(_uuid); bw.updateInboundData(0, count); } float NetworkPeer::getOutboundBandwidth() { - auto & bw = getBandwidthRecorder(_uuid); + auto& bw = getBandwidthRecorder(_uuid); return bw.getAverageOutputKilobitsPerSecond(0); } float NetworkPeer::getInboundBandwidth() { - auto & bw = getBandwidthRecorder(_uuid); + auto& bw = getBandwidthRecorder(_uuid); return bw.getAverageInputKilobitsPerSecond(0); } From 7079b5f978514277f9eb65a939fb5d2f174f5206 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 19 Mar 2015 17:29:57 -0700 Subject: [PATCH 27/27] type & squish again --- libraries/shared/src/TryLocker.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/TryLocker.h b/libraries/shared/src/TryLocker.h index f4b90575f1..a5c8077484 100644 --- a/libraries/shared/src/TryLocker.h +++ b/libraries/shared/src/TryLocker.h @@ -15,7 +15,7 @@ #include class MutexTryLocker { - QMutex & _mutex; + QMutex& _mutex; bool _locked{ false }; public: MutexTryLocker(QMutex &m) : _mutex(m), _locked(m.tryLock()) {}