diff --git a/examples/count.js b/examples/count.js new file mode 100644 index 0000000000..917bec342d --- /dev/null +++ b/examples/count.js @@ -0,0 +1,26 @@ +// +// count.js +// hifi +// +// Created by Brad Hefta-Gaub on 12/31/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// +// This is an example script that runs in a loop and displays a counter to the log +// + +var count = 0; + +function displayCount() { + print("count =" + count); + count++; +} + +function scriptEnding() { + print("SCRIPT ENDNG!!!\n"); +} + +// register the call back so it fires before each data send +Agent.willSendVisualDataCallback.connect(displayCount); + +// register our scriptEnding callback +Agent.scriptEnding.connect(scriptEnding); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 646643c1fc..23113dfd71 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2014,7 +2014,7 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm:: PerformanceWarning warn(showWarnings, "Application::updateAvatars()"); foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { - QMutexLocker(&node->getMutex()); + QMutexLocker locker(&node->getMutex()); if (node->getLinkedData()) { Avatar *avatar = (Avatar *)node->getLinkedData(); if (!avatar->isInitialized()) { @@ -3667,7 +3667,7 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) { NodeList* nodeList = NodeList::getInstance(); foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { - QMutexLocker(&node->getMutex()); + QMutexLocker locker(&node->getMutex()); if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { Avatar *avatar = (Avatar *)node->getLinkedData(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 537fc86240..7299615ecc 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -350,7 +350,6 @@ Menu::Menu() : SLOT(setFilter(bool))); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayLeapHands, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); - addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::BallFromHand, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::VoxelDrumming, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 04fce14510..b356f29a85 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -156,7 +156,6 @@ namespace MenuOption { const QString Avatars = "Avatars"; const QString Atmosphere = "Atmosphere"; const QString AutomaticallyAuditTree = "Automatically Audit Tree Stats"; - const QString BallFromHand = "Ball from Hand"; const QString Bandwidth = "Bandwidth Display"; const QString BandwidthDetails = "Bandwidth Details"; const QString ChatCircling = "Chat Circling"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 7403f205e7..069ad0b7d9 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -317,7 +317,7 @@ bool Avatar::findSphereCollision(const glm::vec3& sphereCenter, float sphereRadi if (handData) { for (int i = 0; i < 2; i++) { const PalmData* palm = handData->getPalm(i); - if (palm) { + if (palm && palm->hasPaddle()) { // create a disk collision proxy where the hand is glm::vec3 fingerAxis(0.f); for (size_t f = 0; f < palm->getNumFingers(); ++f) { @@ -339,10 +339,12 @@ bool Avatar::findSphereCollision(const glm::vec3& sphereCenter, float sphereRadi } glm::vec3 diskCenter = handPosition + HAND_PADDLE_OFFSET * fingerAxis; glm::vec3 diskNormal = palm->getNormal(); + float diskThickness = 0.08f; // collide against the disk if (findSphereDiskPenetration(sphereCenter, sphereRadius, - diskCenter, HAND_PADDLE_RADIUS, diskNormal, collision._penetration)) { + diskCenter, HAND_PADDLE_RADIUS, diskThickness, diskNormal, + collision._penetration)) { collision._addedVelocity = palm->getVelocity(); return true; } diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 0b399c4287..201b332a8c 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -83,7 +83,6 @@ void Hand::reset() { void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, float deltaTime) { Application* app = Application::getInstance(); ParticleTree* particles = app->getParticles()->getTree(); - bool ballFromHand = Menu::getInstance()->isOptionChecked(MenuOption::BallFromHand); int handID = palm.getSixenseID(); const int NEW_BALL_BUTTON = BUTTON_3; @@ -93,7 +92,8 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f bool ballAlreadyInHand = _toyBallInHand[handID]; - glm::vec3 targetPosition = (ballFromHand ? palm.getPosition() : fingerTipPosition) / (float)TREE_SCALE; + glm::vec3 targetPosition; + palm.getBallHoldPosition(targetPosition); float targetRadius = CATCH_RADIUS / (float)TREE_SCALE; // If I don't currently have a ball in my hand, then try to catch closest one @@ -148,7 +148,8 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f if ((palm.getControllerButtons() & NEW_BALL_BUTTON) && (_toyBallInHand[handID] == false)) { _toyBallInHand[handID] = true; // Create a particle on the particle server - glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; + glm::vec3 ballPosition; + palm.getBallHoldPosition(ballPosition); _ballParticleEditHandles[handID] = app->makeParticle( ballPosition / (float)TREE_SCALE, TOY_BALL_RADIUS / (float) TREE_SCALE, @@ -171,7 +172,8 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f xColor colorForParticleInHand = particleInHand ? particleInHand->getXColor() : TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]]; - glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; + glm::vec3 ballPosition; + palm.getBallHoldPosition(ballPosition); _ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE, TOY_BALL_RADIUS / (float) TREE_SCALE, colorForParticleInHand, @@ -187,8 +189,10 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f const float THROWN_VELOCITY_SCALING = 1.5f; _toyBallInHand[handID] = false; - glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; - glm::vec3 ballVelocity = ballFromHand ? palm.getRawVelocity() : palm.getTipVelocity(); + palm.updateCollisionlessPaddleExpiry(); + glm::vec3 ballPosition; + palm.getBallHoldPosition(ballPosition); + glm::vec3 ballVelocity = palm.getTipVelocity(); glm::quat avatarRotation = _owningAvatar->getOrientation(); ballVelocity = avatarRotation * ballVelocity; ballVelocity *= THROWN_VELOCITY_SCALING; @@ -550,7 +554,6 @@ void Hand::renderLeapHands(bool isMine) { //const glm::vec3 handColor = _ballColor; const glm::vec3 handColor(1.0, 0.84, 0.66); // use the skin color - bool ballFromHand = Menu::getInstance()->isOptionChecked(MenuOption::BallFromHand); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); @@ -561,7 +564,8 @@ void Hand::renderLeapHands(bool isMine) { if (!palm.isActive()) { continue; } - glm::vec3 targetPosition = ballFromHand ? palm.getPosition() : palm.getTipPosition(); + glm::vec3 targetPosition; + palm.getBallHoldPosition(targetPosition); glPushMatrix(); ParticleTree* particles = Application::getInstance()->getParticles()->getTree(); diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index bc671d1926..0552c021f1 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -31,7 +31,7 @@ class Avatar; class ProgramObject; const float HAND_PADDLE_OFFSET = 0.1f; -const float HAND_PADDLE_THICKNESS = 0.05f; +const float HAND_PADDLE_THICKNESS = 0.01f; const float HAND_PADDLE_RADIUS = 0.15f; class Hand : public HandData { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3c5fdb243f..d10cd1b17d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -175,8 +175,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) { // Compute instantaneous acceleration float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime; - const float ACCELERATION_PITCH_DECAY = 0.4f; - const float ACCELERATION_PULL_THRESHOLD = 0.2f; const float OCULUS_ACCELERATION_PULL_THRESHOLD = 1.0f; const int OCULUS_YAW_OFFSET_THRESHOLD = 10; @@ -475,14 +473,19 @@ void MyAvatar::loadData(QSettings* settings) { } void MyAvatar::orbit(const glm::vec3& position, int deltaX, int deltaY) { - glm::vec3 vector = getPosition() - position; + // first orbit horizontally glm::quat orientation = getOrientation(); - glm::vec3 up = orientation * IDENTITY_UP; const float ANGULAR_SCALE = 0.5f; - glm::quat rotation = glm::angleAxis(deltaX * -ANGULAR_SCALE, up); - const float LINEAR_SCALE = 0.01f; - setPosition(position + rotation * vector + up * (deltaY * LINEAR_SCALE * _scale)); - setOrientation(rotation * orientation); + glm::quat rotation = glm::angleAxis(deltaX * -ANGULAR_SCALE, orientation * IDENTITY_UP); + setPosition(position + rotation * (getPosition() - position)); + orientation = rotation * orientation; + setOrientation(orientation); + + // then vertically + float oldMousePitch = _head.getMousePitch(); + _head.setMousePitch(oldMousePitch + deltaY * -ANGULAR_SCALE); + rotation = glm::angleAxis(_head.getMousePitch() - oldMousePitch, orientation * IDENTITY_RIGHT); + setPosition(position + rotation * (getPosition() - position)); } float MyAvatar::getAbsoluteHeadYaw() const { diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 24caa33533..12d045dea3 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -98,6 +98,15 @@ void SixenseManager::update(float deltaTime) { // Compute current velocity from position change glm::vec3 rawVelocity = (position - palm->getRawPosition()) / deltaTime / 1000.f; palm->setRawVelocity(rawVelocity); // meters/sec + /* + if (i == 0) + { + printf("ADEBUG rawVelocity = [%e, %e, %e]\n", + rawVelocity.x, + rawVelocity.y, + rawVelocity.z); + } + */ palm->setRawPosition(position); // use the velocity to determine whether there's any movement (if the hand isn't new) diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 1b942e8f07..7fc0c79b47 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -79,7 +79,8 @@ _sixenseID(SIXENSEID_INVALID), _numFramesWithoutData(0), _owningHandData(owningHandData), _isCollidingWithVoxel(false), -_isCollidingWithPalm(false) +_isCollidingWithPalm(false), +_collisionlessPaddleExpiry(0) { for (int i = 0; i < NUM_FINGERS_PER_HAND; ++i) { _fingers.push_back(FingerData(this, owningHandData)); @@ -294,6 +295,15 @@ const glm::vec3& FingerData::getTrailPosition(int index) { return _tipTrailPositions[posIndex]; } +void PalmData::getBallHoldPosition(glm::vec3& position) const { + const float BALL_FORWARD_OFFSET = 0.08f; // put the ball a bit forward of fingers + position = BALL_FORWARD_OFFSET * getNormal(); + if (_fingers.size() > 0) { + position += _fingers[0].getTipPosition(); + } else { + position += getPosition(); + } +} diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 1aa60da927..ef9009312e 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -15,6 +15,8 @@ #include #include +#include "SharedUtil.h" + class AvatarData; class FingerData; class PalmData; @@ -51,7 +53,7 @@ public: return _basePosition + _baseOrientation * (leapPosition * LEAP_UNIT_SCALE); } glm::vec3 leapDirectionToWorldDirection(const glm::vec3& leapDirection) { - return glm::normalize(_baseOrientation * leapDirection); + return _baseOrientation * leapDirection; } glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const; glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const; @@ -193,6 +195,12 @@ public: bool getIsCollidingWithPalm() const { return _isCollidingWithPalm; } void setIsCollidingWithPalm(bool isCollidingWithPalm) { _isCollidingWithPalm = isCollidingWithPalm; } + bool hasPaddle() const { return _collisionlessPaddleExpiry < usecTimestampNow(); } + void updateCollisionlessPaddleExpiry() { _collisionlessPaddleExpiry = usecTimestampNow() + USECS_PER_SECOND; } + + /// Store position where the palm holds the ball. + void getBallHoldPosition(glm::vec3& position) const; + private: std::vector _fingers; glm::quat _rawRotation; @@ -217,7 +225,7 @@ private: bool _isCollidingWithVoxel; /// Whether the finger of this palm is inside a leaf voxel bool _isCollidingWithPalm; - + uint64_t _collisionlessPaddleExpiry; /// Timestamp after which paddle starts colliding }; #endif /* defined(__hifi__HandData__) */ diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp index ae27259f83..d8919ac48e 100644 --- a/libraries/octree/src/JurisdictionListener.cpp +++ b/libraries/octree/src/JurisdictionListener.cpp @@ -20,12 +20,9 @@ JurisdictionListener::JurisdictionListener(NODE_TYPE type, PacketSenderNotify* n { _nodeType = type; ReceivedPacketProcessor::_dontSleep = true; // we handle sleeping so this class doesn't need to - NodeList* nodeList = NodeList::getInstance(); - connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); - - //qDebug("JurisdictionListener::JurisdictionListener(NODE_TYPE type=%c)\n", type); - +// connect(nodeList, &NodeList::nodeKilled, this, &JurisdictionListener::nodeKilled); +// qDebug("JurisdictionListener::JurisdictionListener(NODE_TYPE type=%c)\n", type); } void JurisdictionListener::nodeKilled(SharedNodePointer node) { diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index ed62da8791..8544932181 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -145,7 +145,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE); float radius = particle->getRadius() * (float)(TREE_SCALE); - const float ELASTICITY = 0.95f; + const float ELASTICITY = 0.9f; const float DAMPING = 0.0f; const float COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; @@ -155,12 +155,27 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { AvatarData* avatar = (AvatarData*)_selfAvatar; CollisionInfo collision; if (avatar->findSphereCollision(center, radius, collision)) { - if (glm::dot(particle->getVelocity(), collision._addedVelocity) < 0.f) { + collision._addedVelocity /= (float)(TREE_SCALE); + glm::vec3 relativeVelocity = collision._addedVelocity - particle->getVelocity(); + if (glm::dot(relativeVelocity, collision._penetration) < 0.f) { // only collide when particle and collision point are moving toward each other + // (doing this prevents some "collision snagging" when particle penetrates the object) + + // HACK BEGIN: to allow paddle hands to "hold" particles we attenuate soft collisions against the avatar. + // NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle. + // TODO: make this less hacky when we have more per-collision details + float elasticity = ELASTICITY; + float SLOW_PADDLE_SPEED = 5.0e-5f; + float attenuationFactor = glm::length(collision._addedVelocity) / SLOW_PADDLE_SPEED; + if (attenuationFactor < 1.f) { + collision._addedVelocity *= attenuationFactor; + elasticity *= attenuationFactor; + } + // HACK END + collision._penetration /= (float)(TREE_SCALE); - collision._addedVelocity /= (float)(TREE_SCALE); updateCollisionSound(particle, collision._penetration, COLLISION_FREQUENCY); - applyHardCollision(particle, collision._penetration, ELASTICITY, DAMPING, collision._addedVelocity); + applyHardCollision(particle, collision._penetration, elasticity, DAMPING, collision._addedVelocity); } } } @@ -170,13 +185,24 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { //qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n"; if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { AvatarData* avatar = static_cast(node->getLinkedData()); - CollisionInfo collision; if (avatar->findSphereCollision(center, radius, collision)) { - if (glm::dot(particle->getVelocity(), collision._addedVelocity) < 0.f) { - // only collide when particle and collision point are moving toward each other + collision._addedVelocity /= (float)(TREE_SCALE); + glm::vec3 relativeVelocity = collision._addedVelocity - particle->getVelocity(); + if (glm::dot(relativeVelocity, collision._penetration) < 0.f) { + // HACK BEGIN: to allow paddle hands to "hold" particles we attenuate soft collisions against the avatar. + // NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle. + // TODO: make this less hacky when we have more per-collision details + float elasticity = ELASTICITY; + float SLOW_PADDLE_SPEED = 5.0e-5f; + float attenuationFactor = glm::length(collision._addedVelocity) / SLOW_PADDLE_SPEED; + if (attenuationFactor < 1.f) { + collision._addedVelocity *= attenuationFactor; + elasticity *= attenuationFactor; + } + // HACK END + collision._penetration /= (float)(TREE_SCALE); - collision._addedVelocity /= (float)(TREE_SCALE); updateCollisionSound(particle, collision._penetration, COLLISION_FREQUENCY); applyHardCollision(particle, collision._penetration, ELASTICITY, DAMPING, collision._addedVelocity); } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index db486f9bb9..6b85cf33ad 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -51,11 +51,12 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, if (scriptMenuName) { _scriptMenuName = "Stop "; _scriptMenuName.append(scriptMenuName); + _scriptMenuName.append(QString(" [%1]").arg(_scriptNumber)); } else { _scriptMenuName = "Stop Script "; - _scriptNumber++; _scriptMenuName.append(_scriptNumber); } + _scriptNumber++; _menu = menu; _controllerScriptingInterface = controllerScriptingInterface; } @@ -224,6 +225,7 @@ void ScriptEngine::run() { qDebug() << "Uncaught exception at line" << line << ":" << _engine.uncaughtException().toString(); } } + emit scriptEnding(); cleanMenuItems(); // If we were on a thread, then wait till it's done diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 842b902fcf..06597f82a8 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -57,7 +57,9 @@ public slots: signals: void willSendAudioDataCallback(); void willSendVisualDataCallback(); + void scriptEnding(); void finished(); + protected: QString _scriptContents; bool _isFinished; diff --git a/libraries/shared/src/CollisionInfo.h b/libraries/shared/src/CollisionInfo.h index 4f46a6bfd3..1e4801788e 100644 --- a/libraries/shared/src/CollisionInfo.h +++ b/libraries/shared/src/CollisionInfo.h @@ -18,7 +18,7 @@ public: //glm::vec3 _point; //glm::vec3 _normal; - glm::vec3 _penetration; + glm::vec3 _penetration; // depth that bodyA is penetrates bodyB glm::vec3 _addedVelocity; }; diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index 2627a9035a..ac8e4e97c4 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -6,6 +6,7 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include +#include #include "SharedUtil.h" #include "GeometryUtil.h" @@ -115,20 +116,18 @@ bool findSpherePlanePenetration(const glm::vec3& sphereCenter, float sphereRadiu } bool findSphereDiskPenetration(const glm::vec3& sphereCenter, float sphereRadius, - const glm::vec3& diskCenter, float diskRadius, const glm::vec3& diskNormal, + const glm::vec3& diskCenter, float diskRadius, float diskThickness, const glm::vec3& diskNormal, glm::vec3& penetration) { glm::vec3 localCenter = sphereCenter - diskCenter; - float verticalDistance = glm::dot(localCenter, diskNormal); - - - if (abs(verticalDistance) < sphereRadius) { + float axialDistance = glm::dot(localCenter, diskNormal); + if (std::fabs(axialDistance) < (sphereRadius + 0.5f * diskThickness)) { // sphere hit the plane, but does it hit the disk? // Note: this algorithm ignores edge hits. - glm::vec3 verticalOffset = verticalDistance * diskNormal; - if (glm::length(localCenter - verticalOffset) < diskRadius) { + glm::vec3 axialOffset = axialDistance * diskNormal; + if (glm::length(localCenter - axialOffset) < diskRadius) { // yes, hit the disk - penetration = (sphereRadius - abs(verticalDistance)) * diskNormal; - if (verticalDistance < 0.f) { + penetration = (std::fabs(axialDistance) - (sphereRadius + 0.5f * diskThickness) ) * diskNormal; + if (axialDistance < 0.f) { // hit the backside of the disk, so negate penetration vector penetration *= -1.f; } diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index 59ad055445..12afc7c59c 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -17,7 +17,7 @@ glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec /// \param point the point location relative to sphere center (origin) /// \param defaultDirection the direction of the pentration when the point is near the origin /// \param sphereRadius the radius of the sphere -/// \param penetration the displacement that would move the point out of penetration with the sphere +/// \param penetration[out] the displacement that would move the point out of penetration with the sphere /// \return true if point is inside sphere, otherwise false bool findSpherePenetration(const glm::vec3& point, const glm::vec3& defaultDirection, float sphereRadius, glm::vec3& penetration); @@ -53,9 +53,10 @@ bool findSpherePlanePenetration(const glm::vec3& sphereCenter, float sphereRadiu /// \param diskCenter center of disk /// \param diskRadius radius of disk /// \param diskNormal normal of disk plan +/// \param penetration[out] the depth that the sphere penetrates the disk /// \return true if sphere touches disk (does not handle collisions with disk edge) bool findSphereDiskPenetration(const glm::vec3& sphereCenter, float sphereRadius, - const glm::vec3& diskCenter, float diskRadius, const glm::vec3& diskNormal, + const glm::vec3& diskCenter, float diskRadius, float diskThickness, const glm::vec3& diskNormal, glm::vec3& penetration); bool findCapsuleSpherePenetration(const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius, diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 06d2bbe05b..f33137a092 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -56,6 +56,7 @@ NodeList* NodeList::getInstance() { NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : _nodeHash(), + _nodeHashMutex(), _domainHostname(DEFAULT_DOMAIN_HOSTNAME), _domainSockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), _nodeSocket(), @@ -230,7 +231,7 @@ void NodeList::processBulkNodeData(const HifiSockAddr& senderAddress, unsigned c } int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr, unsigned char *packetData, int dataBytes) { - QMutexLocker(&node->getMutex()); + QMutexLocker locker(&node->getMutex()); node->setLastHeardMicrostamp(usecTimestampNow()); @@ -266,19 +267,25 @@ SharedNodePointer NodeList::nodeWithAddress(const HifiSockAddr &senderSockAddr) } SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID) { + QMutexLocker locker(&_nodeHashMutex); return _nodeHash.value(nodeUUID); } +NodeHash NodeList::getNodeHash() { + QMutexLocker locker(&_nodeHashMutex); + return NodeHash(_nodeHash); +} + void NodeList::clear() { qDebug() << "Clearing the NodeList. Deleting all nodes in list."; + + QMutexLocker locker(&_nodeHashMutex); NodeHash::iterator nodeItem = _nodeHash.begin(); // iterate the nodes in the list while (nodeItem != _nodeHash.end()) { - NodeHash::iterator previousNodeItem = nodeItem; - ++nodeItem; - killNodeAtHashIterator(previousNodeItem); + nodeItem = killNodeAtHashIterator(nodeItem); } } @@ -438,16 +445,18 @@ void NodeList::processSTUNResponse(unsigned char* packetData, size_t dataBytes) } void NodeList::killNodeWithUUID(const QUuid& nodeUUID) { + QMutexLocker locker(&_nodeHashMutex); + NodeHash::iterator nodeItemToKill = _nodeHash.find(nodeUUID); if (nodeItemToKill != _nodeHash.end()) { killNodeAtHashIterator(nodeItemToKill); } } -void NodeList::killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill) { +NodeHash::iterator NodeList::killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill) { qDebug() << "Killed" << *nodeItemToKill.value(); emit nodeKilled(nodeItemToKill.value()); - _nodeHash.erase(nodeItemToKill); + return _nodeHash.erase(nodeItemToKill); } void NodeList::sendKillNode(const char* nodeTypes, int numNodeTypes) { @@ -674,6 +683,8 @@ void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) { SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) { + _nodeHashMutex.lock(); + SharedNodePointer matchingNode = _nodeHash.value(uuid); if (!matchingNode) { @@ -683,13 +694,17 @@ SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, _nodeHash.insert(newNode->getUUID(), newNodeSharedPointer); + _nodeHashMutex.unlock(); + qDebug() << "Added" << *newNode; emit nodeAdded(newNodeSharedPointer); return newNodeSharedPointer; } else { - QMutexLocker(&matchingNode->getMutex()); + _nodeHashMutex.unlock(); + + QMutexLocker locker(&matchingNode->getMutex()); if (matchingNode->getType() == NODE_TYPE_AUDIO_MIXER || matchingNode->getType() == NODE_TYPE_VOXEL_SERVER || @@ -781,24 +796,27 @@ SharedNodePointer NodeList::soloNodeOfType(char nodeType) { void NodeList::removeSilentNodes() { + _nodeHashMutex.lock(); + NodeHash::iterator nodeItem = _nodeHash.begin(); while (nodeItem != _nodeHash.end()) { SharedNodePointer node = nodeItem.value(); - QMutexLocker(&node->getMutex()); + node->getMutex().lock(); if ((usecTimestampNow() - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) { // call our private method to kill this node (removes it and emits the right signal) - NodeHash::iterator previousNodeItem = nodeItem; - ++nodeItem; - - killNodeAtHashIterator(previousNodeItem); + nodeItem = killNodeAtHashIterator(nodeItem); } else { // we didn't kill this node, push the iterator forwards ++nodeItem; } + + node->getMutex().unlock(); } + + _nodeHashMutex.unlock(); } const QString QSETTINGS_GROUP_NAME = "NodeList"; diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 391e329200..b5e27564b1 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -21,6 +21,7 @@ #include // not on windows, not needed for mac or windows #endif +#include #include #include #include @@ -81,7 +82,7 @@ public: void(*linkedDataCreateCallback)(Node *); - const NodeHash& getNodeHash() { return _nodeHash; } + NodeHash getNodeHash(); int size() const { return _nodeHash.size(); } int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; } @@ -140,9 +141,10 @@ private: void processSTUNResponse(unsigned char* packetData, size_t dataBytes); void processKillNode(unsigned char* packetData, size_t dataBytes); - void killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill); + NodeHash::iterator killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill); NodeHash _nodeHash; + QMutex _nodeHashMutex; QString _domainHostname; HifiSockAddr _domainSockAddr; QUdpSocket _nodeSocket;