3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-27 07:15:30 +02:00

Merge branch 'master' into 21369

# Conflicts:
#	libraries/gl/src/gl/OffscreenQmlSurface.cpp
#	libraries/gl/src/gl/OffscreenQmlSurface.h
This commit is contained in:
NeetBhagat 2017-06-07 14:56:34 +05:30
commit ead0d42cf3
62 changed files with 671 additions and 423 deletions

View file

@ -1,5 +1,7 @@
This is a stand-alone guide for creating your first High Fidelity build for Windows 64-bit.
## Building High Fidelity
### Step 1. Installing Visual Studio 2013
If you don't already have the Community or Professional edition of Visual Studio 2013, download and install [Visual Studio Community 2013](https://www.visualstudio.com/en-us/news/releasenotes/vs2013-community-vs). You do not need to install any of the optional components when going through the installer.
@ -18,8 +20,8 @@ Keep the default components checked when going through the installer.
### Step 4. Setting Qt Environment Variable
Go to "Control Panel > System > Advanced System Settings > Environment Variables > New..." (or search “Environment Variables” in Start Search).
* Set "Variable name": QT_CMAKE_PREFIX_PATH
Go to `Control Panel > System > Advanced System Settings > Environment Variables > New...` (or search “Environment Variables” in Start Search).
* Set "Variable name": `QT_CMAKE_PREFIX_PATH`
* Set "Variable value": `%QT_DIR%\5.6\msvc2013_64\lib\cmake`
### Step 5. Installing OpenSSL
@ -29,34 +31,36 @@ Download and install the [Win64 OpenSSL v1.0.2L Installer](https://slproweb.com/
### Step 6. Running CMake to Generate Build Files
Run Command Prompt from Start and run the following commands:
cd "%HIFI_DIR%"
mkdir build
cd build
cmake .. -G "Visual Studio 12 Win64"
````
cd "%HIFI_DIR%"
mkdir build
cd build
cmake .. -G "Visual Studio 12 Win64"
````
Where %HIFI_DIR% is the directory for the highfidelity repository.
Where `%HIFI_DIR%` is the directory for the highfidelity repository.
### Step 7. Making a Build
Open '%HIFI_DIR%\build\hifi.sln' using Visual Studio.
Open `%HIFI_DIR%\build\hifi.sln` using Visual Studio.
Change the Solution Configuration (next to the green play button) from "Debug" to "Release" for best performance.
Run Build > Build Solution.
Run `Build > Build Solution`.
### Step 8. Testing Interface
Create another environment variable (see Step #4)
* Set "Variable name": _NO_DEBUG_HEAP
* Set "Variable value": 1
* Set "Variable name": `_NO_DEBUG_HEAP`
* Set "Variable value": `1`
In Visual Studio, right+click "interface" under the Apps folder in Solution Explorer and select "Set as Startup Project". Run Debug > Start Debugging.
In Visual Studio, right+click "interface" under the Apps folder in Solution Explorer and select "Set as Startup Project". Run `Debug > Start Debugging`.
Now, you should have a full build of High Fidelity and be able to run the Interface using Visual Studio. Please check our [Docs](https://wiki.highfidelity.com/wiki/Main_Page) for more information regarding the programming workflow.
Note: You can also run Interface by launching it from command line or File Explorer from %HIFI_DIR%\build\interface\Release\interface.exe
Note: You can also run Interface by launching it from command line or File Explorer from `%HIFI_DIR%\build\interface\Release\interface.exe`
### Troubleshooting
## Troubleshooting
For any problems after Step #6, first try this:
* Delete your locally cloned copy of the highfidelity repository
@ -66,16 +70,16 @@ For any problems after Step #6, first try this:
#### CMake gives you the same error message repeatedly after the build fails
Remove `CMakeCache.txt` found in the '%HIFI_DIR%\build' directory
Remove `CMakeCache.txt` found in the `%HIFI_DIR%\build` directory.
#### nmake cannot be found
Make sure nmake.exe is located at the following path:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin
If not, add the directory where nmake is located to the PATH environment variable.
#### Qt is throwing an error
Make sure you have the correct version (5.6.2) installed and 'QT_CMAKE_PREFIX_PATH' environment variable is set correctly.
Make sure you have the correct version (5.6.2) installed and `QT_CMAKE_PREFIX_PATH` environment variable is set correctly.

View file

@ -2,7 +2,6 @@ import QtQuick 2.5
import QtQuick.Controls 1.2
import QtWebChannel 1.0
import QtWebEngine 1.2
import FileTypeProfile 1.0
import "controls-uit"
import "styles" as HifiStyles
@ -209,6 +208,7 @@ ScrollingWindow {
WebView {
id: webview
url: "https://highfidelity.com/"
profile: FileTypeProfile;
property alias eventBridgeWrapper: eventBridgeWrapper
@ -218,10 +218,6 @@ ScrollingWindow {
property var eventBridge;
}
profile: FileTypeProfile {
id: webviewProfile
storageName: "qmlWebEngine"
}
webChannel.registeredObjects: [eventBridgeWrapper]

View file

@ -8,7 +8,6 @@ import "controls-uit" as HifiControls
import "styles" as HifiStyles
import "styles-uit"
import "windows"
import HFTabletWebEngineProfile 1.0
Item {
id: root
@ -47,10 +46,7 @@ Item {
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFTabletWebEngineProfile {
id: webviewTabletProfile
storageName: "qmlTabletWebEngine"
}
profile: HFTabletWebEngineProfile;
property string userScriptUrl: ""

View file

@ -10,13 +10,10 @@
import QtQuick 2.5
import QtWebEngine 1.2
import HFWebEngineProfile 1.0
WebEngineView {
id: root
// profile: desktop.browserProfile
Component.onCompleted: {
console.log("Connecting JS messaging to Hifi Logging")
// Ensure the JS from the web-engine makes it to our logging

View file

@ -2,7 +2,6 @@ import QtQuick 2.5
import QtWebEngine 1.1
import QtWebChannel 1.0
import "../controls-uit" as HiFiControls
import HFTabletWebEngineProfile 1.0
Item {
property alias url: root.url
@ -39,10 +38,7 @@ Item {
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFTabletWebEngineProfile {
id: webviewProfile
storageName: "qmlTabletWebEngine"
}
profile: HFTabletWebEngineProfile;
property string userScriptUrl: ""

View file

@ -2,7 +2,6 @@ import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebEngine 1.2
import QtWebChannel 1.0
import HFTabletWebEngineProfile 1.0
import "../controls-uit" as HiFiControls
import "../styles" as HifiStyles
import "../styles-uit"
@ -150,10 +149,7 @@ Item {
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height - web.headerHeight : parent.height - web.headerHeight
anchors.top: buttons.bottom
profile: HFTabletWebEngineProfile {
id: webviewTabletProfile
storageName: "qmlTabletWebEngine"
}
profile: HFTabletWebEngineProfile;
property string userScriptUrl: ""

View file

@ -10,13 +10,9 @@
import QtQuick 2.5
import "."
import FileTypeProfile 1.0
WebView {
viewProfile: FileTypeProfile {
id: webviewProfile
storageName: "qmlWebEngine"
}
viewProfile: FileTypeProfile;
urlTag: "noDownload=true";
}

View file

@ -2,7 +2,6 @@ import QtQuick 2.5
import QtWebEngine 1.1
import QtWebChannel 1.0
import "../controls-uit" as HiFiControls
import HFWebEngineProfile 1.0
Item {
property alias url: root.url
@ -39,10 +38,7 @@ Item {
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFWebEngineProfile {
id: webviewProfile
storageName: "qmlWebEngine"
}
profile: HFWebEngineProfile;
property string userScriptUrl: ""

View file

@ -2,7 +2,6 @@ import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebEngine 1.1;
import Qt.labs.settings 1.0
import HFWebEngineProfile 1.0
import "../desktop" as OriginalDesktop
import ".."
@ -27,11 +26,6 @@ OriginalDesktop.Desktop {
property alias toolWindow: toolWindow
ToolWindow { id: toolWindow }
property var browserProfile: HFWebEngineProfile {
id: webviewProfile
storageName: "qmlWebEngine"
}
Action {
text: "Open Browser"
shortcut: "Ctrl+B"

View file

@ -5,7 +5,6 @@ import QtWebChannel 1.0
import QtQuick.Controls.Styles 1.4
import "../../controls"
import "../toolbars"
import HFWebEngineProfile 1.0
import QtGraphicalEffects 1.0
import "../../controls-uit" as HifiControls
import "../../styles-uit"

View file

@ -4,7 +4,6 @@ import QtQuick.Controls 1.4
import QtQml 2.2
import QtWebChannel 1.0
import QtWebEngine 1.1
import HFWebEngineProfile 1.0
import "."

View file

@ -1,7 +1,6 @@
import QtQuick 2.0
import Hifi 1.0
import QtQuick.Controls 1.4
import HFTabletWebEngineProfile 1.0
import "../../dialogs"
import "../../controls"

View file

@ -72,6 +72,7 @@
#include <ErrorDialog.h>
#include <FileScriptingInterface.h>
#include <Finally.h>
#include <FingerprintUtils.h>
#include <FramebufferCache.h>
#include <gpu/Batch.h>
#include <gpu/Context.h>
@ -114,6 +115,7 @@
#include <RenderDeferredTask.h>
#include <RenderForwardTask.h>
#include <ResourceCache.h>
#include <ResourceRequest.h>
#include <SandboxUtils.h>
#include <SceneScriptingInterface.h>
#include <ScriptEngines.h>
@ -148,9 +150,6 @@
#include "LODManager.h"
#include "ModelPackager.h"
#include "networking/CloseEventSender.h"
#include "networking/HFWebEngineProfile.h"
#include "networking/HFTabletWebEngineProfile.h"
#include "networking/FileTypeProfile.h"
#include "scripting/TestScriptingInterface.h"
#include "scripting/AccountScriptingInterface.h"
#include "scripting/AssetMappingsScriptingInterface.h"
@ -248,6 +247,8 @@ static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStanda
Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS);
static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com";
static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds
static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop";
const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {
{ SVO_EXTENSION, &Application::importSVOFromURL },
@ -951,6 +952,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
properties["processor_l3_cache_count"] = procInfo.numProcessorCachesL3;
}
// add firstRun flag from settings to launch event
Setting::Handle<bool> firstRun { Settings::firstRun, true };
properties["first_run"] = firstRun.get();
// add the user's machine ID to the launch event
properties["machine_fingerprint"] = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint());
UserActivityLogger::getInstance().logAction("launch", properties);
// Tell our entity edit sender about our known jurisdictions
@ -1310,6 +1318,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
properties["kbps_in"] = bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond();
properties["kbps_out"] = bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond();
properties["atp_in_kbps"] = bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AssetServer);
auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer entityServerNode = nodeList->soloNodeOfType(NodeType::EntityServer);
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
@ -1323,8 +1333,61 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
properties["messages_ping"] = messagesMixerNode ? messagesMixerNode->getPingMs() : -1;
auto loadingRequests = ResourceCache::getLoadingRequests();
QJsonArray loadingRequestsStats;
for (const auto& request : loadingRequests) {
QJsonObject requestStats;
requestStats["filename"] = request->getURL().fileName();
requestStats["received"] = request->getBytesReceived();
requestStats["total"] = request->getBytesTotal();
requestStats["attempts"] = (int)request->getDownloadAttempts();
loadingRequestsStats.append(requestStats);
}
properties["active_downloads"] = loadingRequests.size();
properties["pending_downloads"] = ResourceCache::getPendingRequestCount();
properties["active_downloads_details"] = loadingRequestsStats;
auto statTracker = DependencyManager::get<StatTracker>();
properties["processing_resources"] = statTracker->getStat("Processing").toInt();
properties["pending_processing_resources"] = statTracker->getStat("PendingProcessing").toInt();
QJsonObject startedRequests;
startedRequests["atp"] = statTracker->getStat(STAT_ATP_REQUEST_STARTED).toInt();
startedRequests["http"] = statTracker->getStat(STAT_HTTP_REQUEST_STARTED).toInt();
startedRequests["file"] = statTracker->getStat(STAT_FILE_REQUEST_STARTED).toInt();
startedRequests["total"] = startedRequests["atp"].toInt() + startedRequests["http"].toInt()
+ startedRequests["file"].toInt();
properties["started_requests"] = startedRequests;
QJsonObject successfulRequests;
successfulRequests["atp"] = statTracker->getStat(STAT_ATP_REQUEST_SUCCESS).toInt();
successfulRequests["http"] = statTracker->getStat(STAT_HTTP_REQUEST_SUCCESS).toInt();
successfulRequests["file"] = statTracker->getStat(STAT_FILE_REQUEST_SUCCESS).toInt();
successfulRequests["total"] = successfulRequests["atp"].toInt() + successfulRequests["http"].toInt()
+ successfulRequests["file"].toInt();
properties["successful_requests"] = successfulRequests;
QJsonObject failedRequests;
failedRequests["atp"] = statTracker->getStat(STAT_ATP_REQUEST_FAILED).toInt();
failedRequests["http"] = statTracker->getStat(STAT_HTTP_REQUEST_FAILED).toInt();
failedRequests["file"] = statTracker->getStat(STAT_FILE_REQUEST_FAILED).toInt();
failedRequests["total"] = failedRequests["atp"].toInt() + failedRequests["http"].toInt()
+ failedRequests["file"].toInt();
properties["failed_requests"] = failedRequests;
QJsonObject cacheRequests;
cacheRequests["atp"] = statTracker->getStat(STAT_ATP_REQUEST_CACHE).toInt();
cacheRequests["http"] = statTracker->getStat(STAT_HTTP_REQUEST_CACHE).toInt();
cacheRequests["total"] = cacheRequests["atp"].toInt() + cacheRequests["http"].toInt();
properties["cache_requests"] = cacheRequests;
QJsonObject atpMappingRequests;
atpMappingRequests["started"] = statTracker->getStat(STAT_ATP_MAPPING_REQUEST_STARTED).toInt();
atpMappingRequests["failed"] = statTracker->getStat(STAT_ATP_MAPPING_REQUEST_FAILED).toInt();
atpMappingRequests["successful"] = statTracker->getStat(STAT_ATP_MAPPING_REQUEST_SUCCESS).toInt();
properties["atp_mapping_requests"] = atpMappingRequests;
properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false;
@ -1340,9 +1403,43 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
properties["deleted_entity_cnt"] = entityActivityTracking.deletedEntityCount;
properties["edited_entity_cnt"] = entityActivityTracking.editedEntityCount;
NodeToOctreeSceneStats* octreeServerSceneStats = getOcteeSceneStats();
unsigned long totalServerOctreeElements = 0;
for (NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) {
totalServerOctreeElements += i->second.getTotalElements();
}
properties["local_octree_elements"] = (qint64) OctreeElement::getInternalNodeCount();
properties["server_octree_elements"] = (qint64) totalServerOctreeElements;
properties["active_display_plugin"] = getActiveDisplayPlugin()->getName();
properties["using_hmd"] = isHMDMode();
_autoSwitchDisplayModeSupportedHMDPlugin = nullptr;
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
if (displayPlugin->isHmd() &&
displayPlugin->getSupportsAutoSwitch()) {
_autoSwitchDisplayModeSupportedHMDPlugin = displayPlugin;
_autoSwitchDisplayModeSupportedHMDPluginName =
_autoSwitchDisplayModeSupportedHMDPlugin->getName();
_previousHMDWornStatus =
_autoSwitchDisplayModeSupportedHMDPlugin->isDisplayVisible();
break;
}
}
if (_autoSwitchDisplayModeSupportedHMDPlugin) {
if (getActiveDisplayPlugin() != _autoSwitchDisplayModeSupportedHMDPlugin &&
!_autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) {
startHMDStandBySession();
}
// Poll periodically to check whether the user has worn HMD or not. Switch Display mode accordingly.
// If the user wears HMD then switch to VR mode. If the user removes HMD then switch to Desktop mode.
QTimer* autoSwitchDisplayModeTimer = new QTimer(this);
connect(autoSwitchDisplayModeTimer, SIGNAL(timeout()), this, SLOT(switchDisplayMode()));
autoSwitchDisplayModeTimer->start(INTERVAL_TO_CHECK_HMD_WORN_STATUS);
}
auto glInfo = getGLContextData();
properties["gl_info"] = glInfo;
properties["gpu_used_memory"] = (int)BYTES_TO_MB(gpu::Context::getUsedGPUMemSize());
@ -1365,6 +1462,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
lastLeftHandPose = leftHandPose;
lastRightHandPose = rightHandPose;
properties["local_socket_changes"] = DependencyManager::get<StatTracker>()->getStat(LOCAL_SOCKET_CHANGE_STAT).toInt();
UserActivityLogger::getInstance().logAction("stats", properties);
});
sendStatsTimer->start();
@ -1574,7 +1673,10 @@ void Application::aboutToQuit() {
}
getActiveDisplayPlugin()->deactivate();
if (_autoSwitchDisplayModeSupportedHMDPlugin
&& _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) {
_autoSwitchDisplayModeSupportedHMDPlugin->endSession();
}
// use the CloseEventSender via a QThread to send an event that says the user asked for the app to close
auto closeEventSender = DependencyManager::get<CloseEventSender>();
QThread* closureEventThread = new QThread(this);
@ -1852,14 +1954,10 @@ void Application::initializeUi() {
UpdateDialog::registerType();
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference");
qmlRegisterType<HFWebEngineProfile>("HFWebEngineProfile", 1, 0, "HFWebEngineProfile");
qmlRegisterType<HFTabletWebEngineProfile>("HFTabletWebEngineProfile", 1, 0, "HFTabletWebEngineProfile");
qmlRegisterType<FileTypeProfile>("FileTypeProfile", 1, 0, "FileTypeProfile");
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create(_glWidget->qglContext());
auto rootContext = offscreenUi->getRootContext();
auto surfaceContext = offscreenUi->getSurfaceContext();
offscreenUi->setProxyWindow(_window->windowHandle());
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
@ -1871,7 +1969,7 @@ void Application::initializeUi() {
// do better detection in the offscreen UI of what has focus
offscreenUi->setNavigationFocused(false);
auto engine = rootContext->engine();
auto engine = surfaceContext->engine();
connect(engine, &QQmlEngine::quit, [] {
qApp->quit();
});
@ -1880,79 +1978,78 @@ void Application::initializeUi() {
// For some reason there is already an "Application" object in the QML context,
// though I can't find it. Hence, "ApplicationInterface"
rootContext->setContextProperty("ApplicationInterface", this);
rootContext->setContextProperty("Audio", DependencyManager::get<AudioScriptingInterface>().data());
rootContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
rootContext->setContextProperty("AudioScope", DependencyManager::get<AudioScope>().data());
surfaceContext->setContextProperty("Audio", DependencyManager::get<AudioScriptingInterface>().data());
surfaceContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
surfaceContext->setContextProperty("AudioScope", DependencyManager::get<AudioScope>().data());
rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
surfaceContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
surfaceContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
_fileDownload = new FileScriptingInterface(engine);
rootContext->setContextProperty("File", _fileDownload);
surfaceContext->setContextProperty("File", _fileDownload);
connect(_fileDownload, &FileScriptingInterface::unzipResult, this, &Application::handleUnzip);
rootContext->setContextProperty("MyAvatar", getMyAvatar().get());
rootContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data());
rootContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());
rootContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
rootContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
rootContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface);
rootContext->setContextProperty("Rates", new RatesScriptingInterface(this));
rootContext->setContextProperty("pathToFonts", "../../");
surfaceContext->setContextProperty("MyAvatar", getMyAvatar().get());
surfaceContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data());
surfaceContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());
surfaceContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
surfaceContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
surfaceContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface);
surfaceContext->setContextProperty("Rates", new RatesScriptingInterface(this));
rootContext->setContextProperty("TREE_SCALE", TREE_SCALE);
rootContext->setContextProperty("Quat", new Quat());
rootContext->setContextProperty("Vec3", new Vec3());
rootContext->setContextProperty("Uuid", new ScriptUUID());
rootContext->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
surfaceContext->setContextProperty("TREE_SCALE", TREE_SCALE);
// FIXME Quat and Vec3 won't work with QJSEngine used by QML
surfaceContext->setContextProperty("Quat", new Quat());
surfaceContext->setContextProperty("Vec3", new Vec3());
surfaceContext->setContextProperty("Uuid", new ScriptUUID());
surfaceContext->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
rootContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
rootContext->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
surfaceContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
surfaceContext->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
rootContext->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
surfaceContext->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
rootContext->setContextProperty("Camera", &_myCamera);
surfaceContext->setContextProperty("Camera", &_myCamera);
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
rootContext->setContextProperty("SpeechRecognizer", DependencyManager::get<SpeechRecognizer>().data());
surfaceContext->setContextProperty("SpeechRecognizer", DependencyManager::get<SpeechRecognizer>().data());
#endif
rootContext->setContextProperty("Overlays", &_overlays);
rootContext->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
rootContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
rootContext->setContextProperty("Stats", Stats::getInstance());
rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
rootContext->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance());
rootContext->setContextProperty("AvatarBookmarks", DependencyManager::get<AvatarBookmarks>().data());
rootContext->setContextProperty("LocationBookmarks", DependencyManager::get<LocationBookmarks>().data());
surfaceContext->setContextProperty("Overlays", &_overlays);
surfaceContext->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
surfaceContext->setContextProperty("Stats", Stats::getInstance());
surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
surfaceContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
surfaceContext->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance());
surfaceContext->setContextProperty("AvatarBookmarks", DependencyManager::get<AvatarBookmarks>().data());
surfaceContext->setContextProperty("LocationBookmarks", DependencyManager::get<LocationBookmarks>().data());
// Caches
rootContext->setContextProperty("AnimationCache", DependencyManager::get<AnimationCache>().data());
rootContext->setContextProperty("TextureCache", DependencyManager::get<TextureCache>().data());
rootContext->setContextProperty("ModelCache", DependencyManager::get<ModelCache>().data());
rootContext->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
surfaceContext->setContextProperty("AnimationCache", DependencyManager::get<AnimationCache>().data());
surfaceContext->setContextProperty("TextureCache", DependencyManager::get<TextureCache>().data());
surfaceContext->setContextProperty("ModelCache", DependencyManager::get<ModelCache>().data());
surfaceContext->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
rootContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
rootContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
rootContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
rootContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
rootContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
rootContext->setContextProperty("AvatarManager", DependencyManager::get<AvatarManager>().data());
rootContext->setContextProperty("UndoStack", &_undoStackScriptingInterface);
rootContext->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
rootContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data());
rootContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
rootContext->setContextProperty("Scene", DependencyManager::get<SceneScriptingInterface>().data());
rootContext->setContextProperty("Render", _renderEngine->getConfiguration().get());
rootContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
rootContext->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
surfaceContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
surfaceContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
surfaceContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
surfaceContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
surfaceContext->setContextProperty("AvatarManager", DependencyManager::get<AvatarManager>().data());
surfaceContext->setContextProperty("UndoStack", &_undoStackScriptingInterface);
surfaceContext->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
surfaceContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data());
surfaceContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
surfaceContext->setContextProperty("Scene", DependencyManager::get<SceneScriptingInterface>().data());
surfaceContext->setContextProperty("Render", _renderEngine->getConfiguration().get());
surfaceContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
surfaceContext->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
rootContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
rootContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
rootContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get()));
surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get()));
}
@ -6789,6 +6886,35 @@ void Application::updateDisplayMode() {
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
}
void Application::switchDisplayMode() {
if (!_autoSwitchDisplayModeSupportedHMDPlugin) {
return;
}
bool currentHMDWornStatus = _autoSwitchDisplayModeSupportedHMDPlugin->isDisplayVisible();
if (currentHMDWornStatus != _previousHMDWornStatus) {
// Switch to respective mode as soon as currentHMDWornStatus changes
if (currentHMDWornStatus) {
qCDebug(interfaceapp) << "Switching from Desktop to HMD mode";
endHMDSession();
setActiveDisplayPlugin(_autoSwitchDisplayModeSupportedHMDPluginName);
} else {
qCDebug(interfaceapp) << "Switching from HMD to desktop mode";
setActiveDisplayPlugin(DESKTOP_DISPLAY_PLUGIN_NAME);
startHMDStandBySession();
}
emit activeDisplayPluginChanged();
}
_previousHMDWornStatus = currentHMDWornStatus;
}
void Application::startHMDStandBySession() {
_autoSwitchDisplayModeSupportedHMDPlugin->startStandBySession();
}
void Application::endHMDSession() {
_autoSwitchDisplayModeSupportedHMDPlugin->endSession();
}
mat4 Application::getEyeProjection(int eye) const {
QMutexLocker viewLocker(&_viewMutex);
if (isHMDMode()) {

View file

@ -442,7 +442,7 @@ private slots:
void addAssetToWorldErrorTimeout();
void handleSandboxStatus(QNetworkReply* reply);
void switchDisplayMode();
private:
static void initDisplay();
void init();
@ -680,7 +680,11 @@ private:
FileScriptingInterface* _fileDownload;
AudioInjector* _snapshotSoundInjector { nullptr };
SharedSoundPointer _snapshotSound;
DisplayPluginPointer _autoSwitchDisplayModeSupportedHMDPlugin;
QString _autoSwitchDisplayModeSupportedHMDPluginName;
bool _previousHMDWornStatus;
void startHMDStandBySession();
void endHMDSession();
};
#endif // hifi_Application_h

View file

@ -35,15 +35,15 @@ const QString RESULT_ERROR_STYLE = "color: #d13b22;";
const QString GUTTER_PREVIOUS_COMMAND = "<span style=\"color: #57b8bb;\">&lt;</span>";
const QString GUTTER_ERROR = "<span style=\"color: #d13b22;\">X</span>";
const QString JSConsole::_consoleFileName{ "about:console" };
const QString JSConsole::_consoleFileName { "about:console" };
JSConsole::JSConsole(QWidget* parent, ScriptEngine* scriptEngine) :
QWidget(parent),
_ui(new Ui::Console),
_currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND),
_commandHistory(),
_ownScriptEngine(scriptEngine == NULL),
_scriptEngine(NULL) {
QWidget(parent),
_ui(new Ui::Console),
_currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND),
_commandHistory(),
_ownScriptEngine(scriptEngine == NULL),
_scriptEngine(NULL) {
_ui->setupUi(this);
_ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap);
@ -116,9 +116,9 @@ void JSConsole::executeCommand(const QString& command) {
QScriptValue JSConsole::executeCommandInWatcher(const QString& command) {
QScriptValue result;
QMetaObject::invokeMethod(_scriptEngine, "evaluate", Qt::ConnectionType::BlockingQueuedConnection,
Q_RETURN_ARG(QScriptValue, result),
Q_ARG(const QString&, command),
Q_ARG(const QString&, _consoleFileName));
Q_RETURN_ARG(QScriptValue, result),
Q_ARG(const QString&, command),
Q_ARG(const QString&, _consoleFileName));
return result;
}
@ -180,8 +180,7 @@ bool JSConsole::eventFilter(QObject* sender, QEvent* event) {
// If the shift key is being used then treat it as a regular return/enter. If this isn't done,
// a new QTextBlock isn't created.
keyEvent->setModifiers(keyEvent->modifiers() & ~Qt::ShiftModifier);
}
else {
} else {
QString command = _ui->promptTextEdit->toPlainText().trimmed();
if (!command.isEmpty()) {
@ -193,8 +192,7 @@ bool JSConsole::eventFilter(QObject* sender, QEvent* event) {
return true;
}
}
else if (key == Qt::Key_Down) {
} else if (key == Qt::Key_Down) {
// Go to the next command in history if the cursor is at the last line of the current command.
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
int blockCount = _ui->promptTextEdit->document()->blockCount();
@ -202,8 +200,7 @@ bool JSConsole::eventFilter(QObject* sender, QEvent* event) {
setToNextCommandInHistory();
return true;
}
}
else if (key == Qt::Key_Up) {
} else if (key == Qt::Key_Up) {
// Go to the previous command in history if the cursor is at the first line of the current command.
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
if (blockNumber == 0) {
@ -221,8 +218,7 @@ void JSConsole::setToNextCommandInHistory() {
_currentCommandInHistory--;
if (_currentCommandInHistory == NO_CURRENT_HISTORY_COMMAND) {
setAndSelectCommand(_rootCommand);
}
else {
} else {
setAndSelectCommand(_commandHistory[_currentCommandInHistory]);
}
}

View file

@ -35,7 +35,7 @@ public:
void setScriptEngine(ScriptEngine* scriptEngine = NULL);
void clear();
public slots:
public slots:
void executeCommand(const QString& command);
protected:
@ -44,7 +44,7 @@ protected:
virtual void mouseReleaseEvent(QMouseEvent* event) override;
virtual void showEvent(QShowEvent* event) override;
protected slots:
protected slots:
void scrollToBottom();
void resizeTextInput();
void handlePrint(const QString& message, const QString& scriptName);

View file

@ -15,8 +15,8 @@
#include "Application.h"
TestingDialog::TestingDialog(QWidget* parent) :
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint),
_console(new JSConsole(this))
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint),
_console(new JSConsole(this))
{
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle(windowLabel);

View file

@ -51,6 +51,16 @@ Text3DOverlay::~Text3DOverlay() {
}
}
const QString Text3DOverlay::getText() const {
QMutexLocker lock(&_mutex);
return _text;
}
void Text3DOverlay::setText(const QString& text) {
QMutexLocker lock(&_mutex);
_text = text;
}
xColor Text3DOverlay::getBackgroundColor() {
if (_colorPulse == 0.0f) {
return _backgroundColor;
@ -125,7 +135,7 @@ void Text3DOverlay::render(RenderArgs* args) {
// FIXME: Factor out textRenderer so that Text3DOverlay overlay parts can be grouped by pipeline
// for a gpu performance increase. Currently,
// Text renderer sets its own pipeline,
_textRenderer->draw(batch, 0, 0, _text, textColor, glm::vec2(-1.0f), getDrawInFront());
_textRenderer->draw(batch, 0, 0, getText(), textColor, glm::vec2(-1.0f), getDrawInFront());
// so before we continue, we must reset the pipeline
batch.setPipeline(args->_pipeline->pipeline);
args->_pipeline->prepare(batch);
@ -188,7 +198,7 @@ void Text3DOverlay::setProperties(const QVariantMap& properties) {
QVariant Text3DOverlay::getProperty(const QString& property) {
if (property == "text") {
return _text;
return getText();
}
if (property == "textAlpha") {
return _textAlpha;
@ -231,7 +241,7 @@ QSizeF Text3DOverlay::textSize(const QString& text) const {
return QSizeF(extents.x, extents.y) * pointToWorldScale;
}
bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3 &direction, float &distance,
bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3 &direction, float &distance,
BoxFace &face, glm::vec3& surfaceNormal) {
Transform transform = getTransform();
applyTransformTo(transform, true);

View file

@ -12,14 +12,14 @@
#define hifi_Text3DOverlay_h
#include <QString>
#include <QtCore/QMutex>
#include "Billboard3DOverlay.h"
class TextRenderer3D;
class Text3DOverlay : public Billboard3DOverlay {
Q_OBJECT
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
@ -34,7 +34,7 @@ public:
virtual const render::ShapeKey getShapeKey() override;
// getters
const QString& getText() const { return _text; }
const QString getText() const;
float getLineHeight() const { return _lineHeight; }
float getLeftMargin() const { return _leftMargin; }
float getTopMargin() const { return _topMargin; }
@ -45,7 +45,7 @@ public:
float getBackgroundAlpha() { return getAlpha(); }
// setters
void setText(const QString& text) { _text = text; }
void setText(const QString& text);
void setTextAlpha(float alpha) { _textAlpha = alpha; }
void setLineHeight(float value) { _lineHeight = value; }
void setLeftMargin(float margin) { _leftMargin = margin; }
@ -58,15 +58,16 @@ public:
QSizeF textSize(const QString& test) const; // Meters
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal) override;
virtual Text3DOverlay* createClone() const override;
private:
TextRenderer3D* _textRenderer = nullptr;
QString _text;
mutable QMutex _mutex; // used to make get/setText threadsafe, mutable so can be used in const functions
xColor _backgroundColor = xColor { 0, 0, 0 };
float _textAlpha { 1.0f };
float _lineHeight { 1.0f };

View file

@ -135,7 +135,7 @@ Web3DOverlay::~Web3DOverlay() {
void Web3DOverlay::update(float deltatime) {
if (_webSurface) {
// update globalPosition
_webSurface->getRootContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
}
}
@ -163,57 +163,56 @@ void Web3DOverlay::loadSourceURL() {
_webSurface->resume();
_webSurface->getRootItem()->setProperty("url", _url);
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
_webSurface->getRootContext()->setContextProperty("ApplicationInterface", qApp);
} else {
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath()));
_webSurface->load(_url, [&](QQmlContext* context, QObject* obj) {});
_webSurface->resume();
_webSurface->getRootContext()->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
_webSurface->getRootContext()->setContextProperty("Vec3", new Vec3());
_webSurface->getRootContext()->setContextProperty("Quat", new Quat());
_webSurface->getRootContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
_webSurface->getRootContext()->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
_webSurface->getSurfaceContext()->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
_webSurface->getSurfaceContext()->setContextProperty("Vec3", new Vec3());
_webSurface->getSurfaceContext()->setContextProperty("Quat", new Quat());
_webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
_webSurface->getSurfaceContext()->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto flags = tabletScriptingInterface->getFlags();
_webSurface->getRootContext()->setContextProperty("offscreenFlags", flags);
_webSurface->getRootContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
_webSurface->getRootContext()->setContextProperty("Account", AccountScriptingInterface::getInstance());
_webSurface->getRootContext()->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
_webSurface->getRootContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
_webSurface->getRootContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
_webSurface->getRootContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
_webSurface->getRootContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
_webSurface->getRootContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
_webSurface->getRootContext()->setContextProperty("DCModel", DependencyManager::get<DomainConnectionModel>().data());
_webSurface->getRootContext()->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance());
_webSurface->getRootContext()->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
_webSurface->getRootContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
_webSurface->getRootContext()->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
_webSurface->getRootContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags);
_webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
_webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
_webSurface->getSurfaceContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
_webSurface->getSurfaceContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
_webSurface->getSurfaceContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
_webSurface->getSurfaceContext()->setContextProperty("DCModel", DependencyManager::get<DomainConnectionModel>().data());
_webSurface->getSurfaceContext()->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
_webSurface->getSurfaceContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance());
_webSurface->getRootContext()->setContextProperty("pathToFonts", "../../");
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data());
// mark the TabletProxy object as cpp ownership.
QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
_webSurface->getRootContext()->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
_webSurface->getSurfaceContext()->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
// Override min fps for tablet UI, for silky smooth scrolling
setMaxFPS(90);
}
}
_webSurface->getRootContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
}
void Web3DOverlay::setMaxFPS(uint8_t maxFPS) {

View file

@ -339,6 +339,18 @@ void OpenGLDisplayPlugin::deactivate() {
Parent::deactivate();
}
bool OpenGLDisplayPlugin::startStandBySession() {
if (!activateStandBySession()) {
return false;
}
return Parent::startStandBySession();
}
void OpenGLDisplayPlugin::endSession() {
deactivateSession();
Parent::endSession();
}
void OpenGLDisplayPlugin::customizeContext() {
auto presentThread = DependencyManager::get<PresentThread>();
Q_ASSERT(thread() == presentThread->thread());

View file

@ -42,6 +42,8 @@ public:
// between the main thread and the presentation thread
bool activate() override final;
void deactivate() override final;
bool startStandBySession() override final;
void endSession() override final;
bool eventFilter(QObject* receiver, QEvent* event) override;
bool isDisplayVisible() const override { return true; }
@ -99,6 +101,10 @@ protected:
// Returns true on successful activation
virtual bool internalActivate() { return true; }
virtual void internalDeactivate() {}
// Returns true on successful activation of standby session
virtual bool activateStandBySession() { return true; }
virtual void deactivateSession() {}
// Plugin specific functionality to send the composed scene to the output window or device
virtual void internalPresent();

View file

@ -127,7 +127,7 @@ bool RenderableWebEntityItem::buildWebSurface(QSharedPointer<EntityTreeRenderer>
_webSurface->resume();
_webSurface->getRootItem()->setProperty("url", _sourceUrl);
_webSurface->getRootContext()->setContextProperty("desktop", QVariant());
_webSurface->getSurfaceContext()->setContextProperty("desktop", QVariant());
// FIXME - Keyboard HMD only: Possibly add "HMDinfo" object to context for WebView.qml.
// forward web events to EntityScriptingInterface
@ -271,7 +271,7 @@ void RenderableWebEntityItem::loadSourceURL() {
});
_webSurface->getRootItem()->setProperty("url", _sourceUrl);
_webSurface->getRootContext()->setContextProperty("desktop", QVariant());
_webSurface->getSurfaceContext()->setContextProperty("desktop", QVariant());
} else {
_contentType = qmlContent;
@ -284,7 +284,7 @@ void RenderableWebEntityItem::loadSourceURL() {
_webSurface->getRootItem(), _webSurface.data());
}
}
_webSurface->getRootContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
}
@ -420,7 +420,7 @@ void RenderableWebEntityItem::update(const quint64& now) {
if (_webSurface) {
// update globalPosition
_webSurface->getRootContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
}
auto interval = now - _lastRenderTime;

View file

@ -1,6 +1,6 @@
set(TARGET_NAME gl)
setup_hifi_library(OpenGL Qml Quick)
link_hifi_libraries(shared)
link_hifi_libraries(shared networking)
target_opengl()

View file

@ -33,6 +33,9 @@
#include <NetworkAccessManager.h>
#include <GLMHelpers.h>
#include <shared/GlobalAppProperties.h>
#include <FileTypeProfile.h>
#include <HFWebEngineProfile.h>
#include <HFTabletWebEngineProfile.h>
#include "OffscreenGLCanvas.h"
#include "GLHelpers.h"
@ -41,10 +44,11 @@
Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml")
Q_LOGGING_CATEGORY(trace_render_qml_gl, "trace.render.qml.gl")
Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
struct TextureSet {
// The number of surfaces with this size
size_t count{ 0 };
size_t count { 0 };
std::list<OffscreenQmlSurface::TextureAndFence> returnedTextures;
};
@ -193,7 +197,7 @@ private:
std::unordered_map<GLuint, uvec2> _textureSizes;
Mutex _mutex;
std::list<OffscreenQmlSurface::TextureAndFence> _returnedTextures;
size_t _totalTextureUsage{ 0 };
size_t _totalTextureUsage { 0 };
} offscreenTextures;
class UrlHandler : public QObject {
@ -254,8 +258,72 @@ QNetworkAccessManager* QmlNetworkAccessManagerFactory::create(QObject* parent) {
return new QmlNetworkAccessManager(parent);
}
Q_DECLARE_LOGGING_CATEGORY(offscreenFocus)
Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
static QQmlEngine* globalEngine { nullptr };
static size_t globalEngineRefCount { 0 };
QString getEventBridgeJavascript() {
// FIXME: Refactor with similar code in RenderableWebEntityItem
QString javaScriptToInject;
QFile webChannelFile(":qtwebchannel/qwebchannel.js");
QFile createGlobalEventBridgeFile(PathUtils::resourcesPath() + "/html/createGlobalEventBridge.js");
if (webChannelFile.open(QFile::ReadOnly | QFile::Text) &&
createGlobalEventBridgeFile.open(QFile::ReadOnly | QFile::Text)) {
QString webChannelStr = QTextStream(&webChannelFile).readAll();
QString createGlobalEventBridgeStr = QTextStream(&createGlobalEventBridgeFile).readAll();
javaScriptToInject = webChannelStr + createGlobalEventBridgeStr;
} else {
qCWarning(glLogging) << "Unable to find qwebchannel.js or createGlobalEventBridge.js";
}
return javaScriptToInject;
}
QQmlEngine* acquireEngine(QQuickWindow* window) {
Q_ASSERT(QThread::currentThread() == qApp->thread());
if (!globalEngine) {
Q_ASSERT(0 == globalEngineRefCount);
globalEngine = new QQmlEngine();
globalEngine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory);
auto importList = globalEngine->importPathList();
importList.insert(importList.begin(), PathUtils::resourcesPath());
globalEngine->setImportPathList(importList);
for (const auto& path : importList) {
qDebug() << path;
}
if (!globalEngine->incubationController()) {
globalEngine->setIncubationController(window->incubationController());
}
auto rootContext = globalEngine->rootContext();
rootContext->setContextProperty("GL", ::getGLContextData());
rootContext->setContextProperty("urlHandler", new UrlHandler());
rootContext->setContextProperty("resourceDirectoryUrl", QUrl::fromLocalFile(PathUtils::resourcesPath()));
rootContext->setContextProperty("pathToFonts", "../../");
rootContext->setContextProperty("ApplicationInterface", qApp);
auto javaScriptToInject = getEventBridgeJavascript();
if (!javaScriptToInject.isEmpty()) {
rootContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject));
}
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
rootContext->setContextProperty("HFTabletWebEngineProfile", new HFTabletWebEngineProfile(rootContext));
}
++globalEngineRefCount;
return globalEngine;
}
void releaseEngine() {
Q_ASSERT(QThread::currentThread() == qApp->thread());
Q_ASSERT(0 != globalEngineRefCount);
if (0 == --globalEngineRefCount) {
globalEngine->deleteLater();
globalEngine = nullptr;
}
}
void OffscreenQmlSurface::cleanup() {
_canvas->makeCurrent();
@ -286,7 +354,7 @@ void OffscreenQmlSurface::render() {
}
PROFILE_RANGE(render_qml_gl, __FUNCTION__)
_canvas->makeCurrent();
_canvas->makeCurrent();
_renderControl->sync();
_quickWindow->setRenderTarget(_fbo, QSize(_size.x, _size.y));
@ -294,6 +362,7 @@ void OffscreenQmlSurface::render() {
GLuint texture = offscreenTextures.getNextTexture(_size);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_renderControl->render();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, texture);
@ -362,8 +431,8 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
_canvas->deleteLater();
_rootItem->deleteLater();
_qmlComponent->deleteLater();
_qmlEngine->deleteLater();
_quickWindow->deleteLater();
releaseEngine();
}
void OffscreenQmlSurface::onAboutToQuit() {
@ -375,6 +444,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
qCDebug(glLogging) << "Building QML surface";
_renderControl = new QMyQuickRenderControl();
connect(_renderControl, &QQuickRenderControl::renderRequested, this, [this] { _render = true; });
connect(_renderControl, &QQuickRenderControl::sceneChanged, this, [this] { _render = _polish = true; });
QQuickWindow::setDefaultAlphaBuffer(true);
@ -385,7 +456,7 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
// so we wait until after its ctor to move object/context to this thread.
_quickWindow = new QQuickWindow(_renderControl);
_quickWindow->setColor(QColor(255, 255, 255, 0));
_quickWindow->setFlags(_quickWindow->flags() | static_cast<Qt::WindowFlags>(Qt::WA_TranslucentBackground));
_quickWindow->setClearBeforeRendering(false);
_renderControl->_renderWindow = _proxyWindow;
@ -398,32 +469,20 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
connect(_quickWindow, &QQuickWindow::focusObjectChanged, this, &OffscreenQmlSurface::onFocusObjectChanged);
// Create a QML engine.
_qmlEngine = new QQmlEngine;
auto qmlEngine = acquireEngine(_quickWindow);
_qmlContext = new QQmlContext(qmlEngine->rootContext());
_qmlEngine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory);
_qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
_qmlContext->setContextProperty("globalEventBridge", this);
_qmlContext->setContextProperty("webEntity", this);
auto importList = _qmlEngine->importPathList();
importList.insert(importList.begin(), PathUtils::resourcesPath());
_qmlEngine->setImportPathList(importList);
if (!_qmlEngine->incubationController()) {
_qmlEngine->setIncubationController(_quickWindow->incubationController());
}
_qmlComponent = new QQmlComponent(qmlEngine);
// FIXME
_glData = ::getGLContextData(); // Initialize JSON structure so that it can be filled in later and then used in QML.
_qmlEngine->rootContext()->setContextProperty("GL", _glData);
_qmlEngine->rootContext()->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
_qmlComponent = new QQmlComponent(_qmlEngine);
connect(_renderControl, &QQuickRenderControl::renderRequested, this, [this] { _render = true; });
connect(_renderControl, &QQuickRenderControl::sceneChanged, this, [this] { _render = _polish = true; });
if (!_canvas->makeCurrent()) {
qWarning("Failed to make context current for QML Renderer");
return;
}
_glData = ::getGLContextData();
_renderControl->initialize(_canvas->getContext());
// When Quick says there is a need to render, we will not render immediately. Instead,
@ -433,11 +492,6 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
_updateTimer.setTimerType(Qt::PreciseTimer);
_updateTimer.setInterval(MIN_TIMER_MS); // 5ms, Qt::PreciseTimer required
_updateTimer.start();
auto rootContext = getRootContext();
rootContext->setContextProperty("urlHandler", new UrlHandler());
rootContext->setContextProperty("resourceDirectoryUrl", QUrl::fromLocalFile(PathUtils::resourcesPath()));
rootContext->setContextProperty("pathToFonts", "../../");
}
static uvec2 clampSize(const uvec2& size, uint32_t maxDimension) {
@ -460,7 +514,7 @@ void OffscreenQmlSurface::resize(const QSize& newSize_, bool forceResize) {
return;
}
_qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize);
_qmlContext->setContextProperty("surfaceSize", newSize);
if (_rootItem) {
_rootItem->setSize(newSize);
@ -520,20 +574,25 @@ QQuickItem* OffscreenQmlSurface::getRootItem() {
}
void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
_qmlEngine->setBaseUrl(baseUrl);
_qmlContext->setBaseUrl(baseUrl);
}
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
// Synchronous loading may take a while; restart the deadlock timer
QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection);
_qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous);
if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) {
_qmlComponent->loadUrl(_qmlContext->resolvedUrl(qmlSource), QQmlComponent::PreferSynchronous);
} else {
_qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous);
}
if (_qmlComponent->isLoading()) {
connect(_qmlComponent, &QQmlComponent::statusChanged, this,
[this, f](QQmlComponent::Status){
finishQmlLoad(f);
});
finishQmlLoad(f);
});
return nullptr;
}
@ -541,10 +600,22 @@ QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQm
}
void OffscreenQmlSurface::clearCache() {
getRootContext()->engine()->clearComponentCache();
_qmlContext->engine()->clearComponentCache();
}
QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f) {
#if 0
if (!_rootItem) {
QQmlComponent component(_qmlContext->engine());
component.setData(R"QML(
import QtQuick 2.0
import QtWebChannel 1.0
Item { Component.onCompleted: globalEventBridge.WebChannel.id = "globalEventBridge"; }
)QML", QUrl());
QObject *helper = component.create(_qmlContext);
qDebug() << "Created helper";
}
#endif
disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, 0);
if (_qmlComponent->isError()) {
QList<QQmlError> errorList = _qmlComponent->errors();
@ -554,22 +625,8 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb
return nullptr;
}
// FIXME: Refactor with similar code in RenderableWebEntityItem
QString javaScriptToInject;
QFile webChannelFile(":qtwebchannel/qwebchannel.js");
QFile createGlobalEventBridgeFile(PathUtils::resourcesPath() + "/html/createGlobalEventBridge.js");
if (webChannelFile.open(QFile::ReadOnly | QFile::Text) &&
createGlobalEventBridgeFile.open(QFile::ReadOnly | QFile::Text)) {
QString webChannelStr = QTextStream(&webChannelFile).readAll();
QString createGlobalEventBridgeStr = QTextStream(&createGlobalEventBridgeFile).readAll();
javaScriptToInject = webChannelStr + createGlobalEventBridgeStr;
}
else {
qCWarning(glLogging) << "Unable to find qwebchannel.js or createGlobalEventBridge.js";
}
QQmlContext* newContext = new QQmlContext(_qmlEngine, qApp);
QObject* newObject = _qmlComponent->beginCreate(newContext);
QObject* newObject = _qmlComponent->beginCreate(_qmlContext);
if (_qmlComponent->isError()) {
QList<QQmlError> errorList = _qmlComponent->errors();
foreach(const QQmlError& error, errorList)
@ -580,12 +637,10 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb
return nullptr;
}
_qmlEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
_qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
newObject->setProperty("eventBridge", QVariant::fromValue(this));
newContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject));
f(newContext, newObject);
f(_qmlContext, newObject);
_qmlComponent->completeCreate();
@ -635,7 +690,7 @@ void OffscreenQmlSurface::updateQuick() {
if (_polish) {
PROFILE_RANGE(render_qml, "OffscreenQML polish")
_renderControl->polishItems();
_renderControl->polishItems();
_polish = false;
}
@ -649,8 +704,7 @@ QPointF OffscreenQmlSurface::mapWindowToUi(const QPointF& sourcePosition, QObjec
vec2 sourceSize;
if (dynamic_cast<QWidget*>(sourceObject)) {
sourceSize = toGlm(((QWidget*)sourceObject)->size());
}
else if (dynamic_cast<QWindow*>(sourceObject)) {
} else if (dynamic_cast<QWindow*>(sourceObject)) {
sourceSize = toGlm(((QWindow*)sourceObject)->size());
}
vec2 offscreenPosition = toGlm(sourcePosition);
@ -693,61 +747,61 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
#endif
switch (event->type()) {
case QEvent::Resize: {
QResizeEvent* resizeEvent = static_cast<QResizeEvent*>(event);
QWidget* widget = dynamic_cast<QWidget*>(originalDestination);
if (widget) {
this->resize(resizeEvent->size());
case QEvent::Resize: {
QResizeEvent* resizeEvent = static_cast<QResizeEvent*>(event);
QWidget* widget = dynamic_cast<QWidget*>(originalDestination);
if (widget) {
this->resize(resizeEvent->size());
}
break;
}
break;
}
case QEvent::KeyPress:
case QEvent::KeyRelease: {
event->ignore();
if (QCoreApplication::sendEvent(_quickWindow, event)) {
return event->isAccepted();
case QEvent::KeyPress:
case QEvent::KeyRelease: {
event->ignore();
if (QCoreApplication::sendEvent(_quickWindow, event)) {
return event->isAccepted();
}
break;
}
break;
}
case QEvent::Wheel: {
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
QPointF transformedPos = mapToVirtualScreen(wheelEvent->pos(), originalDestination);
QWheelEvent mappedEvent(
transformedPos,
wheelEvent->delta(), wheelEvent->buttons(),
wheelEvent->modifiers(), wheelEvent->orientation());
mappedEvent.ignore();
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
return mappedEvent.isAccepted();
case QEvent::Wheel: {
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
QPointF transformedPos = mapToVirtualScreen(wheelEvent->pos(), originalDestination);
QWheelEvent mappedEvent(
transformedPos,
wheelEvent->delta(), wheelEvent->buttons(),
wheelEvent->modifiers(), wheelEvent->orientation());
mappedEvent.ignore();
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
return mappedEvent.isAccepted();
}
break;
}
break;
}
// Fall through
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseMove: {
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
QPointF transformedPos = mapToVirtualScreen(mouseEvent->localPos(), originalDestination);
QMouseEvent mappedEvent(mouseEvent->type(),
transformedPos,
mouseEvent->screenPos(), mouseEvent->button(),
mouseEvent->buttons(), mouseEvent->modifiers());
if (event->type() == QEvent::MouseMove) {
_qmlEngine->rootContext()->setContextProperty("lastMousePosition", transformedPos);
// Fall through
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseMove: {
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
QPointF transformedPos = mapToVirtualScreen(mouseEvent->localPos(), originalDestination);
QMouseEvent mappedEvent(mouseEvent->type(),
transformedPos,
mouseEvent->screenPos(), mouseEvent->button(),
mouseEvent->buttons(), mouseEvent->modifiers());
if (event->type() == QEvent::MouseMove) {
_qmlContext->setContextProperty("lastMousePosition", transformedPos);
}
mappedEvent.ignore();
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
return mappedEvent.isAccepted();
}
break;
}
mappedEvent.ignore();
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
return mappedEvent.isAccepted();
}
break;
}
default:
break;
default:
break;
}
return false;
@ -764,9 +818,6 @@ void OffscreenQmlSurface::resume() {
if (getRootItem()) {
getRootItem()->setProperty("eventBridge", QVariant::fromValue(this));
}
if (getRootContext()) {
getRootContext()->setContextProperty("webEntity", this);
}
}
bool OffscreenQmlSurface::isPaused() const {
@ -792,8 +843,8 @@ QSize OffscreenQmlSurface::size() const {
return _quickWindow->geometry().size();
}
QQmlContext* OffscreenQmlSurface::getRootContext() {
return _qmlEngine->rootContext();
QQmlContext* OffscreenQmlSurface::getSurfaceContext() {
return _qmlContext;
}
Q_DECLARE_METATYPE(std::function<void()>);
@ -802,7 +853,7 @@ Q_DECLARE_METATYPE(std::function<QVariant()>);
auto VariantLambdaType = qRegisterMetaType<std::function<QVariant()>>();
void OffscreenQmlSurface::executeOnUiThread(std::function<void()> function, bool blocking) {
void OffscreenQmlSurface::executeOnUiThread(std::function<void()> function, bool blocking ) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "executeOnUiThread", blocking ? Qt::BlockingQueuedConnection : Qt::QueuedConnection,
Q_ARG(std::function<void()>, function));
@ -894,20 +945,16 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key) {
if (equals(utf8Key, SHIFT_ARROW) || equals(utf8Key, NUMERIC_SHIFT_ARROW) ||
equals(utf8Key, (uint8_t*)PUNCTUATION_STRING) || equals(utf8Key, (uint8_t*)ALPHABET_STRING)) {
return; // ignore
}
else if (equals(utf8Key, BACKSPACE_SYMBOL)) {
} else if (equals(utf8Key, BACKSPACE_SYMBOL)) {
scanCode = Qt::Key_Backspace;
keyString = "\x08";
}
else if (equals(utf8Key, RETURN_SYMBOL)) {
} else if (equals(utf8Key, RETURN_SYMBOL)) {
scanCode = Qt::Key_Return;
keyString = "\x0d";
}
else if (equals(utf8Key, LEFT_ARROW)) {
} else if (equals(utf8Key, LEFT_ARROW)) {
scanCode = Qt::Key_Left;
keyString = "";
}
else if (equals(utf8Key, RIGHT_ARROW)) {
} else if (equals(utf8Key, RIGHT_ARROW)) {
scanCode = Qt::Key_Right;
keyString = "";
}
@ -947,8 +994,7 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n
void OffscreenQmlSurface::emitScriptEvent(const QVariant& message) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "emitScriptEvent", Qt::QueuedConnection, Q_ARG(QVariant, message));
}
else {
} else {
emit scriptEventReceived(message);
}
}
@ -956,8 +1002,7 @@ void OffscreenQmlSurface::emitScriptEvent(const QVariant& message) {
void OffscreenQmlSurface::emitWebEvent(const QVariant& message) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "emitWebEvent", Qt::QueuedConnection, Q_ARG(QVariant, message));
}
else {
} else {
// Special case to handle raising and lowering the virtual keyboard.
const QString RAISE_KEYBOARD = "_RAISE_KEYBOARD";
const QString RAISE_KEYBOARD_NUMERIC = "_RAISE_KEYBOARD_NUMERIC";
@ -965,11 +1010,9 @@ void OffscreenQmlSurface::emitWebEvent(const QVariant& message) {
QString messageString = message.type() == QVariant::String ? message.toString() : "";
if (messageString.left(RAISE_KEYBOARD.length()) == RAISE_KEYBOARD) {
setKeyboardRaised(_currentFocusItem, true, messageString == RAISE_KEYBOARD_NUMERIC);
}
else if (messageString == LOWER_KEYBOARD) {
} else if (messageString == LOWER_KEYBOARD) {
setKeyboardRaised(_currentFocusItem, false);
}
else {
} else {
emit webEventReceived(message);
}
}
@ -978,8 +1021,7 @@ void OffscreenQmlSurface::emitWebEvent(const QVariant& message) {
void OffscreenQmlSurface::sendToQml(const QVariant& message) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "emitQmlEvent", Qt::QueuedConnection, Q_ARG(QVariant, message));
}
else if (_rootItem) {
} else if (_rootItem) {
// call fromScript method on qml root
QMetaObject::invokeMethod(_rootItem, "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
}

View file

@ -37,7 +37,7 @@ class QQuickItem;
class OffscreenQmlSurface : public QObject {
Q_OBJECT
Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged)
Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged)
public:
OffscreenQmlSurface();
virtual ~OffscreenQmlSurface();
@ -73,7 +73,7 @@ public:
QQuickItem* getRootItem();
QQuickWindow* getWindow();
QObject* getEventHandler();
QQmlContext* getRootContext();
QQmlContext* getSurfaceContext();
QPointF mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget);
bool eventFilter(QObject* originalDestination, QEvent* event) override;
@ -95,12 +95,12 @@ signals:
void focusObjectChanged(QObject* newFocus);
void focusTextChanged(bool focusText);
public slots:
public slots:
void onAboutToQuit();
void focusDestroyed(QObject *obj);
// event bridge
public slots:
public slots:
void emitScriptEvent(const QVariant& scriptMessage);
void emitWebEvent(const QVariant& webMessage);
signals:
@ -108,7 +108,7 @@ signals:
void webEventReceived(const QVariant& message);
// qml event bridge
public slots:
public slots:
void sendToQml(const QVariant& message);
signals:
void fromQml(QVariant message);
@ -126,37 +126,36 @@ private:
void cleanup();
QJsonObject getGLContextData();
private slots:
private slots:
void updateQuick();
void onFocusObjectChanged(QObject* newFocus);
private:
QQuickWindow* _quickWindow{ nullptr };
QQuickWindow* _quickWindow { nullptr };
QMyQuickRenderControl* _renderControl{ nullptr };
QQmlEngine* _qmlEngine{ nullptr };
QQmlComponent* _qmlComponent{ nullptr };
QQuickItem* _rootItem{ nullptr };
OffscreenGLCanvas* _canvas{ nullptr };
QJsonObject _glData;
QQmlContext* _qmlContext { nullptr };
QQmlComponent* _qmlComponent { nullptr };
QQuickItem* _rootItem { nullptr };
OffscreenGLCanvas* _canvas { nullptr };
QTimer _updateTimer;
uint32_t _fbo{ 0 };
uint32_t _depthStencil{ 0 };
uint64_t _lastRenderTime{ 0 };
uint32_t _fbo { 0 };
uint32_t _depthStencil { 0 };
uint64_t _lastRenderTime { 0 };
uvec2 _size;
// Texture management
TextureAndFence _latestTextureAndFence{ 0, 0 };
TextureAndFence _latestTextureAndFence { 0, 0 };
bool _render{ false };
bool _polish{ true };
bool _paused{ true };
bool _focusText{ false };
uint8_t _maxFps{ 60 };
MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p.toPoint(); } };
QWindow* _proxyWindow{ nullptr };
bool _render { false };
bool _polish { true };
bool _paused { true };
bool _focusText { false };
uint8_t _maxFps { 60 };
MouseTranslator _mouseTranslator { [](const QPointF& p) { return p.toPoint(); } };
QWindow* _proxyWindow { nullptr };
QQuickItem* _currentFocusItem{ nullptr };
QQuickItem* _currentFocusItem { nullptr };
};
#endif

