From 12697c6b141475d491ff2a314d7e58f79f192778 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 14:30:13 -0700 Subject: [PATCH 01/21] add method to clear the NodeList --- libraries/shared/src/NodeList.cpp | 15 +++++++++++++++ libraries/shared/src/NodeList.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 391e22a915..b4e3112768 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -70,6 +70,8 @@ NodeList::NodeList(char newOwnerType, unsigned int newSocketListenPort) : NodeList::~NodeList() { delete _nodeTypesOfInterest; + clear(); + // stop the spawned threads, if they were started stopSilentNodeRemovalThread(); @@ -209,6 +211,19 @@ int NodeList::getNumAliveNodes() const { return numAliveNodes; } +void NodeList::clear() { + // delete all of the nodes in the list, set the pointers back to NULL and the number of nodes to 0 + for (int i = 0; i < _numNodes; i++) { + Node** nodeBucket = _nodeBuckets[i / NODES_PER_BUCKET]; + Node* node = nodeBucket[i % NODES_PER_BUCKET]; + + delete node; + node = NULL; + } + + _numNodes = 0; +} + void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) { delete _nodeTypesOfInterest; diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index da9c4a556a..57f8083113 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -65,6 +65,8 @@ public: int size() { return _numNodes; } int getNumAliveNodes() const; + void clear(); + void lock() { pthread_mutex_lock(&mutex); } void unlock() { pthread_mutex_unlock(&mutex); } From d389dc6e3ad73ece5fa78f6835a0a41d07713a83 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 15:17:10 -0700 Subject: [PATCH 02/21] add method to NodeList to set domain IP to local, move mutex lock to node --- animation-server/src/main.cpp | 3 +- audio-mixer/src/main.cpp | 9 +++--- avatar-mixer/src/main.cpp | 3 +- interface/src/Application.cpp | 27 +++++++++++----- interface/src/Audio.cpp | 4 +-- libraries/shared/src/Node.cpp | 4 +++ libraries/shared/src/Node.h | 4 +++ libraries/shared/src/NodeList.cpp | 51 ++++++++++++++++++++----------- libraries/shared/src/NodeList.h | 22 ++++++++----- voxel-server/src/main.cpp | 3 +- 10 files changed, 85 insertions(+), 45 deletions(-) diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index 126216ea9b..c6c38d8748 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -697,8 +697,7 @@ int main(int argc, const char * argv[]) ::wantLocalDomain = cmdOptionExists(argc, argv,local); if (::wantLocalDomain) { printf("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); + nodeList->setDomainIPToLocalhost(); } nodeList->linkedDataCreateCallback = NULL; // do we need a callback? diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index b900c48479..239eb7a32d 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -70,16 +70,15 @@ bool wantLocalDomain = false; int main(int argc, const char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); + NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT); + // Handle Local Domain testing with the --local command line const char* local = "--local"; ::wantLocalDomain = cmdOptionExists(argc, argv,local); if (::wantLocalDomain) { printf("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); - } - - NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT); + nodeList->setDomainIPToLocalhost(); + } ssize_t receivedBytes = 0; diff --git a/avatar-mixer/src/main.cpp b/avatar-mixer/src/main.cpp index f2fd031526..b24fb7dcbc 100644 --- a/avatar-mixer/src/main.cpp +++ b/avatar-mixer/src/main.cpp @@ -60,8 +60,7 @@ int main(int argc, const char* argv[]) { const char* local = "--local"; if (cmdOptionExists(argc, argv, local)) { printf("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); + nodeList->setDomainIPToLocalhost(); } nodeList->linkedDataCreateCallback = attachAvatarDataToNode; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 75f45e8d91..6504c2d87f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -227,14 +227,14 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : const char* domainIP = getCmdOption(argc, constArgv, "--domain"); if (domainIP) { - strcpy(DOMAIN_IP, domainIP); + NodeList::getInstance()->setDomainIP(domainIP); } // Handle Local Domain testing with the --local command line if (cmdOptionExists(argc, constArgv, "--local")) { printLog("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); + + NodeList::getInstance()->setDomainIPToLocalhost(); } // Check to see if the user passed in a command line option for loading a local @@ -1101,8 +1101,14 @@ void Application::editPreferences() { QFormLayout* form = new QFormLayout(); layout->addLayout(form, 1); + const int QLINE_MINIMUM_WIDTH = 400; + + QLineEdit* domainServerHostname = new QLineEdit(QString(NodeList::getInstance()->getDomainHostname())); + domainServerHostname->setMinimumWidth(QLINE_MINIMUM_WIDTH); + form->addRow("Domain server:", domainServerHostname); + QLineEdit* avatarURL = new QLineEdit(_myAvatar.getVoxels()->getVoxelURL().toString()); - avatarURL->setMinimumWidth(400); + avatarURL->setMinimumWidth(QLINE_MINIMUM_WIDTH); form->addRow("Avatar URL:", avatarURL); QSpinBox* horizontalFieldOfView = new QSpinBox(); @@ -1133,9 +1139,11 @@ void Application::editPreferences() { if (dialog.exec() != QDialog::Accepted) { return; } + QUrl url(avatarURL->text()); _myAvatar.getVoxels()->setVoxelURL(url); sendAvatarVoxelURLMessage(url); + _headCameraPitchYawScale = headCameraPitchYawScale->value(); _myAvatar.setLeanScale(leanScale->value()); _audioJitterBufferSamples = audioJitterBufferSamples->value(); @@ -1956,8 +1964,8 @@ void Application::update(float deltaTime) { //loop through all the other avatars and simulate them... NodeList* nodeList = NodeList::getInstance(); - nodeList->lock(); for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + node->lock(); if (node->getLinkedData() != NULL) { Avatar *avatar = (Avatar *)node->getLinkedData(); if (!avatar->isInitialized()) { @@ -1966,8 +1974,8 @@ void Application::update(float deltaTime) { avatar->simulate(deltaTime, NULL); avatar->setMouseRay(mouseRayOrigin, mouseRayDirection); } + node->unlock(); } - nodeList->unlock(); // Simulate myself if (_gravityUse->isChecked()) { @@ -2456,8 +2464,10 @@ void Application::displaySide(Camera& whichCamera) { if (_renderAvatarsOn->isChecked()) { // Render avatars of other nodes NodeList* nodeList = NodeList::getInstance(); - nodeList->lock(); + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + node->lock(); + if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { Avatar *avatar = (Avatar *)node->getLinkedData(); if (!avatar->isInitialized()) { @@ -2466,8 +2476,9 @@ void Application::displaySide(Camera& whichCamera) { avatar->render(false, _renderAvatarBalls->isChecked()); avatar->setDisplayingLookatVectors(_renderLookatOn->isChecked()); } + + node->unlock(); } - nodeList->unlock(); // Render my own Avatar if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 73f971b7da..0e07f50693 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -126,8 +126,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o dataPacket, BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); - interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO) - .updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); + interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO).updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + + leadingBytes); } } diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index 3fddc71ad1..a023a70326 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -53,6 +53,8 @@ Node::Node(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t no } else { _localSocket = NULL; } + + pthread_mutex_init(&mutex, 0); } Node::~Node() { @@ -60,6 +62,8 @@ Node::~Node() { delete _localSocket; delete _linkedData; delete _bytesReceivedMovingAverage; + + pthread_mutex_destroy(&mutex); } // Names of Node Types diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index de43558b7a..d61657d730 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -65,6 +65,9 @@ public: int getPingMs() const { return _pingMs; }; void setPingMs(int pingMs) { _pingMs = pingMs; }; + + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } static void printLog(Node const&); private: @@ -83,6 +86,7 @@ private: NodeData* _linkedData; bool _isAlive; int _pingMs; + pthread_mutex_t mutex; }; diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index b4e3112768..7e34f37535 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -29,9 +29,9 @@ const char SOLO_NODE_TYPES[3] = { NODE_TYPE_VOXEL_SERVER }; -char DOMAIN_HOSTNAME[] = "highfidelity.below92.com"; -char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup -const int DOMAINSERVER_PORT = 40102; +const char DEFAULT_DOMAIN_HOSTNAME[MAX_HOSTNAME_BYTES] = "root.highfidelity.io"; +const char DEFAULT_DOMAIN_IP[INET_ADDRSTRLEN] = ""; // IP Address will be re-set by lookup on startup +const int DEFAULT_DOMAINSERVER_PORT = 40102; bool silentNodeThreadStopFlag = false; bool pingUnknownNodeThreadStopFlag = false; @@ -63,8 +63,10 @@ NodeList::NodeList(char newOwnerType, unsigned int newSocketListenPort) : _ownerType(newOwnerType), _nodeTypesOfInterest(NULL), _ownerID(UNKNOWN_NODE_ID), - _lastNodeID(0) { - pthread_mutex_init(&mutex, 0); + _lastNodeID(0) +{ + memcpy(_domainHostname, DEFAULT_DOMAIN_HOSTNAME, sizeof(DEFAULT_DOMAIN_HOSTNAME)); + memcpy(_domainIP, DEFAULT_DOMAIN_IP, sizeof(DEFAULT_DOMAIN_IP)); } NodeList::~NodeList() { @@ -74,8 +76,19 @@ NodeList::~NodeList() { // stop the spawned threads, if they were started stopSilentNodeRemovalThread(); - - pthread_mutex_destroy(&mutex); +} + +void NodeList::setDomainHostname(const char* domainHostname) { + memcpy(_domainHostname, domainHostname, sizeof(&domainHostname)); +} + +void NodeList::setDomainIP(const char* domainIP) { + memcpy(_domainIP, domainIP, sizeof(&domainIP)); +} + +void NodeList::setDomainIPToLocalhost() { + int ip = getLocalAddress(); + sprintf(_domainIP, "%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); } void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) { @@ -112,7 +125,6 @@ void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetDat } void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes) { - lock(); // find the avatar mixer in our node list and update the lastRecvTime from it Node* bulkSendNode = nodeWithAddress(senderAddress); @@ -149,9 +161,8 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe currentPosition += updateNodeWithData(matchingNode, packetHolder, numTotalBytes - (currentPosition - startPosition)); + } - - unlock(); } int NodeList::updateNodeWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) { @@ -166,6 +177,8 @@ int NodeList::updateNodeWithData(sockaddr *senderAddress, unsigned char *packetD } int NodeList::updateNodeWithData(Node *node, unsigned char *packetData, int dataBytes) { + node->lock(); + node->setLastHeardMicrostamp(usecTimestampNow()); if (node->getActiveSocket()) { @@ -176,7 +189,11 @@ int NodeList::updateNodeWithData(Node *node, unsigned char *packetData, int data linkedDataCreateCallback(node); } - return node->getLinkedData()->parseData(packetData, dataBytes); + int numParsedBytes = node->getLinkedData()->parseData(packetData, dataBytes); + + node->unlock(); + + return numParsedBytes; } Node* NodeList::nodeWithAddress(sockaddr *senderAddress) { @@ -236,18 +253,18 @@ void NodeList::sendDomainServerCheckIn() { static bool printedDomainServerIP = false; // Lookup the IP address of the domain server if we need to - if (atoi(DOMAIN_IP) == 0) { + if (atoi(_domainIP) == 0) { struct hostent* pHostInfo; - if ((pHostInfo = gethostbyname(DOMAIN_HOSTNAME)) != NULL) { + if ((pHostInfo = gethostbyname(_domainHostname)) != NULL) { sockaddr_in tempAddress; memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); - strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr)); - printLog("Domain Server: %s \n", DOMAIN_HOSTNAME); + strcpy(_domainIP, inet_ntoa(tempAddress.sin_addr)); + printLog("Domain Server: %s \n", _domainHostname); } else { printLog("Failed domain server lookup\n"); } } else if (!printedDomainServerIP) { - printLog("Domain Server IP: %s\n", DOMAIN_IP); + printLog("Domain Server IP: %s\n", _domainIP); printedDomainServerIP = true; } @@ -294,7 +311,7 @@ void NodeList::sendDomainServerCheckIn() { checkInPacketSize = packetPosition - checkInPacket; } - _nodeSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, checkInPacketSize); + _nodeSocket.send(_domainIP, DEFAULT_DOMAINSERVER_PORT, checkInPacket, checkInPacketSize); } int NodeList::processDomainServerList(unsigned char* packetData, size_t dataBytes) { diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 57f8083113..20eaddc738 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -9,8 +9,10 @@ #ifndef __hifi__NodeList__ #define __hifi__NodeList__ +#include #include #include +#include #include "Node.h" #include "UDPSocket.h" @@ -30,9 +32,11 @@ const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000; extern const char SOLO_NODE_TYPES[3]; -extern char DOMAIN_HOSTNAME[]; -extern char DOMAIN_IP[100]; // IP Address will be re-set by lookup on startup -extern const int DOMAINSERVER_PORT; +const int MAX_HOSTNAME_BYTES = 255; + +extern const char DEFAULT_DOMAIN_HOSTNAME[MAX_HOSTNAME_BYTES]; +extern const char DEFAULT_DOMAIN_IP[INET_ADDRSTRLEN]; // IP Address will be re-set by lookup on startup +extern const int DEFAULT_DOMAINSERVER_PORT; const int UNKNOWN_NODE_ID = -1; @@ -48,6 +52,12 @@ public: NodeListIterator begin() const; NodeListIterator end() const; + const char* getDomainHostname() const { return _domainHostname; }; + void setDomainHostname(const char* domainHostname); + + void setDomainIP(const char* domainIP); + void setDomainIPToLocalhost(); + char getOwnerType() const { return _ownerType; } uint16_t getLastNodeID() const { return _lastNodeID; } @@ -67,9 +77,6 @@ public: void clear(); - void lock() { pthread_mutex_lock(&mutex); } - void unlock() { pthread_mutex_unlock(&mutex); } - void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest); void sendDomainServerCheckIn(); int processDomainServerList(unsigned char *packetData, size_t dataBytes); @@ -103,6 +110,8 @@ private: void addNodeToList(Node* newNode); + char _domainHostname[MAX_HOSTNAME_BYTES]; + char _domainIP[INET_ADDRSTRLEN]; Node** _nodeBuckets[MAX_NUM_NODES / NODES_PER_BUCKET]; int _numNodes; UDPSocket _nodeSocket; @@ -113,7 +122,6 @@ private: uint16_t _lastNodeID; pthread_t removeSilentNodesThread; pthread_t checkInWithDomainServerThread; - pthread_mutex_t mutex; void handlePingReply(sockaddr *nodeAddress); void timePingReply(sockaddr *nodeAddress, unsigned char *packetData); diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 254b1d2d96..4529d34bd8 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -383,8 +383,7 @@ int main(int argc, const char * argv[]) { ::wantLocalDomain = cmdOptionExists(argc, argv,local); if (::wantLocalDomain) { printf("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); + nodeList->setDomainIPToLocalhost(); } nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode; From 94b6bfccf64f09fb7351bf919aeb42fb61b47dbb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 15:17:53 -0700 Subject: [PATCH 03/21] update the private mutex node variable to standard --- libraries/shared/src/Node.cpp | 4 ++-- libraries/shared/src/Node.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index a023a70326..f7c9758fd0 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -54,7 +54,7 @@ Node::Node(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t no _localSocket = NULL; } - pthread_mutex_init(&mutex, 0); + pthread_mutex_init(&_mutex, 0); } Node::~Node() { @@ -63,7 +63,7 @@ Node::~Node() { delete _linkedData; delete _bytesReceivedMovingAverage; - pthread_mutex_destroy(&mutex); + pthread_mutex_destroy(&_mutex); } // Names of Node Types diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index d61657d730..e5396a5b25 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -86,7 +86,7 @@ private: NodeData* _linkedData; bool _isAlive; int _pingMs; - pthread_mutex_t mutex; + pthread_mutex_t _mutex; }; From e3d1e5db5d3eda5254c3123f1e608c5560f5adcc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 15:45:27 -0700 Subject: [PATCH 04/21] correct reference to mutex to lock in Node --- libraries/shared/src/Node.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index e5396a5b25..aa88cb158c 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -66,8 +66,8 @@ public: int getPingMs() const { return _pingMs; }; void setPingMs(int pingMs) { _pingMs = pingMs; }; - void lock() { pthread_mutex_lock(&mutex); } - void unlock() { pthread_mutex_unlock(&mutex); } + void lock() { pthread_mutex_lock(&_mutex); } + void unlock() { pthread_mutex_unlock(&_mutex); } static void printLog(Node const&); private: From 6b83f95f9e433a3007e136fca575f439b617fbfd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 15:46:04 -0700 Subject: [PATCH 05/21] conditionally set a new hostname on preferences save --- interface/src/Application.cpp | 8 ++++ libraries/shared/src/NodeList.cpp | 70 +++++++++++++++++-------------- 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6504c2d87f..998d2c9126 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1140,6 +1140,14 @@ void Application::editPreferences() { return; } + // check if the domain server hostname is new - if so we need to clear the nodelist and delete the local voxels + const char* newHostname = domainServerHostname->text().toLocal8Bit().data(); + + if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname, sizeof(&newHostname)) != 0) { + NodeList::getInstance()->clear(); + NodeList::getInstance()->setDomainHostname(newHostname); + } + QUrl url(avatarURL->text()); _myAvatar.getVoxels()->setVoxelURL(url); sendAvatarVoxelURLMessage(url); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 7e34f37535..2e12e8ab71 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -78,12 +78,17 @@ NodeList::~NodeList() { stopSilentNodeRemovalThread(); } -void NodeList::setDomainHostname(const char* domainHostname) { - memcpy(_domainHostname, domainHostname, sizeof(&domainHostname)); +void NodeList::setDomainHostname(const char* domainHostname) { + memset(_domainHostname, 0, sizeof(_domainHostname)); + memcpy(_domainHostname, domainHostname, strlen(domainHostname)); + + // reset the domain IP so the hostname is checked again + setDomainIP(""); } void NodeList::setDomainIP(const char* domainIP) { - memcpy(_domainIP, domainIP, sizeof(&domainIP)); + memset(_domainIP, 0, sizeof(_domainIP)); + memcpy(_domainIP, domainIP, strlen(domainIP)); } void NodeList::setDomainIPToLocalhost() { @@ -132,37 +137,37 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe if (bulkSendNode) { bulkSendNode->setLastHeardMicrostamp(usecTimestampNow()); bulkSendNode->recordBytesReceived(numTotalBytes); - } - - int numBytesPacketHeader = numBytesForPacketHeader(packetData); - - unsigned char *startPosition = packetData; - unsigned char *currentPosition = startPosition + numBytesPacketHeader; - unsigned char packetHolder[numTotalBytes]; - - // we've already verified packet version for the bulk packet, so all head data in the packet is also up to date - populateTypeAndVersion(packetHolder, PACKET_TYPE_HEAD_DATA); - - uint16_t nodeID = -1; - - while ((currentPosition - startPosition) < numTotalBytes) { - unpackNodeId(currentPosition, &nodeID); - memcpy(packetHolder + numBytesPacketHeader, - currentPosition, - numTotalBytes - (currentPosition - startPosition)); - Node* matchingNode = nodeWithID(nodeID); + int numBytesPacketHeader = numBytesForPacketHeader(packetData); - if (!matchingNode) { - // we're missing this node, we need to add it to the list - matchingNode = addOrUpdateNode(NULL, NULL, NODE_TYPE_AGENT, nodeID); + unsigned char *startPosition = packetData; + unsigned char *currentPosition = startPosition + numBytesPacketHeader; + unsigned char packetHolder[numTotalBytes]; + + // we've already verified packet version for the bulk packet, so all head data in the packet is also up to date + populateTypeAndVersion(packetHolder, PACKET_TYPE_HEAD_DATA); + + uint16_t nodeID = -1; + + while ((currentPosition - startPosition) < numTotalBytes) { + unpackNodeId(currentPosition, &nodeID); + memcpy(packetHolder + numBytesPacketHeader, + currentPosition, + numTotalBytes - (currentPosition - startPosition)); + + Node* matchingNode = nodeWithID(nodeID); + + if (!matchingNode) { + // we're missing this node, we need to add it to the list + matchingNode = addOrUpdateNode(NULL, NULL, NODE_TYPE_AGENT, nodeID); + } + + currentPosition += updateNodeWithData(matchingNode, + packetHolder, + numTotalBytes - (currentPosition - startPosition)); + } - - currentPosition += updateNodeWithData(matchingNode, - packetHolder, - numTotalBytes - (currentPosition - startPosition)); - - } + } } int NodeList::updateNodeWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) { @@ -234,7 +239,9 @@ void NodeList::clear() { Node** nodeBucket = _nodeBuckets[i / NODES_PER_BUCKET]; Node* node = nodeBucket[i % NODES_PER_BUCKET]; + node->lock(); delete node; + node = NULL; } @@ -254,6 +261,7 @@ void NodeList::sendDomainServerCheckIn() { // Lookup the IP address of the domain server if we need to if (atoi(_domainIP) == 0) { + printf("Looking up %s\n", _domainHostname); struct hostent* pHostInfo; if ((pHostInfo = gethostbyname(_domainHostname)) != NULL) { sockaddr_in tempAddress; From 6c2682833ec0c05d3e9010e4c71f61a0d73d5bac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 15:53:25 -0700 Subject: [PATCH 06/21] lock on the solo voxelServer before deleting local voxels --- interface/src/Application.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 998d2c9126..cbccb5135f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1140,10 +1140,24 @@ void Application::editPreferences() { return; } - // check if the domain server hostname is new - if so we need to clear the nodelist and delete the local voxels + const char* newHostname = domainServerHostname->text().toLocal8Bit().data(); + // check if the domain server hostname is new if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname, sizeof(&newHostname)) != 0) { + // if so we need to clear the nodelist and delete the local voxels + Node *voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); + + if (voxelServer) { + voxelServer->lock(); + } + + _voxels.killLocalVoxels(); + + if (voxelServer) { + voxelServer->unlock(); + } + NodeList::getInstance()->clear(); NodeList::getInstance()->setDomainHostname(newHostname); } From 9fe1c7c63daddb204879745fa4c1e2a063625337 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 15:59:31 -0700 Subject: [PATCH 07/21] lock the voxel server when receiving data to avoid race crash --- interface/src/Application.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cbccb5135f..82851355b7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3270,11 +3270,21 @@ void* Application::networkReceive(void* args) { case PACKET_TYPE_VOXEL_DATA_MONOCHROME: case PACKET_TYPE_Z_COMMAND: case PACKET_TYPE_ERASE_VOXEL: - app->_voxels.parseData(app->_incomingPacket, bytesReceived); - break; - case PACKET_TYPE_ENVIRONMENT_DATA: - app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived); + case PACKET_TYPE_ENVIRONMENT_DATA: { + Node *voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); + if (voxelServer) { + voxelServer->lock(); + + if (app->_incomingPacket[0] == PACKET_TYPE_ENVIRONMENT_DATA) { + app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived); + } else { + app->_voxels.parseData(app->_incomingPacket, bytesReceived); + } + + voxelServer->unlock(); + } break; + } case PACKET_TYPE_BULK_AVATAR_DATA: NodeList::getInstance()->processBulkNodeData(&senderAddress, app->_incomingPacket, From a204a8b87238a9628f551ef40623b4e5c5f4d782 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 16:01:05 -0700 Subject: [PATCH 08/21] lock the audioMixer to avoid crash when grabbing socket --- interface/src/Audio.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 0e07f50693..0307a2df3b 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -96,6 +96,10 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); if (audioMixer) { + audioMixer->lock(); + sockaddr_in audioSocket = *audioMixer->getActiveSocket(); + audioMixer->unlock(); + glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition(); glm::quat headOrientation = interfaceAvatar->getHead().getOrientation(); @@ -122,12 +126,13 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o // copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL); - nodeList->getNodeSocket()->send(audioMixer->getActiveSocket(), - dataPacket, - BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); + nodeList->getNodeSocket()->send(audioSocket, + dataPacket, + BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO).updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); + } } From 33ddda25586e0411cf77fbbb2d5b96dd3a757771 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 16:02:36 -0700 Subject: [PATCH 09/21] correct reference to audio mixer sockaddr_in --- interface/src/Audio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 0307a2df3b..63fc24f56d 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -97,7 +97,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o if (audioMixer) { audioMixer->lock(); - sockaddr_in audioSocket = *audioMixer->getActiveSocket(); + sockaddr_in audioSocket = *(sockaddr_in*) audioMixer->getActiveSocket(); audioMixer->unlock(); glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition(); @@ -126,7 +126,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o // copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL); - nodeList->getNodeSocket()->send(audioSocket, + nodeList->getNodeSocket()->send((sockaddr*) &audioSocket, dataPacket, BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); From 081a44dbff05d390473b280f60776b1b7b5203c1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 16:05:23 -0700 Subject: [PATCH 10/21] only process new domain list if it comes from current DS --- libraries/shared/src/NodeList.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 2e12e8ab71..6d79b9471a 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -112,7 +112,14 @@ void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) { void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetData, size_t dataBytes) { switch (packetData[0]) { case PACKET_TYPE_DOMAIN: { - processDomainServerList(packetData, dataBytes); + // only process the DS if this is our current domain server + sockaddr_in domainServerSocket = *(sockaddr_in*) senderAddress; + const char* domainSenderIP = inet_ntoa(domainServerSocket.sin_addr); + + if (memcmp(domainSenderIP, _domainIP, strlen(domainSenderIP)) == 0) { + processDomainServerList(packetData, dataBytes); + } + break; } case PACKET_TYPE_PING: { From 1fb1622beb5d6e2e8ddd6baaadbbb12ac0c5f7ec Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 15 Jul 2013 16:27:23 -0700 Subject: [PATCH 11/21] added sleep to sendVoxelOperation() to keep from overwhelming server --- interface/src/Application.cpp | 41 +++++++++++++++++++++++++----- libraries/voxels/src/VoxelTree.cpp | 2 +- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 75f45e8d91..96e3dbd3d6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1333,7 +1333,9 @@ struct SendVoxelsOperationArgs { unsigned char* newBaseOctCode; unsigned char messageBuffer[MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE]; int bufferInUse; - + uint64_t lastSendTime; + int packetsSent; + uint64_t bytesSent; }; bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { @@ -1365,17 +1367,30 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { codeColorBuffer[bytesInCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX]; codeColorBuffer[bytesInCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ]; - // TODO: sendVoxelsOperation() is sending voxels too fast. - // This printf function accidently slowed down sending - // and hot-fixed the bug when importing - // large PNG models (256x256 px and more) - static unsigned int sendVoxelsOperationCalled = 0; printf("sending voxel #%u\n", ++sendVoxelsOperationCalled); - // if we have room don't have room in the buffer, then send the previously generated message first if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { + + args->packetsSent++; + args->bytesSent += args->bufferInUse; + controlledBroadcastToNodes(args->messageBuffer, args->bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1); args->bufferInUse = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // reset + + uint64_t now = usecTimestampNow(); + // dynamically sleep until we need to fire off the next set of voxels + const uint64_t CLIENT_TO_SERVER_VOXEL_SEND_INTERVAL_USECS = 1000 * 5; // 1 packet every 10 milliseconds + uint64_t elapsed = now - args->lastSendTime; + int usecToSleep = CLIENT_TO_SERVER_VOXEL_SEND_INTERVAL_USECS - elapsed; + if (usecToSleep > 0) { + printLog("sendVoxelsOperation: packet: %d bytes:%ld elapsed %ld usecs, sleeping for %d usecs!\n", + args->packetsSent, args->bytesSent, elapsed, usecToSleep); + usleep(usecToSleep); + } else { + printLog("sendVoxelsOperation: packet: %d bytes:%ld elapsed %ld usecs, no need to sleep!\n", + args->packetsSent, args->bytesSent, elapsed); + } + args->lastSendTime = now; } // copy this node's code color details into our buffer. @@ -1442,6 +1457,9 @@ void Application::importVoxels() { // the server as an set voxel message, this will also rebase the voxels to the new location unsigned char* calculatedOctCode = NULL; SendVoxelsOperationArgs args; + args.lastSendTime = usecTimestampNow(); + args.packetsSent = 0; + args.bytesSent = 0; int numBytesPacketHeader = populateTypeAndVersion(args.messageBuffer, PACKET_TYPE_SET_VOXEL_DESTRUCTIVE); @@ -1462,6 +1480,9 @@ void Application::importVoxels() { // If we have voxels left in the packet, then send the packet if (args.bufferInUse > (numBytesPacketHeader + sizeof(unsigned short int))) { controlledBroadcastToNodes(args.messageBuffer, args.bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1); + printLog("sending packet: %d\n", ++args.packetsSent); + args.bytesSent += args.bufferInUse; + printLog("total bytes sent: %ld\n", args.bytesSent); } if (calculatedOctCode) { @@ -1495,6 +1516,9 @@ void Application::pasteVoxels() { // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to // the server as an set voxel message, this will also rebase the voxels to the new location SendVoxelsOperationArgs args; + args.lastSendTime = usecTimestampNow(); + args.packetsSent = 0; + args.bytesSent = 0; int numBytesPacketHeader = populateTypeAndVersion(args.messageBuffer, PACKET_TYPE_SET_VOXEL_DESTRUCTIVE); @@ -1516,6 +1540,9 @@ void Application::pasteVoxels() { // If we have voxels left in the packet, then send the packet if (args.bufferInUse > (numBytesPacketHeader + sizeof(unsigned short int))) { controlledBroadcastToNodes(args.messageBuffer, args.bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1); + printLog("sending packet: %d\n", ++args.packetsSent); + args.bytesSent += args.bufferInUse; + printLog("total bytes sent: %ld\n", args.bytesSent); } if (calculatedOctCode) { diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index b84b374309..66fa81c425 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1251,7 +1251,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp } // wants occlusion culling & isLeaf() - bool shouldRender = childNode->calculateShouldRender(params.viewFrustum, params.boundaryLevelAdjust); + bool shouldRender = !params.viewFrustum ? true : childNode->calculateShouldRender(params.viewFrustum, params.boundaryLevelAdjust); // track children with actual color, only if the child wasn't previously in view! if (shouldRender && !childIsOccluded) { From 099fa4b4b10446912fe21cfbdf819ce580e35d14 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 15 Jul 2013 16:40:00 -0700 Subject: [PATCH 12/21] fixed server persistance issue --- voxel-server/src/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 254b1d2d96..e336234838 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -313,6 +313,9 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, uint64_t lastPersistVoxels = 0; void persistVoxelsWhenDirty() { uint64_t now = usecTimestampNow(); + if (::lastPersistVoxels == 0) { + ::lastPersistVoxels = now; + } int sinceLastTime = (now - ::lastPersistVoxels) / 1000; // check the dirty bit and persist here... From c27cd7ae426a49de46a45738d3e8b7f70b6c281a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 16:49:36 -0700 Subject: [PATCH 13/21] couple of type squishes in NodeList --- interface/src/Application.cpp | 2 +- libraries/shared/src/NodeList.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 82851355b7..a9313e7549 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3271,7 +3271,7 @@ void* Application::networkReceive(void* args) { case PACKET_TYPE_Z_COMMAND: case PACKET_TYPE_ERASE_VOXEL: case PACKET_TYPE_ENVIRONMENT_DATA: { - Node *voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); + Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); if (voxelServer) { voxelServer->lock(); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 6d79b9471a..004568584d 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -147,8 +147,8 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe int numBytesPacketHeader = numBytesForPacketHeader(packetData); - unsigned char *startPosition = packetData; - unsigned char *currentPosition = startPosition + numBytesPacketHeader; + unsigned char* startPosition = packetData; + unsigned char* currentPosition = startPosition + numBytesPacketHeader; unsigned char packetHolder[numTotalBytes]; // we've already verified packet version for the bulk packet, so all head data in the packet is also up to date From 38d8041bfb130bf095fb20b8b6ff023bd25ea7e3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 16:41:20 -0700 Subject: [PATCH 14/21] kill local voxels when voxel rendering is turned off --- interface/src/Application.cpp | 9 +++++++-- interface/src/Application.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4f17cd2221..9771cc8255 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1244,6 +1244,12 @@ void Application::setRenderWarnings(bool renderWarnings) { _voxels.setRenderPipelineWarnings(renderWarnings); } +void Application::setRenderVoxels(bool voxelRender) { + if (voxelRender) { + doKillLocalVoxels(); + } +} + void Application::doKillLocalVoxels() { _wantToKillLocalVoxels = true; } @@ -1554,9 +1560,8 @@ void Application::initMenu() { optionsMenu->addAction("Go Home", this, SLOT(goHome())); QMenu* renderMenu = menuBar->addMenu("Render"); - (_renderVoxels = renderMenu->addAction("Voxels"))->setCheckable(true); + (_renderVoxels = renderMenu->addAction("Voxels", this, SLOT(setRenderVoxels(bool)), Qt::SHIFT | Qt::Key_V))->setCheckable(true); _renderVoxels->setChecked(true); - _renderVoxels->setShortcut(Qt::SHIFT | Qt::Key_V); (_renderVoxelTextures = renderMenu->addAction("Voxel Textures"))->setCheckable(true); (_renderStarsOn = renderMenu->addAction("Stars"))->setCheckable(true); _renderStarsOn->setChecked(true); diff --git a/interface/src/Application.h b/interface/src/Application.h index cb1335887d..4e4101408f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -128,6 +128,7 @@ private slots: void cycleFrustumRenderMode(); void setRenderWarnings(bool renderWarnings); + void setRenderVoxels(bool renderVoxels); void doKillLocalVoxels(); void doRandomizeVoxelColors(); void doFalseRandomizeVoxelColors(); From 9f9d8e59bd47e025537a99dc6b0d79161fda13b5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 15 Jul 2013 17:08:55 -0700 Subject: [PATCH 15/21] don't accept voxel packet if rendering is turned off, correct boolean for kill --- interface/src/Application.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9771cc8255..5ad1a46c39 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1245,7 +1245,7 @@ void Application::setRenderWarnings(bool renderWarnings) { } void Application::setRenderVoxels(bool voxelRender) { - if (voxelRender) { + if (!voxelRender) { doKillLocalVoxels(); } } @@ -3224,7 +3224,7 @@ void* Application::networkReceive(void* args) { if (app->_wantToKillLocalVoxels) { app->_voxels.killLocalVoxels(); app->_wantToKillLocalVoxels = false; - } + } if (NodeList::getInstance()->getNodeSocket()->receive(&senderAddress, app->_incomingPacket, &bytesReceived)) { app->_packetCount++; @@ -3246,17 +3246,19 @@ void* Application::networkReceive(void* args) { case PACKET_TYPE_Z_COMMAND: case PACKET_TYPE_ERASE_VOXEL: case PACKET_TYPE_ENVIRONMENT_DATA: { - Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); - if (voxelServer) { - voxelServer->lock(); - - if (app->_incomingPacket[0] == PACKET_TYPE_ENVIRONMENT_DATA) { - app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived); - } else { - app->_voxels.parseData(app->_incomingPacket, bytesReceived); + if (app->_renderVoxels->isChecked()) { + Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); + if (voxelServer) { + voxelServer->lock(); + + if (app->_incomingPacket[0] == PACKET_TYPE_ENVIRONMENT_DATA) { + app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived); + } else { + app->_voxels.parseData(app->_incomingPacket, bytesReceived); + } + + voxelServer->unlock(); } - - voxelServer->unlock(); } break; } From a3009981d0e04e573b6efd79ccbc7d110551b967 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 15 Jul 2013 17:54:50 -0700 Subject: [PATCH 16/21] added Import Voxels to Clipboard --- interface/src/Application.cpp | 37 +++++++++++++++++++++++++++++++++++ interface/src/Application.h | 1 + 2 files changed, 38 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bcbe92f3bb..77f56fdd6b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1419,6 +1419,42 @@ void Application::exportVoxels() { _window->activateWindow(); } +void Application::importVoxelsToClipboard() { + QString desktopLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); + QString fileNameString = QFileDialog::getOpenFileName( + _glWidget, tr("Import Voxels to Clipboard"), desktopLocation, + tr("Sparse Voxel Octree Files, Square PNG, Schematic Files (*.svo *.png *.schematic)")); + + QByteArray fileNameAscii = fileNameString.toAscii(); + const char* fileName = fileNameAscii.data(); + + _clipboardTree.eraseAllVoxels(); + if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) { + QImage pngImage = QImage(fileName); + if (pngImage.height() != pngImage.width()) { + printLog("ERROR: Bad PNG size: height != width.\n"); + return; + } + + const uint32_t* pixels; + if (pngImage.format() == QImage::Format_ARGB32) { + pixels = reinterpret_cast(pngImage.constBits()); + } else { + QImage tmp = pngImage.convertToFormat(QImage::Format_ARGB32); + pixels = reinterpret_cast(tmp.constBits()); + } + + _clipboardTree.readFromSquareARGB32Pixels(pixels, pngImage.height()); + } else if (fileNameString.endsWith(".svo", Qt::CaseInsensitive)) { + _clipboardTree.readFromSVOFile(fileName); + } else if (fileNameString.endsWith(".schematic", Qt::CaseInsensitive)) { + _clipboardTree.readFromSchematicFile(fileName); + } + + // restore the main window's active state + _window->activateWindow(); +} + void Application::importVoxels() { QString desktopLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); QString fileNameString = QFileDialog::getOpenFileName( @@ -1658,6 +1694,7 @@ void Application::initMenu() { voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); + voxelMenu->addAction("Import Voxels to Clipboard", this, SLOT(importVoxelsToClipboard()), Qt::SHIFT | Qt::CTRL | Qt::Key_I); voxelMenu->addAction("Cut Voxels", this, SLOT(cutVoxels()), Qt::CTRL | Qt::Key_X); voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C); voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V); diff --git a/interface/src/Application.h b/interface/src/Application.h index cb1335887d..4c1cfa5969 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -153,6 +153,7 @@ private slots: void exportSettings(); void exportVoxels(); void importVoxels(); + void importVoxelsToClipboard(); void cutVoxels(); void copyVoxels(); void pasteVoxels(); From 802abade4f3db88d752b49fedb4c3285ff35c2e8 Mon Sep 17 00:00:00 2001 From: Eric Johnston Date: Mon, 15 Jul 2013 18:16:50 -0700 Subject: [PATCH 17/21] Fixed problem in idle(), causing events to stack up. The problem was that idle() was set on a zero-ms timer (using idleTimer->start(0)), and the time is then self-regulated by returning early if it's not time yet. Because of this, Qt stays perpetually in the timer servicing, instead of processing events. This causes keys and menu items to be delayed if the user drags the mouse before activating them, especially at low frame rates. It also causes very-delayed multitouch response. The fix I've applied is to reset the idle timer after servicing the idle. I've set it to 2ms because I noticed that 1ms didn't always clear out all of the events. We can tune it to whatever we need, or even calculate it based on the time it took us to service the idle. --- interface/src/Application.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5ad1a46c39..4ea6e0bf84 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -82,6 +82,7 @@ const glm::vec3 START_LOCATION(4.f, 0.f, 5.f); // Where one's own node begins const int IDLE_SIMULATE_MSECS = 16; // How often should call simulate and other stuff // in the idle loop? (60 FPS is default) +static QTimer* idleTimer = NULL; const int STARTUP_JITTER_SAMPLES = PACKET_LENGTH_SAMPLES_PER_CHANNEL / 2; // Startup optimistically with small jitter buffer that @@ -341,7 +342,7 @@ void Application::initializeGL() { timer->start(1000); // call our idle function whenever we can - QTimer* idleTimer = new QTimer(this); + idleTimer = new QTimer(this); connect(idleTimer, SIGNAL(timeout()), SLOT(idle())); idleTimer->start(0); _idleLoopStdev.reset(); @@ -973,19 +974,9 @@ void Application::idle() { gettimeofday(&check, NULL); // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran - sendPostedEvents(NULL, QEvent::TouchBegin); - sendPostedEvents(NULL, QEvent::TouchUpdate); - sendPostedEvents(NULL, QEvent::TouchEnd); double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check); if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) { - - // If we're using multi-touch look, immediately process any - // touch events, and no other events. - // This is necessary because id the idle() call takes longer than the - // interval between idle() calls, the event loop never gets to run, - // and touch events get delayed. - const float BIGGEST_DELTA_TIME_SECS = 0.25f; update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS)); _glWidget->updateGL(); @@ -998,6 +989,9 @@ void Application::idle() { _idleLoopMeasuredJitter = _idleLoopStdev.getStDev(); _idleLoopStdev.reset(); } + + // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. + idleTimer->start(2); } } void Application::terminate() { From 42e5440b7b8406b0fb158777f314ae13c8509936 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 16 Jul 2013 10:00:55 -0700 Subject: [PATCH 18/21] CR feedback --- interface/src/Application.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fa36847805..772cae733d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1455,11 +1455,11 @@ void Application::exportVoxels() { _window->activateWindow(); } +const char* IMPORT_FILE_TYPES = "Sparse Voxel Octree Files, Square PNG, Schematic Files (*.svo *.png *.schematic)"; void Application::importVoxelsToClipboard() { QString desktopLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); - QString fileNameString = QFileDialog::getOpenFileName( - _glWidget, tr("Import Voxels to Clipboard"), desktopLocation, - tr("Sparse Voxel Octree Files, Square PNG, Schematic Files (*.svo *.png *.schematic)")); + QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels to Clipboard"), desktopLocation, + tr(IMPORT_FILE_TYPES)); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); @@ -1493,9 +1493,8 @@ void Application::importVoxelsToClipboard() { void Application::importVoxels() { QString desktopLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); - QString fileNameString = QFileDialog::getOpenFileName( - _glWidget, tr("Import Voxels"), desktopLocation, - tr("Sparse Voxel Octree Files, Square PNG, Schematic Files (*.svo *.png *.schematic)")); + QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), desktopLocation, + tr(IMPORT_FILE_TYPES)); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); From 440352c584da853d8469572d3bd72d2b7b33cef9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 16 Jul 2013 10:02:27 -0700 Subject: [PATCH 19/21] white space --- interface/src/Application.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 772cae733d..c28c8a9097 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1479,8 +1479,7 @@ void Application::importVoxelsToClipboard() { QImage tmp = pngImage.convertToFormat(QImage::Format_ARGB32); pixels = reinterpret_cast(tmp.constBits()); } - - _clipboardTree.readFromSquareARGB32Pixels(pixels, pngImage.height()); + _clipboardTree.readFromSquareARGB32Pixels(pixels, pngImage.height()); } else if (fileNameString.endsWith(".svo", Qt::CaseInsensitive)) { _clipboardTree.readFromSVOFile(fileName); } else if (fileNameString.endsWith(".schematic", Qt::CaseInsensitive)) { From 64ba01e23cedba83097b695563e1303d09611460 Mon Sep 17 00:00:00 2001 From: atlante45 Date: Tue, 16 Jul 2013 10:54:58 -0700 Subject: [PATCH 20/21] added scale to settings --- interface/src/Avatar.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index a1175e3b23..7638ca0047 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -1321,7 +1321,11 @@ void Avatar::loadData(QSettings* settings) { _voxels.setVoxelURL(settings->value("voxelURL").toUrl()); _leanScale = loadSetting(settings, "leanScale", 0.5f); - + + _scale = loadSetting(settings, "scale", 1.0f); + setScale(_scale); + Application::getInstance()->getCamera()->setScale(_scale); + settings->endGroup(); } @@ -1344,6 +1348,7 @@ void Avatar::saveData(QSettings* set) { set->setValue("voxelURL", _voxels.getVoxelURL()); set->setValue("leanScale", _leanScale); + set->setValue("scale", _scale); set->endGroup(); } From e81fed2622df57fef7316172ae093545fb8f88eb Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 16 Jul 2013 12:31:58 -0700 Subject: [PATCH 21/21] Calling glInterleavedArrays enables the client vertex/color array states, so we need to disable them afterwards. --- interface/src/starfield/renderer/Renderer.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/starfield/renderer/Renderer.h b/interface/src/starfield/renderer/Renderer.h index 92fe53f69f..7eab70d178 100644 --- a/interface/src/starfield/renderer/Renderer.h +++ b/interface/src/starfield/renderer/Renderer.h @@ -509,6 +509,8 @@ namespace starfield { _program.release(); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); glDisable(GL_POINT_SMOOTH); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); glPopMatrix(); }