Merge branch 'master' of https://github.com/highfidelity/hifi into do-not-get-stuck-in-floor

This commit is contained in:
howard-stearns 2017-06-07 16:43:25 -07:00
commit fa74daf875
124 changed files with 1279 additions and 1151 deletions

View file

@ -1,5 +1,7 @@
This is a stand-alone guide for creating your first High Fidelity build for Windows 64-bit. 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 ### 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. 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 ### Step 4. Setting Qt Environment Variable
Go to "Control Panel > System > Advanced System Settings > Environment Variables > New..." (or search “Environment Variables” in Start Search). 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 name": `QT_CMAKE_PREFIX_PATH`
* Set "Variable value": `%QT_DIR%\5.6\msvc2013_64\lib\cmake` * Set "Variable value": `%QT_DIR%\5.6\msvc2013_64\lib\cmake`
### Step 5. Installing OpenSSL ### 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 ### Step 6. Running CMake to Generate Build Files
Run Command Prompt from Start and run the following commands: Run Command Prompt from Start and run the following commands:
cd "%HIFI_DIR%" ````
mkdir build cd "%HIFI_DIR%"
cd build mkdir build
cmake .. -G "Visual Studio 12 Win64" 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 ### 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. 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 ### Step 8. Testing Interface
Create another environment variable (see Step #4) Create another environment variable (see Step #4)
* Set "Variable name": _NO_DEBUG_HEAP * Set "Variable name": `_NO_DEBUG_HEAP`
* Set "Variable value": 1 * 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. 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: For any problems after Step #6, first try this:
* Delete your locally cloned copy of the highfidelity repository * 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 #### 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 #### nmake cannot be found
Make sure nmake.exe is located at the following path: Make sure nmake.exe is located at the following path:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin 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. If not, add the directory where nmake is located to the PATH environment variable.
#### Qt is throwing an error #### 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

@ -8,8 +8,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
if (WIN32) if (WIN32)
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${EXTERNAL_NAME}
URL http://s3.amazonaws.com/hifi-public/dependencies/nvtt-win-2.1.0.zip URL http://s3.amazonaws.com/hifi-public/dependencies/nvtt-win-2.1.0.hifi.zip
URL_MD5 3ea6eeadbcc69071acf9c49ba565760e URL_MD5 10da01cf601f88f6dc12a6bc13c89136
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""
INSTALL_COMMAND "" INSTALL_COMMAND ""
@ -29,8 +29,8 @@ else ()
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/nvidia-texture-tools-2.1.0.zip URL http://hifi-public.s3.amazonaws.com/dependencies/nvidia-texture-tools-2.1.0.hifi.zip
URL_MD5 81b8fa6a9ee3f986088eb6e2215d6a57 URL_MD5 5794b950f8b265a9a41b2839b3bf7ebb
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DNVTT_SHARED=1 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DNVTT_SHARED=1 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
LOG_DOWNLOAD 1 LOG_DOWNLOAD 1
LOG_CONFIGURE 1 LOG_CONFIGURE 1

View file

@ -57,6 +57,8 @@
{ "from": "OculusTouch.LeftThumbUp", "to": "Standard.LeftThumbUp" }, { "from": "OculusTouch.LeftThumbUp", "to": "Standard.LeftThumbUp" },
{ "from": "OculusTouch.RightThumbUp", "to": "Standard.RightThumbUp" }, { "from": "OculusTouch.RightThumbUp", "to": "Standard.RightThumbUp" },
{ "from": "OculusTouch.LeftIndexPoint", "to": "Standard.LeftIndexPoint" }, { "from": "OculusTouch.LeftIndexPoint", "to": "Standard.LeftIndexPoint" },
{ "from": "OculusTouch.RightIndexPoint", "to": "Standard.RightIndexPoint" } { "from": "OculusTouch.RightIndexPoint", "to": "Standard.RightIndexPoint" },
{ "from": "OculusTouch.Head", "to" : "Standard.Head", "when" : [ "Application.InHMD"] }
] ]
} }

View file

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

View file

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

View file

