5476 lines · 222.9 KB · C++
RawDownload
        PerformanceTimer perfTimer("devices");        DeviceTracker::updateAll();         FaceTracker* tracker = getSelectedFaceTracker();        if (tracker && Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking) != tracker->isMuted()) {            tracker->toggleMute();        }         tracker = getActiveFaceTracker();        if (tracker && !tracker->isMuted()) {            tracker->update(deltaTime);             // Auto-mute microphone after losing face tracking?            if (tracker->isTracking()) {                _lastFaceTrackerUpdate = usecTimestampNow();            } else {                const quint64 MUTE_MICROPHONE_AFTER_USECS = 5000000;  //5 secs                Menu* menu = Menu::getInstance();                if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !menu->isOptionChecked(MenuOption::MuteAudio)) {                    if (_lastFaceTrackerUpdate > 0                        && ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) {                        menu->triggerOption(MenuOption::MuteAudio);                        _lastFaceTrackerUpdate = 0;                    }                } else {                    _lastFaceTrackerUpdate = 0;                }            }        } else {            _lastFaceTrackerUpdate = 0;        }     }     auto myAvatar = getMyAvatar();    auto userInputMapper = DependencyManager::get<UserInputMapper>();     controller::InputCalibrationData calibrationData = {        myAvatar->getSensorToWorldMatrix(),        createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()),        myAvatar->getHMDSensorMatrix()    };     InputPluginPointer keyboardMousePlugin;    for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {        if (inputPlugin->getName() == KeyboardMouseDevice::NAME) {            keyboardMousePlugin = inputPlugin;        } else if (inputPlugin->isActive()) {            inputPlugin->pluginUpdate(deltaTime, calibrationData);        }    }     userInputMapper->update(deltaTime);     if (keyboardMousePlugin && keyboardMousePlugin->isActive()) {        keyboardMousePlugin->pluginUpdate(deltaTime, calibrationData);    }     _controllerScriptingInterface->updateInputControllers();     // Transfer the user inputs to the driveKeys    // FIXME can we drop drive keys and just have the avatar read the action states directly?    myAvatar->clearDriveKeys();    if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {        if (!_controllerScriptingInterface->areActionsCaptured()) {            myAvatar->setDriveKeys(TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z));            myAvatar->setDriveKeys(TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y));            myAvatar->setDriveKeys(TRANSLATE_X, userInputMapper->getActionState(controller::Action::TRANSLATE_X));            if (deltaTime > FLT_EPSILON) {                myAvatar->setDriveKeys(PITCH, -1.0f * userInputMapper->getActionState(controller::Action::PITCH));                myAvatar->setDriveKeys(YAW, -1.0f * userInputMapper->getActionState(controller::Action::YAW));                myAvatar->setDriveKeys(STEP_YAW, -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW));            }        }        myAvatar->setDriveKeys(ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z));    }     controller::Pose leftHandPose = userInputMapper->getPoseState(controller::Action::LEFT_HAND);    controller::Pose rightHandPose = userInputMapper->getPoseState(controller::Action::RIGHT_HAND);    auto myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition());    auto worldToSensorMatrix = glm::inverse(myAvatar->getSensorToWorldMatrix());    auto avatarToSensorMatrix = worldToSensorMatrix * myAvatarMatrix;    myAvatar->setHandControllerPosesInSensorFrame(leftHandPose.transform(avatarToSensorMatrix), rightHandPose.transform(avatarToSensorMatrix));     updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...    updateDialogs(deltaTime); // update various stats dialogs if present     QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();     if (_physicsEnabled) {        PROFILE_RANGE_EX("Physics", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());         PerformanceTimer perfTimer("physics");         {            PROFILE_RANGE_EX("UpdateStats", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());             PerformanceTimer perfTimer("updateStates)");            static VectorOfMotionStates motionStates;            _entitySimulation->getObjectsToRemoveFromPhysics(motionStates);            _physicsEngine->removeObjects(motionStates);            _entitySimulation->deleteObjectsRemovedFromPhysics();             getEntities()->getTree()->withReadLock([&] {                _entitySimulation->getObjectsToAddToPhysics(motionStates);                _physicsEngine->addObjects(motionStates);             });            getEntities()->getTree()->withReadLock([&] {                _entitySimulation->getObjectsToChange(motionStates);                VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates);                _entitySimulation->setObjectsToChange(stillNeedChange);            });             _entitySimulation->applyActionChanges();              avatarManager->getObjectsToRemoveFromPhysics(motionStates);            _physicsEngine->removeObjects(motionStates);            avatarManager->getObjectsToAddToPhysics(motionStates);            _physicsEngine->addObjects(motionStates);            avatarManager->getObjectsToChange(motionStates);            _physicsEngine->changeObjects(motionStates);             myAvatar->prepareForPhysicsSimulation();            _physicsEngine->forEachAction([&](EntityActionPointer action) {                action->prepareForPhysicsSimulation();            });        }        {            PROFILE_RANGE_EX("StepSimulation", 0xffff8000, (uint64_t)getActiveDisplayPlugin()->presentCount());            PerformanceTimer perfTimer("stepSimulation");            getEntities()->getTree()->withWriteLock([&] {                _physicsEngine->stepSimulation();            });        }        {            PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());            PerformanceTimer perfTimer("harvestChanges");            if (_physicsEngine->hasOutgoingChanges()) {                getEntities()->getTree()->withWriteLock([&] {                    PerformanceTimer perfTimer("handleOutgoingChanges");                    const VectorOfMotionStates& outgoingChanges = _physicsEngine->getOutgoingChanges();                    _entitySimulation->handleOutgoingChanges(outgoingChanges);                    avatarManager->handleOutgoingChanges(outgoingChanges);                });                 auto collisionEvents = _physicsEngine->getCollisionEvents();                avatarManager->handleCollisionEvents(collisionEvents);                 _physicsEngine->dumpStatsIfNecessary();                 if (!_aboutToQuit) {                    PerformanceTimer perfTimer("entities");                    // Collision events (and their scripts) must not be handled when we're locked, above. (That would risk                    // deadlock.)                    _entitySimulation->handleCollisionEvents(collisionEvents);                     // NOTE: the getEntities()->update() call below will wait for lock                    // and will simulate entity motion (the EntityTree has been given an EntitySimulation).                    getEntities()->update(); // update the models...                }                 myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);            }        }    }     // AvatarManager update    {        PerformanceTimer perfTimer("AvatarManger");        _avatarSimCounter.increment();         {            PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());            avatarManager->updateOtherAvatars(deltaTime);        }         qApp->updateMyAvatarLookAtPosition();         {            PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());            avatarManager->updateMyAvatar(deltaTime);        }    }     {        PROFILE_RANGE_EX("Overlays", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());        PerformanceTimer perfTimer("overlays");        _overlays.update(deltaTime);    }     // Update _viewFrustum with latest camera and view frustum data...    // NOTE: we get this from the view frustum, to make it simpler, since the    // loadViewFrumstum() method will get the correct details from the camera    // We could optimize this to not actually load the viewFrustum, since we don't    // actually need to calculate the view frustum planes to send these details    // to the server.    {        QMutexLocker viewLocker(&_viewMutex);        loadViewFrustum(_myCamera, _viewFrustum);    }     quint64 now = usecTimestampNow();     // Update my voxel servers with my current voxel query...    {        PROFILE_RANGE_EX("QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());        QMutexLocker viewLocker(&_viewMutex);        PerformanceTimer perfTimer("queryOctree");        quint64 sinceLastQuery = now - _lastQueriedTime;        const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND;        bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY;        bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum);        // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it        if (queryIsDue || viewIsDifferentEnough) {            _lastQueriedTime = now;            if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {                queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions);            }            _lastQueriedViewFrustum = _viewFrustum;        }    }     // sent nack packets containing missing sequence numbers of received packets from nodes    {        quint64 sinceLastNack = now - _lastNackTime;        const quint64 TOO_LONG_SINCE_LAST_NACK = 1 * USECS_PER_SECOND;        if (sinceLastNack > TOO_LONG_SINCE_LAST_NACK) {            _lastNackTime = now;            sendNackPackets();        }    }     // send packet containing downstream audio stats to the AudioMixer    {        quint64 sinceLastNack = now - _lastSendDownstreamAudioStats;        if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS) {            _lastSendDownstreamAudioStats = now;             QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection);        }    }     avatarManager->postUpdate(deltaTime);     {        PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, (uint64_t)0);         std::unique_lock<std::mutex> guard(_postUpdateLambdasLock);        for (auto& iter : _postUpdateLambdas) {            iter.second();        }        _postUpdateLambdas.clear();    }     AnimDebugDraw::getInstance().update();}  int Application::sendNackPackets() {     // iterates through all nodes in NodeList    auto nodeList = DependencyManager::get<NodeList>();     int packetsSent = 0;     nodeList->eachNode([&](const SharedNodePointer& node){         if (node->getActiveSocket() && node->getType() == NodeType::EntityServer) {             auto nackPacketList = NLPacketList::create(PacketType::OctreeDataNack);             QUuid nodeUUID = node->getUUID();             // if there are octree packets from this node that are waiting to be processed,            // don't send a NACK since the missing packets may be among those waiting packets.            if (_octreeProcessor.hasPacketsToProcessFrom(nodeUUID)) {                return;            }             QSet<OCTREE_PACKET_SEQUENCE> missingSequenceNumbers;            _octreeServerSceneStats.withReadLock([&] {                // retrieve octree scene stats of this node                if (_octreeServerSceneStats.find(nodeUUID) == _octreeServerSceneStats.end()) {                    return;                }                // get sequence number stats of node, prune its missing set, and make a copy of the missing set                SequenceNumberStats& sequenceNumberStats = _octreeServerSceneStats[nodeUUID].getIncomingOctreeSequenceNumberStats();                sequenceNumberStats.pruneMissingSet();                missingSequenceNumbers = sequenceNumberStats.getMissingSet();            });             // construct nack packet(s) for this node            foreach(const OCTREE_PACKET_SEQUENCE& missingNumber, missingSequenceNumbers) {                nackPacketList->writePrimitive(missingNumber);            }             if (nackPacketList->getNumPackets()) {                packetsSent += (int)nackPacketList->getNumPackets();                 // send the packet list                nodeList->sendPacketList(std::move(nackPacketList), *node);            }        }    });      return packetsSent;} void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions, bool forceResend) {     if (!_settingsLoaded) {        return; // bail early if settings are not loaded    }     //qCDebug(interfaceapp) << ">>> inside... queryOctree()... _viewFrustum.getFieldOfView()=" << _viewFrustum.getFieldOfView();    bool wantExtraDebugging = getLogger()->extraDebugging();     ViewFrustum viewFrustum;    copyViewFrustum(viewFrustum);    _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.setCameraCenterRadius(viewFrustum.getCenterRadius());    auto lodManager = DependencyManager::get<LODManager>();    _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale());    _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust());     // Iterate all of the nodes, and get a count of how many octree servers we have...    int totalServers = 0;    int inViewServers = 0;    int unknownJurisdictionServers = 0;     auto nodeList = DependencyManager::get<NodeList>();     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...            if (jurisdictions.find(nodeUUID) == jurisdictions.end()) {                unknownJurisdictionServers++;            } else {                const JurisdictionMap& map = (jurisdictions)[nodeUUID];                 auto rootCode = map.getRootOctalCode();                 if (rootCode) {                    VoxelPositionSize rootDetails;                    voxelDetailsForCode(rootCode.get(), rootDetails);                    AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE,                                                  rootDetails.y * TREE_SCALE,                                                  rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE),                                        rootDetails.s * TREE_SCALE);                    if (viewFrustum.cubeIntersectsKeyhole(serverBounds)) {                        inViewServers++;                    }                }            }        }    });     if (wantExtraDebugging) {        qCDebug(interfaceapp, "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 = getMaxOctreePacketsPerSecond();     // 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(interfaceapp, "perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer);    }     auto queryPacket = NLPacket::create(packetType);     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...            if (jurisdictions.find(nodeUUID) == jurisdictions.end()) {                unknownView = true; // assume it's in view                if (wantExtraDebugging) {                    qCDebug(interfaceapp) << "no known jurisdiction for node " << *node << ", assume it's visible.";                }            } else {                const JurisdictionMap& map = (jurisdictions)[nodeUUID];                 auto rootCode = map.getRootOctalCode();                 if (rootCode) {                    VoxelPositionSize rootDetails;                    voxelDetailsForCode(rootCode.get(), rootDetails);                    AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE,                                                  rootDetails.y * TREE_SCALE,                                                  rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE),                                        rootDetails.s * TREE_SCALE);                      inView = viewFrustum.cubeIntersectsKeyhole(serverBounds);                } else if (wantExtraDebugging) {                    qCDebug(interfaceapp) << "Jurisdiction without RootCode for node " << *node << ". That's unusual!";                }            }             if (inView) {                _octreeQuery.setMaxQueryPacketsPerSecond(perServerPPS);            } else if (unknownView) {                if (wantExtraDebugging) {                    qCDebug(interfaceapp) << "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(interfaceapp) << "Using 'minimal' camera position for node" << *node;                    }                } else {                    if (wantExtraDebugging) {                        qCDebug(interfaceapp) << "Using regular camera position for node" << *node;                    }                }                _octreeQuery.setMaxQueryPacketsPerSecond(perUnknownServer);            } else {                _octreeQuery.setMaxQueryPacketsPerSecond(0);            }             // if asked to forceResend, then set the query's position/orientation to be degenerate in a manner             // that will cause our next query to be guarenteed to be different and the server will resend to us            if (forceResend) {                _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);            }             // encode the query data            int packetSize = _octreeQuery.getBroadcastData(reinterpret_cast<unsigned char*>(queryPacket->getPayload()));            queryPacket->setPayloadSize(packetSize);             // make sure we still have an active socket            nodeList->sendUnreliablePacket(*queryPacket, *node);        }    });}  bool Application::isHMDMode() const {    return getActiveDisplayPlugin()->isHmd();} float Application::getTargetFrameRate() const { return getActiveDisplayPlugin()->getTargetFrameRate(); } QRect Application::getDesirableApplicationGeometry() const {    QRect applicationGeometry = getWindow()->geometry();     // If our parent window is on the HMD, then don't use its geometry, instead use    // the "main screen" geometry.    HMDToolsDialog* hmdTools = DependencyManager::get<DialogsManager>()->getHMDToolsDialog();    if (hmdTools && hmdTools->hasHMDScreen()) {

Lines 3501–4000 of 5476. Previous lines