diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 79f2e3be43..7cf586cbb2 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -7,6 +7,8 @@ // // +#include + #include "OctreeHeadlessViewer.h" OctreeHeadlessViewer::OctreeHeadlessViewer() : @@ -21,3 +23,181 @@ void OctreeHeadlessViewer::init() { setViewFrustum(&_viewFrustum); } +void OctreeHeadlessViewer::queryOctree() { + NodeType_t serverType = getMyNodeType(); + PacketType packetType = getMyQueryMessageType(); + NodeToJurisdictionMap& jurisdictions = *_jurisdictionListener->getJurisdictions(); + + bool wantExtraDebugging = false; + + // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. + _octreeQuery.setWantLowResMoving(true); + _octreeQuery.setWantColor(true); + _octreeQuery.setWantDelta(true); + _octreeQuery.setWantOcclusionCulling(false); + _octreeQuery.setWantCompression(true); // TODO: should be on by default + + _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); + _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); + _octreeQuery.setCameraFov(_viewFrustum.getFieldOfView()); + _octreeQuery.setCameraAspectRatio(_viewFrustum.getAspectRatio()); + _octreeQuery.setCameraNearClip(_viewFrustum.getNearClip()); + _octreeQuery.setCameraFarClip(_viewFrustum.getFarClip()); + _octreeQuery.setCameraEyeOffsetPosition(_viewFrustum.getEyeOffsetPosition()); + _octreeQuery.setOctreeSizeScale(getVoxelSizeScale()); + _octreeQuery.setBoundaryLevelAdjust(getBoundaryLevelAdjust()); + + unsigned char queryPacket[MAX_PACKET_SIZE]; + + // Iterate all of the nodes, and get a count of how many voxel servers we have... + int totalServers = 0; + int inViewServers = 0; + int unknownJurisdictionServers = 0; + + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + // only send to the NodeTypes that are serverType + if (node->getActiveSocket() != NULL && node->getType() == serverType) { + totalServers++; + + // get the server bounds for this server + QUuid nodeUUID = node->getUUID(); + + // if we haven't heard from this voxel server, go ahead and send it a query, so we + // can get the jurisdiction... + if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { + unknownJurisdictionServers++; + } else { + const JurisdictionMap& map = (jurisdictions)[nodeUUID]; + + unsigned char* rootCode = map.getRootOctalCode(); + + if (rootCode) { + VoxelPositionSize rootDetails; + voxelDetailsForCode(rootCode, rootDetails); + AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + serverBounds.scale(TREE_SCALE); + + ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds); + + if (serverFrustumLocation != ViewFrustum::OUTSIDE) { + inViewServers++; + } + } + } + } + } + + if (wantExtraDebugging && unknownJurisdictionServers > 0) { + qDebug("Servers: total %d, in view %d, unknown jurisdiction %d", + totalServers, inViewServers, unknownJurisdictionServers); + } + + int perServerPPS = 0; + const int SMALL_BUDGET = 10; + int perUnknownServer = SMALL_BUDGET; + int totalPPS = getMaxPacketsPerSecond(); + + // determine PPS based on number of servers + if (inViewServers >= 1) { + // set our preferred PPS to be exactly evenly divided among all of the voxel servers... and allocate 1 PPS + // for each unknown jurisdiction server + perServerPPS = (totalPPS / inViewServers) - (unknownJurisdictionServers * perUnknownServer); + } else { + if (unknownJurisdictionServers > 0) { + perUnknownServer = (totalPPS / unknownJurisdictionServers); + } + } + + if (wantExtraDebugging && unknownJurisdictionServers > 0) { + qDebug("perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer); + } + + NodeList* nodeList = NodeList::getInstance(); + + foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { + // only send to the NodeTypes that are serverType + if (node->getActiveSocket() != NULL && node->getType() == serverType) { + + + // get the server bounds for this server + QUuid nodeUUID = node->getUUID(); + + bool inView = false; + bool unknownView = false; + + // if we haven't heard from this voxel server, go ahead and send it a query, so we + // can get the jurisdiction... + if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { + unknownView = true; // assume it's in view + if (wantExtraDebugging) { + qDebug() << "no known jurisdiction for node " << *node << ", assume it's visible."; + } + } else { + const JurisdictionMap& map = (jurisdictions)[nodeUUID]; + + unsigned char* rootCode = map.getRootOctalCode(); + + if (rootCode) { + VoxelPositionSize rootDetails; + voxelDetailsForCode(rootCode, rootDetails); + AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + serverBounds.scale(TREE_SCALE); + + ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds); + if (serverFrustumLocation != ViewFrustum::OUTSIDE) { + inView = true; + } else { + inView = false; + } + } else { + if (wantExtraDebugging) { + qDebug() << "Jurisdiction without RootCode for node " << *node << ". That's unusual!"; + } + } + } + + if (inView) { + _octreeQuery.setMaxOctreePacketsPerSecond(perServerPPS); + } else if (unknownView) { + if (wantExtraDebugging) { + qDebug() << "no known jurisdiction for node " << *node << ", give it budget of " + << perUnknownServer << " to send us jurisdiction."; + } + + // set the query's position/orientation to be degenerate in a manner that will get the scene quickly + // If there's only one server, then don't do this, and just let the normal voxel query pass through + // as expected... this way, we will actually get a valid scene if there is one to be seen + if (totalServers > 1) { + _octreeQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1)); + const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0); + _octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE); + _octreeQuery.setCameraNearClip(0.1f); + _octreeQuery.setCameraFarClip(0.1f); + if (wantExtraDebugging) { + qDebug() << "Using 'minimal' camera position for node" << *node; + } + } else { + if (wantExtraDebugging) { + qDebug() << "Using regular camera position for node" << *node; + } + } + _octreeQuery.setMaxOctreePacketsPerSecond(perUnknownServer); + } else { + _octreeQuery.setMaxOctreePacketsPerSecond(0); + } + // set up the packet for sending... + unsigned char* endOfQueryPacket = queryPacket; + + // insert packet type/version and node UUID + endOfQueryPacket += populatePacketHeader(reinterpret_cast(endOfQueryPacket), packetType); + + // encode the query data... + endOfQueryPacket += _octreeQuery.getBroadcastData(endOfQueryPacket); + + int packetLength = endOfQueryPacket - queryPacket; + + // make sure we still have an active socket + nodeList->writeDatagram(reinterpret_cast(queryPacket), packetLength, node); + } + } +} diff --git a/libraries/octree/src/OctreeHeadlessViewer.h b/libraries/octree/src/OctreeHeadlessViewer.h index 54e4a01043..c178c2b7c8 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.h +++ b/libraries/octree/src/OctreeHeadlessViewer.h @@ -12,7 +12,9 @@ #include #include +#include "JurisdictionListener.h" #include "Octree.h" +#include "OctreeQuery.h" #include "OctreeRenderer.h" #include "Octree.h" #include "ViewFrustum.h" @@ -27,8 +29,23 @@ public: virtual void init(); virtual void render() { /* swallow these */ }; + + void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; } + void queryOctree(); + + void setVoxelSizeScale(float sizeScale); + float getVoxelSizeScale() const { return _voxelSizeScale; } + void setBoundaryLevelAdjust(int boundaryLevelAdjust); + int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } + int getMaxPacketsPerSecond() const { return _maxTotalPPS; } + private: ViewFrustum _viewFrustum; + JurisdictionListener* _jurisdictionListener; + OctreeQuery _octreeQuery; + float _voxelSizeScale; + int _boundaryLevelAdjust; + int _maxTotalPPS; }; #endif /* defined(__hifi__OctreeHeadlessViewer__) */ \ No newline at end of file