@ -10,13 +10,10 @@
import QtQuick 2.5 import QtQuick 2.5
import QtWebEngine 1.2 import QtWebEngine 1.2
import HFWebEngineProfile 1.0
WebEngineView { WebEngineView {
id: root id: root
// profile: desktop.browserProfile
Component.onCompleted: { Component.onCompleted: {
console.log("Connecting JS messaging to Hifi Logging") console.log("Connecting JS messaging to Hifi Logging")
// Ensure the JS from the web-engine makes it to our 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 QtWebEngine 1.1
import QtWebChannel 1.0 import QtWebChannel 1.0
import "../controls-uit" as HiFiControls import "../controls-uit" as HiFiControls
import HFTabletWebEngineProfile 1.0
Item { Item {
property alias url: root.url property alias url: root.url
@ -39,10 +38,7 @@ Item {
width: parent.width width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFTabletWebEngineProfile { profile: HFTabletWebEngineProfile;
id: webviewProfile
storageName: "qmlTabletWebEngine"
}
property string userScriptUrl: "" property string userScriptUrl: ""

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -72,6 +72,7 @@
#include <ErrorDialog.h> #include <ErrorDialog.h>
#include <FileScriptingInterface.h> #include <FileScriptingInterface.h>
#include <Finally.h> #include <Finally.h>
#include <FingerprintUtils.h>
#include <FramebufferCache.h> #include <FramebufferCache.h>
#include <gpu/Batch.h> #include <gpu/Batch.h>
#include <gpu/Context.h> #include <gpu/Context.h>
@ -114,6 +115,7 @@
#include <RenderDeferredTask.h> #include <RenderDeferredTask.h>
#include <RenderForwardTask.h> #include <RenderForwardTask.h>
#include <ResourceCache.h> #include <ResourceCache.h>
#include <ResourceRequest.h>
#include <SandboxUtils.h> #include <SandboxUtils.h>
#include <SceneScriptingInterface.h> #include <SceneScriptingInterface.h>
#include <ScriptEngines.h> #include <ScriptEngines.h>
@ -148,9 +150,6 @@
#include "LODManager.h" #include "LODManager.h"
#include "ModelPackager.h" #include "ModelPackager.h"
#include "networking/CloseEventSender.h" #include "networking/CloseEventSender.h"
#include "networking/HFWebEngineProfile.h"
#include "networking/HFTabletWebEngineProfile.h"
#include "networking/FileTypeProfile.h"
#include "scripting/TestScriptingInterface.h" #include "scripting/TestScriptingInterface.h"
#include "scripting/AccountScriptingInterface.h" #include "scripting/AccountScriptingInterface.h"
#include "scripting/AssetMappingsScriptingInterface.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); Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS);
static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com"; 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 { const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {
{ SVO_EXTENSION, &Application::importSVOFromURL }, { SVO_EXTENSION, &Application::importSVOFromURL },
@ -951,6 +952,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
properties["processor_l3_cache_count"] = procInfo.numProcessorCachesL3; 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); UserActivityLogger::getInstance().logAction("launch", properties);
// Tell our entity edit sender about our known jurisdictions // 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_in"] = bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond();
properties["kbps_out"] = bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond(); properties["kbps_out"] = bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond();
properties["atp_in_kbps"] = bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AssetServer);
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer entityServerNode = nodeList->soloNodeOfType(NodeType::EntityServer); SharedNodePointer entityServerNode = nodeList->soloNodeOfType(NodeType::EntityServer);
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); 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; properties["messages_ping"] = messagesMixerNode ? messagesMixerNode->getPingMs() : -1;
auto loadingRequests = ResourceCache::getLoadingRequests(); 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["active_downloads"] = loadingRequests.size();
properties["pending_downloads"] = ResourceCache::getPendingRequestCount(); 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; 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["deleted_entity_cnt"] = entityActivityTracking.deletedEntityCount;
properties["edited_entity_cnt"] = entityActivityTracking.editedEntityCount; 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["active_display_plugin"] = getActiveDisplayPlugin()->getName();
properties["using_hmd"] = isHMDMode(); 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(); auto glInfo = getGLContextData();
properties["gl_info"] = glInfo; properties["gl_info"] = glInfo;
properties["gpu_used_memory"] = (int)BYTES_TO_MB(gpu::Context::getUsedGPUMemSize()); 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; lastLeftHandPose = leftHandPose;
lastRightHandPose = rightHandPose; lastRightHandPose = rightHandPose;
properties["local_socket_changes"] = DependencyManager::get<StatTracker>()->getStat(LOCAL_SOCKET_CHANGE_STAT).toInt();
UserActivityLogger::getInstance().logAction("stats", properties); UserActivityLogger::getInstance().logAction("stats", properties);
}); });
sendStatsTimer->start(); sendStatsTimer->start();
@ -1574,7 +1673,10 @@ void Application::aboutToQuit() {
} }
getActiveDisplayPlugin()->deactivate(); 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 // 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>(); auto closeEventSender = DependencyManager::get<CloseEventSender>();
QThread* closureEventThread = new QThread(this); QThread* closureEventThread = new QThread(this);
@ -1852,14 +1954,10 @@ void Application::initializeUi() {
UpdateDialog::registerType(); UpdateDialog::registerType();
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference"); 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>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create(_glWidget->qglContext()); offscreenUi->create(_glWidget->qglContext());
auto rootContext = offscreenUi->getRootContext(); auto surfaceContext = offscreenUi->getSurfaceContext();
offscreenUi->setProxyWindow(_window->windowHandle()); offscreenUi->setProxyWindow(_window->windowHandle());
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); 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 // do better detection in the offscreen UI of what has focus
offscreenUi->setNavigationFocused(false); offscreenUi->setNavigationFocused(false);
auto engine = rootContext->engine(); auto engine = surfaceContext->engine();
connect(engine, &QQmlEngine::quit, [] { connect(engine, &QQmlEngine::quit, [] {
qApp->quit(); qApp->quit();
}); });
@ -1880,79 +1978,78 @@ void Application::initializeUi() {
// For some reason there is already an "Application" object in the QML context, // For some reason there is already an "Application" object in the QML context,
// though I can't find it. Hence, "ApplicationInterface" // though I can't find it. Hence, "ApplicationInterface"
rootContext->setContextProperty("ApplicationInterface", this); surfaceContext->setContextProperty("Audio", DependencyManager::get<AudioScriptingInterface>().data());
rootContext->setContextProperty("Audio", DependencyManager::get<AudioScriptingInterface>().data()); surfaceContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
rootContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data()); surfaceContext->setContextProperty("AudioScope", DependencyManager::get<AudioScope>().data());
rootContext->setContextProperty("AudioScope", DependencyManager::get<AudioScope>().data());
rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data()); surfaceContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data()); surfaceContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
_fileDownload = new FileScriptingInterface(engine); _fileDownload = new FileScriptingInterface(engine);
rootContext->setContextProperty("File", _fileDownload); surfaceContext->setContextProperty("File", _fileDownload);
connect(_fileDownload, &FileScriptingInterface::unzipResult, this, &Application::handleUnzip); connect(_fileDownload, &FileScriptingInterface::unzipResult, this, &Application::handleUnzip);
rootContext->setContextProperty("MyAvatar", getMyAvatar().get()); surfaceContext->setContextProperty("MyAvatar", getMyAvatar().get());
rootContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data()); surfaceContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data());
rootContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data()); surfaceContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());
rootContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data()); surfaceContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
rootContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data()); surfaceContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
rootContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface); surfaceContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface);
rootContext->setContextProperty("Rates", new RatesScriptingInterface(this)); surfaceContext->setContextProperty("Rates", new RatesScriptingInterface(this));
rootContext->setContextProperty("pathToFonts", "../../");
rootContext->setContextProperty("TREE_SCALE", TREE_SCALE); surfaceContext->setContextProperty("TREE_SCALE", TREE_SCALE);
rootContext->setContextProperty("Quat", new Quat()); // FIXME Quat and Vec3 won't work with QJSEngine used by QML
rootContext->setContextProperty("Vec3", new Vec3()); surfaceContext->setContextProperty("Quat", new Quat());
rootContext->setContextProperty("Uuid", new ScriptUUID()); surfaceContext->setContextProperty("Vec3", new Vec3());
rootContext->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data()); surfaceContext->setContextProperty("Uuid", new ScriptUUID());
surfaceContext->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
rootContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data()); surfaceContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
rootContext->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().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) #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
rootContext->setContextProperty("SpeechRecognizer", DependencyManager::get<SpeechRecognizer>().data()); surfaceContext->setContextProperty("SpeechRecognizer", DependencyManager::get<SpeechRecognizer>().data());
#endif #endif
rootContext->setContextProperty("Overlays", &_overlays); surfaceContext->setContextProperty("Overlays", &_overlays);
rootContext->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data()); surfaceContext->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
rootContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
rootContext->setContextProperty("Stats", Stats::getInstance()); surfaceContext->setContextProperty("Stats", Stats::getInstance());
rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data()); surfaceContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
rootContext->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance()); surfaceContext->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance());
rootContext->setContextProperty("AvatarBookmarks", DependencyManager::get<AvatarBookmarks>().data()); surfaceContext->setContextProperty("AvatarBookmarks", DependencyManager::get<AvatarBookmarks>().data());
rootContext->setContextProperty("LocationBookmarks", DependencyManager::get<LocationBookmarks>().data()); surfaceContext->setContextProperty("LocationBookmarks", DependencyManager::get<LocationBookmarks>().data());
// Caches // Caches
rootContext->setContextProperty("AnimationCache", DependencyManager::get<AnimationCache>().data()); surfaceContext->setContextProperty("AnimationCache", DependencyManager::get<AnimationCache>().data());
rootContext->setContextProperty("TextureCache", DependencyManager::get<TextureCache>().data()); surfaceContext->setContextProperty("TextureCache", DependencyManager::get<TextureCache>().data());
rootContext->setContextProperty("ModelCache", DependencyManager::get<ModelCache>().data()); surfaceContext->setContextProperty("ModelCache", DependencyManager::get<ModelCache>().data());
rootContext->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data()); surfaceContext->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
rootContext->setContextProperty("Account", AccountScriptingInterface::getInstance()); surfaceContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
rootContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data()); surfaceContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
rootContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface); surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
rootContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance()); surfaceContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
rootContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data()); surfaceContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
rootContext->setContextProperty("AvatarManager", DependencyManager::get<AvatarManager>().data()); surfaceContext->setContextProperty("AvatarManager", DependencyManager::get<AvatarManager>().data());
rootContext->setContextProperty("UndoStack", &_undoStackScriptingInterface); surfaceContext->setContextProperty("UndoStack", &_undoStackScriptingInterface);
rootContext->setContextProperty("LODManager", DependencyManager::get<LODManager>().data()); surfaceContext->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
rootContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data()); surfaceContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data());
rootContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data()); surfaceContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
rootContext->setContextProperty("Scene", DependencyManager::get<SceneScriptingInterface>().data()); surfaceContext->setContextProperty("Scene", DependencyManager::get<SceneScriptingInterface>().data());
rootContext->setContextProperty("Render", _renderEngine->getConfiguration().get()); surfaceContext->setContextProperty("Render", _renderEngine->getConfiguration().get());
rootContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface()); surfaceContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
rootContext->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data()); 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()) { if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
rootContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get())); surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get()));
} }
@ -2091,7 +2188,7 @@ void Application::paintGL() {
_myCamera.setOrientation(glm::quat_cast(camMat)); _myCamera.setOrientation(glm::quat_cast(camMat));
} else { } else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()); _myCamera.setPosition(myAvatar->getDefaultEyePosition());
_myCamera.setOrientation(myAvatar->getMyHead()->getCameraOrientation()); _myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
} }
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
if (isHMDMode()) { if (isHMDMode()) {
@ -2211,6 +2308,9 @@ void Application::paintGL() {
}); });
renderArgs._context->setStereoProjections(eyeProjections); renderArgs._context->setStereoProjections(eyeProjections);
renderArgs._context->setStereoViews(eyeOffsets); renderArgs._context->setStereoViews(eyeOffsets);
// Configure the type of display / stereo
renderArgs._displayMode = (isHMDMode() ? RenderArgs::STEREO_HMD : RenderArgs::STEREO_MONITOR);
} }
renderArgs._blitFramebuffer = finalFramebuffer; renderArgs._blitFramebuffer = finalFramebuffer;
displaySide(&renderArgs, _myCamera); displaySide(&renderArgs, _myCamera);
@ -4015,6 +4115,7 @@ void Application::updateMyAvatarLookAtPosition() {
lookAtPosition.x = -lookAtPosition.x; lookAtPosition.x = -lookAtPosition.x;
} }
if (isHMD) { if (isHMD) {
// TODO -- this code is probably wrong, getHeadPose() returns something in sensor frame, not avatar
glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(); glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose();
glm::quat hmdRotation = glm::quat_cast(headPose); glm::quat hmdRotation = glm::quat_cast(headPose);
lookAtSpot = _myCamera.getPosition() + myAvatar->getOrientation() * (hmdRotation * lookAtPosition); lookAtSpot = _myCamera.getPosition() + myAvatar->getOrientation() * (hmdRotation * lookAtPosition);
@ -4057,8 +4158,9 @@ void Application::updateMyAvatarLookAtPosition() {
} else { } else {
// I am not looking at anyone else, so just look forward // I am not looking at anyone else, so just look forward
if (isHMD) { if (isHMD) {
glm::mat4 worldHMDMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); glm::mat4 worldHeadMat = myAvatar->getSensorToWorldMatrix() *
lookAtSpot = transformPoint(worldHMDMat, glm::vec3(0.0f, 0.0f, -TREE_SCALE)); myAvatar->getHeadControllerPoseInSensorFrame().getMatrix();
lookAtSpot = transformPoint(worldHeadMat, glm::vec3(0.0f, 0.0f, -TREE_SCALE));
} else { } else {
lookAtSpot = myAvatar->getHead()->getEyePosition() + lookAtSpot = myAvatar->getHead()->getEyePosition() +
(myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE)); (myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE));
@ -6785,6 +6887,35 @@ void Application::updateDisplayMode() {
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); 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 { mat4 Application::getEyeProjection(int eye) const {
QMutexLocker viewLocker(&_viewMutex); QMutexLocker viewLocker(&_viewMutex);
if (isHMDMode()) { if (isHMDMode()) {

View file

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

View file

@ -410,7 +410,7 @@ void MyAvatar::update(float deltaTime) {
// update moving average of HMD facing in xz plane. // update moving average of HMD facing in xz plane.
const float HMD_FACING_TIMESCALE = 4.0f; // very slow average const float HMD_FACING_TIMESCALE = 4.0f; // very slow average
float tau = deltaTime / HMD_FACING_TIMESCALE; float tau = deltaTime / HMD_FACING_TIMESCALE;
_hmdSensorFacingMovingAverage = lerp(_hmdSensorFacingMovingAverage, _hmdSensorFacing, tau); _headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, _headControllerFacing, tau);
if (_smoothOrientationTimer < SMOOTH_TIME_ORIENTATION) { if (_smoothOrientationTimer < SMOOTH_TIME_ORIENTATION) {
_rotationChanged = usecTimestampNow(); _rotationChanged = usecTimestampNow();
@ -418,16 +418,18 @@ void MyAvatar::update(float deltaTime) {
} }
#ifdef DEBUG_DRAW_HMD_MOVING_AVERAGE #ifdef DEBUG_DRAW_HMD_MOVING_AVERAGE
glm::vec3 p = transformPoint(getSensorToWorldMatrix(), _hmdSensorPosition + glm::vec3(_hmdSensorFacingMovingAverage.x, 0.0f, _hmdSensorFacingMovingAverage.y)); glm::vec3 p = transformPoint(getSensorToWorldMatrix(), getHeadControllerPoseInAvatarFrame() *
glm::vec3(_headControllerFacingMovingAverage.x, 0.0f, _headControllerFacingMovingAverage.y));
DebugDraw::getInstance().addMarker("facing-avg", getOrientation(), p, glm::vec4(1.0f)); DebugDraw::getInstance().addMarker("facing-avg", getOrientation(), p, glm::vec4(1.0f));
p = transformPoint(getSensorToWorldMatrix(), _hmdSensorPosition + glm::vec3(_hmdSensorFacing.x, 0.0f, _hmdSensorFacing.y)); p = transformPoint(getSensorToWorldMatrix(), getHMDSensorPosition() +
glm::vec3(_headControllerFacing.x, 0.0f, _headControllerFacing.y));
DebugDraw::getInstance().addMarker("facing", getOrientation(), p, glm::vec4(1.0f)); DebugDraw::getInstance().addMarker("facing", getOrientation(), p, glm::vec4(1.0f));
#endif #endif
if (_goToPending) { if (_goToPending) {
setPosition(_goToPosition); setPosition(_goToPosition);
setOrientation(_goToOrientation); setOrientation(_goToOrientation);
_hmdSensorFacingMovingAverage = _hmdSensorFacing; // reset moving average _headControllerFacingMovingAverage = _headControllerFacing; // reset moving average
_goToPending = false; _goToPending = false;
// updateFromHMDSensorMatrix (called from paintGL) expects that the sensorToWorldMatrix is updated for any position changes // updateFromHMDSensorMatrix (called from paintGL) expects that the sensorToWorldMatrix is updated for any position changes
// that happen between render and Application::update (which calls updateSensorToWorldMatrix to do so). // that happen between render and Application::update (which calls updateSensorToWorldMatrix to do so).
@ -642,15 +644,21 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
_hmdSensorMatrix = hmdSensorMatrix; _hmdSensorMatrix = hmdSensorMatrix;
auto newHmdSensorPosition = extractTranslation(hmdSensorMatrix); auto newHmdSensorPosition = extractTranslation(hmdSensorMatrix);
if (newHmdSensorPosition != _hmdSensorPosition && if (newHmdSensorPosition != getHMDSensorPosition() &&
glm::length(newHmdSensorPosition) > MAX_HMD_ORIGIN_DISTANCE) { glm::length(newHmdSensorPosition) > MAX_HMD_ORIGIN_DISTANCE) {
qWarning() << "Invalid HMD sensor position " << newHmdSensorPosition; qWarning() << "Invalid HMD sensor position " << newHmdSensorPosition;
// Ignore unreasonable HMD sensor data // Ignore unreasonable HMD sensor data
return; return;
} }
_hmdSensorPosition = newHmdSensorPosition; _hmdSensorPosition = newHmdSensorPosition;
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix); _hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
_hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation); auto headPose = _headControllerPoseInSensorFrameCache.get();
if (headPose.isValid()) {
_headControllerFacing = getFacingDir2D(headPose.rotation);
} else {
_headControllerFacing = glm::vec2(1.0f, 0.0f);
}
} }
void MyAvatar::updateJointFromController(controller::Action poseKey, ThreadSafeValueCache<glm::mat4>& matrixCache) { void MyAvatar::updateJointFromController(controller::Action poseKey, ThreadSafeValueCache<glm::mat4>& matrixCache) {
@ -688,7 +696,7 @@ void MyAvatar::updateSensorToWorldMatrix() {
// Update avatar head rotation with sensor data // Update avatar head rotation with sensor data
void MyAvatar::updateFromTrackers(float deltaTime) { void MyAvatar::updateFromTrackers(float deltaTime) {
glm::vec3 estimatedPosition, estimatedRotation; glm::vec3 estimatedRotation;
bool inHmd = qApp->isHMDMode(); bool inHmd = qApp->isHMDMode();
bool playing = DependencyManager::get<recording::Deck>()->isPlaying(); bool playing = DependencyManager::get<recording::Deck>()->isPlaying();
@ -699,11 +707,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
FaceTracker* tracker = qApp->getActiveFaceTracker(); FaceTracker* tracker = qApp->getActiveFaceTracker();
bool inFacetracker = tracker && !FaceTracker::isMuted(); bool inFacetracker = tracker && !FaceTracker::isMuted();
if (inHmd) { if (inFacetracker) {
estimatedPosition = extractTranslation(getHMDSensorMatrix());
estimatedPosition.x *= -1.0f;
} else if (inFacetracker) {
estimatedPosition = tracker->getHeadTranslation();
estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation())); estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation()));
} }
@ -1488,12 +1492,12 @@ void MyAvatar::updateMotors() {
if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) { if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) {
if (_characterController.getState() == CharacterController::State::Hover || if (_characterController.getState() == CharacterController::State::Hover ||
_characterController.computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) { _characterController.computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) {
motorRotation = getMyHead()->getCameraOrientation(); motorRotation = getMyHead()->getHeadOrientation();
} else { } else {
// non-hovering = walking: follow camera twist about vertical but not lift // non-hovering = walking: follow camera twist about vertical but not lift
// so we decompose camera's rotation and store the twist part in motorRotation // so we decompose camera's rotation and store the twist part in motorRotation
glm::quat liftRotation; glm::quat liftRotation;
swingTwistDecomposition(getMyHead()->getCameraOrientation(), _worldUpDirection, liftRotation, motorRotation); swingTwistDecomposition(getMyHead()->getHeadOrientation(), _worldUpDirection, liftRotation, motorRotation);
} }
const float DEFAULT_MOTOR_TIMESCALE = 0.2f; const float DEFAULT_MOTOR_TIMESCALE = 0.2f;
const float INVALID_MOTOR_TIMESCALE = 1.0e6f; const float INVALID_MOTOR_TIMESCALE = 1.0e6f;
@ -1507,7 +1511,7 @@ void MyAvatar::updateMotors() {
} }
if (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED) { if (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED) {
if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) { if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) {
motorRotation = getMyHead()->getCameraOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y); motorRotation = getMyHead()->getHeadOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y);
} else if (_scriptedMotorFrame == SCRIPTED_MOTOR_AVATAR_FRAME) { } else if (_scriptedMotorFrame == SCRIPTED_MOTOR_AVATAR_FRAME) {
motorRotation = getOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y); motorRotation = getOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y);
} else { } else {
@ -1860,7 +1864,7 @@ void MyAvatar::updateOrientation(float deltaTime) {
if (getCharacterController()->getState() == CharacterController::State::Hover) { if (getCharacterController()->getState() == CharacterController::State::Hover) {
// This is the direction the user desires to fly in. // This is the direction the user desires to fly in.
glm::vec3 desiredFacing = getMyHead()->getCameraOrientation() * Vectors::UNIT_Z; glm::vec3 desiredFacing = getMyHead()->getHeadOrientation() * Vectors::UNIT_Z;
desiredFacing.y = 0.0f; desiredFacing.y = 0.0f;
// This is our reference frame, it is captured when the user begins to move. // This is our reference frame, it is captured when the user begins to move.
@ -1899,11 +1903,9 @@ void MyAvatar::updateOrientation(float deltaTime) {
getHead()->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime); getHead()->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime);
if (qApp->isHMDMode()) { auto headPose = getHeadControllerPoseInAvatarFrame();
glm::quat orientation = glm::quat_cast(getSensorToWorldMatrix()) * getHMDSensorOrientation(); if (headPose.isValid()) {
glm::quat bodyOrientation = getWorldBodyOrientation(); glm::quat localOrientation = headPose.rotation * Quaternions::Y_180;
glm::quat localOrientation = glm::inverse(bodyOrientation) * orientation;
// these angles will be in radians // these angles will be in radians
// ... so they need to be converted to degrees before we do math... // ... so they need to be converted to degrees before we do math...
glm::vec3 euler = glm::eulerAngles(localOrientation) * DEGREES_PER_RADIAN; glm::vec3 euler = glm::eulerAngles(localOrientation) * DEGREES_PER_RADIAN;
@ -2017,11 +2019,14 @@ void MyAvatar::updatePosition(float deltaTime) {
} }
// capture the head rotation, in sensor space, when the user first indicates they would like to move/fly. // capture the head rotation, in sensor space, when the user first indicates they would like to move/fly.
if (!_hoverReferenceCameraFacingIsCaptured && (fabs(getDriveKey(TRANSLATE_Z)) > 0.1f || fabs(getDriveKey(TRANSLATE_X)) > 0.1f)) { if (!_hoverReferenceCameraFacingIsCaptured &&
(fabs(getDriveKey(TRANSLATE_Z)) > 0.1f || fabs(getDriveKey(TRANSLATE_X)) > 0.1f)) {
_hoverReferenceCameraFacingIsCaptured = true; _hoverReferenceCameraFacingIsCaptured = true;
// transform the camera facing vector into sensor space. // transform the camera facing vector into sensor space.
_hoverReferenceCameraFacing = transformVectorFast(glm::inverse(_sensorToWorldMatrix), getMyHead()->getCameraOrientation() * Vectors::UNIT_Z); _hoverReferenceCameraFacing = transformVectorFast(glm::inverse(_sensorToWorldMatrix),
} else if (_hoverReferenceCameraFacingIsCaptured && (fabs(getDriveKey(TRANSLATE_Z)) <= 0.1f && fabs(getDriveKey(TRANSLATE_X)) <= 0.1f)) { getMyHead()->getHeadOrientation() * Vectors::UNIT_Z);
} else if (_hoverReferenceCameraFacingIsCaptured &&
(fabs(getDriveKey(TRANSLATE_Z)) <= 0.1f && fabs(getDriveKey(TRANSLATE_X)) <= 0.1f)) {
_hoverReferenceCameraFacingIsCaptured = false; _hoverReferenceCameraFacingIsCaptured = false;
} }
} }
@ -2472,36 +2477,27 @@ bool MyAvatar::isDriveKeyDisabled(DriveKeys key) const {
} }
} }
glm::vec3 MyAvatar::getWorldBodyPosition() const {
return transformPoint(_sensorToWorldMatrix, extractTranslation(_bodySensorMatrix));
}
glm::quat MyAvatar::getWorldBodyOrientation() const {
return glm::quat_cast(_sensorToWorldMatrix * _bodySensorMatrix);
}
// old school meat hook style // old school meat hook style
glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
glm::vec3 headPosition;
// HMD is in sensor space. glm::quat headOrientation;
const glm::vec3 hmdPosition = getHMDSensorPosition(); auto headPose = getHeadControllerPoseInSensorFrame();
const glm::quat hmdOrientation = getHMDSensorOrientation(); if (headPose.isValid()) {
const glm::quat hmdOrientationYawOnly = cancelOutRollAndPitch(hmdOrientation); headPosition = getHeadControllerPoseInSensorFrame().translation;
headOrientation = getHeadControllerPoseInSensorFrame().rotation * Quaternions::Y_180;
}
const glm::quat headOrientationYawOnly = cancelOutRollAndPitch(headOrientation);
const Rig& rig = _skeletonModel->getRig(); const Rig& rig = _skeletonModel->getRig();
int rightEyeIndex = rig.indexOfJoint("RightEye"); int headIndex = rig.indexOfJoint("Head");
int leftEyeIndex = rig.indexOfJoint("LeftEye");
int neckIndex = rig.indexOfJoint("Neck"); int neckIndex = rig.indexOfJoint("Neck");
int hipsIndex = rig.indexOfJoint("Hips"); int hipsIndex = rig.indexOfJoint("Hips");
glm::vec3 rigMiddleEyePos = DEFAULT_AVATAR_MIDDLE_EYE_POS; glm::vec3 rigHeadPos = headIndex != -1 ? rig.getAbsoluteDefaultPose(headIndex).trans() : DEFAULT_AVATAR_HEAD_POS;
if (leftEyeIndex >= 0 && rightEyeIndex >= 0) {
rigMiddleEyePos = (rig.getAbsoluteDefaultPose(leftEyeIndex).trans() + rig.getAbsoluteDefaultPose(rightEyeIndex).trans()) / 2.0f;
}
glm::vec3 rigNeckPos = neckIndex != -1 ? rig.getAbsoluteDefaultPose(neckIndex).trans() : DEFAULT_AVATAR_NECK_POS; glm::vec3 rigNeckPos = neckIndex != -1 ? rig.getAbsoluteDefaultPose(neckIndex).trans() : DEFAULT_AVATAR_NECK_POS;
glm::vec3 rigHipsPos = hipsIndex != -1 ? rig.getAbsoluteDefaultPose(hipsIndex).trans() : DEFAULT_AVATAR_HIPS_POS; glm::vec3 rigHipsPos = hipsIndex != -1 ? rig.getAbsoluteDefaultPose(hipsIndex).trans() : DEFAULT_AVATAR_HIPS_POS;
glm::vec3 localEyes = (rigMiddleEyePos - rigHipsPos); glm::vec3 localHead = (rigHeadPos - rigHipsPos);
glm::vec3 localNeck = (rigNeckPos - rigHipsPos); glm::vec3 localNeck = (rigNeckPos - rigHipsPos);
// apply simplistic head/neck model // apply simplistic head/neck model
@ -2510,11 +2506,11 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
// eyeToNeck offset is relative full HMD orientation. // eyeToNeck offset is relative full HMD orientation.
// while neckToRoot offset is only relative to HMDs yaw. // while neckToRoot offset is only relative to HMDs yaw.
// Y_180 is necessary because rig is z forward and hmdOrientation is -z forward // Y_180 is necessary because rig is z forward and hmdOrientation is -z forward
glm::vec3 eyeToNeck = hmdOrientation * Quaternions::Y_180 * (localNeck - localEyes); glm::vec3 headToNeck = headOrientation * Quaternions::Y_180 * (localNeck - localHead);
glm::vec3 neckToRoot = hmdOrientationYawOnly * Quaternions::Y_180 * -localNeck; glm::vec3 neckToRoot = headOrientationYawOnly * Quaternions::Y_180 * -localNeck;
glm::vec3 bodyPos = hmdPosition + eyeToNeck + neckToRoot; glm::vec3 bodyPos = headPosition + headToNeck + neckToRoot;
return createMatFromQuatAndPos(hmdOrientationYawOnly, bodyPos); return createMatFromQuatAndPos(headOrientationYawOnly, bodyPos);
} }
glm::vec3 MyAvatar::getPositionForAudio() { glm::vec3 MyAvatar::getPositionForAudio() {
@ -2630,7 +2626,7 @@ bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, co
} else { } else {
const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees
glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix);
return glm::dot(myAvatar.getHMDSensorFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD; return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD;
} }
} }
@ -2777,9 +2773,10 @@ glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& c
cameraWorldMatrix *= createMatFromScaleQuatAndPos(vec3(-1.0f, 1.0f, 1.0f), glm::quat(), glm::vec3()); cameraWorldMatrix *= createMatFromScaleQuatAndPos(vec3(-1.0f, 1.0f, 1.0f), glm::quat(), glm::vec3());
} }
// compute a NEW sensorToWorldMatrix for the camera. The equation is cameraWorldMatrix = cameraSensorToWorldMatrix * _hmdSensorMatrix. // compute a NEW sensorToWorldMatrix for the camera.
// The equation is cameraWorldMatrix = cameraSensorToWorldMatrix * _hmdSensorMatrix.
// here we solve for the unknown cameraSensorToWorldMatrix. // here we solve for the unknown cameraSensorToWorldMatrix.
glm::mat4 cameraSensorToWorldMatrix = cameraWorldMatrix * glm::inverse(_hmdSensorMatrix); glm::mat4 cameraSensorToWorldMatrix = cameraWorldMatrix * glm::inverse(getHMDSensorMatrix());
// Using the new cameraSensorToWorldMatrix, compute where the controller is in world space. // Using the new cameraSensorToWorldMatrix, compute where the controller is in world space.
glm::mat4 controllerWorldMatrix = cameraSensorToWorldMatrix * controllerSensorMatrix; glm::mat4 controllerWorldMatrix = cameraSensorToWorldMatrix * controllerSensorMatrix;