View file

@ -49,7 +49,6 @@ QSharedPointer<OffscreenQmlSurface> OffscreenQmlSurfaceCache::buildSurface(const
surface->create(currentContext);
surface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
surface->load(rootSource);
surface->getRootContext()->setContextProperty("ApplicationInterface", qApp);
surface->resize(QSize(100, 100));
currentContext->makeCurrent(currentSurface);
return surface;

View file

@ -1,5 +1,5 @@
set(TARGET_NAME networking)
setup_hifi_library(Network)
setup_hifi_library(Network WebEngine)
link_hifi_libraries(shared)
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")

View file

@ -15,11 +15,13 @@
#include <QtCore/QThread>
#include <StatTracker.h>
#include <Trace.h>
#include "AssetClient.h"
#include "NetworkLogging.h"
#include "NodeList.h"
#include "ResourceCache.h"
#include <Trace.h>
static int requestID = 0;
@ -62,9 +64,12 @@ void AssetRequest::start() {
_data = loadFromCache(getUrl());
if (!_data.isNull()) {
_error = NoError;
_loadedFromCache = true;
_state = Finished;
emit finished(this);
return;
}

View file

@ -52,6 +52,8 @@ public:
QUrl getUrl() const { return ::getATPUrl(_hash); }
QString getHash() const { return _hash; }
bool loadedFromCache() const { return _loadedFromCache; }
signals:
void finished(AssetRequest* thisRequest);
void progress(qint64 totalReceived, qint64 total);
@ -66,6 +68,7 @@ private:
int _numPendingRequests { 0 };
MessageID _assetRequestID { INVALID_MESSAGE_ID };
const ByteRange _byteRange;
bool _loadedFromCache { false };
};
#endif

View file

@ -13,12 +13,14 @@
#include <QtCore/QLoggingCategory>
#include <Trace.h>
#include <Profile.h>
#include <StatTracker.h>
#include "AssetClient.h"
#include "AssetUtils.h"
#include "MappingRequest.h"
#include "NetworkLogging.h"
#include <Trace.h>
#include <Profile.h>
static const int DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS = 5;
@ -48,6 +50,8 @@ bool AssetResourceRequest::urlIsAssetHash(const QUrl& url) {
}
void AssetResourceRequest::doSend() {
DependencyManager::get<StatTracker>()->incrementStat(STAT_ATP_REQUEST_STARTED);
// We'll either have a hash or an ATP path to a file (that maps to a hash)
if (urlIsAssetHash(_url)) {
// We've detected that this is a hash - simply use AssetClient to request that asset
@ -65,11 +69,16 @@ void AssetResourceRequest::doSend() {
}
void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
auto statTracker = DependencyManager::get<StatTracker>();
statTracker->incrementStat(STAT_ATP_MAPPING_REQUEST_STARTED);
auto assetClient = DependencyManager::get<AssetClient>();
_assetMappingRequest = assetClient->createGetMappingRequest(path);
// make sure we'll hear about the result of the get mapping request
connect(_assetMappingRequest, &GetMappingRequest::finished, this, [this, path](GetMappingRequest* request){
auto statTracker = DependencyManager::get<StatTracker>();
Q_ASSERT(_state == InProgress);
Q_ASSERT(request == _assetMappingRequest);
@ -80,6 +89,8 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
requestHash(request->getHash());
statTracker->incrementStat(STAT_ATP_MAPPING_REQUEST_SUCCESS);
break;
default: {
switch (request->getError()) {
@ -100,6 +111,9 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
_state = Finished;
emit finished();
statTracker->incrementStat(STAT_ATP_MAPPING_REQUEST_FAILED);
statTracker->incrementStat(STAT_ATP_REQUEST_FAILED);
break;
}
}
@ -140,10 +154,26 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) {
_result = Error;
break;
}
auto statTracker = DependencyManager::get<StatTracker>();
if (_assetRequest->loadedFromCache()) {
_loadedFromCache = true;
}
_state = Finished;
emit finished();
if (_result == Success) {
statTracker->incrementStat(STAT_ATP_REQUEST_SUCCESS);
if (loadedFromCache()) {
statTracker->incrementStat(STAT_ATP_REQUEST_CACHE);
}
} else {
statTracker->incrementStat(STAT_ATP_REQUEST_FAILED);
}
_assetRequest->deleteLater();
_assetRequest = nullptr;
});

View file

@ -15,7 +15,12 @@
#include <QFile>
#include <StatTracker.h>
void FileResourceRequest::doSend() {
auto statTracker = DependencyManager::get<StatTracker>();
statTracker->incrementStat(STAT_FILE_REQUEST_STARTED);
QString filename = _url.toLocalFile();
// sometimes on windows, we see the toLocalFile() return null,
@ -60,4 +65,10 @@ void FileResourceRequest::doSend() {
_state = Finished;
emit finished();
if (_result == ResourceRequest::Success) {
statTracker->incrementStat(STAT_FILE_REQUEST_SUCCESS);
} else {
statTracker->incrementStat(STAT_FILE_REQUEST_FAILED);
}
}

View file

@ -19,6 +19,7 @@ HFTabletWebEngineProfile::HFTabletWebEngineProfile(QObject* parent) : QQuickWebE
static const QString WEB_ENGINE_USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
setHttpUserAgent(WEB_ENGINE_USER_AGENT);
setStorageName(QML_WEB_ENGINE_NAME);
auto requestInterceptor = new HFTabletWebEngineRequestInterceptor(this);
setRequestInterceptor(requestInterceptor);

View file

@ -11,7 +11,7 @@
#include "HFTabletWebEngineRequestInterceptor.h"
#include <QtCore/QDebug>
#include <AccountManager.h>
#include "AccountManager.h"
bool isTabletAuthableHighFidelityURL(const QUrl& url) {
static const QStringList HF_HOSTS = {

View file

@ -20,6 +20,7 @@ HFWebEngineProfile::HFWebEngineProfile(QObject* parent) :
{
static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)";
setHttpUserAgent(WEB_ENGINE_USER_AGENT);
setStorageName(QML_WEB_ENGINE_STORAGE_NAME);
// we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user
auto requestInterceptor = new HFWebEngineRequestInterceptor(this);

View file

@ -13,7 +13,7 @@
#include <QtCore/QDebug>
#include <AccountManager.h>
#include "AccountManager.h"
#include "RequestFilters.h"
void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {

View file

@ -17,6 +17,7 @@
#include <QMetaEnum>
#include <SharedUtil.h>
#include <StatTracker.h>
#include "NetworkAccessManager.h"
#include "NetworkLogging.h"
@ -49,6 +50,8 @@ void HTTPResourceRequest::cleanupTimer() {
}
void HTTPResourceRequest::doSend() {
DependencyManager::get<StatTracker>()->incrementStat(STAT_HTTP_REQUEST_STARTED);
QNetworkRequest networkRequest(_url);
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
@ -178,6 +181,17 @@ void HTTPResourceRequest::onRequestFinished() {
_state = Finished;
emit finished();
auto statTracker = DependencyManager::get<StatTracker>();
if (_result == Success) {
statTracker->incrementStat(STAT_HTTP_REQUEST_SUCCESS);
if (loadedFromCache()) {
statTracker->incrementStat(STAT_HTTP_REQUEST_CACHE);
}
} else {
statTracker->incrementStat(STAT_HTTP_REQUEST_FAILED);
}
}
void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
@ -202,4 +216,6 @@ void HTTPResourceRequest::onTimeout() {
_result = Timeout;
_state = Finished;
emit finished();
DependencyManager::get<StatTracker>()->incrementStat(STAT_HTTP_REQUEST_FAILED);
}

View file

@ -29,6 +29,7 @@
#include <NumericalConstants.h>
#include <SettingHandle.h>
#include <SharedUtil.h>
#include <StatTracker.h>
#include <UUID.h>
#include "AccountManager.h"
@ -37,7 +38,6 @@
#include "HifiSockAddr.h"
#include "NetworkLogging.h"
#include "udt/Packet.h"
#include <Trace.h>
static Setting::Handle<quint16> LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.LocalPort", 0);
@ -1044,10 +1044,10 @@ void LimitedNodeList::setLocalSocket(const HifiSockAddr& sockAddr) {
qCInfo(networking) << "Local socket is" << sockAddr;
} else {
qCInfo(networking) << "Local socket has changed from" << _localSockAddr << "to" << sockAddr;
DependencyManager::get<StatTracker>()->incrementStat(LOCAL_SOCKET_CHANGE_STAT);
}
_localSockAddr = sockAddr;
emit localSockAddrChanged(_localSockAddr);
}
}

View file

@ -66,6 +66,8 @@ const QHostAddress DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME = QHostAddress::Lo
const QString USERNAME_UUID_REPLACEMENT_STATS_KEY = "$username";
const QString LOCAL_SOCKET_CHANGE_STAT = "LocalSocketChanges";
using namespace tbb;
typedef std::pair<QUuid, SharedNodePointer> UUIDNodePair;
typedef concurrent_unordered_map<QUuid, SharedNodePointer, UUIDHasher> NodeHash;

View file

@ -14,7 +14,7 @@
#include <QtCore/QDebug>
#include <AccountManager.h>
#include "AccountManager.h"
namespace {

View file

@ -19,6 +19,21 @@
#include "ByteRange.h"
const QString STAT_ATP_REQUEST_STARTED = "StartedATPRequest";
const QString STAT_HTTP_REQUEST_STARTED = "StartedHTTPRequest";
const QString STAT_FILE_REQUEST_STARTED = "StartedFileRequest";
const QString STAT_ATP_REQUEST_SUCCESS = "SuccessfulATPRequest";
const QString STAT_HTTP_REQUEST_SUCCESS = "SuccessfulHTTPRequest";
const QString STAT_FILE_REQUEST_SUCCESS = "SuccessfulFileRequest";
const QString STAT_ATP_REQUEST_FAILED = "FailedATPRequest";
const QString STAT_HTTP_REQUEST_FAILED = "FailedHTTPRequest";
const QString STAT_FILE_REQUEST_FAILED = "FailedFileRequest";
const QString STAT_ATP_REQUEST_CACHE = "CacheATPRequest";
const QString STAT_HTTP_REQUEST_CACHE = "CacheHTTPRequest";
const QString STAT_ATP_MAPPING_REQUEST_STARTED = "StartedATPMappingRequest";
const QString STAT_ATP_MAPPING_REQUEST_FAILED = "FailedATPMappingRequest";
const QString STAT_ATP_MAPPING_REQUEST_SUCCESS = "SuccessfulATPMappingRequest";
class ResourceRequest : public QObject {
Q_OBJECT
public:

View file

@ -200,6 +200,7 @@ public:
virtual float newFramePresentRate() const { return -1.0f; }
// Rate at which rendered frames are being skipped
virtual float droppedFrameRate() const { return -1.0f; }
virtual bool getSupportsAutoSwitch() { return false; }
// Hardware specific stats
virtual QJsonObject getHardwareStats() const { return QJsonObject(); }

View file

@ -53,6 +53,18 @@ public:
virtual bool isActive() {
return _active;
}
virtual bool startStandBySession() {
_sessionStatus = true;
return _sessionStatus;
}
virtual void endSession() {
_sessionStatus = false;
}
virtual bool isSessionActive() {
return _sessionStatus;
}
/**
* Called by the application during it's idle phase. If the plugin needs to do
@ -73,6 +85,7 @@ signals:
protected:
bool _active { false };
bool _sessionStatus { false };
PluginContainer* _container { nullptr };
static const char* UNKNOWN_PLUGIN_ID;

View file

@ -53,15 +53,8 @@ void ConsoleScriptingInterface::exception(QString message) {
}
void ConsoleScriptingInterface::time(QString labelName) {
QDateTime date;
std::string val_string = "2017-06-06 11:15:00.000";
QString d = QString::fromStdString(val_string.substr(0, 19));
date = QDateTime::fromString(d, "yyyy-MM-dd HH:mm:ss");
qDebug() << d;
qDebug() << d.length() << date.toUTC();
QDateTime _currentTime = QDateTime::currentDateTime().toUTC();
_listOfTimeValues.insert(labelName, date.toUTC());
_listOfTimeValues.insert(labelName, _currentTime.toUTC());
}
void ConsoleScriptingInterface::timeEnd(QString labelName) {
@ -79,6 +72,7 @@ void ConsoleScriptingInterface::timeEnd(QString labelName) {
}
return;
}
QDateTime _currentDateTimeValue = QDateTime::currentDateTime().toUTC();
_dateTimeOfLabel = _listOfTimeValues.value(labelName);
@ -113,7 +107,7 @@ void ConsoleScriptingInterface::asserts(bool condition, QString message) {
if (message.isEmpty()) {
message = assertFailed;
} else {
if (typeid(message) != typeid(QString)) {
if (typeid(message) != typeid(QString)) {
message = assertFailed;
} else {
message = assertFailed + " " + message;
@ -122,7 +116,7 @@ void ConsoleScriptingInterface::asserts(bool condition, QString message) {
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine())) {
scriptEngine->scriptErrorMessage(message);
}
}
}
}
void ConsoleScriptingInterface::trace(QString labelName) {
@ -130,8 +124,9 @@ void ConsoleScriptingInterface::trace(QString labelName) {
scriptEngine->scriptErrorMessage(labelName);
}
}
void ConsoleScriptingInterface::clear() {
void ConsoleScriptingInterface::clear() {
if (ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(engine())) {
scriptEngine->clearConsole();
}
}
}

View file

@ -21,7 +21,7 @@
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtScript/QScriptable>
#include <QMap>
#include <QHash>
/// Scriptable interface of console object. Used exclusively in the JavaScript API
@ -36,14 +36,14 @@ public slots:
void exception(QString message);
void time(QString labelName);
void timeEnd(QString labelName);
void asserts(bool condition, QString data="");
void asserts(bool condition, QString message = "");
void trace(QString labelName);
void clear();
public:
QString secondsToString(qint64 seconds);
bool isInteger(const std::string & s);
private:
QMap<QString, QDateTime> _listOfTimeValues;
QHash<QString, QDateTime> _listOfTimeValues;
const qint64 DAY = 86400;
const QString TIME_FORMAT = "yyyy-MM-dd HH:mm";
};

View file

@ -226,6 +226,7 @@ public:
void scriptWarningMessage(const QString& message);
void scriptInfoMessage(const QString& message);
void scriptPrintedMessage(const QString& message);
void clearConsole();
int getNumRunningEntityScripts() const;
bool getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const;

View file

@ -91,14 +91,14 @@ QObject* OffscreenUi::getFlags() {
void OffscreenUi::create(QOpenGLContext* context) {
OffscreenQmlSurface::create(context);
auto rootContext = getRootContext();
auto myContext = getSurfaceContext();
rootContext->setContextProperty("OffscreenUi", this);
rootContext->setContextProperty("offscreenFlags", offscreenFlags = new OffscreenFlags());
rootContext->setContextProperty("fileDialogHelper", new FileDialogHelper());
myContext->setContextProperty("OffscreenUi", this);
myContext->setContextProperty("offscreenFlags", offscreenFlags = new OffscreenFlags());
myContext->setContextProperty("fileDialogHelper", new FileDialogHelper());
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
rootContext->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
myContext->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
}
void OffscreenUi::show(const QUrl& url, const QString& name, std::function<void(QQmlContext*, QObject*)> f) {
@ -547,14 +547,14 @@ void OffscreenUi::createDesktop(const QUrl& url) {
}
#ifdef DEBUG
getRootContext()->setContextProperty("DebugQML", QVariant(true));
getSurfaceContext()->setContextProperty("DebugQML", QVariant(true));
#else
getRootContext()->setContextProperty("DebugQML", QVariant(false));
getSurfaceContext()->setContextProperty("DebugQML", QVariant(false));
#endif
_desktop = dynamic_cast<QQuickItem*>(load(url));
Q_ASSERT(_desktop);
getRootContext()->setContextProperty("desktop", _desktop);
getSurfaceContext()->setContextProperty("desktop", _desktop);
_toolWindow = _desktop->findChild<QQuickItem*>("ToolWindow");

View file

@ -115,7 +115,7 @@ private:
VrMenu::VrMenu(OffscreenUi* parent) : QObject(parent) {
_rootMenu = parent->getRootItem()->findChild<QObject*>("rootMenu");
parent->getRootContext()->setContextProperty("rootMenu", _rootMenu);
parent->getSurfaceContext()->setContextProperty("rootMenu", _rootMenu);
}
QObject* VrMenu::findMenuObject(const QString& menuOption) {

View file

@ -123,10 +123,19 @@ bool OculusBaseDisplayPlugin::internalActivate() {
void OculusBaseDisplayPlugin::internalDeactivate() {
Parent::internalDeactivate();
}
bool OculusBaseDisplayPlugin::activateStandBySession() {
_session = acquireOculusSession();
if (!_session) {
return false;
}
return true;
}
void OculusBaseDisplayPlugin::deactivateSession() {
releaseOculusSession();
_session = nullptr;
}
void OculusBaseDisplayPlugin::updatePresentPose() {
//mat4 sensorResetMat;
//_currentPresentFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();

View file

@ -26,6 +26,7 @@ public:
void resetSensors() override final;
bool beginFrameRender(uint32_t frameIndex) override;
float getTargetFrameRate() const override { return _hmdDesc.DisplayRefreshRate; }
bool getSupportsAutoSwitch() override final { return true; }
protected:
@ -33,6 +34,8 @@ protected:
void uncustomizeContext() override;
bool internalActivate() override;
void internalDeactivate() override;
bool activateStandBySession() override;
void deactivateSession() override;
void updatePresentPose() override;
protected:

View file

@ -53,4 +53,4 @@ ScriptDiscoveryService.clearDebugWindow.connect(function () {
window.clearConsole();
});
}()); // END LOCAL_SCOPE
}()); // END LOCAL_SCOPE

View file

@ -29,7 +29,7 @@ Rectangle {
height: parent.height
text:""
}
function fromScript(message) {
var MAX_LINE_COUNT = 2000;
var TRIM_LINES = 500;

View file

@ -366,45 +366,25 @@ function Teleporter() {
}
// related to repositioning the avatar after you teleport
var FOOT_JOINT_NAMES = ["RightToe_End", "RightToeBase", "RightFoot"];
var DEFAULT_ROOT_TO_FOOT_OFFSET = 0.5;
function getAvatarFootOffset() {
var data = getJointData();
var upperLeg, lowerLeg, foot, toe, toeTop;
data.forEach(function(d) {
var jointName = d.joint;
if (jointName === "RightUpLeg") {
upperLeg = d.translation.y;
} else if (jointName === "RightLeg") {
lowerLeg = d.translation.y;
} else if (jointName === "RightFoot") {
foot = d.translation.y;
} else if (jointName === "RightToeBase") {
toe = d.translation.y;
} else if (jointName === "RightToe_End") {
toeTop = d.translation.y;
// find a valid foot jointIndex
var footJointIndex = -1;
var i, l = FOOT_JOINT_NAMES.length;
for (i = 0; i < l; i++) {
footJointIndex = MyAvatar.getJointIndex(FOOT_JOINT_NAMES[i]);
if (footJointIndex != -1) {
break;
}
});
var offset = upperLeg + lowerLeg + foot + toe + toeTop;
offset = offset / 100;
return offset;
}
function getJointData() {
var allJointData = [];
var jointNames = MyAvatar.jointNames;
jointNames.forEach(function(joint, index) {
var translation = MyAvatar.getJointTranslation(index);
var rotation = MyAvatar.getJointRotation(index);
allJointData.push({
joint: joint,
index: index,
translation: translation,
rotation: rotation
});
});
return allJointData;
}
if (footJointIndex != -1) {
// default vertical offset from foot to avatar root.
return -MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(footJointIndex).y;
} else {
return DEFAULT_ROOT_TO_FOOT_OFFSET * MyAvatar.scale;
}
}
var leftPad = new ThumbPad('left');