Exemple #1
0
void NodeBounds::draw() {
    if (!(_showVoxelNodes || _showModelNodes || _showParticleNodes)) {
        _overlayText[0] = '\0';
        return;
    }

    NodeToJurisdictionMap& voxelServerJurisdictions = Application::getInstance()->getVoxelServerJurisdictions();
    NodeToJurisdictionMap& modelServerJurisdictions = Application::getInstance()->getModelServerJurisdictions();
    NodeToJurisdictionMap& particleServerJurisdictions = Application::getInstance()->getParticleServerJurisdictions();
    NodeToJurisdictionMap* serverJurisdictions;

    // Compute ray to find selected nodes later on.  We can't use the pre-computed ray in Application because it centers
    // itself after the cursor disappears.
    Application* application = Application::getInstance();
    QGLWidget* glWidget = application->getGLWidget();
    float mouseX = application->getMouseX() / (float)glWidget->width();
    float mouseY = application->getMouseY() / (float)glWidget->height();
    glm::vec3 mouseRayOrigin;
    glm::vec3 mouseRayDirection;
    application->getViewFrustum()->computePickRay(mouseX, mouseY, mouseRayOrigin, mouseRayDirection);

    // Variables to keep track of the selected node and properties to draw the cube later if needed
    Node* selectedNode = NULL;
    float selectedDistance = FLT_MAX;
    bool selectedIsInside = true;
    glm::vec3 selectedCenter;
    float selectedScale = 0;

    NodeList* nodeList = NodeList::getInstance();

    foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
        NodeType_t nodeType = node->getType();

        if (nodeType == NodeType::VoxelServer && _showVoxelNodes) {
            serverJurisdictions = &voxelServerJurisdictions;
        } else if (nodeType == NodeType::ModelServer && _showModelNodes) {
            serverJurisdictions = &modelServerJurisdictions;
        } else if (nodeType == NodeType::ParticleServer && _showParticleNodes) {
            serverJurisdictions = &particleServerJurisdictions;
        } else {
            continue;
        }

        QUuid nodeUUID = node->getUUID();
        if (serverJurisdictions->find(nodeUUID) != serverJurisdictions->end()) {
            const JurisdictionMap& map = serverJurisdictions->value(nodeUUID);

            unsigned char* rootCode = map.getRootOctalCode();

            if (rootCode) {
                VoxelPositionSize rootDetails;
                voxelDetailsForCode(rootCode, rootDetails);
                glm::vec3 location(rootDetails.x, rootDetails.y, rootDetails.z);
                location *= (float)TREE_SCALE;

                AABox serverBounds(location, rootDetails.s * TREE_SCALE);

                glm::vec3 center = serverBounds.getVertex(BOTTOM_RIGHT_NEAR)
                    + ((serverBounds.getVertex(TOP_LEFT_FAR) - serverBounds.getVertex(BOTTOM_RIGHT_NEAR)) / 2.0f);

                const float VOXEL_NODE_SCALE = 1.00f;
                const float MODEL_NODE_SCALE = 0.99f;
                const float PARTICLE_NODE_SCALE = 0.98f;

                float scaleFactor = rootDetails.s * TREE_SCALE;

                // Scale by 0.92 - 1.00 depending on the scale of the node.  This allows smaller nodes to scale in
                // a bit and not overlap larger nodes.
                scaleFactor *= 0.92 + (rootDetails.s * 0.08);

                // Scale different node types slightly differently because it's common for them to overlap.
                if (nodeType == NodeType::VoxelServer) {
                    scaleFactor *= VOXEL_NODE_SCALE;
                } else if (nodeType == NodeType::ModelServer) {
                    scaleFactor *= MODEL_NODE_SCALE;
                } else {
                    scaleFactor *= PARTICLE_NODE_SCALE;
                }

                float red, green, blue;
                getColorForNodeType(nodeType, red, green, blue);
                drawNodeBorder(center, scaleFactor, red, green, blue);

                float distance;
                BoxFace face;
                bool inside = serverBounds.contains(mouseRayOrigin);
                bool colliding = serverBounds.findRayIntersection(mouseRayOrigin, mouseRayDirection, distance, face);

                // If the camera is inside a node it will be "selected" if you don't have your cursor over another node
                // that you aren't inside.
                if (colliding && (!selectedNode || (!inside && (distance < selectedDistance || selectedIsInside)))) {
                    selectedNode = node.data();
                    selectedDistance = distance;
                    selectedIsInside = inside;
                    selectedCenter = center;
                    selectedScale = scaleFactor;
                }
            }
        }
    }

    if (selectedNode) {
        glPushMatrix();

        glTranslatef(selectedCenter.x, selectedCenter.y, selectedCenter.z);
        glScalef(selectedScale, selectedScale, selectedScale);

        NodeType_t selectedNodeType = selectedNode->getType();
        float red, green, blue;
        getColorForNodeType(selectedNode->getType(), red, green, blue);

        glColor4f(red, green, blue, 0.2);
        glutSolidCube(1.0);

        glPopMatrix();

        HifiSockAddr addr = selectedNode->getPublicSocket();
        QString overlay = QString("%1:%2  %3ms")
            .arg(addr.getAddress().toString())
            .arg(addr.getPort())
            .arg(selectedNode->getPingMs())
            .left(MAX_OVERLAY_TEXT_LENGTH);

        // Ideally we'd just use a QString, but I ran into weird blinking issues using
        // constData() directly, as if the data was being overwritten.
        strcpy(_overlayText, overlay.toLocal8Bit().constData());
    } else {
        _overlayText[0] = '\0';
    }
}
void OctreeHeadlessViewer::queryOctree() {
    char serverType = getMyNodeType();
    PacketType packetType = getMyQueryMessageType();
    NodeToJurisdictionMap& jurisdictions = *_jurisdictionListener->getJurisdictions();

    bool wantExtraDebugging = false;

    if (wantExtraDebugging) {
        qCDebug(octree) << "OctreeHeadlessViewer::queryOctree() _jurisdictionListener=" << _jurisdictionListener;
        qCDebug(octree) << "---------------";
        qCDebug(octree) << "_jurisdictionListener=" << _jurisdictionListener;
        qCDebug(octree) << "Jurisdictions...";
        jurisdictions.lockForRead();
        for (NodeToJurisdictionMapIterator i = jurisdictions.begin(); i != jurisdictions.end(); ++i) {
            qCDebug(octree) << i.key() << ": " << &i.value();
        }
        jurisdictions.unlock();
        qCDebug(octree) << "---------------";
    }

    // 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(glm::vec3());

    _octreeQuery.setOctreeSizeScale(getVoxelSizeScale());
    _octreeQuery.setBoundaryLevelAdjust(getBoundaryLevelAdjust());

    // 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;

    DependencyManager::get<NodeList>()->eachNode([&](const SharedNodePointer& node){
        // only send to the NodeTypes that are serverType
        if (node->getActiveSocket() && 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...
            jurisdictions.lockForRead();
            if (jurisdictions.find(nodeUUID) == jurisdictions.end()) {
                jurisdictions.unlock();
                unknownJurisdictionServers++;
            } else {
                const JurisdictionMap& map = (jurisdictions)[nodeUUID];

                unsigned char* rootCode = map.getRootOctalCode();

                if (rootCode) {
                    VoxelPositionSize rootDetails;
                    voxelDetailsForCode(rootCode, rootDetails);
                    jurisdictions.unlock();
                    AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);

                    ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds);

                    if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
                        inViewServers++;
                    }
                } else {
                    jurisdictions.unlock();
                }
            }
        }
    });

    if (wantExtraDebugging) {
        qCDebug(octree, "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) {
        qCDebug(octree, "perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer);
    }

    auto nodeList = DependencyManager::get<NodeList>();
    nodeList->eachNode([&](const SharedNodePointer& node){
        // only send to the NodeTypes that are serverType
        if (node->getActiveSocket() && 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...
            jurisdictions.lockForRead();
            if (jurisdictions.find(nodeUUID) == jurisdictions.end()) {
                jurisdictions.unlock();
                unknownView = true; // assume it's in view
                if (wantExtraDebugging) {
                    qCDebug(octree) << "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);
                    jurisdictions.unlock();
                    AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);

                    ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds);
                    if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
                        inView = true;
                    } else {
                        inView = false;
                    }
                } else {
                    jurisdictions.unlock();
                    if (wantExtraDebugging) {
                        qCDebug(octree) << "Jurisdiction without RootCode for node " << *node << ". That's unusual!";
                    }
                }
            }

            if (inView) {
                _octreeQuery.setMaxQueryPacketsPerSecond(perServerPPS);
                if (wantExtraDebugging) {
                    qCDebug(octree) << "inView for node " << *node << ", give it budget of " << perServerPPS;
                }
            } else if (unknownView) {
                if (wantExtraDebugging) {
                    qCDebug(octree) << "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) {
                        qCDebug(octree) << "Using 'minimal' camera position for node" << *node;
                    }
                } else {
                    if (wantExtraDebugging) {
                        qCDebug(octree) << "Using regular camera position for node" << *node;
                    }
                }
                _octreeQuery.setMaxQueryPacketsPerSecond(perUnknownServer);
            } else {
                _octreeQuery.setMaxQueryPacketsPerSecond(0);
            }

            // setup the query packet
            auto queryPacket = NLPacket::create(packetType);
            _octreeQuery.getBroadcastData(reinterpret_cast<unsigned char*>(queryPacket->getPayload()));

            // ask the NodeList to send it
            nodeList->sendPacket(std::move(queryPacket), *node);
        }
    });
}
Exemple #3
0
void NodeBounds::draw() {
    if (!_showEntityNodes) {
        _overlayText[0] = '\0';
        return;
    }

    NodeToJurisdictionMap& entityServerJurisdictions = Application::getInstance()->getEntityServerJurisdictions();
    NodeToJurisdictionMap* serverJurisdictions;

    // Compute ray to find selected nodes later on.  We can't use the pre-computed ray in Application because it centers
    // itself after the cursor disappears.
    Application* application = Application::getInstance();
    PickRay pickRay = application->getCamera()->computePickRay(application->getTrueMouseX(),
                                                               application->getTrueMouseY());

    // Variables to keep track of the selected node and properties to draw the cube later if needed
    Node* selectedNode = NULL;
    float selectedDistance = FLT_MAX;
    bool selectedIsInside = true;
    glm::vec3 selectedCenter;
    float selectedScale = 0;

    auto nodeList = DependencyManager::get<NodeList>();
    nodeList->eachNode([&](const SharedNodePointer& node){
        NodeType_t nodeType = node->getType();
        
        if (nodeType == NodeType::EntityServer && _showEntityNodes) {
            serverJurisdictions = &entityServerJurisdictions;
        } else {
            return;
        }
        
        QUuid nodeUUID = node->getUUID();
        serverJurisdictions->lockForRead();
        if (serverJurisdictions->find(nodeUUID) != serverJurisdictions->end()) {
            const JurisdictionMap& map = (*serverJurisdictions)[nodeUUID];
            
            unsigned char* rootCode = map.getRootOctalCode();
            
            if (rootCode) {
                VoxelPositionSize rootDetails;
                voxelDetailsForCode(rootCode, rootDetails);
                serverJurisdictions->unlock();
                glm::vec3 location(rootDetails.x, rootDetails.y, rootDetails.z);
                
                AACube serverBounds(location, rootDetails.s);
                
                glm::vec3 center = serverBounds.getVertex(BOTTOM_RIGHT_NEAR)
                + ((serverBounds.getVertex(TOP_LEFT_FAR) - serverBounds.getVertex(BOTTOM_RIGHT_NEAR)) / 2.0f);
                
                const float ENTITY_NODE_SCALE = 0.99f;
                
                float scaleFactor = rootDetails.s;
                
                // Scale by 0.92 - 1.00 depending on the scale of the node.  This allows smaller nodes to scale in
                // a bit and not overlap larger nodes.
                scaleFactor *= 0.92f + (rootDetails.s * 0.08f);
                
                // Scale different node types slightly differently because it's common for them to overlap.
                if (nodeType == NodeType::EntityServer) {
                    scaleFactor *= ENTITY_NODE_SCALE;
                }
                
                float red, green, blue;
                getColorForNodeType(nodeType, red, green, blue);
                drawNodeBorder(center, scaleFactor, red, green, blue);
                
                float distance;
                BoxFace face;
                
                bool inside = serverBounds.contains(pickRay.origin);
                bool colliding = serverBounds.findRayIntersection(pickRay.origin, pickRay.direction, distance, face);

                // If the camera is inside a node it will be "selected" if you don't have your cursor over another node
                // that you aren't inside.
                if (colliding && (!selectedNode || (!inside && (distance < selectedDistance || selectedIsInside)))) {
                    selectedNode = node.data();
                    selectedDistance = distance;
                    selectedIsInside = inside;
                    selectedCenter = center;
                    selectedScale = scaleFactor;
                }
            } else {
                serverJurisdictions->unlock();
            }
        } else {
            serverJurisdictions->unlock();
        }
    });

    if (selectedNode) {
        glPushMatrix();

        glTranslatef(selectedCenter.x, selectedCenter.y, selectedCenter.z);
        glScalef(selectedScale, selectedScale, selectedScale);

        float red, green, blue;
        getColorForNodeType(selectedNode->getType(), red, green, blue);

        DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(red, green, blue, 0.2f));

        glPopMatrix();

        HifiSockAddr addr = selectedNode->getPublicSocket();
        QString overlay = QString("%1:%2  %3ms")
            .arg(addr.getAddress().toString())
            .arg(addr.getPort())
            .arg(selectedNode->getPingMs())
            .left(MAX_OVERLAY_TEXT_LENGTH);

        // Ideally we'd just use a QString, but I ran into weird blinking issues using
        // constData() directly, as if the data was being overwritten.
        strcpy(_overlayText, overlay.toLocal8Bit().constData());
    } else {
        _overlayText[0] = '\0';
    }
}