5476 lines · 222.9 KB · C++
RawDownload
            }             if (!givenOffset) {                EntityItemID parentID = entityItem->getParentID();                if (parentID.isInvalidID() || !entityIDs.contains(parentID) || !entityTree->findEntityByEntityItemID(parentID)) {                    auto position = entityItem->getPosition(); // If parent wasn't selected, we want absolute position, which isn't in properties.                    root.x = glm::min(root.x, position.x);                    root.y = glm::min(root.y, position.y);                    root.z = glm::min(root.z, position.z);                }            }            entities[entityID] = entityItem;        }         if (entities.size() == 0) {            success = false;            return;        }         if (givenOffset) {            root = *givenOffset;        }        for (EntityItemPointer& entityDatum : entities) {            auto properties = entityDatum->getProperties();            EntityItemID parentID = properties.getParentID();            if (parentID.isInvalidID()) {                properties.setPosition(properties.getPosition() - root);            }            else if (!entities.contains(parentID)) {                entityDatum->globalizeProperties(properties, "Parent %3 of %2 %1 is not selected for export.", -root);            } // else valid parent -- don't offset            exportTree->addEntity(entityDatum->getEntityItemID(), properties);        }    });    if (success) {        success = exportTree->writeToJSONFile(filename.toLocal8Bit().constData());         // restore the main window's active state        _window->activateWindow();    }    return success;} bool Application::exportEntities(const QString& filename, float x, float y, float z, float scale) {    glm::vec3 offset(x, y, z);    QVector<EntityItemPointer> entities;    QVector<EntityItemID> ids;    auto entityTree = getEntities()->getTree();    entityTree->withReadLock([&] {        entityTree->findEntities(AACube(offset, scale), entities);        foreach(EntityItemPointer entity, entities) {            ids << entity->getEntityItemID();        }    });    return exportEntities(filename, ids, &offset);} void Application::loadSettings() {     sessionRunTime.set(0); // Just clean living. We're about to saveSettings, which will update value.    DependencyManager::get<AudioClient>()->loadSettings();    DependencyManager::get<LODManager>()->loadSettings();     // DONT CHECK IN    //DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false);     Menu::getInstance()->loadSettings();    // If there is a preferred plugin, we probably messed it up with the menu settings, so fix it.    auto pluginManager = PluginManager::getInstance();    auto plugins = pluginManager->getPreferredDisplayPlugins();    for (auto plugin : plugins) {        auto menu = Menu::getInstance();        if (auto action = menu->getActionForOption(plugin->getName())) {            action->setChecked(true);            action->trigger();            // Find and activated highest priority plugin, bail for the rest            break;        }    }     auto inputs = pluginManager->getInputPlugins();    for (auto plugin : inputs) {        if (!plugin->isActive()) {            plugin->activate();        }    }     getMyAvatar()->loadData();     _settingsLoaded = true;} void Application::saveSettings() const {    sessionRunTime.set(_sessionRunTimer.elapsed() / MSECS_PER_SECOND);    DependencyManager::get<AudioClient>()->saveSettings();    DependencyManager::get<LODManager>()->saveSettings();     Menu::getInstance()->saveSettings();    getMyAvatar()->saveData();    PluginManager::getInstance()->saveSettings();} bool Application::importEntities(const QString& urlOrFilename) {    bool success = false;    _entityClipboard->withWriteLock([&] {        _entityClipboard->eraseAllOctreeElements();         success = _entityClipboard->readFromURL(urlOrFilename);        if (success) {            _entityClipboard->reaverageOctreeElements();        }    });    return success;} QVector<EntityItemID> Application::pasteEntities(float x, float y, float z) {    return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), x, y, z);} void Application::initDisplay() {} void Application::init() {    // Make sure Login state is up to date    DependencyManager::get<DialogsManager>()->toggleLoginDialog();     DependencyManager::get<DeferredLightingEffect>()->init();     DependencyManager::get<AvatarManager>()->init();    _myCamera.setMode(CAMERA_MODE_FIRST_PERSON);     _mirrorCamera.setMode(CAMERA_MODE_MIRROR);     _timerStart.start();    _lastTimeUpdated.start();     // when --url in command line, teleport to location    const QString HIFI_URL_COMMAND_LINE_KEY = "--url";    int urlIndex = arguments().indexOf(HIFI_URL_COMMAND_LINE_KEY);    QString addressLookupString;    if (urlIndex != -1) {        addressLookupString = arguments().value(urlIndex + 1);    }     Setting::Handle<bool> firstRun { Settings::firstRun, true };    if (addressLookupString.isEmpty() && firstRun.get()) {        qDebug() << "First run and no URL passed... attempting to go to Home or Entry...";        DependencyManager::get<AddressManager>()->ifLocalSandboxRunningElse([](){            qDebug() << "Home sandbox appears to be running, going to Home.";            DependencyManager::get<AddressManager>()->goToLocalSandbox();        },         [](){            qDebug() << "Home sandbox does not appear to be running, going to Entry.";            DependencyManager::get<AddressManager>()->goToEntry();        });    } else {        qDebug() << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString);        DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);    }     qCDebug(interfaceapp) << "Loaded settings";     Leapmotion::init();     // fire off an immediate domain-server check in now that settings are loaded    DependencyManager::get<NodeList>()->sendDomainServerCheckIn();     getEntities()->init();    {        QMutexLocker viewLocker(&_viewMutex);        getEntities()->setViewFrustum(_viewFrustum);    }     ObjectMotionState::setShapeManager(&_shapeManager);    _physicsEngine->init();     EntityTreePointer tree = getEntities()->getTree();    _entitySimulation->init(tree, _physicsEngine, &_entityEditSender);    tree->setSimulation(_entitySimulation);     auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();     // connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts    connect(_entitySimulation.get(), &EntitySimulation::entityCollisionWithEntity,            getEntities(), &EntityTreeRenderer::entityCollisionWithEntity);     // connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing    // of events related clicking, hovering over, and entering entities    getEntities()->connectSignalsToSlots(entityScriptingInterface.data());     _entityClipboardRenderer.init();    {        QMutexLocker viewLocker(&_viewMutex);        _entityClipboardRenderer.setViewFrustum(_viewFrustum);    }    _entityClipboardRenderer.setTree(_entityClipboard);     // Make sure any new sounds are loaded as soon as know about them.    connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) {        EntityTreePointer tree = getEntities()->getTree();        if (auto entity = tree->findEntityByEntityItemID(id)) {            auto sound = DependencyManager::get<SoundCache>()->getSound(newURL);            entity->setCollisionSound(sound);        }    }, Qt::QueuedConnection);    connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) {        if (auto avatar = getMyAvatar()) {            auto sound = DependencyManager::get<SoundCache>()->getSound(newURL);            avatar->setCollisionSound(sound);        }    }, Qt::QueuedConnection);} void Application::updateLOD() const {    PerformanceTimer perfTimer("LOD");    // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode    if (!isThrottleRendering()) {        DependencyManager::get<LODManager>()->autoAdjustLOD(_frameCounter.rate());    } else {        DependencyManager::get<LODManager>()->resetLODAdjust();    }} void Application::pushPostUpdateLambda(void* key, std::function<void()> func) {    std::unique_lock<std::mutex> guard(_postUpdateLambdasLock);    _postUpdateLambdas[key] = func;} // Called during Application::update immediately before AvatarManager::updateMyAvatar, updating my data that is then sent to everyone.// (Maybe this code should be moved there?)// The principal result is to call updateLookAtTargetAvatar() and then setLookAtPosition().// Note that it is called BEFORE we update position or joints based on sensors, etc.void Application::updateMyAvatarLookAtPosition() {    PerformanceTimer perfTimer("lookAt");    bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);    PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()");     auto myAvatar = getMyAvatar();    myAvatar->updateLookAtTargetAvatar();    FaceTracker* faceTracker = getActiveFaceTracker();    auto eyeTracker = DependencyManager::get<EyeTracker>();     bool isLookingAtSomeone = false;    bool isHMD = qApp->isHMDMode();    glm::vec3 lookAtSpot;    if (eyeTracker->isTracking() && (isHMD || eyeTracker->isSimulating())) {        //  Look at the point that the user is looking at.        glm::vec3 lookAtPosition = eyeTracker->getLookAtPosition();        if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {            lookAtPosition.x = -lookAtPosition.x;        }        if (isHMD) {            glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose();            glm::quat hmdRotation = glm::quat_cast(headPose);            lookAtSpot = _myCamera.getPosition() + myAvatar->getOrientation() * (hmdRotation * lookAtPosition);        } else {            lookAtSpot = myAvatar->getHead()->getEyePosition()                + (myAvatar->getHead()->getFinalOrientationInWorldFrame() * lookAtPosition);        }    } else {        AvatarSharedPointer lookingAt = myAvatar->getLookAtTargetAvatar().lock();        if (lookingAt && myAvatar != lookingAt.get()) {            //  If I am looking at someone else, look directly at one of their eyes            isLookingAtSomeone = true;            auto lookingAtHead = static_pointer_cast<Avatar>(lookingAt)->getHead();             const float MAXIMUM_FACE_ANGLE = 65.0f * RADIANS_PER_DEGREE;            glm::vec3 lookingAtFaceOrientation = lookingAtHead->getFinalOrientationInWorldFrame() * IDENTITY_FRONT;            glm::vec3 fromLookingAtToMe = glm::normalize(myAvatar->getHead()->getEyePosition()                - lookingAtHead->getEyePosition());            float faceAngle = glm::angle(lookingAtFaceOrientation, fromLookingAtToMe);             if (faceAngle < MAXIMUM_FACE_ANGLE) {                // Randomly look back and forth between look targets                eyeContactTarget target = Menu::getInstance()->isOptionChecked(MenuOption::FixGaze) ?                LEFT_EYE : myAvatar->getEyeContactTarget();                switch (target) {                    case LEFT_EYE:                        lookAtSpot = lookingAtHead->getLeftEyePosition();                        break;                    case RIGHT_EYE:                        lookAtSpot = lookingAtHead->getRightEyePosition();                        break;                    case MOUTH:                        lookAtSpot = lookingAtHead->getMouthPosition();                        break;                }            } else {                // Just look at their head (mid point between eyes)                lookAtSpot = lookingAtHead->getEyePosition();            }        } else {            //  I am not looking at anyone else, so just look forward            if (isHMD) {                glm::mat4 worldHMDMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();                lookAtSpot = transformPoint(worldHMDMat, glm::vec3(0.0f, 0.0f, -TREE_SCALE));            } else {                lookAtSpot = myAvatar->getHead()->getEyePosition() +                    (myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE));            }        }         // Deflect the eyes a bit to match the detected gaze from the face tracker if active.        if (faceTracker && !faceTracker->isMuted()) {            float eyePitch = faceTracker->getEstimatedEyePitch();            float eyeYaw = faceTracker->getEstimatedEyeYaw();            const float GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT = 0.1f;            glm::vec3 origin = myAvatar->getHead()->getEyePosition();            float deflection = faceTracker->getEyeDeflection();            if (isLookingAtSomeone) {                deflection *= GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT;            }            lookAtSpot = origin + _myCamera.getOrientation() * glm::quat(glm::radians(glm::vec3(                eyePitch * deflection, eyeYaw * deflection, 0.0f))) *                glm::inverse(_myCamera.getOrientation()) * (lookAtSpot - origin);        }    }     myAvatar->getHead()->setLookAtPosition(lookAtSpot);} void Application::updateThreads(float deltaTime) {    PerformanceTimer perfTimer("updateThreads");    bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);    PerformanceWarning warn(showWarnings, "Application::updateThreads()");     // parse voxel packets    if (!_enableProcessOctreeThread) {        _octreeProcessor.threadRoutine();        _entityEditSender.threadRoutine();    }} void Application::toggleOverlays() {    auto menu = Menu::getInstance();    menu->setIsOptionChecked(MenuOption::Overlays, menu->isOptionChecked(MenuOption::Overlays));} void Application::setOverlaysVisible(bool visible) {    auto menu = Menu::getInstance();    menu->setIsOptionChecked(MenuOption::Overlays, true);} void Application::cycleCamera() {    auto menu = Menu::getInstance();    if (menu->isOptionChecked(MenuOption::FullscreenMirror)) {         menu->setIsOptionChecked(MenuOption::FullscreenMirror, false);        menu->setIsOptionChecked(MenuOption::FirstPerson, true);     } else if (menu->isOptionChecked(MenuOption::FirstPerson)) {         menu->setIsOptionChecked(MenuOption::FirstPerson, false);        menu->setIsOptionChecked(MenuOption::ThirdPerson, true);     } else if (menu->isOptionChecked(MenuOption::ThirdPerson)) {         menu->setIsOptionChecked(MenuOption::ThirdPerson, false);        menu->setIsOptionChecked(MenuOption::FullscreenMirror, true);     } else if (menu->isOptionChecked(MenuOption::IndependentMode) || menu->isOptionChecked(MenuOption::CameraEntityMode)) {        // do nothing if in independent or camera entity modes        return;    }    cameraMenuChanged(); // handle the menu change} void Application::cameraMenuChanged() {    if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {        if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {            _myCamera.setMode(CAMERA_MODE_MIRROR);        }    } else if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) {        if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) {            _myCamera.setMode(CAMERA_MODE_FIRST_PERSON);            getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN);        }    } else if (Menu::getInstance()->isOptionChecked(MenuOption::ThirdPerson)) {        if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {            _myCamera.setMode(CAMERA_MODE_THIRD_PERSON);            if (getMyAvatar()->getBoomLength() == MyAvatar::ZOOM_MIN) {                getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT);            }        }    } else if (Menu::getInstance()->isOptionChecked(MenuOption::IndependentMode)) {        if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {            _myCamera.setMode(CAMERA_MODE_INDEPENDENT);        }    } else if (Menu::getInstance()->isOptionChecked(MenuOption::CameraEntityMode)) {        if (_myCamera.getMode() != CAMERA_MODE_ENTITY) {            _myCamera.setMode(CAMERA_MODE_ENTITY);        }    }} void Application::resetPhysicsReadyInformation() {    // we've changed domains or cleared out caches or something.  we no longer know enough about the    // collision information of nearby entities to make running bullet be safe.    _fullSceneReceivedCounter = 0;    _fullSceneCounterAtLastPhysicsCheck = 0;    _nearbyEntitiesCountAtLastPhysicsCheck = 0;    _nearbyEntitiesStabilityCount = 0;    _physicsEnabled = false;}  void Application::reloadResourceCaches() {    resetPhysicsReadyInformation();    {        QMutexLocker viewLocker(&_viewMutex);        _viewFrustum.setPosition(glm::vec3(0.0f, 0.0f, TREE_SCALE));        _viewFrustum.setOrientation(glm::quat());    }    // Clear entities out of view frustum    queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions);     DependencyManager::get<AssetClient>()->clearCache();     DependencyManager::get<AnimationCache>()->refreshAll();    DependencyManager::get<ModelCache>()->refreshAll();    DependencyManager::get<SoundCache>()->refreshAll();    DependencyManager::get<TextureCache>()->refreshAll();     DependencyManager::get<NodeList>()->reset();  // Force redownload of .fst models     getMyAvatar()->resetFullAvatarURL();} void Application::rotationModeChanged() const {    if (!Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {        getMyAvatar()->setHeadPitch(0);    }} void Application::updateDialogs(float deltaTime) const {    PerformanceTimer perfTimer("updateDialogs");    bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);    PerformanceWarning warn(showWarnings, "Application::updateDialogs()");    auto dialogsManager = DependencyManager::get<DialogsManager>();     // Update audio stats dialog, if any    AudioStatsDialog* audioStatsDialog = dialogsManager->getAudioStatsDialog();    if(audioStatsDialog) {        audioStatsDialog->update();    }     // Update bandwidth dialog, if any    BandwidthDialog* bandwidthDialog = dialogsManager->getBandwidthDialog();    if (bandwidthDialog) {        bandwidthDialog->update();    }     QPointer<OctreeStatsDialog> octreeStatsDialog = dialogsManager->getOctreeStatsDialog();    if (octreeStatsDialog) {        octreeStatsDialog->update();    }} void Application::update(float deltaTime) {     PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, (uint64_t)_frameCount + 1);     bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);    PerformanceWarning warn(showWarnings, "Application::update()");     updateLOD();     if (!_physicsEnabled) {        // we haven't yet enabled physics.  we wait until we think we have all the collision information        // for nearby entities before starting bullet up.        quint64 now = usecTimestampNow();        bool timeout = false;        const int PHYSICS_CHECK_TIMEOUT = 2 * USECS_PER_SECOND;        if (_lastPhysicsCheckTime > 0 && now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT) {            timeout = true;        }         if (timeout || _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) {            // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway            _lastPhysicsCheckTime = now;            _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter;             // process octree stats packets are sent in between full sends of a scene (this isn't currently true).            // We keep physics disabled until we've received a full scene and everything near the avatar in that            // scene is ready to compute its collision shape.            if (nearbyEntitiesAreReadyForPhysics()) {                _physicsEnabled = true;                getMyAvatar()->updateMotionBehaviorFromMenu();            } else {                auto characterController = getMyAvatar()->getCharacterController();                if (characterController) {                    // if we have a character controller, disable it here so the avatar doesn't get stuck due to                    // a non-loading collision hull.                    characterController->setEnabled(false);                }            }        }    }     {

Lines 3001–3500 of 5476. Previous lines