5129 lines · 206.9 KB · C++
RawDownload
////  Application.cpp//  interface/src////  Created by Andrzej Kapolka on 5/10/13.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "Application.h" #include <glm/glm.hpp>#include <glm/gtx/component_wise.hpp>#include <glm/gtx/quaternion.hpp>#include <glm/gtx/vector_angle.hpp>#include <glm/gtc/type_ptr.hpp> #include <QtCore/QDebug>#include <QtCore/QObject>#include <QtCore/QUrl>#include <QtCore/QTimer>#include <QtCore/QAbstractNativeEventFilter>#include <QtCore/QMimeData> #include <QtGui/QScreen>#include <QtGui/QImage>#include <QtGui/QWheelEvent>#include <QtGui/QWindow>#include <QtQml/QQmlContext>#include <QtGui/QKeyEvent>#include <QtGui/QMouseEvent>#include <QtGui/QDesktopServices> #include <QtWidgets/QActionGroup>#include <QtWidgets/QDesktopWidget>#include <QtWidgets/QFileDialog>#include <QtWidgets/QInputDialog>#include <QtWidgets/QMenuBar>#include <QtWidgets/QMessageBox> #include <QtMultimedia/QMediaPlayer> #include <QtNetwork/QNetworkDiskCache> #include <AccountManager.h>#include <AddressManager.h>#include <ApplicationVersion.h>#include <AssetClient.h>#include <AssetUpload.h>#include <AutoUpdater.h>#include <AudioInjectorManager.h>#include <CursorManager.h>#include <DeferredLightingEffect.h>#include <display-plugins/DisplayPlugin.h>#include <EntityScriptingInterface.h>#include <ErrorDialog.h>#include <Finally.h>#include <FramebufferCache.h>#include <gpu/Batch.h>#include <gpu/Context.h>#include <gpu/GLBackend.h>#include <HFActionEvent.h>#include <HFBackEvent.h>#include <InfoView.h>#include <input-plugins/InputPlugin.h>#include <input-plugins/Joystick.h> // this should probably be removed#include <controllers/UserInputMapper.h>#include <controllers/StateController.h>#include <LogHandler.h>#include <MainWindow.h>#include <MessageDialog.h>#include <MessagesClient.h>#include <ModelEntityItem.h>#include <NetworkAccessManager.h>#include <NetworkingConstants.h>#include <ObjectMotionState.h>#include <OctalCode.h>#include <OctreeSceneStats.h>#include <gl/OffscreenGlCanvas.h>#include <PathUtils.h>#include <PerfStat.h>#include <PhysicsEngine.h>#include <plugins/PluginContainer.h>#include <plugins/PluginManager.h>#include <RenderableWebEntityItem.h>#include <RenderDeferredTask.h>#include <ResourceCache.h>#include <SceneScriptingInterface.h>#include <RecordingScriptingInterface.h>#include <ScriptCache.h>#include <SoundCache.h>#include <TextureCache.h>#include <Tooltip.h>#include <udt/PacketHeaders.h>#include <UserActivityLogger.h>#include <UUID.h>#include <VrMenu.h>#include <recording/Deck.h>#include <recording/Recorder.h> #include "AnimDebugDraw.h"#include "AudioClient.h"#include "audio/AudioScope.h"#include "avatar/AvatarManager.h"#include "CrashHandler.h"#include "input-plugins/SpacemouseManager.h"#include "devices/DdeFaceTracker.h"#include "devices/EyeTracker.h"#include "devices/Faceshift.h"#include "devices/Leapmotion.h"#include "devices/MIDIManager.h"#include "devices/RealSense.h"#include "DiscoverabilityManager.h"#include "GLCanvas.h"#include "InterfaceActionFactory.h"#include "InterfaceLogging.h"#include "LODManager.h"#include "Menu.h"#include "ModelPackager.h"#include "PluginContainerProxy.h"#include "scripting/AccountScriptingInterface.h"#include "scripting/AudioDeviceScriptingInterface.h"#include "scripting/ClipboardScriptingInterface.h"#include "scripting/DesktopScriptingInterface.h"#include "scripting/GlobalServicesScriptingInterface.h"#include "scripting/HMDScriptingInterface.h"#include "scripting/LocationScriptingInterface.h"#include "scripting/MenuScriptingInterface.h"#include "scripting/SettingsScriptingInterface.h"#include "scripting/WebWindowClass.h"#include "scripting/WindowScriptingInterface.h"#include "scripting/ControllerScriptingInterface.h"#if defined(Q_OS_MAC) || defined(Q_OS_WIN)#include "SpeechRecognizer.h"#endif#include "Stars.h"#include "ui/AddressBarDialog.h"#include "ui/RecorderDialog.h"#include "ui/AvatarInputs.h"#include "ui/AssetUploadDialogFactory.h"#include "ui/DataWebDialog.h"#include "ui/DialogsManager.h"#include "ui/LoginDialog.h"#include "ui/overlays/Cube3DOverlay.h"#include "ui/Snapshot.h"#include "ui/StandAloneJSConsole.h"#include "ui/Stats.h"#include "ui/UpdateDialog.h"#include "Util.h"  // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU// FIXME seems to be broken.#if defined(Q_OS_WIN)extern "C" { _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;}#endif using namespace std; static QTimer locationUpdateTimer;static QTimer balanceUpdateTimer;static QTimer identityPacketTimer;static QTimer billboardPacketTimer;static QTimer pingTimer; static const QString SNAPSHOT_EXTENSION  = ".jpg";static const QString SVO_EXTENSION  = ".svo";static const QString SVO_JSON_EXTENSION  = ".svo.json";static const QString JS_EXTENSION  = ".js";static const QString FST_EXTENSION  = ".fst";static const QString FBX_EXTENSION  = ".fbx";static const QString OBJ_EXTENSION  = ".obj"; static const int MIRROR_VIEW_TOP_PADDING = 5;static const int MIRROR_VIEW_LEFT_PADDING = 10;static const int MIRROR_VIEW_WIDTH = 265;static const int MIRROR_VIEW_HEIGHT = 215;static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f;static const float MIRROR_REARVIEW_DISTANCE = 0.722f;static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.56f;static const float MIRROR_FIELD_OF_VIEW = 30.0f; static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND; static const QString INFO_HELP_PATH = "html/interface-welcome.html";static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html"; static const unsigned int THROTTLED_SIM_FRAMERATE = 15;static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE; #ifndef __APPLE__static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);#else// Temporary fix to Qt bug: http://stackoverflow.com/questions/16194475static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).append("/script.js");#endif const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js";Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {    { SNAPSHOT_EXTENSION, &Application::acceptSnapshot },    { SVO_EXTENSION, &Application::importSVOFromURL },    { SVO_JSON_EXTENSION, &Application::importSVOFromURL },    { JS_EXTENSION, &Application::askToLoadScript },    { FST_EXTENSION, &Application::askToSetAvatarUrl }}; #ifdef Q_OS_WINclass MyNativeEventFilter : public QAbstractNativeEventFilter {public:    static MyNativeEventFilter& getInstance() {        static MyNativeEventFilter staticInstance;        return staticInstance;    }     bool nativeEventFilter(const QByteArray &eventType, void* msg, long* result) Q_DECL_OVERRIDE {        if (eventType == "windows_generic_MSG") {            MSG* message = (MSG*)msg;             if (message->message == UWM_IDENTIFY_INSTANCES) {                *result = UWM_IDENTIFY_INSTANCES;                return true;            }             if (message->message == UWM_SHOW_APPLICATION) {                MainWindow* applicationWindow = qApp->getWindow();                if (applicationWindow->isMinimized()) {                    applicationWindow->showNormal();  // Restores to windowed or maximized state appropriately.                }                qApp->setActiveWindow(applicationWindow);  // Flashes the taskbar icon if not focus.                return true;            }             if (message->message == WM_COPYDATA) {                COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)(message->lParam);                QUrl url = QUrl((const char*)(pcds->lpData));                if (url.isValid() && url.scheme() == HIFI_URL_SCHEME) {                    DependencyManager::get<AddressManager>()->handleLookupString(url.toString());                    return true;                }            }        }        return false;    }};#endif enum CustomEventTypes {    Lambda = QEvent::User + 1}; class LambdaEvent : public QEvent {    std::function<void()> _fun;public:    LambdaEvent(const std::function<void()> & fun) :    QEvent(static_cast<QEvent::Type>(Lambda)), _fun(fun) {    }    LambdaEvent(std::function<void()> && fun) :    QEvent(static_cast<QEvent::Type>(Lambda)), _fun(fun) {    }    void call() { _fun(); }}; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {    QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message);     if (!logMessage.isEmpty()) {#ifdef Q_OS_WIN        OutputDebugStringA(logMessage.toLocal8Bit().constData());        OutputDebugStringA("\n");#endif        qApp->getLogger()->addMessage(qPrintable(logMessage + "\n"));    }} bool setupEssentials(int& argc, char** argv) {    unsigned int listenPort = 0; // bind to an ephemeral port by default    const char** constArgv = const_cast<const char**>(argv);    const char* portStr = getCmdOption(argc, constArgv, "--listenPort");    if (portStr) {        listenPort = atoi(portStr);    }    // Set build version    QCoreApplication::setApplicationVersion(BUILD_VERSION);     Setting::preInit();     CrashHandler::checkForAndHandleCrash();    CrashHandler::writeRunningMarkerFiler();    qAddPostRoutine(CrashHandler::deleteRunningMarkerFile);     DependencyManager::registerInheritance<LimitedNodeList, NodeList>();    DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();    DependencyManager::registerInheritance<EntityActionFactoryInterface, InterfaceActionFactory>();     Setting::init();     // Set dependencies    DependencyManager::set<recording::Deck>();    DependencyManager::set<recording::Recorder>();    DependencyManager::set<AddressManager>();    DependencyManager::set<NodeList>(NodeType::Agent, listenPort);    DependencyManager::set<GeometryCache>();    DependencyManager::set<ModelCache>();    DependencyManager::set<ScriptCache>();    DependencyManager::set<SoundCache>();    DependencyManager::set<Faceshift>();    DependencyManager::set<DdeFaceTracker>();    DependencyManager::set<EyeTracker>();    DependencyManager::set<AudioClient>();    DependencyManager::set<AudioScope>();    DependencyManager::set<DeferredLightingEffect>();    DependencyManager::set<TextureCache>();    DependencyManager::set<FramebufferCache>();    DependencyManager::set<AnimationCache>();    DependencyManager::set<ModelBlender>();    DependencyManager::set<AvatarManager>();    DependencyManager::set<LODManager>();    DependencyManager::set<StandAloneJSConsole>();    DependencyManager::set<DialogsManager>();    DependencyManager::set<BandwidthRecorder>();    DependencyManager::set<ResourceCacheSharedItems>();    DependencyManager::set<DesktopScriptingInterface>();    DependencyManager::set<EntityScriptingInterface>();    DependencyManager::set<RecordingScriptingInterface>();    DependencyManager::set<WindowScriptingInterface>();    DependencyManager::set<HMDScriptingInterface>(); #if defined(Q_OS_MAC) || defined(Q_OS_WIN)    DependencyManager::set<SpeechRecognizer>();#endif    DependencyManager::set<DiscoverabilityManager>();    DependencyManager::set<SceneScriptingInterface>();    DependencyManager::set<OffscreenUi>();    DependencyManager::set<AutoUpdater>();    DependencyManager::set<PathUtils>();    DependencyManager::set<InterfaceActionFactory>();    DependencyManager::set<AssetClient>();    DependencyManager::set<AudioInjectorManager>();    DependencyManager::set<MessagesClient>();    DependencyManager::set<UserInputMapper>();    DependencyManager::set<controller::ScriptingInterface, ControllerScriptingInterface>();    return true;} // FIXME move to header, or better yet, design some kind of UI manager// to take care of highlighting keyboard focused items, rather than// continuing to overburden Application.cppCube3DOverlay* _keyboardFocusHighlight{ nullptr };int _keyboardFocusHighlightID{ -1 };PluginContainer* _pluginContainer; Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :    QApplication(argc, argv),    _dependencyManagerIsSetup(setupEssentials(argc, argv)),    _window(new MainWindow(desktop())),    _toolWindow(NULL),    _undoStackScriptingInterface(&_undoStack),    _frameCount(0),    _fps(60.0f),    _physicsEngine(new PhysicsEngine(Vectors::ZERO)),    _entities(true, this, this),    _entityClipboardRenderer(false, this, this),    _entityClipboard(new EntityTree()),    _lastQueriedTime(usecTimestampNow()),    _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),    _firstRun("firstRun", true),    _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),    _scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION),    _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),    _scaleMirror(1.0f),    _rotateMirror(0.0f),    _raiseMirror(0.0f),    _lastMouseMoveWasSimulated(false),    _enableProcessOctreeThread(true),    _runningScriptsWidget(NULL),    _runningScriptsWidgetWasVisible(false),    _lastNackTime(usecTimestampNow()),    _lastSendDownstreamAudioStats(usecTimestampNow()),    _aboutToQuit(false),    _notifiedPacketVersionMismatchThisDomain(false),    _maxOctreePPS(maxOctreePacketsPerSecond.get()),    _lastFaceTrackerUpdate(0){    thread()->setObjectName("Main Thread");     setInstance(this);     auto controllerScriptingInterface = DependencyManager::get<controller::ScriptingInterface>().data();    _controllerScriptingInterface = dynamic_cast<ControllerScriptingInterface*>(controllerScriptingInterface);    // to work around the Qt constant wireless scanning, set the env for polling interval very high    const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT_MAX).toLocal8Bit();    qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);     _entityClipboard->createRootElement();     _pluginContainer = new PluginContainerProxy();#ifdef Q_OS_WIN    installNativeEventFilter(&MyNativeEventFilter::getInstance());#endif     _logger = new FileLogger(this);  // After setting organization name in order to get correct directory     qInstallMessageHandler(messageHandler);     QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf");    _window->setWindowTitle("Interface");     Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us     auto nodeList = DependencyManager::get<NodeList>();     qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());     _bookmarks = new Bookmarks();  // Before setting up the menu     _runningScriptsWidget = new RunningScriptsWidget(_window);    _renderEngine->addTask(make_shared<RenderDeferredTask>());    _renderEngine->registerScene(_main3DScene);     // start the nodeThread so its event loop is running    QThread* nodeThread = new QThread(this);    nodeThread->setObjectName("NodeList Thread");    nodeThread->start();     // make sure the node thread is given highest priority    nodeThread->setPriority(QThread::TimeCriticalPriority);     // setup a timer for domain-server check ins    QTimer* domainCheckInTimer = new QTimer(nodeList.data());    connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);    domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);     // put the NodeList and datagram processing on the node thread    nodeList->moveToThread(nodeThread);     // Model background downloads need to happen on the Datagram Processor Thread.  The idle loop will    // emit checkBackgroundDownloads to cause the ModelCache to check it's queue for requested background    // downloads.    QSharedPointer<ModelCache> modelCacheP = DependencyManager::get<ModelCache>();    ResourceCache* modelCache = modelCacheP.data();    connect(this, &Application::checkBackgroundDownloads, modelCache, &ResourceCache::checkAsynchronousGets);     // put the audio processing on a separate thread    QThread* audioThread = new QThread();    audioThread->setObjectName("Audio Thread");     auto audioIO = DependencyManager::get<AudioClient>();     audioIO->setPositionGetter([this]{ return getMyAvatar()->getPositionForAudio(); });    audioIO->setOrientationGetter([this]{ return getMyAvatar()->getOrientationForAudio(); });     audioIO->moveToThread(audioThread);    recording::Frame::registerFrameHandler(AudioConstants::AUDIO_FRAME_NAME, [=](recording::Frame::ConstPointer frame) {        audioIO->handleRecordedAudioInput(frame->data);    });     connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio){        static auto recorder = DependencyManager::get<recording::Recorder>();        if (recorder->isRecording()) {            static const recording::FrameType AUDIO_FRAME_TYPE = recording::Frame::registerFrameType(AudioConstants::AUDIO_FRAME_NAME);            recorder->recordFrame(AUDIO_FRAME_TYPE, audio);        }    });     auto& audioScriptingInterface = AudioScriptingInterface::getInstance();     connect(audioThread, &QThread::started, audioIO.data(), &AudioClient::start);    connect(audioIO.data(), &AudioClient::destroyed, audioThread, &QThread::quit);    connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater);    connect(audioIO.data(), &AudioClient::muteToggled, this, &Application::audioMuteToggled);    connect(audioIO.data(), &AudioClient::mutedByMixer, &audioScriptingInterface, &AudioScriptingInterface::mutedByMixer);    connect(audioIO.data(), &AudioClient::receivedFirstPacket, &audioScriptingInterface, &AudioScriptingInterface::receivedFirstPacket);    connect(audioIO.data(), &AudioClient::disconnected, &audioScriptingInterface, &AudioScriptingInterface::disconnected);    connect(audioIO.data(), &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) {        auto audioClient = DependencyManager::get<AudioClient>();        auto myAvatarPosition = DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition();        float distance = glm::distance(myAvatarPosition, position);        bool shouldMute = !audioClient->isMuted() && (distance < radius);         if (shouldMute) {            audioClient->toggleMute();            AudioScriptingInterface::getInstance().environmentMuted();        }    });     audioThread->start();     // Setup AssetClient    auto assetClient = DependencyManager::get<AssetClient>();    QThread* assetThread = new QThread;    assetThread->setObjectName("Asset Thread");    assetClient->moveToThread(assetThread);    connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init);    assetThread->start();

Lines 1–500 of 5129.