From d068b668d8a4b08fab0d3c1c4d3d347ab5343d17 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 22 Jan 2014 12:48:10 -0800 Subject: [PATCH 01/17] add marker spheres at 1 meter away from origin for better avatar size testing --- interface/src/Application.cpp | 4 ++-- interface/src/Util.cpp | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b59893a10e..d4a3e7118d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2921,10 +2921,10 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { if (!selfAvatarOnly) { // draw a red sphere - float sphereRadius = 0.25f; + float originSphereRadius = 0.05f; glColor3f(1,0,0); glPushMatrix(); - glutSolidSphere(sphereRadius, 15, 15); + glutSolidSphere(originSphereRadius, 15, 15); glPopMatrix(); // disable specular lighting for ground and voxels diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index d557eb67b3..ffee4c7879 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -332,27 +332,29 @@ void renderWorldBox() { glVertex3f(TREE_SCALE, 0, TREE_SCALE); glVertex3f(TREE_SCALE, 0, 0); glEnd(); - // Draw marker dots at very end + // Draw meter markers along the 3 axis to help with measuring things + const float MARKER_DISTANCE = 1.f; + const float MARKER_RADIUS = 0.05f; glEnable(GL_LIGHTING); glPushMatrix(); - glTranslatef(TREE_SCALE, 0, 0); + glTranslatef(MARKER_DISTANCE, 0, 0); glColor3fv(red); - glutSolidSphere(0.125, 10, 10); + glutSolidSphere(MARKER_RADIUS, 10, 10); glPopMatrix(); glPushMatrix(); - glTranslatef(0, TREE_SCALE, 0); + glTranslatef(0, MARKER_DISTANCE, 0); glColor3fv(green); - glutSolidSphere(0.125, 10, 10); + glutSolidSphere(MARKER_RADIUS, 10, 10); glPopMatrix(); glPushMatrix(); - glTranslatef(0, 0, TREE_SCALE); + glTranslatef(0, 0, MARKER_DISTANCE); glColor3fv(blue); - glutSolidSphere(0.125, 10, 10); + glutSolidSphere(MARKER_RADIUS, 10, 10); glPopMatrix(); glPushMatrix(); glColor3fv(gray); - glTranslatef(TREE_SCALE, 0, TREE_SCALE); - glutSolidSphere(0.125, 10, 10); + glTranslatef(MARKER_DISTANCE, 0, MARKER_DISTANCE); + glutSolidSphere(MARKER_RADIUS, 10, 10); glPopMatrix(); } From e9e2557576714417f758f3b9c4e49dd59a3358f4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jan 2014 14:47:04 -0800 Subject: [PATCH 02/17] change node types of interest to a QSet --- animation-server/src/AnimationServer.cpp | 2 +- assignment-client/src/Agent.cpp | 6 ++--- assignment-client/src/audio/AudioMixer.cpp | 3 +-- assignment-client/src/avatars/AvatarMixer.cpp | 2 +- interface/src/Application.cpp | 6 ++--- libraries/octree-server/src/OctreeServer.cpp | 3 +-- libraries/shared/src/Node.cpp | 2 -- libraries/shared/src/NodeList.cpp | 26 +++++++------------ libraries/shared/src/NodeList.h | 8 +++--- libraries/shared/src/NodeTypes.h | 1 - 10 files changed, 24 insertions(+), 35 deletions(-) diff --git a/animation-server/src/AnimationServer.cpp b/animation-server/src/AnimationServer.cpp index f684a6e672..ba07fac21a 100644 --- a/animation-server/src/AnimationServer.cpp +++ b/animation-server/src/AnimationServer.cpp @@ -807,7 +807,7 @@ AnimationServer::AnimationServer(int &argc, char **argv) : pthread_create(&::animateVoxelThread, NULL, animateVoxels, NULL); - NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_VOXEL_SERVER, 1); + NodeList::getInstance()->addNodeTypeToInterestSet(NODE_TYPE_VOXEL_SERVER); QTimer* domainServerTimer = new QTimer(this); connect(domainServerTimer, SIGNAL(timeout()), nodeList, SLOT(sendDomainServerCheckIn())); diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d27845f337..bb7d7890cc 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -55,10 +55,8 @@ void Agent::run() { // XXXBHG - this seems less than ideal. There might be classes (like jurisdiction listeners, that need access to // other node types, but for them to get access to those node types, we have to add them here. It seems like // NodeList should support adding types of interest - const NODE_TYPE AGENT_NODE_TYPES_OF_INTEREST[] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_PARTICLE_SERVER, - NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER }; - - nodeList->setNodeTypesOfInterest(AGENT_NODE_TYPES_OF_INTEREST, sizeof(AGENT_NODE_TYPES_OF_INTEREST)); + nodeList->addSetOfNodeTypesToNodeInterestSet(QSet() << NODE_TYPE_VOXEL_SERVER << NODE_TYPE_PARTICLE_SERVER + << NODE_TYPE_AUDIO_MIXER << NODE_TYPE_AVATAR_MIXER); // figure out the URL for the script for this agent assignment QString scriptURLString("http://%1:8080/assignment/%2"); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index aa54c874ef..705a877a00 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -241,8 +241,7 @@ void AudioMixer::run() { NodeList* nodeList = NodeList::getInstance(); - const char AUDIO_MIXER_NODE_TYPES_OF_INTEREST[2] = { NODE_TYPE_AGENT, NODE_TYPE_AUDIO_INJECTOR }; - nodeList->setNodeTypesOfInterest(AUDIO_MIXER_NODE_TYPES_OF_INTEREST, sizeof(AUDIO_MIXER_NODE_TYPES_OF_INTEREST)); + nodeList->addNodeTypeToInterestSet(NODE_TYPE_AGENT); nodeList->linkedDataCreateCallback = attachNewBufferToNode; diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 56464d2415..2f7c4a83d4 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -149,7 +149,7 @@ void AvatarMixer::run() { commonInit(AVATAR_MIXER_LOGGING_NAME, NODE_TYPE_AVATAR_MIXER); NodeList* nodeList = NodeList::getInstance(); - nodeList->setNodeTypesOfInterest(&NODE_TYPE_AGENT, 1); + nodeList->addNodeTypeToInterestSet(NODE_TYPE_AGENT); nodeList->linkedDataCreateCallback = attachAvatarDataToNode; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8e1ba5afa1..3d8258e05c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -221,9 +221,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : #endif // tell the NodeList instance who to tell the domain server we care about - const char nodeTypesOfInterest[] = {NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER, NODE_TYPE_VOXEL_SERVER, - NODE_TYPE_PARTICLE_SERVER, NODE_TYPE_METAVOXEL_SERVER}; - nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); + nodeList->addSetOfNodeTypesToNodeInterestSet(QSet() << NODE_TYPE_AUDIO_MIXER << NODE_TYPE_AVATAR_MIXER + << NODE_TYPE_VOXEL_SERVER << NODE_TYPE_PARTICLE_SERVER + << NODE_TYPE_METAVOXEL_SERVER); QTimer* silentNodeTimer = new QTimer(this); connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); diff --git a/libraries/octree-server/src/OctreeServer.cpp b/libraries/octree-server/src/OctreeServer.cpp index 55bc77f1bf..9fe5cc8ca1 100644 --- a/libraries/octree-server/src/OctreeServer.cpp +++ b/libraries/octree-server/src/OctreeServer.cpp @@ -569,8 +569,7 @@ void OctreeServer::run() { nodeList->setOwnerType(getMyNodeType()); // we need to ask the DS about agents so we can ping/reply with them - const char nodeTypesOfInterest[] = { NODE_TYPE_AGENT, NODE_TYPE_ANIMATION_SERVER}; - nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); + nodeList->addSetOfNodeTypesToNodeInterestSet(QSet() << NODE_TYPE_AGENT << NODE_TYPE_ANIMATION_SERVER); setvbuf(stdout, NULL, _IOLBF, 0); diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index 271629ff10..fa8bf0ef8f 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -74,8 +74,6 @@ const char* Node::getTypeName() const { return NODE_TYPE_NAME_AUDIO_MIXER; case NODE_TYPE_AVATAR_MIXER: return NODE_TYPE_NAME_AVATAR_MIXER; - case NODE_TYPE_AUDIO_INJECTOR: - return NODE_TYPE_NAME_AUDIO_INJECTOR; case NODE_TYPE_ANIMATION_SERVER: return NODE_TYPE_NAME_ANIMATION_SERVER; case NODE_TYPE_UNASSIGNED: diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index f33137a092..99003820da 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -61,7 +61,7 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : _domainSockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), _nodeSocket(), _ownerType(newOwnerType), - _nodeTypesOfInterest(NULL), + _nodeTypesOfInterest(), _ownerUUID(QUuid::createUuid()), _numNoReplyDomainCheckIns(0), _assignmentServerSocket(), @@ -75,8 +75,6 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : NodeList::~NodeList() { - delete _nodeTypesOfInterest; - clear(); } @@ -293,19 +291,18 @@ void NodeList::reset() { clear(); _numNoReplyDomainCheckIns = 0; - delete _nodeTypesOfInterest; - _nodeTypesOfInterest = NULL; + _nodeTypesOfInterest.clear(); // refresh the owner UUID _ownerUUID = QUuid::createUuid(); } -void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) { - delete _nodeTypesOfInterest; +void NodeList::addNodeTypeToInterestSet(NODE_TYPE nodeTypeToAdd) { + _nodeTypesOfInterest << nodeTypeToAdd; +} - _nodeTypesOfInterest = new char[numNodeTypesOfInterest + sizeof(char)]; - memcpy(_nodeTypesOfInterest, nodeTypesOfInterest, numNodeTypesOfInterest); - _nodeTypesOfInterest[numNodeTypesOfInterest] = '\0'; +void NodeList::addSetOfNodeTypesToNodeInterestSet(const QSet& setOfNodeTypes) { + _nodeTypesOfInterest.unite(setOfNodeTypes); } const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442; @@ -522,7 +519,7 @@ void NodeList::sendDomainServerCheckIn() { sendSTUNRequest(); } else { // construct the DS check in packet if we need to - int numBytesNodesOfInterest = _nodeTypesOfInterest ? strlen((char*) _nodeTypesOfInterest) : 0; + int numBytesNodesOfInterest = _nodeTypesOfInterest.size(); const int IP_ADDRESS_BYTES = 4; @@ -563,11 +560,8 @@ void NodeList::sendDomainServerCheckIn() { *(packetPosition++) = numBytesNodesOfInterest; // copy over the bytes for node types of interest, if required - if (numBytesNodesOfInterest > 0) { - memcpy(packetPosition, - _nodeTypesOfInterest, - numBytesNodesOfInterest); - packetPosition += numBytesNodesOfInterest; + foreach (NODE_TYPE nodeTypeOfInterest, _nodeTypesOfInterest) { + *(packetPosition++) = nodeTypeOfInterest; } _nodeSocket.writeDatagram((char*) checkInPacket, packetPosition - checkInPacket, diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index b5e27564b1..eac125d889 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -22,6 +22,7 @@ #endif #include +#include #include #include #include @@ -89,8 +90,9 @@ public: void clear(); void reset(); - - void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest); + + void addNodeTypeToInterestSet(NODE_TYPE nodeTypeToAdd); + void addSetOfNodeTypesToNodeInterestSet(const QSet& setOfNodeTypes); int processDomainServerList(unsigned char *packetData, size_t dataBytes); @@ -149,7 +151,7 @@ private: HifiSockAddr _domainSockAddr; QUdpSocket _nodeSocket; char _ownerType; - char* _nodeTypesOfInterest; + QSet _nodeTypesOfInterest; QUuid _ownerUUID; int _numNoReplyDomainCheckIns; HifiSockAddr _assignmentServerSocket; diff --git a/libraries/shared/src/NodeTypes.h b/libraries/shared/src/NodeTypes.h index 37e0503bab..6e8523c7d7 100644 --- a/libraries/shared/src/NodeTypes.h +++ b/libraries/shared/src/NodeTypes.h @@ -25,7 +25,6 @@ const NODE_TYPE NODE_TYPE_ENVIRONMENT_SERVER = 'E'; const NODE_TYPE NODE_TYPE_AGENT = 'I'; const NODE_TYPE NODE_TYPE_AUDIO_MIXER = 'M'; const NODE_TYPE NODE_TYPE_AVATAR_MIXER = 'W'; -const NODE_TYPE NODE_TYPE_AUDIO_INJECTOR = 'A'; const NODE_TYPE NODE_TYPE_ANIMATION_SERVER = 'a'; const NODE_TYPE NODE_TYPE_UNASSIGNED = 1; From 6979135fe3999f84700d469bb3ded291c1d1fc31 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jan 2014 16:23:24 -0800 Subject: [PATCH 03/17] move some of the node interest additions to correct spots --- assignment-client/src/Agent.cpp | 6 +----- libraries/octree-server/src/OctreeServer.cpp | 2 +- libraries/particles/src/ParticlesScriptingInterface.cpp | 1 + libraries/voxel-server/src/VoxelServer.cpp | 2 ++ libraries/voxels/src/VoxelsScriptingInterface.cpp | 4 ++++ libraries/voxels/src/VoxelsScriptingInterface.h | 2 ++ 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 3584dd9f5d..4f81c42046 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -52,11 +52,7 @@ void Agent::run() { NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_AGENT); - // XXXBHG - this seems less than ideal. There might be classes (like jurisdiction listeners, that need access to - // other node types, but for them to get access to those node types, we have to add them here. It seems like - // NodeList should support adding types of interest - nodeList->addSetOfNodeTypesToNodeInterestSet(QSet() << NODE_TYPE_VOXEL_SERVER << NODE_TYPE_PARTICLE_SERVER - << NODE_TYPE_AUDIO_MIXER << NODE_TYPE_AVATAR_MIXER); + nodeList->addSetOfNodeTypesToNodeInterestSet(QSet() << NODE_TYPE_AUDIO_MIXER << NODE_TYPE_AVATAR_MIXER); // figure out the URL for the script for this agent assignment QString scriptURLString("http://%1:8080/assignment/%2"); diff --git a/libraries/octree-server/src/OctreeServer.cpp b/libraries/octree-server/src/OctreeServer.cpp index 64f19700a8..cc362f58a0 100644 --- a/libraries/octree-server/src/OctreeServer.cpp +++ b/libraries/octree-server/src/OctreeServer.cpp @@ -569,7 +569,7 @@ void OctreeServer::run() { nodeList->setOwnerType(getMyNodeType()); // we need to ask the DS about agents so we can ping/reply with them - nodeList->addSetOfNodeTypesToNodeInterestSet(QSet() << NODE_TYPE_AGENT << NODE_TYPE_ANIMATION_SERVER); + nodeList->addNodeTypeToInterestSet(NODE_TYPE_AGENT); setvbuf(stdout, NULL, _IOLBF, 0); diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 14388b6ac4..d52ed5ba13 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -13,6 +13,7 @@ ParticlesScriptingInterface::ParticlesScriptingInterface() : _nextCreatorTokenID(0), _particleTree(NULL) { + NodeList::getInstance()->addNodeTypeToInterestSet(NODE_TYPE_PARTICLE_SERVER); } diff --git a/libraries/voxel-server/src/VoxelServer.cpp b/libraries/voxel-server/src/VoxelServer.cpp index a1f5eaf55e..c8aee246e3 100644 --- a/libraries/voxel-server/src/VoxelServer.cpp +++ b/libraries/voxel-server/src/VoxelServer.cpp @@ -68,4 +68,6 @@ void VoxelServer::beforeRun() { qDebug("Using Minimal Environment=%s", debug::valueOf(_sendMinimalEnvironment)); } qDebug("Sending environments=%s", debug::valueOf(_sendEnvironments)); + + NodeList::getInstance()->addNodeTypeToInterestSet(NODE_TYPE_ANIMATION_SERVER); } diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index 3f4e19f60a..40c6ff8d1d 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -8,6 +8,10 @@ #include "VoxelsScriptingInterface.h" +VoxelsScriptingInterface::VoxelsScriptingInterface() { + NodeList::getInstance()->addNodeTypeToInterestSet(NODE_TYPE_VOXEL_SERVER); +} + void VoxelsScriptingInterface::queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDetail& addVoxelDetails) { getVoxelPacketSender()->queueVoxelEditMessages(addPacketType, 1, &addVoxelDetails); } diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h index a1f52fc1c3..500a0cbc5d 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ b/libraries/voxels/src/VoxelsScriptingInterface.h @@ -20,6 +20,8 @@ class VoxelsScriptingInterface : public OctreeScriptingInterface { Q_OBJECT public: + VoxelsScriptingInterface(); + VoxelEditPacketSender* getVoxelPacketSender() { return (VoxelEditPacketSender*)getPacketSender(); } virtual NODE_TYPE getServerNodeType() const { return NODE_TYPE_VOXEL_SERVER; } From b965d850d5f47651a5890cbfc8b6dc7aef57422a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jan 2014 16:26:28 -0800 Subject: [PATCH 04/17] move node interest add for JL to JL --- libraries/octree/src/JurisdictionListener.cpp | 3 +++ libraries/particles/src/ParticlesScriptingInterface.cpp | 1 - libraries/voxels/src/VoxelsScriptingInterface.cpp | 4 ---- libraries/voxels/src/VoxelsScriptingInterface.h | 4 +--- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp index 6ed039f0bd..d8686debad 100644 --- a/libraries/octree/src/JurisdictionListener.cpp +++ b/libraries/octree/src/JurisdictionListener.cpp @@ -23,6 +23,9 @@ JurisdictionListener::JurisdictionListener(NODE_TYPE type, PacketSenderNotify* n connect(NodeList::getInstance(), &NodeList::nodeKilled, this, &JurisdictionListener::nodeKilled); //qDebug("JurisdictionListener::JurisdictionListener(NODE_TYPE type=%c)", type); + + // tell our NodeList we want to hear about nodes with our node type + NodeList::getInstance()->addNodeTypeToInterestSet(type); } void JurisdictionListener::nodeKilled(SharedNodePointer node) { diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index d52ed5ba13..14388b6ac4 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -13,7 +13,6 @@ ParticlesScriptingInterface::ParticlesScriptingInterface() : _nextCreatorTokenID(0), _particleTree(NULL) { - NodeList::getInstance()->addNodeTypeToInterestSet(NODE_TYPE_PARTICLE_SERVER); } diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index 40c6ff8d1d..3f4e19f60a 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -8,10 +8,6 @@ #include "VoxelsScriptingInterface.h" -VoxelsScriptingInterface::VoxelsScriptingInterface() { - NodeList::getInstance()->addNodeTypeToInterestSet(NODE_TYPE_VOXEL_SERVER); -} - void VoxelsScriptingInterface::queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDetail& addVoxelDetails) { getVoxelPacketSender()->queueVoxelEditMessages(addPacketType, 1, &addVoxelDetails); } diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h index 500a0cbc5d..97bdfb2c59 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ b/libraries/voxels/src/VoxelsScriptingInterface.h @@ -19,9 +19,7 @@ /// handles scripting of voxel commands from JS passed to assigned clients class VoxelsScriptingInterface : public OctreeScriptingInterface { Q_OBJECT -public: - VoxelsScriptingInterface(); - +public: VoxelEditPacketSender* getVoxelPacketSender() { return (VoxelEditPacketSender*)getPacketSender(); } virtual NODE_TYPE getServerNodeType() const { return NODE_TYPE_VOXEL_SERVER; } From 3d0d5f130aac4abff587dad52a9cff7571cfde90 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 23 Jan 2014 10:02:04 -0800 Subject: [PATCH 05/17] fix particle-server spinning out at 100% cpu% --- libraries/octree/src/Octree.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index dad97b18cd..808b49d475 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1390,9 +1390,8 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* node) { bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params); unlock(); - // if bytesWritten == 0, then it means that the subTree couldn't fit, and so we should reset the packet - // and reinsert the node in our bag and try again... - if (bytesWritten == 0) { + // if the subTree couldn't fit, and so we should reset the packet and reinsert the node in our bag and try again... + if (bytesWritten == 0 && (params.stopReason == EncodeBitstreamParams::DIDNT_FIT)) { if (packetData.hasContent()) { file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize()); lastPacketWritten = true; From 7efc9e2e78427732fc84966ad4079a32ccbdd5ac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jan 2014 10:32:23 -0800 Subject: [PATCH 06/17] move datagram processing back to separate thread --- interface/src/Application.cpp | 126 +++++++--------------------- interface/src/Application.h | 10 +-- interface/src/Audio.cpp | 2 +- interface/src/DatagramProcessor.cpp | 110 ++++++++++++++++++++++++ interface/src/DatagramProcessor.h | 31 +++++++ libraries/shared/src/NodeList.cpp | 2 +- 6 files changed, 176 insertions(+), 105 deletions(-) create mode 100644 interface/src/DatagramProcessor.cpp create mode 100644 interface/src/DatagramProcessor.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3d206e4e73..cf865ce299 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -108,6 +108,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : QApplication(argc, argv), _window(new QMainWindow(desktop())), _glWidget(new GLCanvas()), + _nodeThread(new QThread(this)), + _datagramProcessor(new DatagramProcessor()), _frameCount(0), _fps(120.0f), _justStarted(true), @@ -145,10 +147,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _voxelHideShowThread(&_voxels), _voxelEditSender(this), _particleEditSender(this), - _packetCount(0), _packetsPerSecond(0), _bytesPerSecond(0), - _bytesCount(0), _recentMaxPackets(0), _resetRecentMaxPacketsSoon(true), _swatch(NULL), @@ -173,11 +173,21 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : if (portStr) { listenPort = atoi(portStr); } - + + // put the NodeList and datagram processing on the node thread NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, listenPort); - - // connect our processDatagrams slot to the QUDPSocket readyRead() signal - connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(processDatagrams())); + + nodeList->moveToThread(_nodeThread); + _datagramProcessor->moveToThread(_nodeThread); + + // connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal + connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), _datagramProcessor, SLOT(processDatagrams())); + + // make sure the node thread is given highest priority + _nodeThread->setPriority(QThread::TimeCriticalPriority); + + // start the nodeThread so its event loop is running + _nodeThread->start(); // put the audio processing on a separate thread QThread* audioThread = new QThread(this); @@ -192,7 +202,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer))); connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer))); - + // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings applicationInfo("resources/info/ApplicationInfo.ini", QSettings::IniFormat); @@ -225,8 +235,10 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : NODE_TYPE_PARTICLE_SERVER, NODE_TYPE_METAVOXEL_SERVER}; nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); + // move the silentNodeTimer to the _nodeThread QTimer* silentNodeTimer = new QTimer(this); connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); + silentNodeTimer->moveToThread(_nodeThread); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); @@ -273,6 +285,10 @@ Application::~Application() { // make sure we don't call the idle timer any more delete idleTimer; + + // ask the datagram processing thread to quit and wait until it is done + _nodeThread->thread()->quit(); + _nodeThread->thread()->wait(); // ask the audio thread to quit and wait until it is done _audio.thread()->quit(); @@ -1312,11 +1328,12 @@ void Application::timer() { } _fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); - _packetsPerSecond = (float)_packetCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); - _bytesPerSecond = (float)_bytesCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); + + _packetsPerSecond = (float) _datagramProcessor->getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); + _bytesPerSecond = (float) _datagramProcessor->getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); _frameCount = 0; - _packetCount = 0; - _bytesCount = 0; + + _datagramProcessor->resetCounters(); gettimeofday(&_timerStart, NULL); @@ -4052,93 +4069,6 @@ int Application::parseOctreeStats(unsigned char* messageData, ssize_t messageLen return statsMessageLength; } -// Receive packets from other nodes/servers and decide what to do with them! -void Application::processDatagrams() { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::networkReceive()"); - - HifiSockAddr senderSockAddr; - ssize_t bytesReceived; - - while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams() && - (bytesReceived = NodeList::getInstance()->getNodeSocket().readDatagram((char*) _incomingPacket, - MAX_PACKET_SIZE, - senderSockAddr.getAddressPointer(), - senderSockAddr.getPortPointer()))) { - - _packetCount++; - _bytesCount += bytesReceived; - - if (packetVersionMatch(_incomingPacket)) { - // only process this packet if we have a match on the packet version - switch (_incomingPacket[0]) { - case PACKET_TYPE_TRANSMITTER_DATA_V2: - // V2 = IOS transmitter app - _myTransmitter.processIncomingData(_incomingPacket, bytesReceived); - - break; - case PACKET_TYPE_MIXED_AUDIO: - QMetaObject::invokeMethod(&_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection, - Q_ARG(QByteArray, QByteArray((char*) _incomingPacket, bytesReceived))); - break; - - case PACKET_TYPE_PARTICLE_ADD_RESPONSE: - // this will keep creatorTokenIDs to IDs mapped correctly - Particle::handleAddParticleResponse(_incomingPacket, bytesReceived); - break; - - case PACKET_TYPE_PARTICLE_DATA: - case PACKET_TYPE_PARTICLE_ERASE: - case PACKET_TYPE_VOXEL_DATA: - case PACKET_TYPE_VOXEL_ERASE: - case PACKET_TYPE_OCTREE_STATS: - case PACKET_TYPE_ENVIRONMENT_DATA: { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::networkReceive()... _voxelProcessor.queueReceivedPacket()"); - - bool wantExtraDebugging = getLogger()->extraDebugging(); - if (wantExtraDebugging && _incomingPacket[0] == PACKET_TYPE_VOXEL_DATA) { - int numBytesPacketHeader = numBytesForPacketHeader(_incomingPacket); - unsigned char* dataAt = _incomingPacket + numBytesPacketHeader; - dataAt += sizeof(VOXEL_PACKET_FLAGS); - VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); - dataAt += sizeof(VOXEL_PACKET_SEQUENCE); - VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); - dataAt += sizeof(VOXEL_PACKET_SENT_TIME); - VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); - int flightTime = arrivedAt - sentAt; - - printf("got PACKET_TYPE_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime); - } - - // add this packet to our list of voxel packets and process them on the voxel processing - _voxelProcessor.queueReceivedPacket(senderSockAddr, _incomingPacket, bytesReceived); - break; - } - case PACKET_TYPE_METAVOXEL_DATA: - _metavoxels.processData(QByteArray((const char*) _incomingPacket, bytesReceived), - senderSockAddr); - break; - case PACKET_TYPE_BULK_AVATAR_DATA: - NodeList::getInstance()->processBulkNodeData(senderSockAddr, - _incomingPacket, - bytesReceived); - getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived); - break; - case PACKET_TYPE_DATA_SERVER_GET: - case PACKET_TYPE_DATA_SERVER_PUT: - case PACKET_TYPE_DATA_SERVER_SEND: - case PACKET_TYPE_DATA_SERVER_CONFIRM: - DataServerClient::processMessageFromDataServer(_incomingPacket, bytesReceived); - break; - default: - NodeList::getInstance()->processNodeData(senderSockAddr, _incomingPacket, bytesReceived); - break; - } - } - } -} - void Application::packetSentNotification(ssize_t length) { _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(length); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 6be01db39f..514591e1df 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -33,6 +33,7 @@ #include "BandwidthMeter.h" #include "Camera.h" #include "Cloud.h" +#include "DatagramProcessor.h" #include "Environment.h" #include "GLCanvas.h" #include "MetavoxelSystem.h" @@ -96,6 +97,7 @@ class Application : public QApplication, public PacketSenderNotify { friend class VoxelPacketProcessor; friend class VoxelEditPacketSender; + friend class DatagramProcessor; public: static Application* getInstance() { return static_cast(QCoreApplication::instance()); } @@ -208,8 +210,6 @@ public slots: void domainChanged(const QString& domainHostname); void nodeKilled(SharedNodePointer node); - void processDatagrams(); - void exportVoxels(); void importVoxels(); void cutVoxels(); @@ -331,6 +331,9 @@ private: QGLWidget* _glWidget; BandwidthMeter _bandwidthMeter; + + QThread* _nodeThread; + DatagramProcessor* _datagramProcessor; QNetworkAccessManager* _networkAccessManager; QSettings* _settings; @@ -461,11 +464,8 @@ private: VoxelEditPacketSender _voxelEditSender; ParticleEditPacketSender _particleEditSender; - unsigned char _incomingPacket[MAX_PACKET_SIZE]; - int _packetCount; int _packetsPerSecond; int _bytesPerSecond; - int _bytesCount; int _recentMaxPackets; // recent max incoming voxel packets to process bool _resetRecentMaxPacketsSoon; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 0709b40624..f31ab9056f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -415,7 +415,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { _totalPacketsReceived++; double timeDiff = diffclock(&_lastReceiveTime, ¤tReceiveTime); - + // Discard first few received packets for computing jitter (often they pile up on start) if (_totalPacketsReceived > NUM_INITIAL_PACKETS_DISCARD) { _stdev.addValue(timeDiff); diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp new file mode 100644 index 0000000000..9a6c1bea05 --- /dev/null +++ b/interface/src/DatagramProcessor.cpp @@ -0,0 +1,110 @@ +// +// DatagramProcessor.cpp +// hifi +// +// Created by Stephen Birarda on 1/23/2014. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// + +#include + +#include "Application.h" +#include "Menu.h" + +#include "DatagramProcessor.h" + +DatagramProcessor::DatagramProcessor(QObject* parent) : + QObject(parent) +{ + +} + +void DatagramProcessor::processDatagrams() { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "DatagramProcessor::processDatagrams()"); + + HifiSockAddr senderSockAddr; + ssize_t bytesReceived; + + static unsigned char incomingPacket[MAX_PACKET_SIZE]; + + Application* application = Application::getInstance(); + + while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams() && + (bytesReceived = NodeList::getInstance()->getNodeSocket().readDatagram((char*) incomingPacket, + MAX_PACKET_SIZE, + senderSockAddr.getAddressPointer(), + senderSockAddr.getPortPointer()))) { + + _packetCount++; + _byteCount += bytesReceived; + + if (packetVersionMatch(incomingPacket)) { + // only process this packet if we have a match on the packet version + switch (incomingPacket[0]) { + case PACKET_TYPE_TRANSMITTER_DATA_V2: + // V2 = IOS transmitter app + application->_myTransmitter.processIncomingData(incomingPacket, bytesReceived); + + break; + case PACKET_TYPE_MIXED_AUDIO: + QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection, + Q_ARG(QByteArray, QByteArray((char*) incomingPacket, bytesReceived))); + break; + + case PACKET_TYPE_PARTICLE_ADD_RESPONSE: + // this will keep creatorTokenIDs to IDs mapped correctly + Particle::handleAddParticleResponse(incomingPacket, bytesReceived); + break; + + case PACKET_TYPE_PARTICLE_DATA: + case PACKET_TYPE_PARTICLE_ERASE: + case PACKET_TYPE_VOXEL_DATA: + case PACKET_TYPE_VOXEL_ERASE: + case PACKET_TYPE_OCTREE_STATS: + case PACKET_TYPE_ENVIRONMENT_DATA: { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::networkReceive()... _voxelProcessor.queueReceivedPacket()"); + + bool wantExtraDebugging = application->getLogger()->extraDebugging(); + if (wantExtraDebugging && incomingPacket[0] == PACKET_TYPE_VOXEL_DATA) { + int numBytesPacketHeader = numBytesForPacketHeader(incomingPacket); + unsigned char* dataAt = incomingPacket + numBytesPacketHeader; + dataAt += sizeof(VOXEL_PACKET_FLAGS); + VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(VOXEL_PACKET_SEQUENCE); + VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); + dataAt += sizeof(VOXEL_PACKET_SENT_TIME); + VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); + int flightTime = arrivedAt - sentAt; + + printf("got PACKET_TYPE_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime); + } + + // add this packet to our list of voxel packets and process them on the voxel processing + application->_voxelProcessor.queueReceivedPacket(senderSockAddr, incomingPacket, bytesReceived); + break; + } + case PACKET_TYPE_METAVOXEL_DATA: + application->_metavoxels.processData(QByteArray((const char*) incomingPacket, bytesReceived), + senderSockAddr); + break; + case PACKET_TYPE_BULK_AVATAR_DATA: + NodeList::getInstance()->processBulkNodeData(senderSockAddr, + incomingPacket, + bytesReceived); + application->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived); + break; + case PACKET_TYPE_DATA_SERVER_GET: + case PACKET_TYPE_DATA_SERVER_PUT: + case PACKET_TYPE_DATA_SERVER_SEND: + case PACKET_TYPE_DATA_SERVER_CONFIRM: + DataServerClient::processMessageFromDataServer(incomingPacket, bytesReceived); + break; + default: + NodeList::getInstance()->processNodeData(senderSockAddr, incomingPacket, bytesReceived); + break; + } + } + } +} \ No newline at end of file diff --git a/interface/src/DatagramProcessor.h b/interface/src/DatagramProcessor.h new file mode 100644 index 0000000000..722e5a9d41 --- /dev/null +++ b/interface/src/DatagramProcessor.h @@ -0,0 +1,31 @@ +// +// DatagramProcessor.h +// hifi +// +// Created by Stephen Birarda on 1/23/2014. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__DatagramProcessor__ +#define __hifi__DatagramProcessor__ + +#include + +class DatagramProcessor : public QObject { + Q_OBJECT +public: + DatagramProcessor(QObject* parent = 0); + + int getPacketCount() const { return _packetCount; } + int getByteCount() const { return _byteCount; } + + void resetCounters() { _packetCount = 0; _byteCount = 0; } +public slots: + void processDatagrams(); + +private: + int _packetCount; + int _byteCount; +}; + +#endif /* defined(__hifi__DatagramProcessor__) */ diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index f37f2b48dc..034c272536 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -59,7 +59,7 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : _nodeHashMutex(), _domainHostname(DEFAULT_DOMAIN_HOSTNAME), _domainSockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), - _nodeSocket(), + _nodeSocket(this), _ownerType(newOwnerType), _nodeTypesOfInterest(NULL), _ownerUUID(QUuid::createUuid()), From ccc30d95fb1f5b0f4b0cf52ec15a4f78983a026a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 23 Jan 2014 10:32:42 -0800 Subject: [PATCH 07/17] fix crashing particle server bug --- libraries/particles/src/ParticleTree.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index a3c8072b3a..31f5216462 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -390,17 +390,20 @@ bool ParticleTree::encodeParticlesDeletedSince(uint64_t& sinceTime, unsigned cha // called by the server when it knows all nodes have been sent deleted packets void ParticleTree::forgetParticlesDeletedBefore(uint64_t sinceTime) { + //qDebug() << "forgetParticlesDeletedBefore()"; _recentlyDeletedParticlesLock.lockForWrite(); - QMultiMap::const_iterator iterator = _recentlyDeletedParticleIDs.constBegin(); - while (iterator != _recentlyDeletedParticleIDs.constEnd()) { + QMultiMap::iterator iterator = _recentlyDeletedParticleIDs.begin(); + while (iterator != _recentlyDeletedParticleIDs.end()) { //qDebug() << "considering... time/key:" << iterator.key(); if (iterator.key() <= sinceTime) { //qDebug() << "YES older... time/key:" << iterator.key(); _recentlyDeletedParticleIDs.remove(iterator.key()); } + //qDebug() << "about to ++iterator"; ++iterator; } _recentlyDeletedParticlesLock.unlock(); + //qDebug() << "DONE forgetParticlesDeletedBefore()"; } From 04286e39e68975819b1b4a68cda8e0d57c1c411f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jan 2014 10:49:51 -0800 Subject: [PATCH 08/17] use NodeList getNodeHash getter for methods that can be called from other threads --- libraries/shared/src/NodeList.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 034c272536..65993cb275 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -257,7 +257,7 @@ int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr, SharedNodePointer NodeList::nodeWithAddress(const HifiSockAddr &senderSockAddr) { // naively returns the first node that has a matching active HifiSockAddr // note that there can be multiple nodes that have a matching active socket, so this isn't a good way to uniquely identify - foreach (const SharedNodePointer& node, _nodeHash) { + foreach (const SharedNodePointer& node, getNodeHash()) { if (node->getActiveSocket() && *node->getActiveSocket() == senderSockAddr) { return node; } @@ -738,7 +738,7 @@ SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) { unsigned n = 0; - foreach (const SharedNodePointer& node, _nodeHash) { + foreach (const SharedNodePointer& node, getNodeHash()) { // only send to the NodeTypes we are asked to send to. if (memchr(nodeTypes, node->getType(), numNodeTypes)) { if (getNodeActiveSocketOrPing(node.data())) { From fa3c3448f4689d6b6bf61e205e559c8e0c95bb69 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 23 Jan 2014 10:55:51 -0800 Subject: [PATCH 09/17] Adding option to disable hand collisions against their own avatar. --- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/avatar/Hand.cpp | 18 ++++++++++-------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 1723e10f61..740effcf1c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -352,6 +352,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::VoxelDrumming, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b356f29a85..dd3d5b7588 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -188,6 +188,7 @@ namespace MenuOption { const QString ExportVoxels = "Export Voxels"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString HeadMouse = "Head Mouse"; + const QString HandsCollideWithSelf = "Collide With Self"; const QString FaceshiftTCP = "Faceshift (TCP)"; const QString FalseColorByDistance = "FALSE Color By Distance"; const QString FalseColorBySource = "FALSE Color By Source"; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 51f1bc10de..e5aa33ad40 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -231,14 +231,16 @@ void Hand::updateCollisions() { } } - // and the current avatar (ignoring everything below the parent of the parent of the last free joint) - glm::vec3 owningPenetration; - const Model& skeletonModel = _owningAvatar->getSkeletonModel(); - int skipIndex = skeletonModel.getParentJointIndex(skeletonModel.getParentJointIndex( - skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : - (i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); - if (_owningAvatar->findSpherePenetration(palm.getPosition(), scaledPalmRadius, owningPenetration, skipIndex)) { - totalPenetration = addPenetrations(totalPenetration, owningPenetration); + if (Menu::getInstance()->isOptionChecked(MenuOption::HandsCollideWithSelf)) { + // and the current avatar (ignoring everything below the parent of the parent of the last free joint) + glm::vec3 owningPenetration; + const Model& skeletonModel = _owningAvatar->getSkeletonModel(); + int skipIndex = skeletonModel.getParentJointIndex(skeletonModel.getParentJointIndex( + skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : + (i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); + if (_owningAvatar->findSpherePenetration(palm.getPosition(), scaledPalmRadius, owningPenetration, skipIndex)) { + totalPenetration = addPenetrations(totalPenetration, owningPenetration); + } } // un-penetrate From b5a72ef669af70f14b99cf410047329c12cb0c09 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jan 2014 11:11:22 -0800 Subject: [PATCH 10/17] more nodelist repairs for concurrency issues --- interface/src/Application.cpp | 65 ++++++++++++++----------------- interface/src/Application.h | 1 - libraries/shared/src/NodeList.cpp | 10 +++-- libraries/shared/src/NodeList.h | 2 +- 4 files changed, 37 insertions(+), 41 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cf865ce299..ff320340bf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -174,6 +174,12 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : listenPort = atoi(portStr); } + // start the nodeThread so its event loop is running + _nodeThread->start(); + + // make sure the node thread is given highest priority + _nodeThread->setPriority(QThread::TimeCriticalPriority); + // put the NodeList and datagram processing on the node thread NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, listenPort); @@ -182,12 +188,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : // connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), _datagramProcessor, SLOT(processDatagrams())); - - // make sure the node thread is given highest priority - _nodeThread->setPriority(QThread::TimeCriticalPriority); - - // start the nodeThread so its event loop is running - _nodeThread->start(); // put the audio processing on a separate thread QThread* audioThread = new QThread(this); @@ -236,7 +236,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); // move the silentNodeTimer to the _nodeThread - QTimer* silentNodeTimer = new QTimer(this); + QTimer* silentNodeTimer = new QTimer(); connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeTimer->moveToThread(_nodeThread); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); @@ -282,17 +282,35 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : Application::~Application() { qInstallMessageHandler(NULL); - + // make sure we don't call the idle timer any more delete idleTimer; + Menu::getInstance()->saveSettings(); + + _rearMirrorTools->saveSettings(_settings); + _settings->sync(); + + // let the avatar mixer know we're out + NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1); + // ask the datagram processing thread to quit and wait until it is done - _nodeThread->thread()->quit(); - _nodeThread->thread()->wait(); - + _nodeThread->quit(); + _nodeThread->wait(); + // ask the audio thread to quit and wait until it is done _audio.thread()->quit(); _audio.thread()->wait(); + + _voxelProcessor.terminate(); + _voxelHideShowThread.terminate(); + _voxelEditSender.terminate(); + _particleEditSender.terminate(); + if (_persistThread) { + _persistThread->terminate(); + _persistThread->deleteLater(); + _persistThread = NULL; + } storeSizeAndPosition(); saveScripts(); @@ -377,9 +395,6 @@ void Application::initializeGL() { qDebug("Voxel parsing thread created."); } - // call terminate before exiting - connect(this, SIGNAL(aboutToQuit()), SLOT(terminate())); - // call our timer function every second QTimer* timer = new QTimer(this); connect(timer, SIGNAL(timeout()), SLOT(timer())); @@ -1412,28 +1427,6 @@ void Application::idle() { } } -void Application::terminate() { - // Close serial port - // close(serial_fd); - - Menu::getInstance()->saveSettings(); - _rearMirrorTools->saveSettings(_settings); - _settings->sync(); - - // let the avatar mixer know we're out - NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1); - - _voxelProcessor.terminate(); - _voxelHideShowThread.terminate(); - _voxelEditSender.terminate(); - _particleEditSender.terminate(); - if (_persistThread) { - _persistThread->terminate(); - _persistThread->deleteLater(); - _persistThread = NULL; - } -} - void Application::checkBandwidthMeterClick() { // ... to be called upon button release diff --git a/interface/src/Application.h b/interface/src/Application.h index 514591e1df..ba25db928f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -230,7 +230,6 @@ private slots: void timer(); void idle(); - void terminate(); void setFullscreen(bool fullscreen); void setEnable3DTVMode(bool enable3DTVMode); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 65993cb275..6bb582fcd5 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -236,7 +236,11 @@ int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr, node->setLastHeardMicrostamp(usecTimestampNow()); if (!senderSockAddr.isNull()) { - activateSocketFromNodeCommunication(senderSockAddr); + if (senderSockAddr == node->getPublicSocket()) { + node->activatePublicSocket(); + } else if (senderSockAddr == node->getLocalSocket()) { + node->activateLocalSocket(); + } } if (node->getActiveSocket() || senderSockAddr.isNull()) { @@ -754,7 +758,7 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt } void NodeList::pingInactiveNodes() { - foreach (const SharedNodePointer& node, _nodeHash) { + foreach (const SharedNodePointer& node, getNodeHash()) { if (!node->getActiveSocket()) { // we don't have an active link to this node, ping it to set that up pingPublicAndLocalSocketsForInactiveNode(node.data()); @@ -791,7 +795,7 @@ void NodeList::activateSocketFromNodeCommunication(const HifiSockAddr& nodeAddre SharedNodePointer NodeList::soloNodeOfType(char nodeType) { if (memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES)) != NULL) { - foreach (const SharedNodePointer& node, _nodeHash) { + foreach (const SharedNodePointer& node, getNodeHash()) { if (node->getType() == nodeType) { return node; } diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 9ac6c5970c..851110f0b4 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -87,7 +87,6 @@ public: int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; } - void clear(); void reset(); void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest); @@ -163,6 +162,7 @@ private: void timePingReply(const HifiSockAddr& nodeAddress, unsigned char *packetData); void resetDomainData(char domainField[], const char* domainData); void domainLookup(); + void clear(); }; #endif /* defined(__hifi__NodeList__) */ From 24bed0947382f57dc49434ac1040d1e3521b3753 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jan 2014 11:13:03 -0800 Subject: [PATCH 11/17] DatagramProcessor need not be a pointer in Application --- interface/src/Application.cpp | 12 ++++++------ interface/src/Application.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ff320340bf..432a8ae2d2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -109,7 +109,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _window(new QMainWindow(desktop())), _glWidget(new GLCanvas()), _nodeThread(new QThread(this)), - _datagramProcessor(new DatagramProcessor()), + _datagramProcessor(), _frameCount(0), _fps(120.0f), _justStarted(true), @@ -184,10 +184,10 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, listenPort); nodeList->moveToThread(_nodeThread); - _datagramProcessor->moveToThread(_nodeThread); + _datagramProcessor.moveToThread(_nodeThread); // connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal - connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), _datagramProcessor, SLOT(processDatagrams())); + connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), &_datagramProcessor, SLOT(processDatagrams())); // put the audio processing on a separate thread QThread* audioThread = new QThread(this); @@ -1344,11 +1344,11 @@ void Application::timer() { _fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); - _packetsPerSecond = (float) _datagramProcessor->getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); - _bytesPerSecond = (float) _datagramProcessor->getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); + _packetsPerSecond = (float) _datagramProcessor.getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); + _bytesPerSecond = (float) _datagramProcessor.getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); _frameCount = 0; - _datagramProcessor->resetCounters(); + _datagramProcessor.resetCounters(); gettimeofday(&_timerStart, NULL); diff --git a/interface/src/Application.h b/interface/src/Application.h index ba25db928f..803cb296a2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -332,7 +332,7 @@ private: BandwidthMeter _bandwidthMeter; QThread* _nodeThread; - DatagramProcessor* _datagramProcessor; + DatagramProcessor _datagramProcessor; QNetworkAccessManager* _networkAccessManager; QSettings* _settings; From c54eacbf36a8a9eebc71f7d750b6338c44e95007 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jan 2014 11:15:21 -0800 Subject: [PATCH 12/17] make sure starve is displayed even if ring buffer just received data --- interface/src/Audio.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index f31ab9056f..47ab8b0aba 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -443,6 +443,15 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { QByteArray outputBuffer; outputBuffer.resize(numRequiredOutputSamples * sizeof(int16_t)); + + if (!_ringBuffer.isStarved() && _audioOutput->bytesFree() == _audioOutput->bufferSize()) { + // we don't have any audio data left in the output buffer + // we just starved + qDebug() << "Audio output just starved."; + _ringBuffer.setIsStarved(true); + _numFramesDisplayStarve = 10; + } + // if there is anything in the ring buffer, decide what to do if (_ringBuffer.samplesAvailable() > 0) { if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO @@ -515,12 +524,6 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { } } - } else if (_audioOutput->bytesFree() == _audioOutput->bufferSize()) { - // we don't have any audio data left in the output buffer, and the ring buffer from - // the network has nothing in it either - we just starved - qDebug() << "Audio output just starved."; - _ringBuffer.setIsStarved(true); - _numFramesDisplayStarve = 10; } Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO).updateValue(audioByteArray.size()); From b32b0a495a175392266c551838a5712a5068c407 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 23 Jan 2014 11:49:34 -0800 Subject: [PATCH 13/17] Remove eyes' hovering on mouse avatar, voxels. Closes #1643. --- interface/src/Application.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f85f375118..178bbd0615 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2008,15 +2008,9 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& _viewFrustum.computePickRay(0.5f, 0.5f, rayOrigin, rayDirection); lookAtSpot = rayOrigin + rayDirection * FAR_AWAY_STARE; - } else if (!_lookatTargetAvatar) { - if (_isHoverVoxel) { - // Look at the hovered voxel - lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel); - - } else { - // Just look in direction of the mouse ray - lookAtSpot = lookAtRayOrigin + lookAtRayDirection * FAR_AWAY_STARE; - } + } else { + // just look in direction of the mouse ray + lookAtSpot = lookAtRayOrigin + lookAtRayDirection * FAR_AWAY_STARE; } if (_faceshift.isActive()) { // deflect using Faceshift gaze data From 86e37f8fc2a0f86c4ba15eb4974eb8aa56474ad8 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 23 Jan 2014 11:53:46 -0800 Subject: [PATCH 14/17] new sounds for drumsticks --- examples/drumStick.js | 4 ++-- examples/fountain.js | 6 +++--- examples/toyball.js | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/drumStick.js b/examples/drumStick.js index 5224900414..955fddbdee 100644 --- a/examples/drumStick.js +++ b/examples/drumStick.js @@ -18,8 +18,8 @@ function vMinus(a, b) { // First, load two percussion sounds to be used on the sticks -var drum1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/MusicalInstruments/drums/snare.raw"); -var drum2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/MusicalInstruments/drums/snare.raw"); +var drum1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Drums/RackTomHi.raw"); +var drum2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Drums/RackTomLo.raw"); // State Machine: // 0 = not triggered diff --git a/examples/fountain.js b/examples/fountain.js index 86c125a834..a095f91ed3 100644 --- a/examples/fountain.js +++ b/examples/fountain.js @@ -42,7 +42,7 @@ Voxels.setVoxel(position.x, 0, position.z, 0.5, 0, 0, 255); var totalParticles = 0; function makeFountain() { - if (Math.random() < 0.06) { + if (Math.random() < 0.10) { //print("Made particle!\n"); var properties = { position: position, @@ -51,9 +51,9 @@ function makeFountain() { velocity: { x: (Math.random() * 1.0 - 0.5), y: (1.0 + (Math.random() * 2.0)), z: (Math.random() * 1.0 - 0.5) }, - gravity: { x: 0, y: -0.5, z: 0 }, + gravity: { x: 0, y: -0.1, z: 0 }, damping: 0.25, - lifetime: 2 + lifetime: 1 } Particles.addParticle(properties); diff --git a/examples/toyball.js b/examples/toyball.js index 1682cbe3d4..ddb3ac9135 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -134,8 +134,9 @@ function checkControllerSide(whichSide) { gravity: { x: 0, y: 0, z: 0}, inHand: true, radius: 0.05, + damping: 0.999, color: { red: 255, green: 0, blue: 0 }, - lifetime: 10 // 10 seconds + lifetime: 10 // 10 seconds }; newParticle = Particles.addParticle(properties); From 8aa7a915e7077f7b0a94d9a60507d3c7218d4602 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 23 Jan 2014 13:01:07 -0800 Subject: [PATCH 15/17] ok, one more shot at fixing particle-server crash --- libraries/particles/src/ParticleTree.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index 31f5216462..73e8dd6711 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -391,17 +391,26 @@ bool ParticleTree::encodeParticlesDeletedSince(uint64_t& sinceTime, unsigned cha // called by the server when it knows all nodes have been sent deleted packets void ParticleTree::forgetParticlesDeletedBefore(uint64_t sinceTime) { //qDebug() << "forgetParticlesDeletedBefore()"; + QSet keysToRemove; + _recentlyDeletedParticlesLock.lockForWrite(); QMultiMap::iterator iterator = _recentlyDeletedParticleIDs.begin(); + // First find all the keys in the map that are older and need to be deleted while (iterator != _recentlyDeletedParticleIDs.end()) { //qDebug() << "considering... time/key:" << iterator.key(); if (iterator.key() <= sinceTime) { //qDebug() << "YES older... time/key:" << iterator.key(); - _recentlyDeletedParticleIDs.remove(iterator.key()); + keysToRemove << iterator.key(); } - //qDebug() << "about to ++iterator"; ++iterator; } + + // Now run through the keysToRemove and remove them + foreach (uint64_t value, keysToRemove) { + //qDebug() << "removing the key, _recentlyDeletedParticleIDs.remove(value); time/key:" << value; + _recentlyDeletedParticleIDs.remove(value); + } + _recentlyDeletedParticlesLock.unlock(); //qDebug() << "DONE forgetParticlesDeletedBefore()"; } From d2bf3a2a5de032b6d1f7169ad99472d8c7230e10 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 23 Jan 2014 13:46:12 -0800 Subject: [PATCH 16/17] set default particle lifetime to 10 seconds, make sure lifetime is always honored --- examples/toyball.js | 2 +- libraries/particles/src/Particle.cpp | 2 +- libraries/particles/src/Particle.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/toyball.js b/examples/toyball.js index 1682cbe3d4..be26c3d3fb 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -135,7 +135,7 @@ function checkControllerSide(whichSide) { inHand: true, radius: 0.05, color: { red: 255, green: 0, blue: 0 }, - lifetime: 10 // 10 seconds + lifetime: 10 // 10 seconds - same as default, not needed but here as an example }; newParticle = Particles.addParticle(properties); diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 5570797ab4..5cf5e9248d 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -682,7 +682,7 @@ void Particle::update(const uint64_t& now) { const uint64_t REALLY_OLD = 30 * USECS_PER_SECOND; // 30 seconds bool isReallyOld = ((now - _created) > REALLY_OLD); bool isInHand = getInHand(); - bool shouldDie = getShouldDie() || (!isInHand && isStopped && isReallyOld); + bool shouldDie = (getAge() > getLifetime()) || getShouldDie() || (!isInHand && isStopped && isReallyOld); setShouldDie(shouldDie); runUpdateScript(); // allow the javascript to alter our state diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 9c93423c08..e534c7b418 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -42,7 +42,7 @@ const uint16_t PACKET_CONTAINS_INHAND = 128; const uint16_t PACKET_CONTAINS_SCRIPT = 256; const uint16_t PACKET_CONTAINS_SHOULDDIE = 512; -const float DEFAULT_LIFETIME = 60.0f * 60.0f * 24.0f; // particles live for 1 day by default +const float DEFAULT_LIFETIME = 10.0f; // particles live for 10 seconds by default const float DEFAULT_DAMPING = 0.99f; const float DEFAULT_RADIUS = 0.1f / TREE_SCALE; const float MINIMUM_PARTICLE_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container From 29f33a4e795c98b1068797ba9f10d3b9a3d37276 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 23 Jan 2014 13:54:45 -0800 Subject: [PATCH 17/17] =?UTF-8?q?Balls=20rolling=20on=20voxels=20don?= =?UTF-8?q?=E2=80=99t=20make=20sound?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libraries/particles/src/ParticleCollisionSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index ff65bc4298..def6768e46 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -276,7 +276,7 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, float elast void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency) { // consider whether to have the collision make a sound - const float AUDIBLE_COLLISION_THRESHOLD = 0.1f; + const float AUDIBLE_COLLISION_THRESHOLD = 0.3f; const float COLLISION_LOUDNESS = 1.f; const float DURATION_SCALING = 0.004f; const float NOISE_SCALING = 0.1f;