View file

@ -185,7 +185,6 @@ public:
const glm::mat4& getHMDSensorMatrix() const { return _hmdSensorMatrix; } const glm::mat4& getHMDSensorMatrix() const { return _hmdSensorMatrix; }
const glm::vec3& getHMDSensorPosition() const { return _hmdSensorPosition; } const glm::vec3& getHMDSensorPosition() const { return _hmdSensorPosition; }
const glm::quat& getHMDSensorOrientation() const { return _hmdSensorOrientation; } const glm::quat& getHMDSensorOrientation() const { return _hmdSensorOrientation; }
const glm::vec2& getHMDSensorFacingMovingAverage() const { return _hmdSensorFacingMovingAverage; }
Q_INVOKABLE void setOrientationVar(const QVariant& newOrientationVar); Q_INVOKABLE void setOrientationVar(const QVariant& newOrientationVar);
Q_INVOKABLE QVariant getOrientationVar() const; Q_INVOKABLE QVariant getOrientationVar() const;
@ -470,6 +469,8 @@ public:
controller::Pose getHeadControllerPoseInSensorFrame() const; controller::Pose getHeadControllerPoseInSensorFrame() const;
controller::Pose getHeadControllerPoseInWorldFrame() const; controller::Pose getHeadControllerPoseInWorldFrame() const;
controller::Pose getHeadControllerPoseInAvatarFrame() const; controller::Pose getHeadControllerPoseInAvatarFrame() const;
const glm::vec2& getHeadControllerFacingMovingAverage() const { return _headControllerFacingMovingAverage; }
void setArmControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right); void setArmControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right);
controller::Pose getLeftArmControllerPoseInSensorFrame() const; controller::Pose getLeftArmControllerPoseInSensorFrame() const;
@ -569,8 +570,6 @@ signals:
private: private:
glm::vec3 getWorldBodyPosition() const;
glm::quat getWorldBodyOrientation() const;
bool requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& positionOut); bool requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& positionOut);
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail) override; virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail) override;
@ -682,13 +681,13 @@ private:
// working copies -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access // working copies -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
glm::mat4 _sensorToWorldMatrix { glm::mat4() }; glm::mat4 _sensorToWorldMatrix { glm::mat4() };
// cache of the current HMD sensor position and orientation // cache of the current HMD sensor position and orientation in sensor space.
// in sensor space.
glm::mat4 _hmdSensorMatrix; glm::mat4 _hmdSensorMatrix;
glm::quat _hmdSensorOrientation; glm::quat _hmdSensorOrientation;
glm::vec3 _hmdSensorPosition; glm::vec3 _hmdSensorPosition;
glm::vec2 _hmdSensorFacing; // facing vector in xz plane // cache head controller pose in sensor space
glm::vec2 _hmdSensorFacingMovingAverage { 0, 0 }; // facing vector in xz plane glm::vec2 _headControllerFacing; // facing vector in xz plane
glm::vec2 _headControllerFacingMovingAverage { 0, 0 }; // facing vector in xz plane
// cache of the current body position and orientation of the avatar's body, // cache of the current body position and orientation of the avatar's body,
// in sensor space. // in sensor space.

View file

