mirror of
https://github.com/overte-org/overte.git
synced 2025-07-14 20:36:38 +02:00
940 lines
32 KiB
C++
940 lines
32 KiB
C++
//
|
|
// Application.h
|
|
// interface/src
|
|
//
|
|
// Created by Andrzej Kapolka on 5/10/13.
|
|
// Copyright 2013 High Fidelity, Inc.
|
|
// Copyright 2020 Vircadia contributors.
|
|
// Copyright 2022-2023 Overte e.V.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#ifndef hifi_Application_h
|
|
#define hifi_Application_h
|
|
|
|
#include <QtWidgets/QApplication>
|
|
|
|
#include <AbstractScriptingServicesInterface.h>
|
|
#include <AbstractUriHandler.h>
|
|
#include <AbstractViewStateInterface.h>
|
|
#include <AvatarHashMap.h>
|
|
#include <EntityEditPacketSender.h>
|
|
#include <ModerationFlags.h>
|
|
#include <OctreeQuery.h>
|
|
#include <PhysicsEngine.h>
|
|
#include <ShapeManager.h>
|
|
#include <TouchEvent.h>
|
|
#include <ui-plugins/PluginContainer.h>
|
|
|
|
#include "avatar/MyAvatar.h"
|
|
#include "ConnectionMonitor.h"
|
|
#include "CursorManager.h"
|
|
#include "FancyCamera.h"
|
|
#include "graphics/GraphicsEngine.h"
|
|
#include "LoginStateManager.h"
|
|
#include "octree/OctreePacketProcessor.h"
|
|
#include "PerformanceManager.h"
|
|
#include "RefreshRateManager.h"
|
|
#include "scripting/DialogsManagerScriptingInterface.h"
|
|
#include "ui/ApplicationOverlay.h"
|
|
#include "ui/OverlayConductor.h"
|
|
#include "ui/overlays/Overlays.h"
|
|
#include "VisionSqueeze.h"
|
|
#include "workload/GameWorkload.h"
|
|
|
|
class ArchiveDownloadInterface;
|
|
class AudioInjector;
|
|
class CompositorHelper;
|
|
class ControllerScriptingInterface;
|
|
class DiscordPresence;
|
|
class EntityScriptServerLogDialog;
|
|
class FileLogger;
|
|
class GLCanvas;
|
|
class KeyboardMouseDevice;
|
|
class LogDialog;
|
|
class MainWindow;
|
|
class ModalDialogListener;
|
|
class OffscreenUi;
|
|
class TouchscreenDevice;
|
|
class TouchscreenVirtualPadDevice;
|
|
class QCommandLineParser;
|
|
class QGestureEvent;
|
|
class QQmlContext;
|
|
class QQuickItem;
|
|
|
|
namespace controller {
|
|
class StateController;
|
|
}
|
|
|
|
class Application;
|
|
#if defined(qApp)
|
|
#undef qApp
|
|
#endif
|
|
#define qApp (static_cast<Application*>(QCoreApplication::instance()))
|
|
|
|
class Application : public QApplication,
|
|
public AbstractViewStateInterface,
|
|
public AbstractScriptingServicesInterface,
|
|
public AbstractUriHandler,
|
|
public PluginContainer
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
Application(
|
|
int& argc, char** argv,
|
|
const QCommandLineParser& parser,
|
|
QElapsedTimer& startup_time
|
|
);
|
|
~Application();
|
|
|
|
/**
|
|
* @brief Initialize everything
|
|
*
|
|
* This is a QApplication, and for Qt reasons it's desirable to create this object
|
|
* as early as possible. Without that some Qt functions don't work, like QCoreApplication::applicationDirPath()
|
|
*
|
|
* So we keep the constructor as minimal as possible, and do the rest of the work in
|
|
* this function.
|
|
*/
|
|
void initialize(const QCommandLineParser &parser);
|
|
|
|
MainWindow* getWindow() const { return _window; }
|
|
virtual QThread* getMainThread() override { return thread(); }
|
|
|
|
bool isAboutToQuit() const { return _aboutToQuit; }
|
|
bool isServerlessMode() const;
|
|
bool isInterstitialMode() const { return _interstitialMode; }
|
|
bool failedToConnectToEntityServer() const { return _failedToConnectToEntityServer; }
|
|
|
|
void setPreviousSessionCrashed(bool value) { _previousSessionCrashed = value; }
|
|
|
|
// Return an HTTP User-Agent string with OS and device information.
|
|
Q_INVOKABLE QString getUserAgent();
|
|
|
|
PerformanceManager& getPerformanceManager() { return _performanceManager; }
|
|
RefreshRateManager& getRefreshRateManager() { return _refreshRateManager; }
|
|
float getGameLoopRate() const { return _gameLoopCounter.rate(); }
|
|
|
|
#ifndef Q_OS_ANDROID
|
|
FileLogger* getLogger() const { return _logger; }
|
|
#endif
|
|
|
|
QString getPreviousScriptLocation() { return _previousScriptLocation.get(); }
|
|
void setPreviousScriptLocation(const QString& previousScriptLocation) { _previousScriptLocation.set(previousScriptLocation); }
|
|
|
|
void replaceDomainContent(const QString& url, const QString& itemName);
|
|
|
|
void openDirectory(const QString& path);
|
|
|
|
void overrideEntry() { _overrideEntry = true; }
|
|
void forceDisplayName(const QString& displayName) { getMyAvatar()->setDisplayName(displayName); }
|
|
void forceLoginWithTokens(const QString& tokens);
|
|
void setConfigFileURL(const QString& fileUrl);
|
|
|
|
void loadAvatarScripts(const QVector<QString>& urls);
|
|
void unloadAvatarScripts();
|
|
|
|
Q_INVOKABLE void copyToClipboard(const QString& text);
|
|
|
|
Q_INVOKABLE void setMinimumGPUTextureMemStabilityCount(int stabilityCount) { _minimumGPUTextureMemSizeStabilityCount = stabilityCount; }
|
|
|
|
virtual ControllerScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; }
|
|
virtual void registerScriptEngineWithApplicationServices(ScriptManagerPointer& scriptManager) override;
|
|
|
|
// used by preferences and HMDScriptingInterface...
|
|
VisionSqueeze& getVisionSqueeze() { return _visionSqueeze; }
|
|
|
|
|
|
// UI
|
|
virtual ui::Menu* getPrimaryMenu() override;
|
|
virtual void showDisplayPluginsTools(bool show) override;
|
|
virtual GLWidget* getPrimaryWidget() override;
|
|
virtual MainWindow* getPrimaryWindow() override;
|
|
virtual QOpenGLContext* getPrimaryContext() override;
|
|
virtual bool isForeground() const override;
|
|
|
|
bool hasFocus() const;
|
|
void setFocus();
|
|
void raise();
|
|
|
|
void showCursor(const Cursor::Icon& cursor);
|
|
|
|
Overlays& getOverlays() { return _overlays; }
|
|
ApplicationOverlay& getApplicationOverlay() { return *_applicationOverlay; }
|
|
const ApplicationOverlay& getApplicationOverlay() const { return *_applicationOverlay; }
|
|
CompositorHelper& getApplicationCompositor() const;
|
|
|
|
virtual PickRay computePickRay(float x, float y) const override;
|
|
|
|
static void setupQmlSurface(QQmlContext* surfaceContext, bool setAdditionalContextProperties);
|
|
|
|
float getHMDTabletScale() { return _hmdTabletScale.get(); }
|
|
void setHMDTabletScale(float hmdTabletScale) { _hmdTabletScale.set(hmdTabletScale); }
|
|
float getDesktopTabletScale() { return _desktopTabletScale.get(); }
|
|
void setDesktopTabletScale(float desktopTabletScale) { _desktopTabletScale.set(desktopTabletScale); }
|
|
|
|
bool getDesktopTabletBecomesToolbarSetting() { return _desktopTabletBecomesToolbarSetting.get(); }
|
|
void setDesktopTabletBecomesToolbarSetting(bool value);
|
|
bool getHmdTabletBecomesToolbarSetting() { return _hmdTabletBecomesToolbarSetting.get(); }
|
|
void setHmdTabletBecomesToolbarSetting(bool value);
|
|
|
|
bool getLogWindowOnTopSetting() { return _keepLogWindowOnTop.get(); }
|
|
void setLogWindowOnTopSetting(bool keepOnTop) { _keepLogWindowOnTop.set(keepOnTop); }
|
|
bool getPreferStylusOverLaser() { return _preferStylusOverLaserSetting.get(); }
|
|
void setPreferStylusOverLaser(bool value) { _preferStylusOverLaserSetting.set(value); }
|
|
bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
|
void setPreferAvatarFingerOverStylus(bool value) { _preferAvatarFingerOverStylusSetting.set(value); }
|
|
|
|
void setMouseCaptureVR(bool value);
|
|
bool getMouseCaptureVR();
|
|
|
|
bool getShowGraphicsIcon() { return _showGraphicsIconSetting.get(); }
|
|
void setShowGraphicsIcon(bool value);
|
|
|
|
bool getMiniTabletEnabled() { return _miniTabletEnabledSetting.get(); }
|
|
void setMiniTabletEnabled(bool enabled);
|
|
|
|
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
|
void setSettingConstrainToolbarPosition(bool setting);
|
|
|
|
float getAwayStateWhenFocusLostInVREnabled() { return _awayStateWhenFocusLostInVREnabled.get(); }
|
|
void setAwayStateWhenFocusLostInVREnabled(bool setting);
|
|
|
|
QUuid getTabletScreenID() const;
|
|
QUuid getTabletHomeButtonID() const;
|
|
QUuid getTabletFrameID() const;
|
|
QVector<QUuid> getTabletIDs() const;
|
|
|
|
void confirmConnectWithoutAvatarEntities();
|
|
|
|
bool getLoginDialogPoppedUp() const { return _loginDialogPoppedUp; }
|
|
void createLoginDialog();
|
|
void updateLoginDialogPosition();
|
|
|
|
void createAvatarInputsBar();
|
|
void destroyAvatarInputsBar();
|
|
|
|
|
|
// Plugins
|
|
/**
|
|
* @brief Initialize the plugin manager
|
|
*
|
|
* This both does the initial startup and parses arguments. This
|
|
* is necessary because the plugin manager's options must be set
|
|
* before any usage of it is made, or they won't apply.
|
|
*
|
|
* @param parser
|
|
*/
|
|
void initializePluginManager(const QCommandLineParser& parser);
|
|
|
|
virtual void requestReset() override { resetSensors(false); }
|
|
virtual bool makeRenderingContextCurrent() override { return true; }
|
|
|
|
static void shutdownPlugins();
|
|
|
|
void initializeDisplayPlugins();
|
|
virtual DisplayPluginPointer getActiveDisplayPlugin() const override;
|
|
void setActiveDisplayPlugin(const QString& pluginName);
|
|
|
|
glm::uvec2 getUiSize() const;
|
|
QRect getRecommendedHUDRect() const;
|
|
glm::vec2 getDeviceSize() const;
|
|
bool isThrottleRendering() const;
|
|
float getTargetRenderFrameRate() const; // frames/second
|
|
|
|
// Check if a headset is connected
|
|
bool hasRiftControllers();
|
|
bool hasViveControllers();
|
|
|
|
// the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display
|
|
// rendering of several elements depend on that
|
|
// TODO: carry that information on the Camera as a setting
|
|
virtual bool isHMDMode() const override;
|
|
glm::mat4 getHMDSensorPose() const;
|
|
glm::mat4 getEyeOffset(int eye) const;
|
|
glm::mat4 getEyeProjection(int eye) const;
|
|
|
|
|
|
// Graphics
|
|
void initializeGL();
|
|
void initializeRenderEngine();
|
|
void initializeUi();
|
|
|
|
void resizeGL();
|
|
|
|
glm::uvec2 getCanvasSize() const;
|
|
float getRenderResolutionScale() const;
|
|
|
|
render::ScenePointer getMain3DScene() override { return _graphicsEngine->getRenderScene(); }
|
|
render::EnginePointer getRenderEngine() override { return _graphicsEngine->getRenderEngine(); }
|
|
gpu::ContextPointer getGPUContext() const { return _graphicsEngine->getGPUContext(); }
|
|
float getRenderLoopRate() const { return _graphicsEngine->getRenderLoopRate(); }
|
|
|
|
|
|
// Events
|
|
bool notify(QObject*, QEvent*) override;
|
|
bool event(QEvent* event) override;
|
|
bool eventFilter(QObject* object, QEvent* event) override;
|
|
|
|
void postLambdaEvent(const std::function<void()>& f) override;
|
|
void sendLambdaEvent(const std::function<void()>& f) override;
|
|
virtual void pushPostUpdateLambda(void* key, const std::function<void()>& func) override;
|
|
|
|
|
|
// Camera
|
|
Camera& getCamera() { return _myCamera; }
|
|
const Camera& getCamera() const { return _myCamera; }
|
|
// Represents the current view frustum of the avatar.
|
|
void copyViewFrustum(ViewFrustum& viewOut) const;
|
|
// Represents the view frustum of the current rendering pass,
|
|
// which might be different from the viewFrustum, i.e. shadowmap
|
|
// passes, mirror window passes, etc
|
|
void copyDisplayViewFrustum(ViewFrustum& viewOut) const;
|
|
|
|
void updateCamera(RenderArgs& renderArgs, float deltaTime);
|
|
void updateSecondaryCameraViewFrustum();
|
|
|
|
const ConicalViewFrustums& getConicalViews() const override { return _conicalViews; }
|
|
|
|
float getFieldOfView() { return _fieldOfView.get(); }
|
|
void setFieldOfView(float fov);
|
|
|
|
bool getCameraClippingEnabled() { return _cameraClippingEnabled.get(); }
|
|
void setCameraClippingEnabled(bool enabled);
|
|
|
|
void updateMyAvatarLookAtPosition(float deltaTime);
|
|
|
|
|
|
// Entities
|
|
QSharedPointer<EntityTreeRenderer> getEntities() const { return DependencyManager::get<EntityTreeRenderer>(); }
|
|
EntityTreePointer getEntityClipboard() const { return _entityClipboard; }
|
|
const OctreePacketProcessor& getOctreePacketProcessor() const { return *_octreeProcessor; }
|
|
std::shared_ptr<EntityEditPacketSender> getEntityEditPacketSender() { return _entityEditSender; }
|
|
|
|
void setMaxOctreePacketsPerSecond(int maxOctreePPS);
|
|
int getMaxOctreePacketsPerSecond() const { return _maxOctreePPS; }
|
|
bool isMissingSequenceNumbers() { return _isMissingSequenceNumbers; }
|
|
|
|
NodeToOctreeSceneStats* getOcteeSceneStats() { return _octreeProcessor->getOctreeSceneStats(); }
|
|
|
|
|
|
// Assets
|
|
virtual bool canAcceptURL(const QString& url) const override;
|
|
virtual bool acceptURL(const QString& url, bool defaultUpload = false) override;
|
|
|
|
|
|
// Physics
|
|
bool isPhysicsEnabled() const { return _physicsEnabled; }
|
|
PhysicsEnginePointer getPhysicsEngine() { return _physicsEngine; }
|
|
const GameWorkload& getGameWorkload() const { return _gameWorkload; }
|
|
|
|
float getNumCollisionObjects() const { return _physicsEngine ? _physicsEngine->getNumCollisionObjects() : 0; }
|
|
void saveNextPhysicsStats(QString filename) { _physicsEngine->saveNextPhysicsStats(filename); }
|
|
|
|
|
|
// Avatar
|
|
virtual glm::vec3 getAvatarPosition() const override { return getMyAvatar()->getWorldPosition(); }
|
|
|
|
void clearAvatarOverrideUrl() { _avatarOverrideUrl = QUrl(); _saveAvatarOverrideUrl = false; }
|
|
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
|
|
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
|
|
|
|
int getOtherAvatarsReplicaCount() { return DependencyManager::get<AvatarHashMap>()->getReplicaCount(); }
|
|
void setOtherAvatarsReplicaCount(int count) { DependencyManager::get<AvatarHashMap>()->setReplicaCount(count); }
|
|
|
|
|
|
// Snapshots
|
|
using SnapshotOperator = std::tuple<std::function<void(const QImage&)>, float, bool>;
|
|
void addSnapshotOperator(const SnapshotOperator& snapshotOperator);
|
|
bool takeSnapshotOperators(std::queue<SnapshotOperator>& snapshotOperators);
|
|
|
|
void takeSnapshot(bool notify, bool includeAnimated = false, float aspectRatio = 0.0f, const QString& filename = QString());
|
|
void takeSecondaryCameraSnapshot(const bool& notify, const QString& filename = QString());
|
|
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition,
|
|
const bool& cubemapOutputFormat,
|
|
const bool& notify,
|
|
const QString& filename = QString());
|
|
void shareSnapshot(const QString& filename, const QUrl& href = QUrl(""));
|
|
|
|
|
|
#if defined(Q_OS_ANDROID)
|
|
void beforeEnterBackground();
|
|
void enterBackground();
|
|
void enterForeground();
|
|
void toggleAwayMode();
|
|
#endif
|
|
|
|
signals:
|
|
void svoImportRequested(const QString& url);
|
|
|
|
void fullAvatarURLChanged(const QString& newValue, const QString& modelName);
|
|
|
|
void beforeAboutToQuit();
|
|
void activeDisplayPluginChanged();
|
|
|
|
void uploadRequest(QString path);
|
|
|
|
void interstitialModeChanged(bool isInInterstitialMode);
|
|
|
|
void loginDialogFocusEnabled();
|
|
void loginDialogFocusDisabled();
|
|
|
|
void miniTabletEnabledChanged(bool enabled);
|
|
void awayStateWhenFocusLostInVRChanged(bool enabled);
|
|
|
|
void darkThemePreferenceChanged(bool useDarkTheme);
|
|
|
|
public slots:
|
|
void updateThreadPoolCount() const;
|
|
|
|
static void gotoTutorial();
|
|
void goToErrorDomainURL(QUrl errorDomainURL);
|
|
void handleLocalServerConnection() const;
|
|
void readArgumentsFromLocalSocket() const;
|
|
void showUrlHandler(const QUrl& url);
|
|
|
|
#if (PR_BUILD || DEV_BUILD)
|
|
void sendWrongProtocolVersionsSignature(bool checked) { ::sendWrongProtocolVersionsSignature(checked); }
|
|
#endif
|
|
|
|
void hmdVisibleChanged(bool visible);
|
|
|
|
void reloadResourceCaches();
|
|
|
|
void updateHeartbeat() const;
|
|
|
|
static void deadlockApplication();
|
|
static void unresponsiveApplication(); // cause main thread to be unresponsive for 35 seconds
|
|
void crashOnShutdown(); // used to test "shutdown" crash annotation.
|
|
|
|
void rotationModeChanged() const;
|
|
|
|
void setIsServerlessMode(bool serverlessDomain);
|
|
std::map<QString, QString> prepareServerlessDomainContents(QUrl domainURL, QByteArray data);
|
|
|
|
void loadServerlessDomain(QUrl domainURL);
|
|
void loadErrorDomain(QUrl domainURL);
|
|
void setIsInterstitialMode(bool interstitialMode);
|
|
|
|
void updateVerboseLogging();
|
|
|
|
void setCachebustRequire();
|
|
|
|
QString getGraphicsCardType();
|
|
bool gpuTextureMemSizeStable();
|
|
|
|
Q_INVOKABLE SharedSoundPointer getSampleSound() const { return _sampleSound; }
|
|
|
|
static void runTests();
|
|
|
|
// UI
|
|
void showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const QString& name) const;
|
|
Q_INVOKABLE void loadDialog();
|
|
Q_INVOKABLE void loadScriptURLDialog() const;
|
|
void toggleLogDialog();
|
|
void recreateLogWindow(int);
|
|
void toggleEntityScriptServerLogDialog();
|
|
Q_INVOKABLE void showAssetServerWidget(QString filePath = "");
|
|
Q_INVOKABLE void loadAddAvatarBookmarkDialog() const;
|
|
Q_INVOKABLE void loadAvatarBrowser() const;
|
|
|
|
void showLoginScreen();
|
|
static void showHelp();
|
|
|
|
void updateSystemTabletMode();
|
|
|
|
void captureMouseChanged(bool captureMouse);
|
|
void toggleOverlays();
|
|
void setOverlaysVisible(bool visible);
|
|
Q_INVOKABLE void centerUI() { _overlayConductor.centerUI(); }
|
|
|
|
void addAssetToWorldMessageClose();
|
|
|
|
void loadLODToolsDialog();
|
|
void loadEntityStatisticsDialog();
|
|
void loadDomainConnectionDialog();
|
|
void showScriptLogs();
|
|
|
|
const QString getPreferredCursor() const { return _preferredCursor.get(); }
|
|
void setPreferredCursor(const QString& cursor);
|
|
|
|
bool getDarkThemePreference() const { return _darkTheme.get(); }
|
|
void setDarkThemePreference(bool value);
|
|
|
|
/**
|
|
* @brief Shows/hides VR keyboard input for Overlay windows
|
|
*
|
|
* This is used by QML scripts to show and hide VR keyboard. Unlike JS API Keyboard.raised = true,
|
|
* with showVRKeyboardForHudUI the input is passed to the active window on the overlay first.
|
|
*
|
|
* @param show
|
|
* If set to true, then keyboard is shown, for false it's hidden.
|
|
*/
|
|
Q_INVOKABLE void showVRKeyboardForHudUI(bool show);
|
|
|
|
|
|
// Plugins
|
|
void resetSensors(bool andReload = false);
|
|
|
|
|
|
// Entities
|
|
QVector<EntityItemID> pasteEntities(const QString& entityHostType, float x, float y, float z);
|
|
bool exportEntities(const QString& filename, const QVector<QUuid>& entityIDs, const glm::vec3* givenOffset = nullptr);
|
|
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
|
|
bool importEntities(const QString& url, const bool isObservable = true, const qint64 callerId = -1);
|
|
|
|
void setKeyboardFocusHighlight(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions);
|
|
QUuid getKeyboardFocusEntity() const { return _keyboardFocusedEntity.get(); } // thread-safe
|
|
void setKeyboardFocusEntity(const QUuid& id);
|
|
|
|
|
|
// Assets
|
|
void addAssetToWorldFromURL(QString url);
|
|
void addAssetToWorldFromURLRequestFinished();
|
|
void addAssetToWorld(QString filePath, QString zipFile, bool isZip = false);
|
|
void addAssetToWorldUnzipFailure(QString filePath);
|
|
void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy, bool isZip = false);
|
|
void addAssetToWorldUpload(QString filePath, QString mapping, bool isZip = false);
|
|
void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash, bool isZip = false);
|
|
void addAssetToWorldAddEntity(QString filePath, QString mapping);
|
|
|
|
void handleUnzip(QString sourceFile, QStringList destinationFile, bool autoAdd, bool isZip);
|
|
|
|
ArchiveDownloadInterface* getFileDownloadInterface() { return _fileDownload; }
|
|
|
|
static void packageModel();
|
|
|
|
|
|
// Camera
|
|
void cycleCamera();
|
|
void cameraModeChanged();
|
|
void cameraMenuChanged();
|
|
|
|
void changeViewAsNeeded(float boomLength);
|
|
|
|
|
|
// Physics
|
|
void resetPhysicsReadyInformation();
|
|
|
|
|
|
private slots:
|
|
void onAboutToQuit();
|
|
|
|
void loadSettings(const QCommandLineParser& parser);
|
|
void saveSettings() const;
|
|
void setFailedToConnectToEntityServer() { _failedToConnectToEntityServer = true; }
|
|
|
|
bool acceptSnapshot(const QString& urlString);
|
|
|
|
void setSessionUUID(const QUuid& sessionUUID) const;
|
|
|
|
void domainURLChanged(QUrl domainURL);
|
|
void domainConnectionRefused(const QString& reasonMessage, int reason, const QString& extraInfo);
|
|
|
|
void updateWindowTitle() const;
|
|
void nodeAdded(SharedNodePointer node);
|
|
void nodeActivated(SharedNodePointer node);
|
|
void nodeKilled(SharedNodePointer node);
|
|
|
|
void handleSandboxStatus(QNetworkReply* reply);
|
|
|
|
|
|
// UI
|
|
void onDesktopRootItemCreated(QQuickItem* qmlContext);
|
|
void onDesktopRootContextCreated(QQmlContext* qmlContext);
|
|
void showDesktop();
|
|
|
|
void notifyPacketVersionMismatch();
|
|
|
|
bool askToSetAvatarUrl(const QString& url);
|
|
bool askToLoadScript(const QString& scriptFilenameOrURL);
|
|
bool askToReplaceDomainContent(const QString& url);
|
|
|
|
void onDismissedLoginDialog();
|
|
|
|
|
|
// Entities
|
|
void clearDomainOctreeDetails(bool clearAll = true);
|
|
void resettingDomain();
|
|
|
|
|
|
// Events
|
|
void onPresent(quint32 frameCount);
|
|
|
|
void activeChanged(Qt::ApplicationState state);
|
|
void windowMinimizedChanged(bool minimized);
|
|
|
|
|
|
// Plugins
|
|
void updateDisplayMode();
|
|
void switchDisplayMode();
|
|
void setDisplayPlugin(DisplayPluginPointer newPlugin);
|
|
|
|
|
|
// Assets
|
|
void addAssetToWorldCheckModelSize();
|
|
void onAssetToWorldMessageBoxClosed();
|
|
void addAssetToWorldInfoTimeout();
|
|
void addAssetToWorldErrorTimeout();
|
|
|
|
|
|
// Physics
|
|
void setShowBulletWireframe(bool value) { _physicsEngine->setShowBulletWireframe(value); }
|
|
void setShowBulletAABBs(bool value) { _physicsEngine->setShowBulletAABBs(value); }
|
|
void setShowBulletContactPoints(bool value) { _physicsEngine->setShowBulletContactPoints(value); }
|
|
void setShowBulletConstraints(bool value) { _physicsEngine->setShowBulletConstraints(value); }
|
|
void setShowBulletConstraintLimits(bool value) { _physicsEngine->setShowBulletConstraintLimits(value); }
|
|
|
|
void setShowTrackedObjects(bool value) { _showTrackedObjects = value; }
|
|
|
|
private:
|
|
void cleanupBeforeQuit();
|
|
|
|
void idle();
|
|
void update(float deltaTime);
|
|
void updateLOD(float deltaTime) const;
|
|
void updateThreads(float deltaTime);
|
|
|
|
void userKickConfirmation(const QUuid& nodeID, unsigned int banFlags = ModerationFlags::getDefaultBanFlags());
|
|
|
|
|
|
// Setup
|
|
void init();
|
|
void setupSignalsAndOperators();
|
|
|
|
|
|
// UI
|
|
bool initMenu();
|
|
void pauseUntilLoginDetermined();
|
|
void resumeAfterLoginDialogActionTaken();
|
|
|
|
static QSharedPointer<OffscreenUi> getOffscreenUI();
|
|
|
|
void updateDialogs(float deltaTime) const;
|
|
|
|
void maybeToggleMenuVisible(QMouseEvent* event) const;
|
|
void toggleTabletUI(bool shouldOpen = false) const;
|
|
|
|
bool shouldCaptureMouse() const;
|
|
void checkChangeCursor();
|
|
|
|
void addAssetToWorldInfo(QString modelName, QString infoText);
|
|
void addAssetToWorldInfoClear(QString modelName);
|
|
void addAssetToWorldInfoDone(QString modelName);
|
|
void addAssetToWorldError(QString modelName, QString errorText);
|
|
|
|
|
|
// Events
|
|
void resizeEvent(QResizeEvent* size) { resizeGL(); }
|
|
|
|
void keyPressEvent(QKeyEvent* event);
|
|
void keyReleaseEvent(QKeyEvent* event);
|
|
|
|
void focusOutEvent(QFocusEvent* event);
|
|
void synthesizeKeyReleasEvents();
|
|
|
|
void mouseMoveEvent(QMouseEvent* event);
|
|
void mousePressEvent(QMouseEvent* event);
|
|
void mouseDoublePressEvent(QMouseEvent* event);
|
|
void mouseReleaseEvent(QMouseEvent* event);
|
|
|
|
void touchBeginEvent(QTouchEvent* event);
|
|
void touchEndEvent(QTouchEvent* event);
|
|
void touchUpdateEvent(QTouchEvent* event);
|
|
void touchGestureEvent(QGestureEvent* event);
|
|
|
|
void wheelEvent(QWheelEvent* event) const;
|
|
void dropEvent(QDropEvent* event);
|
|
static void dragEnterEvent(QDragEnterEvent* event) { event->acceptProposedAction(); }
|
|
|
|
bool handleInputMethodEventForFocusedEntity(QEvent* event);
|
|
bool handleKeyEventForFocusedEntity(QEvent* event);
|
|
bool handleFileOpenEvent(QFileOpenEvent* event);
|
|
|
|
|
|
// Entities
|
|
void queryOctree(NodeType_t serverType, PacketType packetType);
|
|
|
|
int sendNackPackets();
|
|
|
|
|
|
// Graphics
|
|
void updateRenderArgs(float deltaTime);
|
|
|
|
|
|
// Plugins
|
|
void startHMDStandBySession();
|
|
void endHMDSession();
|
|
|
|
|
|
// Assets
|
|
bool importJSONFromURL(const QString& urlString);
|
|
bool importSVOFromURL(const QString& urlString);
|
|
bool importFromZIP(const QString& filePath);
|
|
bool importImage(const QString& urlString);
|
|
|
|
|
|
// Avatars
|
|
std::shared_ptr<MyAvatar> getMyAvatar() const;
|
|
void checkSkeleton() const;
|
|
|
|
void queryAvatars();
|
|
|
|
|
|
// Physics
|
|
void tryToEnablePhysics();
|
|
|
|
|
|
// Member Variables
|
|
// The window needs to be initialized early as other initializers try to access it
|
|
MainWindow* _window;
|
|
// _isMenuInitialized: used to initialize menu early enough before it's needed by other
|
|
// initializers. Fixes a deadlock issue with recent Qt versions.
|
|
bool _isMenuInitialized;
|
|
|
|
bool _startUpFinished { false };
|
|
bool _quitWhenFinished { false };
|
|
bool _crashOnShutdown { false };
|
|
bool _aboutToQuit { false };
|
|
bool _previousSessionCrashed { false };
|
|
|
|
QUrl _urlParam;
|
|
bool _overrideEntry { false };
|
|
bool _settingsLoaded { false };
|
|
|
|
bool _domainLoadingInProgress { false };
|
|
bool _interstitialMode { false };
|
|
bool _interstitialModeEnabled { false };
|
|
|
|
PerformanceManager _performanceManager;
|
|
RefreshRateManager _refreshRateManager;
|
|
GameWorkload _gameWorkload;
|
|
|
|
ConnectionMonitor _connectionMonitor;
|
|
|
|
#ifndef Q_OS_ANDROID
|
|
FileLogger* _logger { nullptr };
|
|
#endif
|
|
|
|
QElapsedTimer& _sessionRunTimer;
|
|
QElapsedTimer _lastTimeUpdated;
|
|
QTimer _locationUpdateTimer;
|
|
QTimer _minimizedWindowTimer;
|
|
// Frame Rate Measurement
|
|
RateCounter<500> _gameLoopCounter;
|
|
|
|
using SteadyClock = std::chrono::steady_clock;
|
|
using TimePoint = SteadyClock::time_point;
|
|
TimePoint _queryExpiry;
|
|
|
|
quint64 _lastNackTime;
|
|
quint64 _lastSendDownstreamAudioStats;
|
|
|
|
bool _notifiedPacketVersionMismatchThisDomain { false };
|
|
|
|
QDir _defaultScriptsLocation;
|
|
// If above is only set by parameter, below is unnecessary.
|
|
bool _overrideDefaultScriptsLocation;
|
|
|
|
qint64 _gpuTextureMemSizeStabilityCount { 0 };
|
|
qint64 _gpuTextureMemSizeAtLastCheck { 0 };
|
|
int _minimumGPUTextureMemSizeStabilityCount { 30 };
|
|
|
|
SharedSoundPointer _sampleSound { nullptr };
|
|
|
|
VisionSqueeze _visionSqueeze;
|
|
|
|
DiscordPresence* _discordPresence { nullptr };
|
|
|
|
Setting::Handle<bool> _firstRun;
|
|
Setting::Handle<QString> _previousScriptLocation;
|
|
|
|
|
|
// UI
|
|
GLCanvas* _glWidget { nullptr };
|
|
|
|
Overlays _overlays;
|
|
std::shared_ptr<ApplicationOverlay> _applicationOverlay;
|
|
OverlayConductor _overlayConductor;
|
|
|
|
mutable QRecursiveMutex _changeCursorLock;
|
|
Qt::CursorShape _desiredCursor { Qt::BlankCursor };
|
|
bool _cursorNeedsChanging { false };
|
|
bool _useSystemCursor { false };
|
|
|
|
DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface;
|
|
|
|
QPointer<LogDialog> _logDialog;
|
|
QPointer<EntityScriptServerLogDialog> _entityScriptServerLogDialog;
|
|
ModalDialogListener* _confirmConnectWithoutAvatarEntitiesDialog { nullptr };
|
|
|
|
QUuid _loginDialogID;
|
|
QUuid _avatarInputsBarID;
|
|
LoginStateManager _loginStateManager;
|
|
|
|
QQuickItem* _addAssetToWorldMessageBox { nullptr };
|
|
QStringList _addAssetToWorldInfoKeys; // Model name
|
|
QStringList _addAssetToWorldInfoMessages; // Info message
|
|
QTimer _addAssetToWorldInfoTimer;
|
|
QTimer _addAssetToWorldErrorTimer;
|
|
|
|
ArchiveDownloadInterface* _fileDownload;
|
|
|
|
bool _loginDialogPoppedUp { false };
|
|
bool _developerMenuVisible { false };
|
|
bool _noLoginSuggestion { false };
|
|
|
|
bool _resumeAfterLoginDialogActionTaken_WasPostponed { false };
|
|
bool _resumeAfterLoginDialogActionTaken_SafeToRun { false };
|
|
|
|
bool _isForeground { true }; // starts out assumed to be in foreground
|
|
|
|
Setting::Handle<float> _hmdTabletScale;
|
|
Setting::Handle<float> _desktopTabletScale;
|
|
Setting::Handle<bool> _desktopTabletBecomesToolbarSetting;
|
|
Setting::Handle<bool> _hmdTabletBecomesToolbarSetting;
|
|
Setting::Handle<bool> _preferStylusOverLaserSetting;
|
|
Setting::Handle<bool> _preferAvatarFingerOverStylusSetting;
|
|
Setting::Handle<bool> _defaultMouseCaptureVR;
|
|
Setting::Handle<bool> _showGraphicsIconSetting;
|
|
Setting::Handle<bool> _constrainToolbarPosition;
|
|
Setting::Handle<bool> _awayStateWhenFocusLostInVREnabled;
|
|
Setting::Handle<QString> _preferredCursor;
|
|
// TODO Qt6: Qt5 doesn't have anything for system theme preferences, Qt6.5+ does
|
|
Setting::Handle<bool> _darkTheme;
|
|
Setting::Handle<bool> _miniTabletEnabledSetting;
|
|
Setting::Handle<bool> _keepLogWindowOnTop { "keepLogWindowOnTop", false };
|
|
|
|
void updateThemeColors();
|
|
|
|
|
|
// Plugins
|
|
DisplayPluginPointer _displayPlugin;
|
|
mutable std::mutex _displayPluginLock;
|
|
|
|
std::shared_ptr<controller::StateController> _applicationStateDevice; // Default ApplicationDevice reflecting the state of different properties of the session
|
|
std::shared_ptr<KeyboardMouseDevice> _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad
|
|
std::shared_ptr<TouchscreenDevice> _touchscreenDevice; // the good old touchscreen
|
|
std::shared_ptr<TouchscreenVirtualPadDevice> _touchscreenVirtualPadDevice;
|
|
bool _keyboardDeviceHasFocus { true };
|
|
|
|
ControllerScriptingInterface* _controllerScriptingInterface { nullptr };
|
|
|
|
DisplayPluginPointer _autoSwitchDisplayModeSupportedHMDPlugin { nullptr };
|
|
QString _autoSwitchDisplayModeSupportedHMDPluginName;
|
|
bool _previousHMDWornStatus { false };
|
|
|
|
|
|
// Events
|
|
QHash<int, QKeyEvent> _keysPressed;
|
|
TouchEvent _lastTouchEvent;
|
|
quint64 _lastAcceptedKeyPress { 0 };
|
|
|
|
ThreadSafeValueCache<EntityItemID> _keyboardFocusedEntity;
|
|
|
|
bool _reticleClickPressed { false };
|
|
bool _keyboardFocusWaitingOnRenderable { false };
|
|
|
|
bool _captureMouse { false };
|
|
bool _ignoreMouseMove { false };
|
|
QPointF _mouseCaptureTarget { NAN, NAN };
|
|
|
|
std::map<void*, std::function<void()>> _postUpdateLambdas;
|
|
std::mutex _postUpdateLambdasLock;
|
|
|
|
std::atomic<bool> _pendingIdleEvent { true };
|
|
|
|
|
|
// Entities
|
|
EntityTreePointer _entityClipboard;
|
|
|
|
std::shared_ptr<OctreePacketProcessor> _octreeProcessor;
|
|
std::shared_ptr<EntityEditPacketSender> _entityEditSender;
|
|
OctreeQuery _octreeQuery { true }; // NodeData derived class for querying octee cells from octree servers
|
|
bool _enableProcessOctreeThread { true };
|
|
|
|
uint32_t _fullSceneCounterAtLastPhysicsCheck { 0 }; // _fullSceneReceivedCounter last time we checked physics ready
|
|
|
|
mutable QTimer _entityServerConnectionTimer;
|
|
|
|
QUuid _keyboardFocusHighlightID;
|
|
|
|
bool _failedToConnectToEntityServer { false };
|
|
bool _isMissingSequenceNumbers { false };
|
|
|
|
Setting::Handle<int> _maxOctreePacketsPerSecond;
|
|
int _maxOctreePPS { DEFAULT_MAX_OCTREE_PPS };
|
|
|
|
|
|
// Assets
|
|
typedef bool (Application::*AcceptURLMethod)(const QString&);
|
|
static const std::vector<std::pair<QString, AcceptURLMethod>> _acceptedExtensions;
|
|
|
|
QTimer _addAssetToWorldResizeTimer;
|
|
QHash<QUuid, int> _addAssetToWorldResizeList;
|
|
|
|
|
|
// Camera
|
|
FancyCamera _myCamera; // My view onto the world
|
|
|
|
CameraMode _previousCameraMode;
|
|
glm::vec3 _thirdPersonHMDCameraBoom { 0.0f, 0.0f, -1.0f };
|
|
bool _thirdPersonHMDCameraBoomValid { true };
|
|
float _scaleMirror { 1.0f };
|
|
float _mirrorYawOffset { 0.0f };
|
|
float _raiseMirror { 0.0f };
|
|
|
|
mutable QRecursiveMutex _viewMutex;
|
|
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
|
ViewFrustum _displayViewFrustum;
|
|
|
|
ConicalViewFrustums _conicalViews;
|
|
ConicalViewFrustums _lastQueriedViews; // last views used to query servers
|
|
|
|
Setting::Handle<float> _fieldOfView;
|
|
Setting::Handle<float> _cameraClippingEnabled;
|
|
|
|
bool _prevCameraClippingEnabled { false };
|
|
unsigned int _cameraClippingRayPickID;
|
|
|
|
|
|
// Graphics
|
|
std::shared_ptr<GraphicsEngine> _graphicsEngine;
|
|
glm::uvec2 _renderResolution;
|
|
|
|
bool _isGLInitialized { false };
|
|
|
|
|
|
// Avatars
|
|
QString _previousAvatarSkeletonModel;
|
|
float _previousAvatarTargetScale;
|
|
|
|
QUrl _avatarOverrideUrl;
|
|
bool _saveAvatarOverrideUrl { false };
|
|
|
|
|
|
// Physics
|
|
ShapeManager _shapeManager;
|
|
PhysicalEntitySimulationPointer _entitySimulation;
|
|
PhysicsEnginePointer _physicsEngine;
|
|
|
|
bool _physicsEnabled { false };
|
|
// This is needed so that physics do not get re-enabled before safe landing starts when moving from
|
|
// serverless to domain server.
|
|
// It's set to true by Application::clearDomainOctreeData and is cleared by Application::setIsServerlessMode
|
|
bool _waitForServerlessToBeSet { true };
|
|
|
|
bool _showTrackedObjects { false };
|
|
bool _prevShowTrackedObjects { false };
|
|
|
|
|
|
// Snapshots
|
|
std::mutex _snapshotMutex;
|
|
std::queue<SnapshotOperator> _snapshotOperators;
|
|
bool _hasPrimarySnapshot { false };
|
|
};
|
|
#endif // hifi_Application_h
|