//// 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 <sstream> #include <stdlib.h>#include <cmath>#include <math.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 this before QGLWidget, which includes an earlier version of OpenGL#include "InterfaceConfig.h" #include <QAbstractNativeEventFilter>#include <QActionGroup>#include <QColorDialog>#include <QCoreApplication>#include <QDesktopWidget>#include <QCheckBox>#include <QImage>#include <QInputDialog>#include <QKeyEvent>#include <QMenuBar>#include <QMouseEvent>#include <QNetworkReply>#include <QNetworkDiskCache>#include <QObject>#include <QWheelEvent>#include <QScreen>#include <QShortcut>#include <QSystemTrayIcon>#include <QTimer>#include <QUrl>#include <QWindow>#include <QtDebug>#include <QFileDialog>#include <QDesktopServices>#include <QXmlStreamReader>#include <QXmlStreamAttributes>#include <QMediaPlayer>#include <QMimeData>#include <QMessageBox>#include <QJsonDocument> #include <AccountManager.h>#include <AddressManager.h>#include <CursorManager.h>#include <AmbientOcclusionEffect.h>#include <AudioInjector.h>#include <AutoUpdater.h>#include <DeferredLightingEffect.h>#include <DependencyManager.h>#include <EntityScriptingInterface.h>#include <ErrorDialog.h>#include <GlowEffect.h>#include <gpu/Batch.h>#include <gpu/Context.h>#include <gpu/GLBackend.h>#include <HFActionEvent.h>#include <HFBackEvent.h>#include <InfoView.h>#include <LogHandler.h>#include <MainWindow.h>#include <MessageDialog.h>#include <ModelEntityItem.h>#include <NetworkAccessManager.h>#include <NetworkingConstants.h>#include <ObjectMotionState.h>#include <OctalCode.h>#include <OctreeSceneStats.h>#include <PacketHeaders.h>#include <PathUtils.h>#include <PerfStat.h>#include <PhysicsEngine.h>#include <ProgramObject.h>#include <RenderDeferredTask.h>#include <ResourceCache.h>#include <SceneScriptingInterface.h>#include <ScriptCache.h>#include <SettingHandle.h>#include <SoundCache.h>#include <TextRenderer.h>#include <Tooltip.h>#include <UserActivityLogger.h>#include <UUID.h>#include <VrMenu.h> #include "Application.h"#include "AudioClient.h"#include "DiscoverabilityManager.h"#include "InterfaceVersion.h"#include "LODManager.h"#include "Menu.h"#include "ModelPackager.h"#include "Util.h"#include "InterfaceLogging.h"#include "InterfaceActionFactory.h" #include "avatar/AvatarManager.h" #include "audio/AudioIOStatsRenderer.h"#include "audio/AudioScope.h" #include "devices/DdeFaceTracker.h"#include "devices/Faceshift.h"#include "devices/Leapmotion.h"#include "devices/RealSense.h"#include "devices/SDL2Manager.h"#include "devices/MIDIManager.h"#include "devices/OculusManager.h"#include "devices/TV3DManager.h" #include "scripting/AccountScriptingInterface.h"#include "scripting/AudioDeviceScriptingInterface.h"#include "scripting/ClipboardScriptingInterface.h"#include "scripting/HMDScriptingInterface.h"#include "scripting/GlobalServicesScriptingInterface.h"#include "scripting/LocationScriptingInterface.h"#include "scripting/MenuScriptingInterface.h"#include "scripting/SettingsScriptingInterface.h"#include "scripting/WindowScriptingInterface.h"#include "scripting/WebWindowClass.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN)#include "SpeechRecognizer.h"#endif #include "ui/AvatarInputs.h"#include "ui/DataWebDialog.h"#include "ui/DialogsManager.h"#include "ui/LoginDialog.h"#include "ui/Snapshot.h"#include "ui/StandAloneJSConsole.h"#include "ui/Stats.h"#include "ui/AddressBarDialog.h"#include "ui/UpdateDialog.h" // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU#if defined(Q_OS_WIN)extern "C" { _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;}#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(); }}; using namespace std; // Starfield informationstatic unsigned STARFIELD_NUM_STARS = 50000;static unsigned STARFIELD_SEED = 1; const qint64 MAXIMUM_CACHE_SIZE = 10 * BYTES_PER_GIGABYTES; // 10GB static QTimer* locationUpdateTimer = NULL;static QTimer* balanceUpdateTimer = NULL;static QTimer* identityPacketTimer = NULL;static QTimer* billboardPacketTimer = NULL;static QTimer* checkFPStimer = NULL;static QTimer* idleTimer = NULL; const QString CHECK_VERSION_URL = "https://highfidelity.com/latestVersion.xml";const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion"; const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js";Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); #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 = Application::getInstance()->getWindow(); if (applicationWindow->isMinimized()) { applicationWindow->showNormal(); // Restores to windowed or maximized state appropriately. } Application::getInstance()->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 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 Application::getInstance()->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); DependencyManager::registerInheritance<LimitedNodeList, NodeList>(); DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>(); DependencyManager::registerInheritance<EntityActionFactoryInterface, InterfaceActionFactory>(); Setting::init(); // Set dependencies auto addressManager = DependencyManager::set<AddressManager>(); auto nodeList = DependencyManager::set<NodeList>(NodeType::Agent, listenPort); auto geometryCache = DependencyManager::set<GeometryCache>(); auto scriptCache = DependencyManager::set<ScriptCache>(); auto soundCache = DependencyManager::set<SoundCache>(); auto glowEffect = DependencyManager::set<GlowEffect>(); auto faceshift = DependencyManager::set<Faceshift>(); auto audio = DependencyManager::set<AudioClient>(); auto audioScope = DependencyManager::set<AudioScope>(); auto audioIOStatsRenderer = DependencyManager::set<AudioIOStatsRenderer>(); auto deferredLightingEffect = DependencyManager::set<DeferredLightingEffect>(); auto ambientOcclusionEffect = DependencyManager::set<AmbientOcclusionEffect>(); auto textureCache = DependencyManager::set<TextureCache>(); auto animationCache = DependencyManager::set<AnimationCache>(); auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>(); auto modelBlender = DependencyManager::set<ModelBlender>(); auto avatarManager = DependencyManager::set<AvatarManager>(); auto lodManager = DependencyManager::set<LODManager>(); auto jsConsole = DependencyManager::set<StandAloneJSConsole>(); auto dialogsManager = DependencyManager::set<DialogsManager>(); auto bandwidthRecorder = DependencyManager::set<BandwidthRecorder>(); auto resourceCacheSharedItems = DependencyManager::set<ResourceCacheSharedItems>(); auto entityScriptingInterface = DependencyManager::set<EntityScriptingInterface>(); auto windowScriptingInterface = DependencyManager::set<WindowScriptingInterface>();#if defined(Q_OS_MAC) || defined(Q_OS_WIN) auto speechRecognizer = DependencyManager::set<SpeechRecognizer>();#endif auto discoverabilityManager = DependencyManager::set<DiscoverabilityManager>(); auto sceneScriptingInterface = DependencyManager::set<SceneScriptingInterface>(); auto offscreenUi = DependencyManager::set<OffscreenUi>(); auto autoUpdater = DependencyManager::set<AutoUpdater>(); auto pathUtils = DependencyManager::set<PathUtils>(); auto actionFactory = DependencyManager::set<InterfaceActionFactory>(); return true;} Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : QApplication(argc, argv), _dependencyManagerIsSetup(setupEssentials(argc, argv)), _window(new MainWindow(desktop())), _toolWindow(NULL), _friendsWindow(NULL), _datagramProcessor(), _undoStack(), _undoStackScriptingInterface(&_undoStack), _frameCount(0), _fps(60.0f), _justStarted(true), _physicsEngine(glm::vec3(0.0f)), _entities(true, this, this), _entityClipboardRenderer(false, this, this), _entityClipboard(), _viewFrustum(), _lastQueriedViewFrustum(), _lastQueriedTime(usecTimestampNow()), _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), _firstRun("firstRun", true), _previousScriptLocation("LastScriptLocation"), _scriptsLocationHandle("scriptsLocation"), _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES), _viewTransform(), _scaleMirror(1.0f), _rotateMirror(0.0f), _raiseMirror(0.0f), _cursorVisible(true), _lastMouseMove(usecTimestampNow()), _lastMouseMoveWasSimulated(false), _isTouchPressed(false), _mousePressed(false), _enableProcessOctreeThread(true), _octreeProcessor(), _nodeBoundsDisplay(this), _runningScriptsWidget(NULL), _runningScriptsWidgetWasVisible(false), _trayIcon(new QSystemTrayIcon(_window)), _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()), _isVSyncOn(true), _aboutToQuit(false), _notifiedPacketVersionMismatchThisDomain(false), _domainConnectionRefusals(QList<QString>()), _maxOctreePPS(maxOctreePacketsPerSecond.get()), _lastFaceTrackerUpdate(0), _applicationOverlay(){ setInstance(this);#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>(); _myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); _applicationStartupTime = startup_time; qCDebug(interfaceapp) << "[VERSION] Build sequence: " << qPrintable(applicationVersion()); _bookmarks = new Bookmarks(); // Before setting up the menu _runningScriptsWidget = new RunningScriptsWidget(_window); _renderEngine->addTask(render::TaskPointer(new RenderDeferredTask())); _renderEngine->registerScene(_main3DScene); // start the nodeThread so its event loop is running QThread* nodeThread = new QThread(this); nodeThread->setObjectName("Datagram Processor Thread"); nodeThread->start(); // make sure the node thread is given highest priority nodeThread->setPriority(QThread::TimeCriticalPriority); _datagramProcessor = new DatagramProcessor(nodeList.data()); // have the NodeList use deleteLater from DM customDeleter nodeList->setCustomDeleter([](Dependency* dependency) { static_cast<NodeList*>(dependency)->deleteLater(); }); // put the NodeList and datagram processing on the node thread nodeList->moveToThread(nodeThread); // geometry background downloads need to happen on the Datagram Processor Thread. The idle loop will // emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background // downloads. QSharedPointer<GeometryCache> geometryCacheP = DependencyManager::get<GeometryCache>(); ResourceCache* geometryCache = geometryCacheP.data(); connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets); // connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _datagramProcessor, &DatagramProcessor::processDatagrams); // put the audio processing on a separate thread QThread* audioThread = new QThread(); audioThread->setObjectName("Audio Thread"); auto audioIO = DependencyManager::get<AudioClient>(); audioIO->setPositionGetter(getPositionForAudio); audioIO->setOrientationGetter(getOrientationForAudio); audioIO->moveToThread(audioThread); 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::receivedFirstPacket, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::receivedFirstPacket); connect(audioIO.data(), &AudioClient::disconnected, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::disconnected); audioThread->start(); const DomainHandler& domainHandler = nodeList->getDomainHandler(); connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails())); connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived); connect(&domainHandler, &DomainHandler::hostnameChanged, DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress); // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000; locationUpdateTimer = new QTimer(this); auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>(); connect(locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS); // if we get a domain change, immediately attempt update location in metaverse server connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded); connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled); connect(nodeList.data(), SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); connect(nodeList.data(), &NodeList::uuidChanged, _myAvatar, &MyAvatar::setSessionUUID); connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID); connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset); connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); // connect to appropriate slots on AccountManager AccountManager& accountManager = AccountManager::getInstance(); const qint64 BALANCE_UPDATE_INTERVAL_MSECS = 5 * 1000; balanceUpdateTimer = new QTimer(this); connect(balanceUpdateTimer, &QTimer::timeout, &accountManager, &AccountManager::updateBalance); balanceUpdateTimer->start(BALANCE_UPDATE_INTERVAL_MSECS); connect(&accountManager, &AccountManager::balanceChanged, this, &Application::updateWindowTitle); auto dialogsManager = DependencyManager::get<DialogsManager>(); connect(&accountManager, &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog); connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle); // set the account manager's root URL and trigger a login request if we don't have the access token accountManager.setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); UserActivityLogger::getInstance().launch(applicationVersion()); // once the event loop has started, check and signal for an access token QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection); auto addressManager = DependencyManager::get<AddressManager>(); // use our MyAvatar position and quat for address manager path addressManager->setPositionGetter(getPositionForPath); addressManager->setOrientationGetter(getOrientationForPath); connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); #ifdef _WIN32 WSADATA WsaData; int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData); #endif // tell the NodeList instance who to tell the domain server we care about nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer << NodeType::EntityServer); // connect to the packet sent signal of the _entityEditSenderLines 1–500 of 4770. Load more
// // 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 <sstream> #include <stdlib.h> #include <cmath> #include <math.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 this before QGLWidget, which includes an earlier version of OpenGL #include "InterfaceConfig.h" #include <QAbstractNativeEventFilter> #include <QActionGroup> #include <QColorDialog> #include <QCoreApplication> #include <QDesktopWidget> #include <QCheckBox> #include <QImage> #include <QInputDialog> #include <QKeyEvent> #include <QMenuBar> #include <QMouseEvent> #include <QNetworkReply> #include <QNetworkDiskCache> #include <QObject> #include <QWheelEvent> #include <QScreen> #include <QShortcut> #include <QSystemTrayIcon> #include <QTimer> #include <QUrl> #include <QWindow> #include <QtDebug> #include <QFileDialog> #include <QDesktopServices> #include <QXmlStreamReader> #include <QXmlStreamAttributes> #include <QMediaPlayer> #include <QMimeData> #include <QMessageBox> #include <QJsonDocument> #include <AccountManager.h> #include <AddressManager.h> #include <CursorManager.h> #include <AmbientOcclusionEffect.h> #include <AudioInjector.h> #include <AutoUpdater.h> #include <DeferredLightingEffect.h> #include <DependencyManager.h> #include <EntityScriptingInterface.h> #include <ErrorDialog.h> #include <GlowEffect.h> #include <gpu/Batch.h> #include <gpu/Context.h> #include <gpu/GLBackend.h> #include <HFActionEvent.h> #include <HFBackEvent.h> #include <InfoView.h> #include <LogHandler.h> #include <MainWindow.h> #include <MessageDialog.h> #include <ModelEntityItem.h> #include <NetworkAccessManager.h> #include <NetworkingConstants.h> #include <ObjectMotionState.h> #include <OctalCode.h> #include <OctreeSceneStats.h> #include <PacketHeaders.h> #include <PathUtils.h> #include <PerfStat.h> #include <PhysicsEngine.h> #include <ProgramObject.h> #include <RenderDeferredTask.h> #include <ResourceCache.h> #include <SceneScriptingInterface.h> #include <ScriptCache.h> #include <SettingHandle.h> #include <SoundCache.h> #include <TextRenderer.h> #include <Tooltip.h> #include <UserActivityLogger.h> #include <UUID.h> #include <VrMenu.h> #include "Application.h" #include "AudioClient.h" #include "DiscoverabilityManager.h" #include "InterfaceVersion.h" #include "LODManager.h" #include "Menu.h" #include "ModelPackager.h" #include "Util.h" #include "InterfaceLogging.h" #include "InterfaceActionFactory.h" #include "avatar/AvatarManager.h" #include "audio/AudioIOStatsRenderer.h" #include "audio/AudioScope.h" #include "devices/DdeFaceTracker.h" #include "devices/Faceshift.h" #include "devices/Leapmotion.h" #include "devices/RealSense.h" #include "devices/SDL2Manager.h" #include "devices/MIDIManager.h" #include "devices/OculusManager.h" #include "devices/TV3DManager.h" #include "scripting/AccountScriptingInterface.h" #include "scripting/AudioDeviceScriptingInterface.h" #include "scripting/ClipboardScriptingInterface.h" #include "scripting/HMDScriptingInterface.h" #include "scripting/GlobalServicesScriptingInterface.h" #include "scripting/LocationScriptingInterface.h" #include "scripting/MenuScriptingInterface.h" #include "scripting/SettingsScriptingInterface.h" #include "scripting/WindowScriptingInterface.h" #include "scripting/WebWindowClass.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) #include "SpeechRecognizer.h" #endif #include "ui/AvatarInputs.h" #include "ui/DataWebDialog.h" #include "ui/DialogsManager.h" #include "ui/LoginDialog.h" #include "ui/Snapshot.h" #include "ui/StandAloneJSConsole.h" #include "ui/Stats.h" #include "ui/AddressBarDialog.h" #include "ui/UpdateDialog.h" // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU #if defined(Q_OS_WIN) extern "C" { _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; } #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(); } }; using namespace std; // Starfield information static unsigned STARFIELD_NUM_STARS = 50000; static unsigned STARFIELD_SEED = 1; const qint64 MAXIMUM_CACHE_SIZE = 10 * BYTES_PER_GIGABYTES; // 10GB static QTimer* locationUpdateTimer = NULL; static QTimer* balanceUpdateTimer = NULL; static QTimer* identityPacketTimer = NULL; static QTimer* billboardPacketTimer = NULL; static QTimer* checkFPStimer = NULL; static QTimer* idleTimer = NULL; const QString CHECK_VERSION_URL = "https://highfidelity.com/latestVersion.xml"; const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion"; const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js"; Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); #ifdef Q_OS_WIN class 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 = Application::getInstance()->getWindow(); if (applicationWindow->isMinimized()) { applicationWindow->showNormal(); // Restores to windowed or maximized state appropriately. } Application::getInstance()->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 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 Application::getInstance()->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); DependencyManager::registerInheritance<LimitedNodeList, NodeList>(); DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>(); DependencyManager::registerInheritance<EntityActionFactoryInterface, InterfaceActionFactory>(); Setting::init(); // Set dependencies auto addressManager = DependencyManager::set<AddressManager>(); auto nodeList = DependencyManager::set<NodeList>(NodeType::Agent, listenPort); auto geometryCache = DependencyManager::set<GeometryCache>(); auto scriptCache = DependencyManager::set<ScriptCache>(); auto soundCache = DependencyManager::set<SoundCache>(); auto glowEffect = DependencyManager::set<GlowEffect>(); auto faceshift = DependencyManager::set<Faceshift>(); auto audio = DependencyManager::set<AudioClient>(); auto audioScope = DependencyManager::set<AudioScope>(); auto audioIOStatsRenderer = DependencyManager::set<AudioIOStatsRenderer>(); auto deferredLightingEffect = DependencyManager::set<DeferredLightingEffect>(); auto ambientOcclusionEffect = DependencyManager::set<AmbientOcclusionEffect>(); auto textureCache = DependencyManager::set<TextureCache>(); auto animationCache = DependencyManager::set<AnimationCache>(); auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>(); auto modelBlender = DependencyManager::set<ModelBlender>(); auto avatarManager = DependencyManager::set<AvatarManager>(); auto lodManager = DependencyManager::set<LODManager>(); auto jsConsole = DependencyManager::set<StandAloneJSConsole>(); auto dialogsManager = DependencyManager::set<DialogsManager>(); auto bandwidthRecorder = DependencyManager::set<BandwidthRecorder>(); auto resourceCacheSharedItems = DependencyManager::set<ResourceCacheSharedItems>(); auto entityScriptingInterface = DependencyManager::set<EntityScriptingInterface>(); auto windowScriptingInterface = DependencyManager::set<WindowScriptingInterface>(); #if defined(Q_OS_MAC) || defined(Q_OS_WIN) auto speechRecognizer = DependencyManager::set<SpeechRecognizer>(); #endif auto discoverabilityManager = DependencyManager::set<DiscoverabilityManager>(); auto sceneScriptingInterface = DependencyManager::set<SceneScriptingInterface>(); auto offscreenUi = DependencyManager::set<OffscreenUi>(); auto autoUpdater = DependencyManager::set<AutoUpdater>(); auto pathUtils = DependencyManager::set<PathUtils>(); auto actionFactory = DependencyManager::set<InterfaceActionFactory>(); return true; } Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : QApplication(argc, argv), _dependencyManagerIsSetup(setupEssentials(argc, argv)), _window(new MainWindow(desktop())), _toolWindow(NULL), _friendsWindow(NULL), _datagramProcessor(), _undoStack(), _undoStackScriptingInterface(&_undoStack), _frameCount(0), _fps(60.0f), _justStarted(true), _physicsEngine(glm::vec3(0.0f)), _entities(true, this, this), _entityClipboardRenderer(false, this, this), _entityClipboard(), _viewFrustum(), _lastQueriedViewFrustum(), _lastQueriedTime(usecTimestampNow()), _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), _firstRun("firstRun", true), _previousScriptLocation("LastScriptLocation"), _scriptsLocationHandle("scriptsLocation"), _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES), _viewTransform(), _scaleMirror(1.0f), _rotateMirror(0.0f), _raiseMirror(0.0f), _cursorVisible(true), _lastMouseMove(usecTimestampNow()), _lastMouseMoveWasSimulated(false), _isTouchPressed(false), _mousePressed(false), _enableProcessOctreeThread(true), _octreeProcessor(), _nodeBoundsDisplay(this), _runningScriptsWidget(NULL), _runningScriptsWidgetWasVisible(false), _trayIcon(new QSystemTrayIcon(_window)), _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()), _isVSyncOn(true), _aboutToQuit(false), _notifiedPacketVersionMismatchThisDomain(false), _domainConnectionRefusals(QList<QString>()), _maxOctreePPS(maxOctreePacketsPerSecond.get()), _lastFaceTrackerUpdate(0), _applicationOverlay() { setInstance(this); #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>(); _myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); _applicationStartupTime = startup_time; qCDebug(interfaceapp) << "[VERSION] Build sequence: " << qPrintable(applicationVersion()); _bookmarks = new Bookmarks(); // Before setting up the menu _runningScriptsWidget = new RunningScriptsWidget(_window); _renderEngine->addTask(render::TaskPointer(new RenderDeferredTask())); _renderEngine->registerScene(_main3DScene); // start the nodeThread so its event loop is running QThread* nodeThread = new QThread(this); nodeThread->setObjectName("Datagram Processor Thread"); nodeThread->start(); // make sure the node thread is given highest priority nodeThread->setPriority(QThread::TimeCriticalPriority); _datagramProcessor = new DatagramProcessor(nodeList.data()); // have the NodeList use deleteLater from DM customDeleter nodeList->setCustomDeleter([](Dependency* dependency) { static_cast<NodeList*>(dependency)->deleteLater(); }); // put the NodeList and datagram processing on the node thread nodeList->moveToThread(nodeThread); // geometry background downloads need to happen on the Datagram Processor Thread. The idle loop will // emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background // downloads. QSharedPointer<GeometryCache> geometryCacheP = DependencyManager::get<GeometryCache>(); ResourceCache* geometryCache = geometryCacheP.data(); connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets); // connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _datagramProcessor, &DatagramProcessor::processDatagrams); // put the audio processing on a separate thread QThread* audioThread = new QThread(); audioThread->setObjectName("Audio Thread"); auto audioIO = DependencyManager::get<AudioClient>(); audioIO->setPositionGetter(getPositionForAudio); audioIO->setOrientationGetter(getOrientationForAudio); audioIO->moveToThread(audioThread); 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::receivedFirstPacket, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::receivedFirstPacket); connect(audioIO.data(), &AudioClient::disconnected, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::disconnected); audioThread->start(); const DomainHandler& domainHandler = nodeList->getDomainHandler(); connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails())); connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived); connect(&domainHandler, &DomainHandler::hostnameChanged, DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress); // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000; locationUpdateTimer = new QTimer(this); auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>(); connect(locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS); // if we get a domain change, immediately attempt update location in metaverse server connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded); connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled); connect(nodeList.data(), SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); connect(nodeList.data(), &NodeList::uuidChanged, _myAvatar, &MyAvatar::setSessionUUID); connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID); connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset); connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); // connect to appropriate slots on AccountManager AccountManager& accountManager = AccountManager::getInstance(); const qint64 BALANCE_UPDATE_INTERVAL_MSECS = 5 * 1000; balanceUpdateTimer = new QTimer(this); connect(balanceUpdateTimer, &QTimer::timeout, &accountManager, &AccountManager::updateBalance); balanceUpdateTimer->start(BALANCE_UPDATE_INTERVAL_MSECS); connect(&accountManager, &AccountManager::balanceChanged, this, &Application::updateWindowTitle); auto dialogsManager = DependencyManager::get<DialogsManager>(); connect(&accountManager, &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog); connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle); // set the account manager's root URL and trigger a login request if we don't have the access token accountManager.setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); UserActivityLogger::getInstance().launch(applicationVersion()); // once the event loop has started, check and signal for an access token QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection); auto addressManager = DependencyManager::get<AddressManager>(); // use our MyAvatar position and quat for address manager path addressManager->setPositionGetter(getPositionForPath); addressManager->setOrientationGetter(getOrientationForPath); connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); #ifdef _WIN32 WSADATA WsaData; int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData); #endif // tell the NodeList instance who to tell the domain server we care about nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer << NodeType::EntityServer); // connect to the packet sent signal of the _entityEditSender