@ -26,19 +26,20 @@ using namespace std;
MyHead::MyHead(MyAvatar* owningAvatar) : Head(owningAvatar) { MyHead::MyHead(MyAvatar* owningAvatar) : Head(owningAvatar) {
} }
glm::quat MyHead::getCameraOrientation() const { glm::quat MyHead::getHeadOrientation() const {
// NOTE: Head::getCameraOrientation() is not used for orienting the camera "view" while in Oculus mode, so // NOTE: Head::getHeadOrientation() is not used for orienting the camera "view" while in Oculus mode, so
// you may wonder why this code is here. This method will be called while in Oculus mode to determine how // you may wonder why this code is here. This method will be called while in Oculus mode to determine how
// to change the driving direction while in Oculus mode. It is used to support driving toward where you're // to change the driving direction while in Oculus mode. It is used to support driving toward where you're
// head is looking. Note that in oculus mode, your actual camera view and where your head is looking is not // head is looking. Note that in oculus mode, your actual camera view and where your head is looking is not
// always the same. // always the same.
if (qApp->isHMDMode()) {
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar); MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
return glm::quat_cast(myAvatar->getSensorToWorldMatrix()) * myAvatar->getHMDSensorOrientation(); auto headPose = myAvatar->getHeadControllerPoseInWorldFrame();
} else { if (headPose.isValid()) {
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar); return headPose.rotation * Quaternions::Y_180;
return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, 0.0f, 0.0f)));
} }
return myAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, 0.0f, 0.0f)));
} }
void MyHead::simulate(float deltaTime) { void MyHead::simulate(float deltaTime) {

View file

@ -18,7 +18,7 @@ public:
explicit MyHead(MyAvatar* owningAvatar); explicit MyHead(MyAvatar* owningAvatar);
/// \return orientationBody * orientationBasePitch /// \return orientationBody * orientationBasePitch
glm::quat getCameraOrientation() const; glm::quat getHeadOrientation() const;
void simulate(float deltaTime) override; void simulate(float deltaTime) override;
private: private:

View file

@ -52,27 +52,19 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
// input action is the highest priority source for head orientation. // input action is the highest priority source for head orientation.
auto avatarHeadPose = myAvatar->getHeadControllerPoseInAvatarFrame(); auto avatarHeadPose = myAvatar->getHeadControllerPoseInAvatarFrame();
if (avatarHeadPose.isValid()) { if (avatarHeadPose.isValid()) {
glm::mat4 rigHeadMat = Matrices::Y_180 * createMatFromQuatAndPos(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation()); glm::mat4 rigHeadMat = Matrices::Y_180 *
createMatFromQuatAndPos(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation());
headParams.rigHeadPosition = extractTranslation(rigHeadMat); headParams.rigHeadPosition = extractTranslation(rigHeadMat);
headParams.rigHeadOrientation = glmExtractRotation(rigHeadMat); headParams.rigHeadOrientation = glmExtractRotation(rigHeadMat);
headParams.headEnabled = true; headParams.headEnabled = true;
} else { } else {
if (qApp->isHMDMode()) { // even though full head IK is disabled, the rig still needs the head orientation to rotate the head up and
// get HMD position from sensor space into world space, and back into rig space // down in desktop mode.
glm::mat4 worldHMDMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
glm::mat4 rigToWorld = createMatFromQuatAndPos(getRotation(), getTranslation());
glm::mat4 worldToRig = glm::inverse(rigToWorld);
glm::mat4 rigHMDMat = worldToRig * worldHMDMat;
_rig.computeHeadFromHMD(AnimPose(rigHMDMat), headParams.rigHeadPosition, headParams.rigHeadOrientation);
headParams.headEnabled = true;
} else {
// even though full head IK is disabled, the rig still needs the head orientation to rotate the head up and down in desktop mode.
// preMult 180 is necessary to convert from avatar to rig coordinates. // preMult 180 is necessary to convert from avatar to rig coordinates.
// postMult 180 is necessary to convert head from -z forward to z forward. // postMult 180 is necessary to convert head from -z forward to z forward.
headParams.rigHeadOrientation = Quaternions::Y_180 * head->getFinalOrientationInLocalFrame() * Quaternions::Y_180; headParams.rigHeadOrientation = Quaternions::Y_180 * head->getFinalOrientationInLocalFrame() * Quaternions::Y_180;
headParams.headEnabled = false; headParams.headEnabled = false;
} }
}
auto avatarHipsPose = myAvatar->getHipsControllerPoseInAvatarFrame(); auto avatarHipsPose = myAvatar->getHipsControllerPoseInAvatarFrame();
if (avatarHipsPose.isValid()) { if (avatarHipsPose.isValid()) {

View file

@ -54,6 +54,10 @@ bool HMDScriptingInterface::isHMDAvailable(const QString& name) {
return PluginUtils::isHMDAvailable(name); return PluginUtils::isHMDAvailable(name);
} }
bool HMDScriptingInterface::isHeadControllerAvailable(const QString& name) {
return PluginUtils::isHeadControllerAvailable(name);
}
bool HMDScriptingInterface::isHandControllerAvailable(const QString& name) { bool HMDScriptingInterface::isHandControllerAvailable(const QString& name) {
return PluginUtils::isHandControllerAvailable(name); return PluginUtils::isHandControllerAvailable(name);
} }

View file

@ -43,6 +43,7 @@ public:
Q_INVOKABLE QString preferredAudioOutput() const; Q_INVOKABLE QString preferredAudioOutput() const;
Q_INVOKABLE bool isHMDAvailable(const QString& name = ""); Q_INVOKABLE bool isHMDAvailable(const QString& name = "");
Q_INVOKABLE bool isHeadControllerAvailable(const QString& name = "");
Q_INVOKABLE bool isHandControllerAvailable(const QString& name = ""); Q_INVOKABLE bool isHandControllerAvailable(const QString& name = "");
Q_INVOKABLE bool isSubdeviceContainingNameAvailable(const QString& name); Q_INVOKABLE bool isSubdeviceContainingNameAvailable(const QString& name);

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() { xColor Text3DOverlay::getBackgroundColor() {
if (_colorPulse == 0.0f) { if (_colorPulse == 0.0f) {
return _backgroundColor; 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 // FIXME: Factor out textRenderer so that Text3DOverlay overlay parts can be grouped by pipeline
// for a gpu performance increase. Currently, // for a gpu performance increase. Currently,
// Text renderer sets its own pipeline, // 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 // so before we continue, we must reset the pipeline
batch.setPipeline(args->_pipeline->pipeline); batch.setPipeline(args->_pipeline->pipeline);
args->_pipeline->prepare(batch); args->_pipeline->prepare(batch);
@ -188,7 +198,7 @@ void Text3DOverlay::setProperties(const QVariantMap& properties) {
QVariant Text3DOverlay::getProperty(const QString& property) { QVariant Text3DOverlay::getProperty(const QString& property) {
if (property == "text") { if (property == "text") {
return _text; return getText();
} }
if (property == "textAlpha") { if (property == "textAlpha") {
return _textAlpha; return _textAlpha;

View file

@ -12,7 +12,7 @@
#define hifi_Text3DOverlay_h #define hifi_Text3DOverlay_h
#include <QString> #include <QString>
#include <QtCore/QMutex>
#include "Billboard3DOverlay.h" #include "Billboard3DOverlay.h"
class TextRenderer3D; class TextRenderer3D;
@ -34,7 +34,7 @@ public:
virtual const render::ShapeKey getShapeKey() override; virtual const render::ShapeKey getShapeKey() override;
// getters // getters
const QString& getText() const { return _text; } const QString getText() const;
float getLineHeight() const { return _lineHeight; } float getLineHeight() const { return _lineHeight; }
float getLeftMargin() const { return _leftMargin; } float getLeftMargin() const { return _leftMargin; }
float getTopMargin() const { return _topMargin; } float getTopMargin() const { return _topMargin; }
@ -45,7 +45,7 @@ public:
float getBackgroundAlpha() { return getAlpha(); } float getBackgroundAlpha() { return getAlpha(); }
// setters // setters
void setText(const QString& text) { _text = text; } void setText(const QString& text);
void setTextAlpha(float alpha) { _textAlpha = alpha; } void setTextAlpha(float alpha) { _textAlpha = alpha; }
void setLineHeight(float value) { _lineHeight = value; } void setLineHeight(float value) { _lineHeight = value; }
void setLeftMargin(float margin) { _leftMargin = margin; } void setLeftMargin(float margin) { _leftMargin = margin; }
@ -67,6 +67,7 @@ private:
TextRenderer3D* _textRenderer = nullptr; TextRenderer3D* _textRenderer = nullptr;
QString _text; 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 }; xColor _backgroundColor = xColor { 0, 0, 0 };
float _textAlpha { 1.0f }; float _textAlpha { 1.0f };
float _lineHeight { 1.0f }; float _lineHeight { 1.0f };

View file

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

View file

@ -1135,9 +1135,9 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
} }
glm::vec3 headUp = headQuat * Vectors::UNIT_Y; glm::vec3 headUp = headQuat * Vectors::UNIT_Y;
glm::vec3 z, y, x; glm::vec3 z, y, zCrossY;
generateBasisVectors(lookAtVector, headUp, z, y, x); generateBasisVectors(lookAtVector, headUp, z, y, zCrossY);
glm::mat3 m(glm::cross(y, z), y, z); glm::mat3 m(-zCrossY, y, z);
glm::quat desiredQuat = glm::normalize(glm::quat_cast(m)); glm::quat desiredQuat = glm::normalize(glm::quat_cast(m));
glm::quat deltaQuat = desiredQuat * glm::inverse(headQuat); glm::quat deltaQuat = desiredQuat * glm::inverse(headQuat);

View file

@ -304,18 +304,6 @@ glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const {
return rotationBetween(orientation * IDENTITY_FORWARD, lookAtDelta + glm::length(lookAtDelta) * _saccade) * orientation; return rotationBetween(orientation * IDENTITY_FORWARD, lookAtDelta + glm::length(lookAtDelta) * _saccade) * orientation;
} }
void Head::setFinalPitch(float finalPitch) {
_deltaPitch = glm::clamp(finalPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH) - _basePitch;
}
void Head::setFinalYaw(float finalYaw) {
_deltaYaw = glm::clamp(finalYaw, MIN_HEAD_YAW, MAX_HEAD_YAW) - _baseYaw;
}
void Head::setFinalRoll(float finalRoll) {
_deltaRoll = glm::clamp(finalRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL) - _baseRoll;
}
float Head::getFinalYaw() const { float Head::getFinalYaw() const {
return glm::clamp(_baseYaw + _deltaYaw, MIN_HEAD_YAW, MAX_HEAD_YAW); return glm::clamp(_baseYaw + _deltaYaw, MIN_HEAD_YAW, MAX_HEAD_YAW);
} }

View file

@ -71,9 +71,6 @@ public:
void setDeltaRoll(float roll) { _deltaRoll = roll; } void setDeltaRoll(float roll) { _deltaRoll = roll; }
float getDeltaRoll() const { return _deltaRoll; } float getDeltaRoll() const { return _deltaRoll; }
virtual void setFinalYaw(float finalYaw) override;
virtual void setFinalPitch(float finalPitch) override;
virtual void setFinalRoll(float finalRoll) override;
virtual float getFinalPitch() const override; virtual float getFinalPitch() const override;
virtual float getFinalYaw() const override; virtual float getFinalYaw() const override;
virtual float getFinalRoll() const override; virtual float getFinalRoll() const override;

View file

@ -45,9 +45,6 @@ public:
float getBaseRoll() const { return _baseRoll; } float getBaseRoll() const { return _baseRoll; }
void setBaseRoll(float roll) { _baseRoll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); } void setBaseRoll(float roll) { _baseRoll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); }
virtual void setFinalYaw(float finalYaw) { _baseYaw = finalYaw; }
virtual void setFinalPitch(float finalPitch) { _basePitch = finalPitch; }
virtual void setFinalRoll(float finalRoll) { _baseRoll = finalRoll; }
virtual float getFinalYaw() const { return _baseYaw; } virtual float getFinalYaw() const { return _baseYaw; }
virtual float getFinalPitch() const { return _basePitch; } virtual float getFinalPitch() const { return _basePitch; }
virtual float getFinalRoll() const { return _baseRoll; } virtual float getFinalRoll() const { return _baseRoll; }

View file

@ -39,6 +39,7 @@ namespace controller {
quat getRotation() const { return rotation; } quat getRotation() const { return rotation; }
vec3 getVelocity() const { return velocity; } vec3 getVelocity() const { return velocity; }
vec3 getAngularVelocity() const { return angularVelocity; } vec3 getAngularVelocity() const { return angularVelocity; }
mat4 getMatrix() const { return createMatFromQuatAndPos(rotation, translation); }
Pose transform(const glm::mat4& mat) const; Pose transform(const glm::mat4& mat) const;
Pose postTransform(const glm::mat4& mat) const; Pose postTransform(const glm::mat4& mat) const;

View file

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

View file

@ -42,6 +42,8 @@ public:
// between the main thread and the presentation thread // between the main thread and the presentation thread
bool activate() override final; bool activate() override final;
void deactivate() override final; void deactivate() override final;
bool startStandBySession() override final;
void endSession() override final;
bool eventFilter(QObject* receiver, QEvent* event) override; bool eventFilter(QObject* receiver, QEvent* event) override;
bool isDisplayVisible() const override { return true; } bool isDisplayVisible() const override { return true; }
@ -100,6 +102,10 @@ protected:
virtual bool internalActivate() { return true; } virtual bool internalActivate() { return true; }
virtual void internalDeactivate() {} 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 // Plugin specific functionality to send the composed scene to the output window or device
virtual void internalPresent(); virtual void internalPresent();

View file

@ -13,6 +13,7 @@
#include <DependencyManager.h> #include <DependencyManager.h>
#include <PerfStat.h> #include <PerfStat.h>
#include <GeometryCache.h> #include <GeometryCache.h>
#include <StencilMaskPass.h>
#include <AbstractViewStateInterface.h> #include <AbstractViewStateInterface.h>
#include "EntitiesRendererLogging.h" #include "EntitiesRendererLogging.h"
@ -292,6 +293,7 @@ void RenderableParticleEffectEntityItem::createPipelines() {
state->setDepthTest(true, false, gpu::LESS_EQUAL); state->setDepthTest(true, false, gpu::LESS_EQUAL);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE, state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMask(*state);
auto vertShader = gpu::Shader::createVertex(std::string(untextured_particle_vert)); auto vertShader = gpu::Shader::createVertex(std::string(untextured_particle_vert));
auto fragShader = gpu::Shader::createPixel(std::string(untextured_particle_frag)); auto fragShader = gpu::Shader::createPixel(std::string(untextured_particle_frag));
@ -305,6 +307,7 @@ void RenderableParticleEffectEntityItem::createPipelines() {
state->setDepthTest(true, false, gpu::LESS_EQUAL); state->setDepthTest(true, false, gpu::LESS_EQUAL);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE, state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMask(*state);
auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert)); auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert));
auto fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag)); auto fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag));

View file

@ -12,6 +12,7 @@
#include <glm/gtx/quaternion.hpp> #include <glm/gtx/quaternion.hpp>
#include <GeometryCache.h> #include <GeometryCache.h>
#include <StencilMaskPass.h>
#include <TextureCache.h> #include <TextureCache.h>
#include <PathUtils.h> #include <PathUtils.h>
#include <PerfStat.h> #include <PerfStat.h>
@ -69,6 +70,7 @@ void RenderablePolyLineEntityItem::createPipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMask(*state);
state->setBlendFunction(true, state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);

View file

@ -46,6 +46,9 @@
#endif #endif
#include "model/Geometry.h" #include "model/Geometry.h"
#include "StencilMaskPass.h"
#include "EntityTreeRenderer.h" #include "EntityTreeRenderer.h"
#include "polyvox_vert.h" #include "polyvox_vert.h"
#include "polyvox_frag.h" #include "polyvox_frag.h"
@ -743,6 +746,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
auto state = std::make_shared<gpu::State>(); auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK); state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMaskDrawShape(*state);
_pipeline = gpu::Pipeline::create(program, state); _pipeline = gpu::Pipeline::create(program, state);
@ -750,6 +754,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
wireframeState->setCullMode(gpu::State::CULL_BACK); wireframeState->setCullMode(gpu::State::CULL_BACK);
wireframeState->setDepthTest(true, true, gpu::LESS_EQUAL); wireframeState->setDepthTest(true, true, gpu::LESS_EQUAL);
wireframeState->setFillMode(gpu::State::FILL_LINE); wireframeState->setFillMode(gpu::State::FILL_LINE);
PrepareStencil::testMaskDrawShape(*wireframeState);
_wireframePipeline = gpu::Pipeline::create(program, wireframeState); _wireframePipeline = gpu::Pipeline::create(program, wireframeState);
} }

View file

