From b19622738530be7b5212dda99d9e5cae2363ae75 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 13 May 2013 15:02:46 -0700 Subject: [PATCH] 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); + } } }