From 777dd6dc535074d6749e0ce5210b8c0f72904219 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 13 May 2013 09:57:36 -0700 Subject: [PATCH 1/6] Added PointerStack class, and implemented support for monochrome in VoxelTree --- libraries/shared/src/PointerStack.cpp | 42 +++++++++++++++++++ libraries/shared/src/PointerStack.h | 59 +++++++++++++++++++++++++++ libraries/voxels/src/VoxelTree.cpp | 52 ++++++++++++----------- libraries/voxels/src/VoxelTree.h | 8 ++-- 4 files changed, 133 insertions(+), 28 deletions(-) create mode 100644 libraries/shared/src/PointerStack.cpp create mode 100644 libraries/shared/src/PointerStack.h diff --git a/libraries/shared/src/PointerStack.cpp b/libraries/shared/src/PointerStack.cpp new file mode 100644 index 0000000000..2098312298 --- /dev/null +++ b/libraries/shared/src/PointerStack.cpp @@ -0,0 +1,42 @@ +// +// PointerStack.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 5/11/2013 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include "PointerStack.h" +#include + +PointerStack::~PointerStack() { + deleteAll(); +} + +void PointerStack::deleteAll() { + if (_elements) { + delete[] _elements; + } + _elements = NULL; + _elementsInUse = 0; + _sizeOfElementsArray = 0; +} + +const int GROW_BY = 100; + +void PointerStack::growAndPush(void* element) { + //printf("PointerStack::growAndPush() _sizeOfElementsArray=%d",_sizeOfElementsArray); + void** oldElements = _elements; + _elements = new void* [_sizeOfElementsArray + GROW_BY]; + _sizeOfElementsArray += GROW_BY; + + // If we had an old stack... + if (oldElements) { + // copy old elements into the new stack + memcpy(_elements, oldElements, _elementsInUse * sizeof(void*)); + delete[] oldElements; + } + _elements[_elementsInUse] = element; + _elementsInUse++; +} + diff --git a/libraries/shared/src/PointerStack.h b/libraries/shared/src/PointerStack.h new file mode 100644 index 0000000000..a9066c54fc --- /dev/null +++ b/libraries/shared/src/PointerStack.h @@ -0,0 +1,59 @@ +// +// PointerStack.h +// hifi +// +// Created by Brad Hefta-Gaub on 4/25/2013 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// + +#ifndef __hifi__PointerStack__ +#define __hifi__PointerStack__ + +#include // for NULL + +class PointerStack { + +public: + PointerStack() : + _elements(NULL), + _elementsInUse(0), + _sizeOfElementsArray(0) {}; + + ~PointerStack(); + + void push(void* element) { + if (_sizeOfElementsArray < _elementsInUse + 1) { + return growAndPush(element); + } + _elements[_elementsInUse] = element; + _elementsInUse++; + }; + + void* pop() { + if (_elementsInUse) { + // get the last element + void* element = _elements[_elementsInUse - 1]; + // reduce the count + _elementsInUse--; + return element; + } + return NULL; + }; + + + void* top() const { return (_elementsInUse) ? _elements[_elementsInUse - 1] : NULL; } + bool isEmpty() const { return (_elementsInUse == 0); }; + bool empty() const { return (_elementsInUse == 0); }; + int count() const { return _elementsInUse; }; + int size() const { return _elementsInUse; }; + +private: + void growAndPush(void* element); + void deleteAll(); + void** _elements; + int _elementsInUse; + int _sizeOfElementsArray; +}; + +#endif /* defined(__hifi__PointerStack__) */ diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 0120c7bfe1..f7da5f443f 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -115,7 +115,7 @@ VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char } } -int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, int bytesLeftToRead) { +int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, int bytesLeftToRead, bool includeColor) { // instantiate variable for bytes already read int bytesRead = 1; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { @@ -133,9 +133,11 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, } // pull the color for this child - nodeColor newColor; - memcpy(newColor, nodeData + bytesRead, 3); - newColor[3] = 1; + nodeColor newColor = { 128, 128, 128, 1}; + if (includeColor) { + memcpy(newColor, nodeData + bytesRead, 3); + bytesRead += 3; + } bool nodeWasDirty = destinationNode->getChildAtIndex(i)->isDirty(); destinationNode->getChildAtIndex(i)->setColor(newColor); bool nodeIsDirty = destinationNode->getChildAtIndex(i)->isDirty(); @@ -147,8 +149,6 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, } this->voxelsColored++; this->voxelsColoredStats.updateAverage(1); - - bytesRead += 3; } } @@ -180,7 +180,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, // tell the child to read the subsequent data bytesRead += readNodeData(destinationNode->getChildAtIndex(childIndex), nodeData + bytesRead, - bytesLeftToRead - bytesRead); + bytesLeftToRead - bytesRead, includeColor); } childIndex++; @@ -189,7 +189,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, return bytesRead; } -void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes) { +void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, bool includeColor) { int bytesRead = 0; unsigned char* bitstreamAt = bitstream; @@ -218,7 +218,7 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int int theseBytesRead = 0; theseBytesRead += octalCodeBytes; theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes, - bufferSizeBytes - (bytesRead + octalCodeBytes)); + bufferSizeBytes - (bytesRead + octalCodeBytes), includeColor); // skip bitstream to new startPoint bitstreamAt += theseBytesRead; @@ -719,7 +719,7 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe } int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const { + VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor) const { // How many bytes have we written so far at this level; int bytesWritten = 0; @@ -739,14 +739,14 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned int currentEncodeLevel = 0; int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel, - node, outputBuffer, availableBytes, bag, viewFrustum); + node, outputBuffer, availableBytes, bag, viewFrustum, includeColor); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); - // if childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some reason - // couldn't be written... so reset them here... - if (childBytesWritten == 2) { + // if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some reason + // couldn't be written... so reset them here... This isn't true for the non-color included case + if (includeColor && childBytesWritten == 2) { childBytesWritten = 0; } @@ -762,7 +762,7 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const { + VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -847,11 +847,13 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count // write the color data... - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (oneAtBit(childrenColoredBits, i)) { - memcpy(writeToThisLevelBuffer, &node->getChildAtIndex(i)->getColor(), BYTES_PER_COLOR); - writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color - bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color + if (includeColor) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (oneAtBit(childrenColoredBits, i)) { + memcpy(writeToThisLevelBuffer, &node->getChildAtIndex(i)->getColor(), BYTES_PER_COLOR); + writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color + bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color + } } } // write the child exist bits @@ -894,7 +896,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco int thisLevel = currentEncodeLevel; int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode, - outputBuffer, availableBytes, bag, viewFrustum); + outputBuffer, availableBytes, bag, + viewFrustum, includeColor); // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. @@ -912,7 +915,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! // // we can make this act like no bytes out, by just resetting the bytes out in this case - if (childTreeBytesOut == 2) { + if (includeColor && childTreeBytesOut == 2) { childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } @@ -947,7 +950,7 @@ bool VoxelTree::readFromFileV2(const char* fileName) { // read the entire file into a buffer, WHAT!? Why not. unsigned char* entireFile = new unsigned char[fileLength]; file.read((char*)entireFile, fileLength); - readBitstreamToTree(entireFile, fileLength); + readBitstreamToTree(entireFile, fileLength, true); delete[] entireFile; file.close(); @@ -971,7 +974,8 @@ void VoxelTree::writeToFileV2(const char* fileName) const { while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); - bytesWritten = encodeTreeBitstream(INT_MAX, subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, NULL); + bytesWritten = encodeTreeBitstream(INT_MAX, subTree, &outputBuffer[0], + MAX_VOXEL_PACKET_SIZE - 1, nodeBag, NULL, true); file.write((const char*)&outputBuffer[0], bytesWritten); } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 8cecff035d..fc3b44f413 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -40,7 +40,7 @@ public: void eraseAllVoxels(); void processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes); - void readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes); + void readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, bool includeColor = true); void readCodeColorBufferToTree(unsigned char *codeColorBuffer); void deleteVoxelCodeFromTree(unsigned char *codeBuffer); void printTreeForDebugging(VoxelNode *startNode); @@ -55,7 +55,7 @@ public: void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const; + VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor = true) const; int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); @@ -79,7 +79,7 @@ public: private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const; + VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor) const; int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); @@ -89,7 +89,7 @@ private: void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); - int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes); + int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, bool includeColor = true); bool _isDirty; unsigned long int _nodesChangedFromBitstream; From b19622738530be7b5212dda99d9e5cae2363ae75 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 13 May 2013 15:02:46 -0700 Subject: [PATCH 2/6] Added wantResIn and wantColor feature between client and server - Updated Voxel Server to support non-res-in version of voxel distribution - Updated agent data to allow client to send desired res-in and color state - added menu items to client debug menu to toggle wantResIn and wantColor --- interface/src/VoxelSystem.cpp | 7 ++ interface/src/main.cpp | 23 ++++++ libraries/avatars/src/AvatarData.cpp | 31 ++------ libraries/avatars/src/AvatarData.h | 34 ++++++++- libraries/shared/src/PacketHeaders.h | 1 + voxel-server/src/VoxelAgentData.cpp | 2 +- voxel-server/src/main.cpp | 110 ++++++++++++++++++++++++++- 7 files changed, 180 insertions(+), 28 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index a0576a71a8..b3c483717d 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -104,6 +104,13 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { _tree->readBitstreamToTree(voxelData, numBytes - 1); } break; + case PACKET_HEADER_VOXEL_DATA_MONOCHROME: + { + PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()"); + // ask the VoxelTree to read the MONOCHROME bitstream into the tree + _tree->readBitstreamToTree(voxelData, numBytes - 1, false); + } + break; case PACKET_HEADER_ERASE_VOXEL: // ask the tree to read the "remove" bitstream _tree->processRemoveVoxelBitstream(sourceBuffer, numBytes); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 6fc11d934b..3b665f1455 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -163,6 +163,8 @@ bool paintOn = false; // Whether to paint voxels as you fly aroun VoxelDetail paintingVoxel; // The voxel we're painting if we're painting unsigned char dominantColor = 0; // The dominant color of the voxel we're painting bool perfStatsOn = false; // Do we want to display perfStats? +bool wantMonochrome = false; // ask server to send us in monochrome +bool wantResIn = false; // ask server to res in bool logOn = true; // Whether to show on-screen log @@ -1278,6 +1280,22 @@ int setRenderWarnings(int state) { return value; } +int setWantResIn(int state) { + int value = setValue(state, &::wantResIn); + if (state == MENU_ROW_PICKED) { + ::myAvatar.setWantResIn(::wantResIn); + } + return value; +} + +int setWantMonochrome(int state) { + int value = setValue(state, &::wantMonochrome); + if (state == MENU_ROW_PICKED) { + ::myAvatar.setWantColor(!::wantMonochrome); + } + return value; +} + int setDisplayFrustum(int state) { return setValue(state, &::frustumOn); } @@ -1370,6 +1388,8 @@ int doFalseColorizeInView(int state) { return state; } + + const char* modeAll = " - All "; const char* modeVectors = " - Vectors "; const char* modePlanes = " - Planes "; @@ -1441,6 +1461,8 @@ void initMenu() { menuColumnDebug->addRow("FALSE Color Voxel Out of View", doFalseColorizeInView); menuColumnDebug->addRow("Show TRUE Colors", doTrueVoxelColors); menuColumnDebug->addRow("Calculate Tree Stats", doTreeStats); + menuColumnDebug->addRow("Wants Res-In", setWantResIn); + menuColumnDebug->addRow("Wants Monochrome", setWantMonochrome); } void testPointToVoxel() { @@ -1728,6 +1750,7 @@ void* networkReceive(void* args) { myAvatar.processTransmitterData(incomingPacket, bytesReceived); break; case PACKET_HEADER_VOXEL_DATA: + case PACKET_HEADER_VOXEL_DATA_MONOCHROME: case PACKET_HEADER_Z_COMMAND: case PACKET_HEADER_ERASE_VOXEL: voxels.parseData(incomingPacket, bytesReceived); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 8279851458..60d28ce6fb 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -34,29 +34,6 @@ int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPo return sizeof(uint16_t); } -AvatarData::AvatarData() : - _handPosition(0,0,0), - _bodyYaw(-90.0), - _bodyPitch(0.0), - _bodyRoll(0.0), - _headYaw(0), - _headPitch(0), - _headRoll(0), - _headLeanSideways(0), - _headLeanForward(0), - _handState(0), - _cameraPosition(0,0,0), - _cameraDirection(0,0,0), - _cameraUp(0,0,0), - _cameraRight(0,0,0), - _cameraFov(0.0f), - _cameraAspectRatio(0.0f), - _cameraNearClip(0.0f), - _cameraFarClip(0.0f), - _keyState(NO_KEY_DOWN) { - -} - AvatarData::~AvatarData() { } @@ -130,6 +107,10 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, _chatMessage.data(), _chatMessage.size() * sizeof(char)); destinationBuffer += _chatMessage.size() * sizeof(char); + // voxel sending features... + *destinationBuffer++ = _wantResIn; + *destinationBuffer++ = _wantColor; + return destinationBuffer - bufferStart; } @@ -201,6 +182,10 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { int chatMessageSize = *sourceBuffer++; _chatMessage = string((char*)sourceBuffer, chatMessageSize); sourceBuffer += chatMessageSize * sizeof(char); + + // voxel sending features... + _wantResIn = (bool)*sourceBuffer++; + _wantColor = (bool)*sourceBuffer++; return sourceBuffer - startPosition; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 9ce2bb2c77..dd1b6b970e 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -24,7 +24,30 @@ enum KeyState class AvatarData : public AgentData { public: - AvatarData(); + AvatarData() : + _handPosition(0,0,0), + _bodyYaw(-90.0), + _bodyPitch(0.0), + _bodyRoll(0.0), + _headYaw(0), + _headPitch(0), + _headRoll(0), + _headLeanSideways(0), + _headLeanForward(0), + _handState(0), + _cameraPosition(0,0,0), + _cameraDirection(0,0,0), + _cameraUp(0,0,0), + _cameraRight(0,0,0), + _cameraFov(0.0f), + _cameraAspectRatio(0.0f), + _cameraNearClip(0.0f), + _cameraFarClip(0.0f), + _keyState(NO_KEY_DOWN), + _wantResIn(false), + _wantColor(true) { }; + + ~AvatarData(); AvatarData* clone() const; @@ -96,6 +119,12 @@ public: // chat message void setChatMessage(const std::string& msg) { _chatMessage = msg; } const std::string& chatMessage () const { return _chatMessage; } + + // related to Voxel Sending strategies + bool getWantResIn() const { return _wantResIn; } + bool getWantColor() const { return _wantColor; } + void setWantResIn(bool wantResIn) { _wantResIn = wantResIn; } + void setWantColor(bool wantColor) { _wantColor = wantColor; } protected: glm::vec3 _position; @@ -137,6 +166,9 @@ protected: // chat message std::string _chatMessage; + + bool _wantResIn; + bool _wantColor; }; #endif /* defined(__hifi__AvatarData__) */ diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index da972e85c2..49b2fe9d00 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -23,6 +23,7 @@ const PACKET_HEADER PACKET_HEADER_INJECT_AUDIO = 'I'; const PACKET_HEADER PACKET_HEADER_SET_VOXEL = 'S'; const PACKET_HEADER PACKET_HEADER_ERASE_VOXEL = 'E'; const PACKET_HEADER PACKET_HEADER_VOXEL_DATA = 'V'; +const PACKET_HEADER PACKET_HEADER_VOXEL_DATA_MONOCHROME = 'v'; const PACKET_HEADER PACKET_HEADER_BULK_AVATAR_DATA = 'X'; const PACKET_HEADER PACKET_HEADER_TRANSMITTER_DATA = 't'; const PACKET_HEADER PACKET_HEADER_ENVIRONMENT_DATA = 'e'; diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 7eba95364b..32526be383 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -25,7 +25,7 @@ void VoxelAgentData::init() { } void VoxelAgentData::resetVoxelPacket() { - _voxelPacket[0] = PACKET_HEADER_VOXEL_DATA; + _voxelPacket[0] = getWantColor() ? PACKET_HEADER_VOXEL_DATA : PACKET_HEADER_VOXEL_DATA_MONOCHROME; _voxelPacketAt = &_voxelPacket[1]; _voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - 1; _voxelPacketWaiting = false; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 9b66f427c6..456596754a 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -104,7 +104,13 @@ void eraseVoxelTreeAndCleanupAgentVisitData() { } -void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) { +// Version of voxel distributor that sends each LOD level at a time +void resInVoxelDistributor(AgentList* agentList, + AgentList::iterator& agent, + VoxelAgentData* agentData, + ViewFrustum& viewFrustum) { + + printf("resInVoxelDistributor()\n"); bool searchReset = false; int searchLoops = 0; int searchLevelWas = agentData->getMaxSearchLevel(); @@ -158,7 +164,8 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge VoxelNode* subTree = agentData->nodeBag.extract(); bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, - agentData->nodeBag, &viewFrustum); + agentData->nodeBag, &viewFrustum, + agentData->getWantColor()); if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); @@ -216,6 +223,99 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge } } +// Version of voxel distributor that sends each LOD level at a time +void deepestLevelVoxelDistributor(AgentList* agentList, + AgentList::iterator& agent, + VoxelAgentData* agentData, + ViewFrustum& viewFrustum) { + + printf("deepestLevelVoxelDistributor()\n"); + + int maxLevelReached = 0; + double start = usecTimestampNow(); + if (agentData->nodeBag.isEmpty()) { + maxLevelReached = randomTree.searchForColoredNodes(INT_MAX, randomTree.rootNode, viewFrustum, agentData->nodeBag); + } + double end = usecTimestampNow(); + double elapsedmsec = (end - start)/1000.0; + if (elapsedmsec > 100) { + if (elapsedmsec > 1000) { + double elapsedsec = (end - start)/1000000.0; + printf("WARNING! searchForColoredNodes() took %lf seconds to identify %d nodes at level %d\n", + elapsedsec, agentData->nodeBag.count(), maxLevelReached); + } else { + printf("WARNING! searchForColoredNodes() took %lf milliseconds to identify %d nodes at level %d\n", + elapsedmsec, agentData->nodeBag.count(), maxLevelReached); + } + } else if (::debugVoxelSending) { + printf("searchForColoredNodes() took %lf milliseconds to identify %d nodes at level %d\n", + elapsedmsec, agentData->nodeBag.count(), maxLevelReached); + } + + // If we have something in our nodeBag, then turn them into packets and send them out... + if (!agentData->nodeBag.isEmpty()) { + static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static + int bytesWritten = 0; + int packetsSentThisInterval = 0; + int truePacketsSent = 0; + int trueBytesSent = 0; + double start = usecTimestampNow(); + + while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - 1) { + if (!agentData->nodeBag.isEmpty()) { + VoxelNode* subTree = agentData->nodeBag.extract(); + bytesWritten = randomTree.encodeTreeBitstream(INT_MAX, subTree, + &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, + agentData->nodeBag, &viewFrustum, + agentData->getWantColor()); + + if (agentData->getAvailable() >= bytesWritten) { + agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); + } else { + agentList->getAgentSocket().send(agent->getActiveSocket(), + agentData->getPacket(), agentData->getPacketLength()); + trueBytesSent += agentData->getPacketLength(); + truePacketsSent++; + packetsSentThisInterval++; + agentData->resetVoxelPacket(); + agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); + } + } else { + if (agentData->isPacketWaiting()) { + agentList->getAgentSocket().send(agent->getActiveSocket(), + agentData->getPacket(), agentData->getPacketLength()); + trueBytesSent += agentData->getPacketLength(); + truePacketsSent++; + agentData->resetVoxelPacket(); + + } + packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left + } + } + // send the environment packet + int envPacketLength = environmentData.getBroadcastData(tempOutputBuffer); + agentList->getAgentSocket().send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength); + trueBytesSent += envPacketLength; + truePacketsSent++; + + double end = usecTimestampNow(); + double elapsedmsec = (end - start)/1000.0; + if (elapsedmsec > 100) { + if (elapsedmsec > 1000) { + double elapsedsec = (end - start)/1000000.0; + printf("WARNING! packetLoop() took %lf seconds to generate %d bytes in %d packets %d nodes still to send\n", + elapsedsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count()); + } else { + printf("WARNING! packetLoop() took %lf milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", + elapsedmsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count()); + } + } else if (::debugVoxelSending) { + printf("packetLoop() took %lf milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", + elapsedmsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count()); + } + } +} + void persistVoxelsWhenDirty() { // check the dirty bit and persist here... if (::wantVoxelPersist && ::randomTree.isDirty()) { @@ -253,7 +353,11 @@ void *distributeVoxelsToListeners(void *args) { viewFrustum.calculate(); - voxelDistributor(agentList, agent, agentData, viewFrustum); + if (agentData->getWantResIn()) { + resInVoxelDistributor(agentList, agent, agentData, viewFrustum); + } else { + deepestLevelVoxelDistributor(agentList, agent, agentData, viewFrustum); + } } } From 12a5ab6ea222951559d55c28be6b85cc4451258a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 13 May 2013 15:06:39 -0700 Subject: [PATCH 3/6] fixed comment --- voxel-server/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 456596754a..29b211e44f 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -223,7 +223,7 @@ void resInVoxelDistributor(AgentList* agentList, } } -// Version of voxel distributor that sends each LOD level at a time +// Version of voxel distributor that sends the deepest LOD level at once void deepestLevelVoxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, From 0f9d72e2c1ead7d0dbf61fad93f1eb404496d64f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 13 May 2013 16:14:17 -0700 Subject: [PATCH 4/6] keep one last PairableDevice and one last RequestingClient --- pairing-server/src/main.cpp | 69 +++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/pairing-server/src/main.cpp b/pairing-server/src/main.cpp index 3d7a36f14c..3c7c24c141 100644 --- a/pairing-server/src/main.cpp +++ b/pairing-server/src/main.cpp @@ -24,6 +24,15 @@ struct PairableDevice { sockaddr_in localSocket; }; +struct RequestingClient { + char address[INET_ADDRSTRLEN]; + int port; +}; + +UDPSocket serverSocket(PAIRING_SERVER_LISTEN_PORT); +PairableDevice *lastDevice = NULL; +RequestingClient *lastClient = NULL; + int indexOfFirstOccurenceOfCharacter(char* haystack, char needle) { int currentIndex = 0; @@ -34,70 +43,80 @@ int indexOfFirstOccurenceOfCharacter(char* haystack, char needle) { return currentIndex; } +void sendLastClientToLastDevice() { + char pairData[INET_ADDRSTRLEN + 6] = {}; + int bytesWritten = sprintf(pairData, "%s:%d", ::lastClient->address, ::lastClient->port); + + ::serverSocket.send((sockaddr*) &::lastDevice->sendingSocket, pairData, bytesWritten); +} + int main(int argc, const char* argv[]) { - UDPSocket serverSocket(PAIRING_SERVER_LISTEN_PORT); sockaddr_in senderSocket; char senderData[MAX_PACKET_SIZE_BYTES] = {}; ssize_t receivedBytes = 0; - std::vector devices; - while (true) { - if (serverSocket.receive((sockaddr *)&senderSocket, &senderData, &receivedBytes)) { - + if (::serverSocket.receive((sockaddr *)&senderSocket, &senderData, &receivedBytes)) { if (senderData[0] == 'A') { // this is a device reporting itself as available - // create a new PairableDevice - PairableDevice newDevice = {}; + PairableDevice tempDevice = {}; char deviceAddress[INET_ADDRSTRLEN] = {}; int socketPort = 0; int numMatches = sscanf(senderData, "Available %s%[^:]:%d %s", - newDevice.identifier, + tempDevice.identifier, deviceAddress, &socketPort, - newDevice.name); + tempDevice.name); if (numMatches >= 3) { - // if we have fewer than 6 matches the packet wasn't properly formatted + // if we have fewer than 3 matches the packet wasn't properly formatted + // otherwise copy the tempDevice to the persisting lastDevice + *::lastDevice = tempDevice; // setup the localSocket for the pairing device - newDevice.localSocket.sin_family = AF_INET; - inet_pton(AF_INET, deviceAddress, &newDevice); - newDevice.localSocket.sin_port = socketPort; + ::lastDevice->localSocket.sin_family = AF_INET; + inet_pton(AF_INET, deviceAddress, &::lastDevice); + ::lastDevice->localSocket.sin_port = socketPort; // store this device's sending socket so we can talk back to it - newDevice.sendingSocket = senderSocket; + ::lastDevice->sendingSocket = senderSocket; // push this new device into the vector printf("Adding device %s (%s) - %s:%d to list\n", - newDevice.identifier, - newDevice.name, + ::lastDevice->identifier, + ::lastDevice->name, deviceAddress, socketPort); - devices.push_back(newDevice); + if (::lastClient) { + sendLastClientToLastDevice(); + } } } else if (senderData[0] == 'F') { // this is a client looking to pair with a device // send the most recent device this address so it can attempt to pair - char requestorAddress[INET_ADDRSTRLEN] = {}; - int requestorPort = 0; + RequestingClient tempClient = {}; - int requestorMatches = sscanf(senderData, "Find %[^:]:%d", requestorAddress, &requestorPort); - printf("Find request from interface client at %s:%d\n", requestorAddress, requestorPort); + int requestorMatches = sscanf(senderData, "Find %[^:]:%d", + tempClient.address, + &tempClient.port); if (requestorMatches == 2) { - PairableDevice lastDevice = devices[devices.size() - 1]; + // good data, copy the tempClient to the persisting lastInterfaceClient + *::lastClient = tempClient; - char pairData[INET_ADDRSTRLEN + 6] = {}; - sprintf(pairData, "%s:%d", requestorAddress, requestorPort); + printf("Find request from interface client at %s:%d\n", + ::lastClient->address, + ::lastClient->port); - serverSocket.send((sockaddr*) &lastDevice.sendingSocket, pairData, strlen(pairData)); + if (::lastDevice) { + sendLastClientToLastDevice(); + } } } } From cc4492bad8088156fdc55b84473985b03da99891 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 13 May 2013 16:29:43 -0700 Subject: [PATCH 5/6] fix memory breakages after previous change --- pairing-server/src/main.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/pairing-server/src/main.cpp b/pairing-server/src/main.cpp index 3c7c24c141..96a4606eae 100644 --- a/pairing-server/src/main.cpp +++ b/pairing-server/src/main.cpp @@ -66,7 +66,7 @@ int main(int argc, const char* argv[]) { char deviceAddress[INET_ADDRSTRLEN] = {}; int socketPort = 0; - int numMatches = sscanf(senderData, "Available %s%[^:]:%d %s", + int numMatches = sscanf(senderData, "Available %s %[^:]:%d %s", tempDevice.identifier, deviceAddress, &socketPort, @@ -74,23 +74,24 @@ int main(int argc, const char* argv[]) { if (numMatches >= 3) { // if we have fewer than 3 matches the packet wasn't properly formatted - // otherwise copy the tempDevice to the persisting lastDevice - *::lastDevice = tempDevice; // setup the localSocket for the pairing device - ::lastDevice->localSocket.sin_family = AF_INET; + tempDevice.localSocket.sin_family = AF_INET; inet_pton(AF_INET, deviceAddress, &::lastDevice); - ::lastDevice->localSocket.sin_port = socketPort; + tempDevice.localSocket.sin_port = socketPort; // store this device's sending socket so we can talk back to it - ::lastDevice->sendingSocket = senderSocket; + tempDevice.sendingSocket = senderSocket; // push this new device into the vector - printf("Adding device %s (%s) - %s:%d to list\n", - ::lastDevice->identifier, - ::lastDevice->name, + printf("New last device is %s (%s) at %s:%d\n", + tempDevice.identifier, + tempDevice.name, deviceAddress, socketPort); + + // copy the tempDevice to the persisting lastDevice + ::lastDevice = new PairableDevice(tempDevice); if (::lastClient) { sendLastClientToLastDevice(); @@ -107,10 +108,10 @@ int main(int argc, const char* argv[]) { &tempClient.port); if (requestorMatches == 2) { - // good data, copy the tempClient to the persisting lastInterfaceClient - *::lastClient = tempClient; + // good data, copy the tempClient to the persisting lastInterfaceClient + ::lastClient = new RequestingClient(tempClient); - printf("Find request from interface client at %s:%d\n", + printf("New last client is at %s:%d\n", ::lastClient->address, ::lastClient->port); From 0b9b8a14d14b2763bbd08aa3b05f219b367eb453 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 13 May 2013 16:36:55 -0700 Subject: [PATCH 6/6] couple of type squishes --- pairing-server/src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pairing-server/src/main.cpp b/pairing-server/src/main.cpp index 96a4606eae..0422251403 100644 --- a/pairing-server/src/main.cpp +++ b/pairing-server/src/main.cpp @@ -30,8 +30,8 @@ struct RequestingClient { }; UDPSocket serverSocket(PAIRING_SERVER_LISTEN_PORT); -PairableDevice *lastDevice = NULL; -RequestingClient *lastClient = NULL; +PairableDevice* lastDevice = NULL; +RequestingClient* lastClient = NULL; int indexOfFirstOccurenceOfCharacter(char* haystack, char needle) { int currentIndex = 0; @@ -57,7 +57,7 @@ int main(int argc, const char* argv[]) { ssize_t receivedBytes = 0; while (true) { - if (::serverSocket.receive((sockaddr *)&senderSocket, &senderData, &receivedBytes)) { + if (::serverSocket.receive((sockaddr*) &senderSocket, &senderData, &receivedBytes)) { if (senderData[0] == 'A') { // this is a device reporting itself as available