@ -13,6 +13,7 @@
#include <gpu/Batch.h> #include <gpu/Batch.h>
#include <DependencyManager.h> #include <DependencyManager.h>
#include <StencilMaskPass.h>
#include <GeometryCache.h> #include <GeometryCache.h>
#include <PerfStat.h> #include <PerfStat.h>
@ -93,6 +94,7 @@ void RenderableShapeEntityItem::render(RenderArgs* args) {
_procedural->_fragmentSource = simple_frag; _procedural->_fragmentSource = simple_frag;
_procedural->_opaqueState->setCullMode(gpu::State::CULL_NONE); _procedural->_opaqueState->setCullMode(gpu::State::CULL_NONE);
_procedural->_opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL); _procedural->_opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMaskDrawShape(*_procedural->_opaqueState);
_procedural->_opaqueState->setBlendFunction(false, _procedural->_opaqueState->setBlendFunction(false,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);

View file

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

View file

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

View file

@ -33,6 +33,9 @@
#include <NetworkAccessManager.h> #include <NetworkAccessManager.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <shared/GlobalAppProperties.h> #include <shared/GlobalAppProperties.h>
#include <FileTypeProfile.h>
#include <HFWebEngineProfile.h>
#include <HFTabletWebEngineProfile.h>
#include "OffscreenGLCanvas.h" #include "OffscreenGLCanvas.h"
#include "GLHelpers.h" #include "GLHelpers.h"
@ -41,6 +44,7 @@
Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml") Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml")
Q_LOGGING_CATEGORY(trace_render_qml_gl, "trace.render.qml.gl") Q_LOGGING_CATEGORY(trace_render_qml_gl, "trace.render.qml.gl")
Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
struct TextureSet { struct TextureSet {
// The number of surfaces with this size // The number of surfaces with this size
@ -254,8 +258,72 @@ QNetworkAccessManager* QmlNetworkAccessManagerFactory::create(QObject* parent) {
return new QmlNetworkAccessManager(parent); return new QmlNetworkAccessManager(parent);
} }
Q_DECLARE_LOGGING_CATEGORY(offscreenFocus) static QQmlEngine* globalEngine { nullptr };
Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus") 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() { void OffscreenQmlSurface::cleanup() {
_canvas->makeCurrent(); _canvas->makeCurrent();
@ -294,6 +362,7 @@ void OffscreenQmlSurface::render() {
GLuint texture = offscreenTextures.getNextTexture(_size); GLuint texture = offscreenTextures.getNextTexture(_size);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0); glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_renderControl->render(); _renderControl->render();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
@ -362,8 +431,8 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
_canvas->deleteLater(); _canvas->deleteLater();
_rootItem->deleteLater(); _rootItem->deleteLater();
_qmlComponent->deleteLater(); _qmlComponent->deleteLater();
_qmlEngine->deleteLater();
_quickWindow->deleteLater(); _quickWindow->deleteLater();
releaseEngine();
} }
void OffscreenQmlSurface::onAboutToQuit() { void OffscreenQmlSurface::onAboutToQuit() {
@ -375,6 +444,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
qCDebug(glLogging) << "Building QML surface"; qCDebug(glLogging) << "Building QML surface";
_renderControl = new QMyQuickRenderControl(); _renderControl = new QMyQuickRenderControl();
connect(_renderControl, &QQuickRenderControl::renderRequested, this, [this] { _render = true; });
connect(_renderControl, &QQuickRenderControl::sceneChanged, this, [this] { _render = _polish = true; });
QQuickWindow::setDefaultAlphaBuffer(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. // so we wait until after its ctor to move object/context to this thread.
_quickWindow = new QQuickWindow(_renderControl); _quickWindow = new QQuickWindow(_renderControl);
_quickWindow->setColor(QColor(255, 255, 255, 0)); _quickWindow->setColor(QColor(255, 255, 255, 0));
_quickWindow->setFlags(_quickWindow->flags() | static_cast<Qt::WindowFlags>(Qt::WA_TranslucentBackground)); _quickWindow->setClearBeforeRendering(false);
_renderControl->_renderWindow = _proxyWindow; _renderControl->_renderWindow = _proxyWindow;
@ -398,32 +469,20 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
connect(_quickWindow, &QQuickWindow::focusObjectChanged, this, &OffscreenQmlSurface::onFocusObjectChanged); connect(_quickWindow, &QQuickWindow::focusObjectChanged, this, &OffscreenQmlSurface::onFocusObjectChanged);
// Create a QML engine. // 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(); _qmlComponent = new QQmlComponent(qmlEngine);
importList.insert(importList.begin(), PathUtils::resourcesPath());
_qmlEngine->setImportPathList(importList);
if (!_qmlEngine->incubationController()) {
_qmlEngine->setIncubationController(_quickWindow->incubationController());
}
// 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()) { if (!_canvas->makeCurrent()) {
qWarning("Failed to make context current for QML Renderer"); qWarning("Failed to make context current for QML Renderer");
return; return;
} }
_glData = ::getGLContextData();
_renderControl->initialize(_canvas->getContext()); _renderControl->initialize(_canvas->getContext());
// When Quick says there is a need to render, we will not render immediately. Instead, // 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.setTimerType(Qt::PreciseTimer);
_updateTimer.setInterval(MIN_TIMER_MS); // 5ms, Qt::PreciseTimer required _updateTimer.setInterval(MIN_TIMER_MS); // 5ms, Qt::PreciseTimer required
_updateTimer.start(); _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) { static uvec2 clampSize(const uvec2& size, uint32_t maxDimension) {
@ -460,7 +514,7 @@ void OffscreenQmlSurface::resize(const QSize& newSize_, bool forceResize) {
return; return;
} }
_qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize); _qmlContext->setContextProperty("surfaceSize", newSize);
if (_rootItem) { if (_rootItem) {
_rootItem->setSize(newSize); _rootItem->setSize(newSize);
@ -520,14 +574,19 @@ QQuickItem* OffscreenQmlSurface::getRootItem() {
} }
void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) { void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
_qmlEngine->setBaseUrl(baseUrl); _qmlContext->setBaseUrl(baseUrl);
} }
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) { QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
// Synchronous loading may take a while; restart the deadlock timer // Synchronous loading may take a while; restart the deadlock timer
QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection); QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection);
if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) {
_qmlComponent->loadUrl(_qmlContext->resolvedUrl(qmlSource), QQmlComponent::PreferSynchronous);
} else {
_qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous); _qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous);
}
if (_qmlComponent->isLoading()) { if (_qmlComponent->isLoading()) {
connect(_qmlComponent, &QQmlComponent::statusChanged, this, connect(_qmlComponent, &QQmlComponent::statusChanged, this,
@ -541,10 +600,22 @@ QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQm
} }
void OffscreenQmlSurface::clearCache() { void OffscreenQmlSurface::clearCache() {
getRootContext()->engine()->clearComponentCache(); _qmlContext->engine()->clearComponentCache();
} }
QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f) { 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); disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, 0);
if (_qmlComponent->isError()) { if (_qmlComponent->isError()) {
QList<QQmlError> errorList = _qmlComponent->errors(); QList<QQmlError> errorList = _qmlComponent->errors();
@ -554,21 +625,8 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb
return nullptr; 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(_qmlContext);
QObject* newObject = _qmlComponent->beginCreate(newContext);
if (_qmlComponent->isError()) { if (_qmlComponent->isError()) {
QList<QQmlError> errorList = _qmlComponent->errors(); QList<QQmlError> errorList = _qmlComponent->errors();
foreach(const QQmlError& error, errorList) foreach(const QQmlError& error, errorList)
@ -579,12 +637,10 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb
return nullptr; return nullptr;
} }
_qmlEngine->setObjectOwnership(this, QQmlEngine::CppOwnership); _qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
newObject->setProperty("eventBridge", QVariant::fromValue(this)); newObject->setProperty("eventBridge", QVariant::fromValue(this));
newContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject)); f(_qmlContext, newObject);
f(newContext, newObject);
_qmlComponent->completeCreate(); _qmlComponent->completeCreate();
@ -735,7 +791,7 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
mouseEvent->screenPos(), mouseEvent->button(), mouseEvent->screenPos(), mouseEvent->button(),
mouseEvent->buttons(), mouseEvent->modifiers()); mouseEvent->buttons(), mouseEvent->modifiers());
if (event->type() == QEvent::MouseMove) { if (event->type() == QEvent::MouseMove) {
_qmlEngine->rootContext()->setContextProperty("lastMousePosition", transformedPos); _qmlContext->setContextProperty("lastMousePosition", transformedPos);
} }
mappedEvent.ignore(); mappedEvent.ignore();
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) { if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
@ -762,9 +818,6 @@ void OffscreenQmlSurface::resume() {
if (getRootItem()) { if (getRootItem()) {
getRootItem()->setProperty("eventBridge", QVariant::fromValue(this)); getRootItem()->setProperty("eventBridge", QVariant::fromValue(this));
} }
if (getRootContext()) {
getRootContext()->setContextProperty("webEntity", this);
}
} }
bool OffscreenQmlSurface::isPaused() const { bool OffscreenQmlSurface::isPaused() const {
@ -790,8 +843,8 @@ QSize OffscreenQmlSurface::size() const {
return _quickWindow->geometry().size(); return _quickWindow->geometry().size();
} }
QQmlContext* OffscreenQmlSurface::getRootContext() { QQmlContext* OffscreenQmlSurface::getSurfaceContext() {
return _qmlEngine->rootContext(); return _qmlContext;
} }
Q_DECLARE_METATYPE(std::function<void()>); Q_DECLARE_METATYPE(std::function<void()>);

View file

@ -73,7 +73,7 @@ public:
QQuickItem* getRootItem(); QQuickItem* getRootItem();
QQuickWindow* getWindow(); QQuickWindow* getWindow();
QObject* getEventHandler(); QObject* getEventHandler();
QQmlContext* getRootContext(); QQmlContext* getSurfaceContext();
QPointF mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget); QPointF mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget);
bool eventFilter(QObject* originalDestination, QEvent* event) override; bool eventFilter(QObject* originalDestination, QEvent* event) override;
@ -133,11 +133,10 @@ private slots:
private: private:
QQuickWindow* _quickWindow { nullptr }; QQuickWindow* _quickWindow { nullptr };
QMyQuickRenderControl* _renderControl{ nullptr }; QMyQuickRenderControl* _renderControl{ nullptr };
QQmlEngine* _qmlEngine { nullptr }; QQmlContext* _qmlContext { nullptr };
QQmlComponent* _qmlComponent { nullptr }; QQmlComponent* _qmlComponent { nullptr };
QQuickItem* _rootItem { nullptr }; QQuickItem* _rootItem { nullptr };
OffscreenGLCanvas* _canvas { nullptr }; OffscreenGLCanvas* _canvas { nullptr };
QJsonObject _glData;
QTimer _updateTimer; QTimer _updateTimer;
uint32_t _fbo { 0 }; uint32_t _fbo { 0 };

View file

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

View file

@ -0,0 +1,28 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// Draw and transform the fed vertex position with the standard MVP stack
// Output the clip position
//
// Created by Sam Gateau on 5/30/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
layout(location = 0) in vec4 inPosition;
out vec3 varWorldPos;
void main(void) {
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
}

View file

@ -2,25 +2,18 @@
<$VERSION_HEADER$> <$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$> // Generated on <$_SCRIBE_DATE$>
// //
// hit_effect.vert // Draw the fed vertex position, pass straight as clip pos
// vertex shader // Output the clip position
// //
// Created by Eric Levin on 7/20/15. // Created by Sam Gateau on 5/30/2017
// Copyright 2015 High Fidelity, Inc. // Copyright 2017 High Fidelity, Inc.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
<@include gpu/Inputs.slh@> layout(location = 0) in vec4 inPosition;
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
out vec2 varQuadPosition;
void main(void) { void main(void) {
varQuadPosition = inPosition.xy;
gl_Position = inPosition; gl_Position = inPosition;
} }

View file

@ -2,15 +2,17 @@
<$VERSION_HEADER$> <$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$> // Generated on <$_SCRIBE_DATE$>
// //
// drawOpaqueStencil.frag // Draw white
// fragment shader
// //
// Created by Sam Gateau on 9/29/15. // Created by Sam Gateau on 5/30/2017
// Copyright 2015 High Fidelity, Inc. // Copyright 2017 High Fidelity, Inc.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
out vec4 outFragColor;
void main(void) { void main(void) {
outFragColor = vec4(1.0);
} }

View file

@ -16,6 +16,12 @@
#include "DrawTransformUnitQuad_vert.h" #include "DrawTransformUnitQuad_vert.h"
#include "DrawTexcoordRectTransformUnitQuad_vert.h" #include "DrawTexcoordRectTransformUnitQuad_vert.h"
#include "DrawViewportQuadTransformTexcoord_vert.h" #include "DrawViewportQuadTransformTexcoord_vert.h"
#include "DrawVertexPosition_vert.h"
#include "DrawTransformVertexPosition_vert.h"
const char DrawNada_frag[] = "void main(void) {}"; // DrawNada is really simple...
#include "DrawWhite_frag.h"
#include "DrawTexture_frag.h" #include "DrawTexture_frag.h"
#include "DrawTextureOpaque_frag.h" #include "DrawTextureOpaque_frag.h"
#include "DrawColoredTexture_frag.h" #include "DrawColoredTexture_frag.h"
@ -26,6 +32,10 @@ ShaderPointer StandardShaderLib::_drawUnitQuadTexcoordVS;
ShaderPointer StandardShaderLib::_drawTransformUnitQuadVS; ShaderPointer StandardShaderLib::_drawTransformUnitQuadVS;
ShaderPointer StandardShaderLib::_drawTexcoordRectTransformUnitQuadVS; ShaderPointer StandardShaderLib::_drawTexcoordRectTransformUnitQuadVS;
ShaderPointer StandardShaderLib::_drawViewportQuadTransformTexcoordVS; ShaderPointer StandardShaderLib::_drawViewportQuadTransformTexcoordVS;
ShaderPointer StandardShaderLib::_drawVertexPositionVS;
ShaderPointer StandardShaderLib::_drawTransformVertexPositionVS;
ShaderPointer StandardShaderLib::_drawNadaPS;
ShaderPointer StandardShaderLib::_drawWhitePS;
ShaderPointer StandardShaderLib::_drawTexturePS; ShaderPointer StandardShaderLib::_drawTexturePS;
ShaderPointer StandardShaderLib::_drawTextureOpaquePS; ShaderPointer StandardShaderLib::_drawTextureOpaquePS;
ShaderPointer StandardShaderLib::_drawColoredTexturePS; ShaderPointer StandardShaderLib::_drawColoredTexturePS;
@ -85,6 +95,34 @@ ShaderPointer StandardShaderLib::getDrawViewportQuadTransformTexcoordVS() {
return _drawViewportQuadTransformTexcoordVS; return _drawViewportQuadTransformTexcoordVS;
} }
ShaderPointer StandardShaderLib::getDrawVertexPositionVS() {
if (!_drawVertexPositionVS) {
_drawVertexPositionVS = gpu::Shader::createVertex(std::string(DrawVertexPosition_vert));
}
return _drawVertexPositionVS;
}
ShaderPointer StandardShaderLib::getDrawTransformVertexPositionVS() {
if (!_drawTransformVertexPositionVS) {
_drawTransformVertexPositionVS = gpu::Shader::createVertex(std::string(DrawTransformVertexPosition_vert));
}
return _drawTransformVertexPositionVS;
}
ShaderPointer StandardShaderLib::getDrawNadaPS() {
if (!_drawNadaPS) {
_drawNadaPS = gpu::Shader::createPixel(std::string(DrawNada_frag));
}
return _drawNadaPS;
}
ShaderPointer StandardShaderLib::getDrawWhitePS() {
if (!_drawWhitePS) {
_drawWhitePS = gpu::Shader::createPixel(std::string(DrawWhite_frag));
}
return _drawWhitePS;
}
ShaderPointer StandardShaderLib::getDrawTexturePS() { ShaderPointer StandardShaderLib::getDrawTexturePS() {
if (!_drawTexturePS) { if (!_drawTexturePS) {
_drawTexturePS = gpu::Shader::createPixel(std::string(DrawTexture_frag)); _drawTexturePS = gpu::Shader::createPixel(std::string(DrawTexture_frag));
@ -99,8 +137,6 @@ ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() {
return _drawTextureOpaquePS; return _drawTextureOpaquePS;
} }
ShaderPointer StandardShaderLib::getDrawColoredTexturePS() { ShaderPointer StandardShaderLib::getDrawColoredTexturePS() {
if (!_drawColoredTexturePS) { if (!_drawColoredTexturePS) {
_drawColoredTexturePS = gpu::Shader::createPixel(std::string(DrawColoredTexture_frag)); _drawColoredTexturePS = gpu::Shader::createPixel(std::string(DrawColoredTexture_frag));

View file

@ -37,6 +37,15 @@ public:
// Shader draws the unit quad in the full viewport clipPos = ([(-1,-1),(1,1)]) and transform the texcoord = [(0,0),(1,1)] by the model transform. // Shader draws the unit quad in the full viewport clipPos = ([(-1,-1),(1,1)]) and transform the texcoord = [(0,0),(1,1)] by the model transform.
static ShaderPointer getDrawViewportQuadTransformTexcoordVS(); static ShaderPointer getDrawViewportQuadTransformTexcoordVS();
// Shader draw the fed vertex position and transform it by the full model transform stack (Model, View, Proj).
// simply output the world pos and the clip pos to the next stage
static ShaderPointer getDrawVertexPositionVS();
static ShaderPointer getDrawTransformVertexPositionVS();
// PShader does nothing, no really nothing, but still needed for defining a program triggering rasterization
static ShaderPointer getDrawNadaPS();
static ShaderPointer getDrawWhitePS();
static ShaderPointer getDrawTexturePS(); static ShaderPointer getDrawTexturePS();
static ShaderPointer getDrawTextureOpaquePS(); static ShaderPointer getDrawTextureOpaquePS();
static ShaderPointer getDrawColoredTexturePS(); static ShaderPointer getDrawColoredTexturePS();
@ -51,6 +60,12 @@ protected:
static ShaderPointer _drawTransformUnitQuadVS; static ShaderPointer _drawTransformUnitQuadVS;
static ShaderPointer _drawTexcoordRectTransformUnitQuadVS; static ShaderPointer _drawTexcoordRectTransformUnitQuadVS;
static ShaderPointer _drawViewportQuadTransformTexcoordVS; static ShaderPointer _drawViewportQuadTransformTexcoordVS;
static ShaderPointer _drawVertexPositionVS;
static ShaderPointer _drawTransformVertexPositionVS;
static ShaderPointer _drawNadaPS;
static ShaderPointer _drawWhitePS;
static ShaderPointer _drawTexturePS; static ShaderPointer _drawTexturePS;
static ShaderPointer _drawTextureOpaquePS; static ShaderPointer _drawTextureOpaquePS;
static ShaderPointer _drawColoredTexturePS; static ShaderPointer _drawColoredTexturePS;

View file

@ -70,8 +70,6 @@ public:
bool isSupported() const override { return true; } bool isSupported() const override { return true; }
const QString getName() const override { return NAME; } const QString getName() const override { return NAME; }
bool isHandController() const override { return false; }
void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;

View file

@ -39,8 +39,6 @@ public:
virtual bool isSupported() const override; virtual bool isSupported() const override;
virtual const QString getName() const override { return NAME; } virtual const QString getName() const override { return NAME; }
bool isHandController() const override { return false; }
virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;

View file

@ -241,6 +241,42 @@ void Mesh::forEach(std::function<void(glm::vec3)> vertexFunc,
} }
} }
MeshPointer Mesh::createIndexedTriangles_P3F(uint32_t numVertices, uint32_t numIndices, const glm::vec3* vertices, const uint32_t* indices) {
MeshPointer mesh;
if (numVertices == 0) { return mesh; }
if (numIndices < 3) { return mesh; }
mesh = std::make_shared<Mesh>();
// Vertex buffer
mesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(numVertices * sizeof(glm::vec3), (gpu::Byte*) vertices), gpu::Element::VEC3F_XYZ));
// trim down the indices to shorts if possible
if (numIndices < std::numeric_limits<uint16_t>::max()) {
Indices16 shortIndicesVector;
int16_t* shortIndices = nullptr;
if (indices) {
shortIndicesVector.resize(numIndices);
for (uint32_t i = 0; i < numIndices; i++) {
shortIndicesVector[i] = indices[i];
}
shortIndices = shortIndicesVector.data();
}
mesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(numIndices * sizeof(uint16_t), (gpu::Byte*) shortIndices), gpu::Element::INDEX_UINT16));
} else {
mesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(numIndices * sizeof(uint32_t), (gpu::Byte*) indices), gpu::Element::INDEX_INT32));
}
std::vector<model::Mesh::Part> parts;
parts.push_back(model::Mesh::Part(0, numIndices, 0, model::Mesh::TRIANGLES));
mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));
return mesh;
}
Geometry::Geometry() { Geometry::Geometry() {
} }
@ -256,3 +292,5 @@ Geometry::~Geometry() {
void Geometry::setMesh(const MeshPointer& mesh) { void Geometry::setMesh(const MeshPointer& mesh) {
_mesh = mesh; _mesh = mesh;
} }

View file

@ -65,6 +65,9 @@ public:
const gpu::BufferStream& getVertexStream() const { return _vertexStream; } const gpu::BufferStream& getVertexStream() const { return _vertexStream; }
// Index Buffer // Index Buffer
using Indices16 = std::vector<int16_t>;
using Indices32 = std::vector<int32_t>;
void setIndexBuffer(const BufferView& buffer); void setIndexBuffer(const BufferView& buffer);
const BufferView& getIndexBuffer() const { return _indexBuffer; } const BufferView& getIndexBuffer() const { return _indexBuffer; }
size_t getNumIndices() const { return _indexBuffer.getNumElements(); } size_t getNumIndices() const { return _indexBuffer.getNumElements(); }
@ -127,6 +130,9 @@ public:
std::function<void(glm::vec3)> normalFunc, std::function<void(glm::vec3)> normalFunc,
std::function<void(uint32_t)> indexFunc); std::function<void(uint32_t)> indexFunc);
static MeshPointer createIndexedTriangles_P3F(uint32_t numVertices, uint32_t numTriangles, const glm::vec3* vertices = nullptr, const uint32_t* indices = nullptr);
protected: protected:
gpu::Stream::FormatPointer _vertexFormat; gpu::Stream::FormatPointer _vertexFormat;

View file

@ -97,7 +97,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
} }
auto skyState = std::make_shared<gpu::State>(); auto skyState = std::make_shared<gpu::State>();
skyState->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); skyState->setStencilTest(true, 0xFF, gpu::State::StencilTest(1, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
thePipeline = gpu::Pipeline::create(skyShader, skyState); thePipeline = gpu::Pipeline::create(skyShader, skyState);
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -15,7 +15,12 @@
#include <QFile> #include <QFile>
#include <StatTracker.h>
void FileResourceRequest::doSend() { void FileResourceRequest::doSend() {
auto statTracker = DependencyManager::get<StatTracker>();
statTracker->incrementStat(STAT_FILE_REQUEST_STARTED);
QString filename = _url.toLocalFile(); QString filename = _url.toLocalFile();
// sometimes on windows, we see the toLocalFile() return null, // sometimes on windows, we see the toLocalFile() return null,
@ -60,4 +65,10 @@ void FileResourceRequest::doSend() {
_state = Finished; _state = Finished;
emit 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"; 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); setHttpUserAgent(WEB_ENGINE_USER_AGENT);
setStorageName(QML_WEB_ENGINE_NAME);
auto requestInterceptor = new HFTabletWebEngineRequestInterceptor(this); auto requestInterceptor = new HFTabletWebEngineRequestInterceptor(this);
setRequestInterceptor(requestInterceptor); setRequestInterceptor(requestInterceptor);

View file

@ -11,7 +11,7 @@
#include "HFTabletWebEngineRequestInterceptor.h" #include "HFTabletWebEngineRequestInterceptor.h"
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <AccountManager.h> #include "AccountManager.h"
bool isTabletAuthableHighFidelityURL(const QUrl& url) { bool isTabletAuthableHighFidelityURL(const QUrl& url) {
static const QStringList HF_HOSTS = { 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)"; static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)";
setHttpUserAgent(WEB_ENGINE_USER_AGENT); 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 // we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user
auto requestInterceptor = new HFWebEngineRequestInterceptor(this); auto requestInterceptor = new HFWebEngineRequestInterceptor(this);

View file

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

View file

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

View file

@ -29,6 +29,7 @@
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <SettingHandle.h> #include <SettingHandle.h>
#include <SharedUtil.h> #include <SharedUtil.h>
#include <StatTracker.h>
#include <UUID.h> #include <UUID.h>
#include "AccountManager.h" #include "AccountManager.h"
@ -37,7 +38,6 @@
#include "HifiSockAddr.h" #include "HifiSockAddr.h"
#include "NetworkLogging.h" #include "NetworkLogging.h"
#include "udt/Packet.h" #include "udt/Packet.h"
#include <Trace.h>
static Setting::Handle<quint16> LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.LocalPort", 0); 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; qCInfo(networking) << "Local socket is" << sockAddr;
} else { } else {
qCInfo(networking) << "Local socket has changed from" << _localSockAddr << "to" << sockAddr; qCInfo(networking) << "Local socket has changed from" << _localSockAddr << "to" << sockAddr;
DependencyManager::get<StatTracker>()->incrementStat(LOCAL_SOCKET_CHANGE_STAT);
} }
_localSockAddr = sockAddr; _localSockAddr = sockAddr;
emit localSockAddrChanged(_localSockAddr); 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 USERNAME_UUID_REPLACEMENT_STATS_KEY = "$username";
const QString LOCAL_SOCKET_CHANGE_STAT = "LocalSocketChanges";
using namespace tbb; using namespace tbb;
typedef std::pair<QUuid, SharedNodePointer> UUIDNodePair; typedef std::pair<QUuid, SharedNodePointer> UUIDNodePair;
typedef concurrent_unordered_map<QUuid, SharedNodePointer, UUIDHasher> NodeHash; typedef concurrent_unordered_map<QUuid, SharedNodePointer, UUIDHasher> NodeHash;

View file

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

View file

@ -19,6 +19,21 @@
#include "ByteRange.h" #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 { class ResourceRequest : public QObject {
Q_OBJECT Q_OBJECT
public: public:

View file

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

View file

@ -24,6 +24,7 @@ public:
// Some input plugins are comprised of multiple subdevices (SDL2, for instance). // Some input plugins are comprised of multiple subdevices (SDL2, for instance).
// If an input plugin is only a single device, it will only return it's primary name. // If an input plugin is only a single device, it will only return it's primary name.
virtual QStringList getSubdeviceNames() { return { getName() }; }; virtual QStringList getSubdeviceNames() { return { getName() }; };
virtual bool isHandController() const = 0; virtual bool isHandController() const { return false; }
virtual bool isHeadController() const { return false; }
}; };

View file

@ -53,6 +53,18 @@ public:
virtual bool isActive() { virtual bool isActive() {
return _active; 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 * Called by the application during it's idle phase. If the plugin needs to do
@ -73,6 +85,7 @@ signals:
protected: protected:
bool _active { false }; bool _active { false };
bool _sessionStatus { false };
PluginContainer* _container { nullptr }; PluginContainer* _container { nullptr };
static const char* UNKNOWN_PLUGIN_ID; static const char* UNKNOWN_PLUGIN_ID;

View file

@ -24,6 +24,15 @@ bool PluginUtils::isHMDAvailable(const QString& pluginName) {
return false; return false;
} }
bool PluginUtils::isHeadControllerAvailable(const QString& pluginName) {
for (auto& inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
if (inputPlugin->isHeadController() && (pluginName.isEmpty() || inputPlugin->getName() == pluginName)) {
return true;
}
}
return false;
};
bool PluginUtils::isHandControllerAvailable(const QString& pluginName) { bool PluginUtils::isHandControllerAvailable(const QString& pluginName) {
for (auto& inputPlugin : PluginManager::getInstance()->getInputPlugins()) { for (auto& inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
if (inputPlugin->isHandController() && (pluginName.isEmpty() || inputPlugin->getName() == pluginName)) { if (inputPlugin->isHandController() && (pluginName.isEmpty() || inputPlugin->getName() == pluginName)) {

View file

@ -16,6 +16,7 @@ class PluginUtils {
public: public:
static bool isHMDAvailable(const QString& pluginName = ""); static bool isHMDAvailable(const QString& pluginName = "");
static bool isHandControllerAvailable(const QString& pluginName = ""); static bool isHandControllerAvailable(const QString& pluginName = "");
static bool isHeadControllerAvailable(const QString& pluginName = "");
static bool isSubdeviceContainingNameAvailable(QString name); static bool isSubdeviceContainingNameAvailable(QString name);
static bool isViveControllerAvailable(); static bool isViveControllerAvailable();
static bool isOculusTouchControllerAvailable(); static bool isOculusTouchControllerAvailable();

View file

@ -23,7 +23,7 @@ ProceduralSkybox::ProceduralSkybox() : model::Skybox() {
_procedural._fragmentSource = skybox_frag; _procedural._fragmentSource = skybox_frag;
// Adjust the pipeline state for background using the stencil test // Adjust the pipeline state for background using the stencil test
_procedural.setDoesFade(false); _procedural.setDoesFade(false);
_procedural._opaqueState->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); _procedural._opaqueState->setStencilTest(true, 0xFF, gpu::State::StencilTest(1, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
} }
bool ProceduralSkybox::empty() { bool ProceduralSkybox::empty() {

View file

@ -260,7 +260,7 @@ static void addLink(const AnimPose& rootPose, const AnimPose& pose, const AnimPo
// there is room, so lets draw a nice bone // there is room, so lets draw a nice bone
glm::vec3 uAxis, vAxis, wAxis; glm::vec3 uAxis, vAxis, wAxis;
generateBasisVectors(boneAxis0, glm::vec3(1, 0, 0), uAxis, vAxis, wAxis); generateBasisVectors(boneAxis0, glm::vec3(1.0f, 0.0f, 0.0f), uAxis, vAxis, wAxis);
glm::vec3 boneBaseCorners[NUM_BASE_CORNERS]; glm::vec3 boneBaseCorners[NUM_BASE_CORNERS];
boneBaseCorners[0] = pose0 * ((uAxis * radius) + (vAxis * radius) + (wAxis * radius)); boneBaseCorners[0] = pose0 * ((uAxis * radius) + (vAxis * radius) + (wAxis * radius));

View file

@ -17,6 +17,7 @@
#include <gpu/Context.h> #include <gpu/Context.h>
#include "AntialiasingEffect.h" #include "AntialiasingEffect.h"
#include "StencilMaskPass.h"
#include "TextureCache.h" #include "TextureCache.h"
#include "FramebufferCache.h" #include "FramebufferCache.h"
#include "DependencyManager.h" #include "DependencyManager.h"
@ -70,6 +71,8 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); gpu::StatePointer state = gpu::StatePointer(new gpu::State());
PrepareStencil::testMask(*state);
state->setDepthTest(false, false, gpu::LESS_EQUAL); state->setDepthTest(false, false, gpu::LESS_EQUAL);
// Good to go add the brand new pipeline // Good to go add the brand new pipeline
@ -93,6 +96,7 @@ const gpu::PipelinePointer& Antialiasing::getBlendPipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(false, false, gpu::LESS_EQUAL); state->setDepthTest(false, false, gpu::LESS_EQUAL);
PrepareStencil::testMask(*state);
// Good to go add the brand new pipeline // Good to go add the brand new pipeline
_blendPipeline = gpu::Pipeline::create(program, state); _blendPipeline = gpu::Pipeline::create(program, state);

View file

@ -18,6 +18,7 @@
#include <gpu/Batch.h> #include <gpu/Batch.h>
#include <gpu/Context.h> #include <gpu/Context.h>
#include "StencilMaskPass.h"
#include "AbstractViewStateInterface.h" #include "AbstractViewStateInterface.h"
#include "GeometryCache.h" #include "GeometryCache.h"
#include "TextureCache.h" #include "TextureCache.h"
@ -27,18 +28,15 @@
#include "deferred_light_point_vert.h" #include "deferred_light_point_vert.h"
#include "deferred_light_spot_vert.h" #include "deferred_light_spot_vert.h"
#include "directional_light_frag.h"
#include "directional_ambient_light_frag.h" #include "directional_ambient_light_frag.h"
#include "directional_skybox_light_frag.h" #include "directional_skybox_light_frag.h"
#include "directional_light_shadow_frag.h"
#include "directional_ambient_light_shadow_frag.h" #include "directional_ambient_light_shadow_frag.h"
#include "directional_skybox_light_shadow_frag.h" #include "directional_skybox_light_shadow_frag.h"
#include "local_lights_shading_frag.h" #include "local_lights_shading_frag.h"
#include "local_lights_drawOutline_frag.h" #include "local_lights_drawOutline_frag.h"
#include "point_light_frag.h"
#include "spot_light_frag.h"
using namespace render; using namespace render;
@ -82,48 +80,26 @@ enum DeferredShader_BufferSlot {
}; };
static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations);
static void loadLightVolumeProgram(const char* vertSource, const char* fragSource, bool front, gpu::PipelinePointer& program, LightLocationsPtr& locations);
const char no_light_frag[] =
R"SCRIBE(
out vec4 _fragColor;
void main(void) {
_fragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
)SCRIBE"
;
void DeferredLightingEffect::init() { void DeferredLightingEffect::init() {
_directionalLightLocations = std::make_shared<LightLocations>();
_directionalAmbientSphereLightLocations = std::make_shared<LightLocations>(); _directionalAmbientSphereLightLocations = std::make_shared<LightLocations>();
_directionalSkyboxLightLocations = std::make_shared<LightLocations>(); _directionalSkyboxLightLocations = std::make_shared<LightLocations>();
_directionalLightShadowLocations = std::make_shared<LightLocations>();
_directionalAmbientSphereLightShadowLocations = std::make_shared<LightLocations>(); _directionalAmbientSphereLightShadowLocations = std::make_shared<LightLocations>();
_directionalSkyboxLightShadowLocations = std::make_shared<LightLocations>(); _directionalSkyboxLightShadowLocations = std::make_shared<LightLocations>();
_localLightLocations = std::make_shared<LightLocations>(); _localLightLocations = std::make_shared<LightLocations>();
_localLightOutlineLocations = std::make_shared<LightLocations>(); _localLightOutlineLocations = std::make_shared<LightLocations>();
_pointLightLocations = std::make_shared<LightLocations>();
_spotLightLocations = std::make_shared<LightLocations>();
loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations);
loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations);
loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations); loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations);
loadLightProgram(deferred_light_vert, directional_light_shadow_frag, false, _directionalLightShadow, _directionalLightShadowLocations);
loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_frag, false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations); loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_frag, false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations);
loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations);
loadLightProgram(deferred_light_vert, local_lights_shading_frag, true, _localLight, _localLightLocations); loadLightProgram(deferred_light_vert, local_lights_shading_frag, true, _localLight, _localLightLocations);
loadLightProgram(deferred_light_vert, local_lights_drawOutline_frag, true, _localLightOutline, _localLightOutlineLocations); loadLightProgram(deferred_light_vert, local_lights_drawOutline_frag, true, _localLightOutline, _localLightOutlineLocations);
loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, false, _pointLightBack, _pointLightLocations);
loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, true, _pointLightFront, _pointLightLocations);
loadLightVolumeProgram(deferred_light_spot_vert, no_light_frag, false, _spotLightBack, _spotLightLocations);
loadLightVolumeProgram(deferred_light_spot_vert, no_light_frag, true, _spotLightFront, _spotLightLocations);
// Light Stage and clusters // Light Stage and clusters
_lightStage = std::make_shared<LightStage>(); _lightStage = std::make_shared<LightStage>();
@ -267,7 +243,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
state->setColorWriteMask(true, true, true, false); state->setColorWriteMask(true, true, true, false);
if (lightVolume) { if (lightVolume) {
state->setStencilTest(true, 0x00, gpu::State::StencilTest(1, 0xFF, gpu::LESS_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); PrepareStencil::testShape(*state);
state->setCullMode(gpu::State::CULL_BACK); state->setCullMode(gpu::State::CULL_BACK);
// state->setCullMode(gpu::State::CULL_FRONT); // state->setCullMode(gpu::State::CULL_FRONT);
@ -280,7 +256,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
} else { } else {
// Stencil test all the light passes for objects pixels only, not the background // Stencil test all the light passes for objects pixels only, not the background
state->setStencilTest(true, 0x00, gpu::State::StencilTest(0, 0x01, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); PrepareStencil::testShape(*state);
state->setCullMode(gpu::State::CULL_BACK); state->setCullMode(gpu::State::CULL_BACK);
// additive blending // additive blending
@ -290,39 +266,6 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
} }
static void loadLightVolumeProgram(const char* vertSource, const char* fragSource, bool front, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) {
gpu::ShaderPointer program = makeLightProgram(vertSource, fragSource, locations);
auto state = std::make_shared<gpu::State>();
// Stencil test all the light passes for objects pixels only, not the background
if (front) {
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, false, gpu::LESS_EQUAL);
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_DECR, gpu::State::STENCIL_OP_KEEP));
// state->setDepthClampEnable(true);
// TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases
// additive blending
// state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
//state->setColorWriteMask(true, true, true, false);
state->setColorWriteMask(false, false, false, false);
} else {
state->setCullMode(gpu::State::CULL_FRONT);
state->setDepthTest(true, false, gpu::LESS_EQUAL);
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_INCR, gpu::State::STENCIL_OP_KEEP));
// additive blending
// state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
// state->setColorWriteMask(true, true, true, false);
state->setColorWriteMask(false, false, false, false);
}
pipeline = gpu::Pipeline::create(program, state);
}
void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) { void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) {
/* auto globalLight = _allocatedLights.front(); /* auto globalLight = _allocatedLights.front();
globalLight->setDirection(light->getDirection()); globalLight->setDirection(light->getDirection());
@ -535,7 +478,7 @@ void PrepareDeferred::run(const RenderContextPointer& renderContext, const Input
gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_COLOR1 | gpu::Framebuffer::BUFFER_COLOR2 | gpu::Framebuffer::BUFFER_COLOR3 | gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_COLOR1 | gpu::Framebuffer::BUFFER_COLOR2 | gpu::Framebuffer::BUFFER_COLOR3 |
gpu::Framebuffer::BUFFER_DEPTH | gpu::Framebuffer::BUFFER_DEPTH |
gpu::Framebuffer::BUFFER_STENCIL, gpu::Framebuffer::BUFFER_STENCIL,
vec4(vec3(0), 0), 1.0, 0.0, true); vec4(vec3(0), 0), 1.0, 1, true);
// For the rest of the rendering, bind the lighting model // For the rest of the rendering, bind the lighting model
batch.setUniformBuffer(LIGHTING_MODEL_BUFFER_SLOT, lightingModel->getParametersBuffer()); batch.setUniformBuffer(LIGHTING_MODEL_BUFFER_SLOT, lightingModel->getParametersBuffer());
@ -619,8 +562,8 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow->map); batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow->map);
} }
auto& program = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadow : deferredLightingEffect->_directionalLight; auto& program = deferredLightingEffect->_directionalSkyboxLight;
LightLocationsPtr locations = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadowLocations : deferredLightingEffect->_directionalLightLocations; LightLocationsPtr locations = deferredLightingEffect->_directionalSkyboxLightLocations;
const auto& keyLight = deferredLightingEffect->_allocatedLights[deferredLightingEffect->_globalLights.front()]; const auto& keyLight = deferredLightingEffect->_allocatedLights[deferredLightingEffect->_globalLights.front()];
// Setup the global directional pass pipeline // Setup the global directional pass pipeline

View file

@ -82,32 +82,21 @@ private:
gpu::PipelinePointer _directionalSkyboxLight; gpu::PipelinePointer _directionalSkyboxLight;
gpu::PipelinePointer _directionalAmbientSphereLight; gpu::PipelinePointer _directionalAmbientSphereLight;
gpu::PipelinePointer _directionalLight;
gpu::PipelinePointer _directionalSkyboxLightShadow; gpu::PipelinePointer _directionalSkyboxLightShadow;
gpu::PipelinePointer _directionalAmbientSphereLightShadow; gpu::PipelinePointer _directionalAmbientSphereLightShadow;
gpu::PipelinePointer _directionalLightShadow;
gpu::PipelinePointer _localLight; gpu::PipelinePointer _localLight;
gpu::PipelinePointer _localLightOutline; gpu::PipelinePointer _localLightOutline;
gpu::PipelinePointer _pointLightBack;
gpu::PipelinePointer _pointLightFront;
gpu::PipelinePointer _spotLightBack;
gpu::PipelinePointer _spotLightFront;
LightLocationsPtr _directionalSkyboxLightLocations; LightLocationsPtr _directionalSkyboxLightLocations;
LightLocationsPtr _directionalAmbientSphereLightLocations; LightLocationsPtr _directionalAmbientSphereLightLocations;
LightLocationsPtr _directionalLightLocations;
LightLocationsPtr _directionalSkyboxLightShadowLocations; LightLocationsPtr _directionalSkyboxLightShadowLocations;
LightLocationsPtr _directionalAmbientSphereLightShadowLocations; LightLocationsPtr _directionalAmbientSphereLightShadowLocations;
LightLocationsPtr _directionalLightShadowLocations;
LightLocationsPtr _localLightLocations; LightLocationsPtr _localLightLocations;
LightLocationsPtr _localLightOutlineLocations; LightLocationsPtr _localLightOutlineLocations;
LightLocationsPtr _pointLightLocations;
LightLocationsPtr _spotLightLocations;
using Lights = std::vector<model::LightPointer>; using Lights = std::vector<model::LightPointer>;

View file

@ -24,6 +24,7 @@
#include "TextureCache.h" #include "TextureCache.h"
#include "RenderUtilsLogging.h" #include "RenderUtilsLogging.h"
#include "StencilMaskPass.h"
#include "gpu/StandardShaderLib.h" #include "gpu/StandardShaderLib.h"
@ -1610,6 +1611,9 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const
state->setBlendFunction(true, state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMask(*state);
gpu::Shader::BindingSet slotBindings; gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("lineData"), LINE_DATA_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("lineData"), LINE_DATA_SLOT));
gpu::Shader::makeProgram(*program, slotBindings); gpu::Shader::makeProgram(*program, slotBindings);
@ -1663,11 +1667,14 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
// enable decal blend // enable decal blend
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
PrepareStencil::testMask(*state);
_standardDrawPipeline = gpu::Pipeline::create(program, state); _standardDrawPipeline = gpu::Pipeline::create(program, state);
auto stateNoBlend = std::make_shared<gpu::State>(); auto stateNoBlend = std::make_shared<gpu::State>();
PrepareStencil::testMaskDrawShape(*state);
auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS(); auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS();
auto programNoBlend = gpu::Shader::createProgram(vs, noBlendPS); auto programNoBlend = gpu::Shader::createProgram(vs, noBlendPS);
gpu::Shader::makeProgram((*programNoBlend)); gpu::Shader::makeProgram((*programNoBlend));
@ -1690,12 +1697,14 @@ void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bo
auto stateLayered = std::make_shared<gpu::State>(); auto stateLayered = std::make_shared<gpu::State>();
stateLayered->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); stateLayered->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
PrepareStencil::testMask(*stateLayered);
_gridPipelineLayered = gpu::Pipeline::create(program, stateLayered); _gridPipelineLayered = gpu::Pipeline::create(program, stateLayered);
auto state = std::make_shared<gpu::State>(stateLayered->getValues()); auto state = std::make_shared<gpu::State>(stateLayered->getValues());
const float DEPTH_BIAS = 0.001f; const float DEPTH_BIAS = 0.001f;
state->setDepthBias(DEPTH_BIAS); state->setDepthBias(DEPTH_BIAS);
state->setDepthTest(true, false, gpu::LESS_EQUAL); state->setDepthTest(true, false, gpu::LESS_EQUAL);
PrepareStencil::testMaskDrawShape(*state);
_gridPipeline = gpu::Pipeline::create(program, state); _gridPipeline = gpu::Pipeline::create(program, state);
} }
@ -1773,6 +1782,11 @@ static void buildWebShader(const std::string& vertShaderText, const std::string&
state->setBlendFunction(blendEnable, state->setBlendFunction(blendEnable,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
if (blendEnable) {
PrepareStencil::testMask(*state);
} else {
PrepareStencil::testMaskDrawShape(*state);
}
pipelinePointerOut = gpu::Pipeline::create(shaderPointerOut, state); pipelinePointerOut = gpu::Pipeline::create(shaderPointerOut, state);
} }
@ -1858,6 +1872,12 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
if (config.isTransparent()) {
PrepareStencil::testMask(*state);
} else {
PrepareStencil::testMaskDrawShape(*state);
}
gpu::ShaderPointer program = (config.isUnlit()) ? _unlitShader : _simpleShader; gpu::ShaderPointer program = (config.isUnlit()) ? _unlitShader : _simpleShader;
gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state);
_simplePrograms.insert(config, pipeline); _simplePrograms.insert(config, pipeline);

View file

@ -1,94 +0,0 @@
//
// HitEffect.cpp
// interface/src/renderer
//
// Created by Andrzej Kapolka on 7/14/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
#include <glm/gtc/random.hpp>
#include <DependencyManager.h>
#include <PathUtils.h>
#include <SharedUtil.h>
#include "AbstractViewStateInterface.h"
#include "HitEffect.h"
#include "TextureCache.h"
#include "DependencyManager.h"
#include "ViewFrustum.h"
#include "GeometryCache.h"
#include <gpu/Context.h>
#include "hit_effect_vert.h"
#include "hit_effect_frag.h"
HitEffect::HitEffect() {
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
HitEffect::~HitEffect() {
auto geometryCache = DependencyManager::get<GeometryCache>();
if (_geometryId && geometryCache) {
geometryCache->releaseID(_geometryId);
}
}
const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() {
if (!_hitEffectPipeline) {
auto vs = gpu::Shader::createVertex(std::string(hit_effect_vert));
auto ps = gpu::Shader::createPixel(std::string(hit_effect_frag));
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(false, false, gpu::LESS_EQUAL);
// Blend on transparent
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
// Good to go add the brand new pipeline
_hitEffectPipeline = gpu::Pipeline::create(program, state);
}
return _hitEffectPipeline;
}
void HitEffect::run(const render::RenderContextPointer& renderContext) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
RenderArgs* args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
batch.setModelTransform(Transform());
batch.setPipeline(getHitEffectPipeline());
static const glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f);
static const glm::vec2 bottomLeft(-1.0f, -1.0f);
static const glm::vec2 topRight(1.0f, 1.0f);
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, color, _geometryId);
});
}

View file

@ -1,38 +0,0 @@
//
// hitEffect.h
// hifi
//
// Created by eric levin on 7/17/15.
//
//
#ifndef hifi_hitEffect_h
#define hifi_hitEffect_h
#include <render/DrawTask.h>
class HitEffectConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled)
public:
HitEffectConfig() : render::Job::Config(false) {}
};
class HitEffect {
public:
using Config = HitEffectConfig;
using JobModel = render::Job::Model<HitEffect, Config>;
HitEffect();
~HitEffect();
void configure(const Config& config) {}
void run(const render::RenderContextPointer& renderContext);
const gpu::PipelinePointer& getHitEffectPipeline();
private:
int _geometryId { 0 };
gpu::PipelinePointer _hitEffectPipeline;
};
#endif

View file

@ -16,6 +16,8 @@
#include <gpu/StandardShaderLib.h> #include <gpu/StandardShaderLib.h>
#include "StencilMaskPass.h"
#include "lightClusters_drawGrid_vert.h" #include "lightClusters_drawGrid_vert.h"
#include "lightClusters_drawGrid_frag.h" #include "lightClusters_drawGrid_frag.h"

View file

@ -27,12 +27,12 @@
#include <render/BlurTask.h> #include <render/BlurTask.h>
#include "LightingModel.h" #include "LightingModel.h"
#include "StencilMaskPass.h"
#include "DebugDeferredBuffer.h" #include "DebugDeferredBuffer.h"
#include "DeferredFramebuffer.h" #include "DeferredFramebuffer.h"
#include "DeferredLightingEffect.h" #include "DeferredLightingEffect.h"
#include "SurfaceGeometryPass.h" #include "SurfaceGeometryPass.h"
#include "FramebufferCache.h" #include "FramebufferCache.h"
#include "HitEffect.h"
#include "TextureCache.h" #include "TextureCache.h"
#include "ZoneRenderer.h" #include "ZoneRenderer.h"
@ -43,8 +43,6 @@
#include <gpu/StandardShaderLib.h> #include <gpu/StandardShaderLib.h>
#include "drawOpaqueStencil_frag.h"
using namespace render; using namespace render;
extern void initOverlay3DPipelines(render::ShapePlumber& plumber); extern void initOverlay3DPipelines(render::ShapePlumber& plumber);
@ -85,13 +83,13 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto deferredFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(0); const auto deferredFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(0);
const auto lightingFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(1); const auto lightingFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(1);
// draw a stencil mask in hidden regions of the framebuffer.
task.addJob<PrepareStencil>("PrepareStencil", primaryFramebuffer);
// Render opaque objects in DeferredBuffer // Render opaque objects in DeferredBuffer
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying(); const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying();
task.addJob<DrawStateSortDeferred>("DrawOpaqueDeferred", opaqueInputs, shapePlumber); task.addJob<DrawStateSortDeferred>("DrawOpaqueDeferred", opaqueInputs, shapePlumber);
// Once opaque is all rendered create stencil background
task.addJob<DrawStencilDeferred>("DrawOpaqueStencil", deferredFramebuffer);
task.addJob<EndGPURangeTimer>("OpaqueRangeTimer", opaqueRangeTimer); task.addJob<EndGPURangeTimer>("OpaqueRangeTimer", opaqueRangeTimer);
@ -387,88 +385,6 @@ void DrawOverlay3D::run(const RenderContextPointer& renderContext, const Inputs&
} }
} }
gpu::PipelinePointer DrawStencilDeferred::getOpaquePipeline() {
if (!_opaquePipeline) {
const gpu::int8 STENCIL_OPAQUE = 1;
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
auto ps = gpu::Shader::createPixel(std::string(drawOpaqueStencil_frag));
auto program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::makeProgram((*program));
auto state = std::make_shared<gpu::State>();
state->setDepthTest(true, false, gpu::LESS_EQUAL);
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_OPAQUE, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_KEEP));
state->setColorWriteMask(0);
_opaquePipeline = gpu::Pipeline::create(program, state);
}
return _opaquePipeline;
}
void DrawStencilDeferred::run(const RenderContextPointer& renderContext, const DeferredFramebufferPointer& deferredFramebuffer) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
// from the touched pixel generate the stencil buffer
RenderArgs* args = renderContext->args;
doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
auto deferredFboColorDepthStencil = deferredFramebuffer->getDeferredFramebufferDepthColor();
batch.enableStereo(false);
batch.setFramebuffer(deferredFboColorDepthStencil);
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
batch.setPipeline(getOpaquePipeline());
batch.draw(gpu::TRIANGLE_STRIP, 4);
batch.setResourceTexture(0, nullptr);
});
args->_batch = nullptr;
}
void DrawBackgroundDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
const auto& inItems = inputs.get0();
const auto& lightingModel = inputs.get1();
if (!lightingModel->isBackgroundEnabled()) {
return;
}
RenderArgs* args = renderContext->args;
doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
// _gpuTimer.begin(batch);
batch.enableSkybox(true);
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
renderItems(renderContext, inItems);
// _gpuTimer.end(batch);
});
args->_batch = nullptr;
// std::static_pointer_cast<Config>(renderContext->jobConfig)->gpuTime = _gpuTimer.getAverage();
}
void Blit::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer) { void Blit::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer) {
assert(renderContext->args); assert(renderContext->args);
assert(renderContext->args->_context); assert(renderContext->args->_context);
@ -538,3 +454,4 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer
} }
}); });
} }

View file

@ -120,35 +120,6 @@ protected:
bool _stateSort; bool _stateSort;
}; };
class DeferredFramebuffer;
class DrawStencilDeferred {
public:
using JobModel = render::Job::ModelI<DrawStencilDeferred, std::shared_ptr<DeferredFramebuffer>>;
void run(const render::RenderContextPointer& renderContext, const std::shared_ptr<DeferredFramebuffer>& deferredFramebuffer);
protected:
gpu::PipelinePointer _opaquePipeline;
gpu::PipelinePointer getOpaquePipeline();
};
using DrawBackgroundDeferredConfig = render::GPUJobConfig;
class DrawBackgroundDeferred {
public:
using Inputs = render::VaryingSet2 <render::ItemBounds, LightingModelPointer>;
using Config = DrawBackgroundDeferredConfig;
using JobModel = render::Job::ModelI<DrawBackgroundDeferred, Inputs, Config>;
void configure(const Config& config) {}
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
protected:
gpu::RangeTimerPointer _gpuTimer;
};
class DrawOverlay3DConfig : public render::Job::Config { class DrawOverlay3DConfig : public render::Job::Config {
Q_OBJECT Q_OBJECT
Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged) Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged)

View file

@ -15,6 +15,7 @@
#include <gpu/Context.h> #include <gpu/Context.h>
#include <gpu/StandardShaderLib.h> #include <gpu/StandardShaderLib.h>
#include "StencilMaskPass.h"
#include "DeferredLightingEffect.h" #include "DeferredLightingEffect.h"
#include "TextureCache.h" #include "TextureCache.h"
#include "render/DrawTask.h" #include "render/DrawTask.h"
@ -330,6 +331,7 @@ void addPlumberPipeline(ShapePlumber& plumber,
bool isWireframed = (i & 4); bool isWireframed = (i & 4);
auto state = std::make_shared<gpu::State>(); auto state = std::make_shared<gpu::State>();
PrepareStencil::testMaskDrawShape(*state);
// Depth test depends on transparency // Depth test depends on transparency
state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL);

View file

@ -0,0 +1,126 @@
//
// StencilMaskPass.cpp
// render-utils/src/
//
// Created by Sam Gateau on 5/31/17.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "StencilMaskPass.h"
#include <RenderArgs.h>
#include <ViewFrustum.h>
#include <gpu/Context.h>
#include <gpu/StandardShaderLib.h>
#include "stencil_drawMask_frag.h"
using namespace render;
void PrepareStencil::configure(const Config& config) {
_maskMode = config.maskMode;
_forceDraw = config.forceDraw;
}
model::MeshPointer PrepareStencil::getMesh() {
if (!_mesh) {
std::vector<glm::vec3> vertices {
{ -1.0f, -1.0f, 0.0f }, { -1.0f, 0.0f, 0.0f },
{ -1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f },
{ 1.0f, 1.0f, 0.0f }, { 1.0f, 0.0f, 0.0f },
{ 1.0f, -1.0f, 0.0f }, { 0.0f, -1.0f, 0.0f } };
std::vector<uint32_t> indices { 0, 7, 1, 1, 3, 2, 3, 5, 4, 5, 7, 6 };
_mesh = model::Mesh::createIndexedTriangles_P3F((uint32_t) vertices.size(), (uint32_t) indices.size(), vertices.data(), indices.data());
}
return _mesh;
}
gpu::PipelinePointer PrepareStencil::getMeshStencilPipeline() {
if (!_meshStencilPipeline) {
auto vs = gpu::StandardShaderLib::getDrawVertexPositionVS();
auto ps = gpu::StandardShaderLib::getDrawNadaPS();
auto program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::makeProgram((*program));
auto state = std::make_shared<gpu::State>();
drawMask(*state);
state->setColorWriteMask(0);
_meshStencilPipeline = gpu::Pipeline::create(program, state);
}
return _meshStencilPipeline;
}
gpu::PipelinePointer PrepareStencil::getPaintStencilPipeline() {
if (!_paintStencilPipeline) {
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
auto ps = gpu::Shader::createPixel(std::string(stencil_drawMask_frag));
auto program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::makeProgram((*program));
auto state = std::make_shared<gpu::State>();
drawMask(*state);
state->setColorWriteMask(0);
_paintStencilPipeline = gpu::Pipeline::create(program, state);
}
return _paintStencilPipeline;
}
void PrepareStencil::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer) {
RenderArgs* args = renderContext->args;
// Only draw the stencil mask if in HMD mode or not forced.
if (!_forceDraw && (args->_displayMode != RenderArgs::STEREO_HMD)) {
return;
}
doInBatch(args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false);
batch.setViewportTransform(args->_viewport);
if (_maskMode < 0) {
batch.setPipeline(getMeshStencilPipeline());
auto mesh = getMesh();
batch.setIndexBuffer(mesh->getIndexBuffer());
batch.setInputFormat((mesh->getVertexFormat()));
batch.setInputStream(0, mesh->getVertexStream());
// Draw
auto part = mesh->getPartBuffer().get<model::Mesh::Part>(0);
batch.drawIndexed(gpu::TRIANGLES, part._numIndices, part._startIndex);
} else {
batch.setPipeline(getPaintStencilPipeline());
batch.draw(gpu::TRIANGLE_STRIP, 4);
}
});
}
void PrepareStencil::drawMask(gpu::State& state) {
state.setStencilTest(true, 0xFF, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE));
}
void PrepareStencil::testMask(gpu::State& state) {
state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
}
void PrepareStencil::testBackground(gpu::State& state) {
state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_BACKGROUND, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
}
void PrepareStencil::testMaskDrawShape(gpu::State& state) {
state.setStencilTest(true, 0xFF, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_ZERO));
}
void PrepareStencil::testShape(gpu::State& state) {
state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_SHAPE, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
}

View file

@ -0,0 +1,71 @@
//
// StencilMaskPass.h
// render-utils/src/
//
// Created by Sam Gateau on 5/31/17.
// Copyright 20154 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef hifi_StencilMaskPass_h
#define hifi_StencilMaskPass_h
#include <render/Engine.h>
#include <gpu/Pipeline.h>
#include <model/Geometry.h>
class PrepareStencilConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(int maskMode MEMBER maskMode NOTIFY dirty)
Q_PROPERTY(bool forceDraw MEMBER forceDraw NOTIFY dirty)
public:
PrepareStencilConfig(bool enabled = true) : JobConfig(enabled) {}
int maskMode { 0 };
bool forceDraw { false };
signals:
void dirty();
};
class PrepareStencil {
public:
using Config = PrepareStencilConfig;
using JobModel = render::Job::ModelI<PrepareStencil, gpu::FramebufferPointer, Config>;
void configure(const Config& config);
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& dstFramebuffer);
static const gpu::int8 STENCIL_MASK = 2;
static const gpu::int8 STENCIL_BACKGROUND = 1;
static const gpu::int8 STENCIL_SHAPE = 0;
static void drawMask(gpu::State& state);
static void testMask(gpu::State& state);
static void testBackground(gpu::State& state);
static void testMaskDrawShape(gpu::State& state);
static void testShape(gpu::State& state);
private:
gpu::PipelinePointer _meshStencilPipeline;
gpu::PipelinePointer getMeshStencilPipeline();
gpu::PipelinePointer _paintStencilPipeline;
gpu::PipelinePointer getPaintStencilPipeline();
model::MeshPointer _mesh;
model::MeshPointer getMesh();
int _maskMode { 0 };
bool _forceDraw { false };
};
#endif // hifi_StencilMaskPass_h

View file

@ -14,7 +14,7 @@
#include <gpu/Context.h> #include <gpu/Context.h>
#include <gpu/StandardShaderLib.h> #include <gpu/StandardShaderLib.h>
#include "StencilMaskPass.h"
const int DepthLinearPass_FrameTransformSlot = 0; const int DepthLinearPass_FrameTransformSlot = 0;
const int DepthLinearPass_DepthMapSlot = 0; const int DepthLinearPass_DepthMapSlot = 0;
@ -224,7 +224,7 @@ const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); gpu::StatePointer state = gpu::StatePointer(new gpu::State());
// Stencil test the curvature pass for objects pixels only, not the background // Stencil test the curvature pass for objects pixels only, not the background
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); PrepareStencil::testShape(*state);
state->setColorWriteMask(true, false, false, false); state->setColorWriteMask(true, false, false, false);
@ -250,6 +250,7 @@ const gpu::PipelinePointer& LinearDepthPass::getDownsamplePipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); gpu::StatePointer state = gpu::StatePointer(new gpu::State());
PrepareStencil::testShape(*state);
state->setColorWriteMask(true, true, true, false); state->setColorWriteMask(true, true, true, false);
@ -554,7 +555,7 @@ const gpu::PipelinePointer& SurfaceGeometryPass::getCurvaturePipeline() {
#ifdef USE_STENCIL_TEST #ifdef USE_STENCIL_TEST
// Stencil test the curvature pass for objects pixels only, not the background // Stencil test the curvature pass for objects pixels only, not the background
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); PrepareStencil::testShape(*state);
#endif #endif
// Good to go add the brand new pipeline // Good to go add the brand new pipeline
_curvaturePipeline = gpu::Pipeline::create(program, state); _curvaturePipeline = gpu::Pipeline::create(program, state);

View file

@ -15,7 +15,7 @@
#include <gpu/StandardShaderLib.h> #include <gpu/StandardShaderLib.h>
#include <RenderArgs.h> #include <RenderArgs.h>
#include "StencilMaskPass.h"
#include "FramebufferCache.h" #include "FramebufferCache.h"
#include "toneMapping_frag.h" #include "toneMapping_frag.h"

View file

@ -17,6 +17,7 @@
#include <render/FilterTask.h> #include <render/FilterTask.h>
#include <render/DrawTask.h> #include <render/DrawTask.h>
#include "StencilMaskPass.h"
#include "DeferredLightingEffect.h" #include "DeferredLightingEffect.h"
#include "zone_drawKeyLight_frag.h" #include "zone_drawKeyLight_frag.h"
@ -74,6 +75,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); gpu::StatePointer state = gpu::StatePointer(new gpu::State());
PrepareStencil::testMask(*state);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
_keyLightPipeline = gpu::Pipeline::create(program, state); _keyLightPipeline = gpu::Pipeline::create(program, state);
} }
@ -95,6 +97,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getAmbientPipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); gpu::StatePointer state = gpu::StatePointer(new gpu::State());
PrepareStencil::testMask(*state);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
_ambientPipeline = gpu::Pipeline::create(program, state); _ambientPipeline = gpu::Pipeline::create(program, state);
} }
@ -115,6 +118,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getBackgroundPipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); gpu::StatePointer state = gpu::StatePointer(new gpu::State());
PrepareStencil::testMask(*state);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
_backgroundPipeline = gpu::Pipeline::create(program, state); _backgroundPipeline = gpu::Pipeline::create(program, state);
} }

View file

@ -1,47 +0,0 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// directional_light.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/3/14.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferRead.slh@>
<@include DeferredGlobalLight.slh@>
<$declareEvalLightmappedColor()$>
<$declareEvalAmbientGlobalColor()$>
in vec2 _texCoord0;
out vec4 _fragColor;
void main(void) {
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
float shadowAttenuation = 1.0;
if (frag.mode == FRAG_MODE_UNLIT) {
discard;
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
discard;
} else {
vec3 color = evalAmbientGlobalColor(
getViewInverse(),
shadowAttenuation,
frag.obscurance,
frag.position.xyz,
frag.normal,
frag.albedo,
frag.fresnel,
frag.metallic,
frag.roughness);
_fragColor = vec4(color, 1.0);
}
}

View file

@ -1,49 +0,0 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// directional_light_shadow.frag
// fragment shader
//
// Created by Zach Pomerantz on 1/18/2016.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include Shadow.slh@>
<@include DeferredBufferRead.slh@>
<@include DeferredGlobalLight.slh@>
<$declareEvalLightmappedColor()$>
<$declareEvalAmbientGlobalColor()$>
in vec2 _texCoord0;
out vec4 _fragColor;
void main(void) {
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
vec4 worldPos = getViewInverse() * vec4(frag.position.xyz, 1.0);
float shadowAttenuation = evalShadowAttenuation(worldPos);
if (frag.mode == FRAG_MODE_UNLIT) {
discard;
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
discard;
} else {
vec3 color = evalAmbientGlobalColor(
getViewInverse(),
shadowAttenuation,
frag.obscurance,
frag.position.xyz,
frag.normal,
frag.albedo,
frag.fresnel,
frag.metallic,
frag.roughness);
_fragColor = vec4(color, 1.0);
}
}

View file

@ -1,27 +0,0 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// hit_effect.frag
// fragment shader
//
// Created by Eric Levin on 7/20
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
in vec2 varQuadPosition;
out vec4 outFragColor;
void main(void) {
vec2 center = vec2(0.0, 0.0);
float distFromCenter = distance( vec2(0.0, 0.0), varQuadPosition);
float alpha = mix(0.0, 0.5, pow(distFromCenter,5.));
outFragColor = vec4(1.0, 0.0, 0.0, alpha);
}

Some files were not shown because too many files have changed in this diff Show more