Merge branch 'master' of github.com:highfidelity/hifi into head-controller

This commit is contained in:
Seth Alves 2017-06-07 10:09:46 -07:00
commit b1c7c251ac
100 changed files with 1124 additions and 1039 deletions

View file

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

View file

@ -8,8 +8,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
if (WIN32)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://s3.amazonaws.com/hifi-public/dependencies/nvtt-win-2.1.0.zip
URL_MD5 3ea6eeadbcc69071acf9c49ba565760e
URL http://s3.amazonaws.com/hifi-public/dependencies/nvtt-win-2.1.0.hifi.zip
URL_MD5 10da01cf601f88f6dc12a6bc13c89136
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
@ -29,8 +29,8 @@ else ()
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/nvidia-texture-tools-2.1.0.zip
URL_MD5 81b8fa6a9ee3f986088eb6e2215d6a57
URL http://hifi-public.s3.amazonaws.com/dependencies/nvidia-texture-tools-2.1.0.hifi.zip
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>
LOG_DOWNLOAD 1
LOG_CONFIGURE 1

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -13,6 +13,7 @@
#include <DependencyManager.h>
#include <PerfStat.h>
#include <GeometryCache.h>
#include <StencilMaskPass.h>
#include <AbstractViewStateInterface.h>
#include "EntitiesRendererLogging.h"
@ -292,6 +293,7 @@ void RenderableParticleEffectEntityItem::createPipelines() {
state->setDepthTest(true, false, gpu::LESS_EQUAL);
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);
PrepareStencil::testMask(*state);
auto vertShader = gpu::Shader::createVertex(std::string(untextured_particle_vert));
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->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);
PrepareStencil::testMask(*state);
auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert));
auto fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -33,6 +33,9 @@
#include <NetworkAccessManager.h>
#include <GLMHelpers.h>
#include <shared/GlobalAppProperties.h>
#include <FileTypeProfile.h>
#include <HFWebEngineProfile.h>
#include <HFTabletWebEngineProfile.h>
#include "OffscreenGLCanvas.h"
#include "GLHelpers.h"
@ -41,6 +44,7 @@
Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml")
Q_LOGGING_CATEGORY(trace_render_qml_gl, "trace.render.qml.gl")
Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
struct TextureSet {
// The number of surfaces with this size
@ -254,8 +258,72 @@ QNetworkAccessManager* QmlNetworkAccessManagerFactory::create(QObject* parent) {
return new QmlNetworkAccessManager(parent);
}
Q_DECLARE_LOGGING_CATEGORY(offscreenFocus)
Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
static QQmlEngine* globalEngine { nullptr };
static size_t globalEngineRefCount { 0 };
QString getEventBridgeJavascript() {
// FIXME: Refactor with similar code in RenderableWebEntityItem
QString javaScriptToInject;
QFile webChannelFile(":qtwebchannel/qwebchannel.js");
QFile createGlobalEventBridgeFile(PathUtils::resourcesPath() + "/html/createGlobalEventBridge.js");
if (webChannelFile.open(QFile::ReadOnly | QFile::Text) &&
createGlobalEventBridgeFile.open(QFile::ReadOnly | QFile::Text)) {
QString webChannelStr = QTextStream(&webChannelFile).readAll();
QString createGlobalEventBridgeStr = QTextStream(&createGlobalEventBridgeFile).readAll();
javaScriptToInject = webChannelStr + createGlobalEventBridgeStr;
} else {
qCWarning(glLogging) << "Unable to find qwebchannel.js or createGlobalEventBridge.js";
}
return javaScriptToInject;
}
QQmlEngine* acquireEngine(QQuickWindow* window) {
Q_ASSERT(QThread::currentThread() == qApp->thread());
if (!globalEngine) {
Q_ASSERT(0 == globalEngineRefCount);
globalEngine = new QQmlEngine();
globalEngine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory);
auto importList = globalEngine->importPathList();
importList.insert(importList.begin(), PathUtils::resourcesPath());
globalEngine->setImportPathList(importList);
for (const auto& path : importList) {
qDebug() << path;
}
if (!globalEngine->incubationController()) {
globalEngine->setIncubationController(window->incubationController());
}
auto rootContext = globalEngine->rootContext();
rootContext->setContextProperty("GL", ::getGLContextData());
rootContext->setContextProperty("urlHandler", new UrlHandler());
rootContext->setContextProperty("resourceDirectoryUrl", QUrl::fromLocalFile(PathUtils::resourcesPath()));
rootContext->setContextProperty("pathToFonts", "../../");
rootContext->setContextProperty("ApplicationInterface", qApp);
auto javaScriptToInject = getEventBridgeJavascript();
if (!javaScriptToInject.isEmpty()) {
rootContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject));
}
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
rootContext->setContextProperty("HFTabletWebEngineProfile", new HFTabletWebEngineProfile(rootContext));
}
++globalEngineRefCount;
return globalEngine;
}
void releaseEngine() {
Q_ASSERT(QThread::currentThread() == qApp->thread());
Q_ASSERT(0 != globalEngineRefCount);
if (0 == --globalEngineRefCount) {
globalEngine->deleteLater();
globalEngine = nullptr;
}
}
void OffscreenQmlSurface::cleanup() {
_canvas->makeCurrent();
@ -294,6 +362,7 @@ void OffscreenQmlSurface::render() {
GLuint texture = offscreenTextures.getNextTexture(_size);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_renderControl->render();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, texture);
@ -362,8 +431,8 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
_canvas->deleteLater();
_rootItem->deleteLater();
_qmlComponent->deleteLater();
_qmlEngine->deleteLater();
_quickWindow->deleteLater();
releaseEngine();
}
void OffscreenQmlSurface::onAboutToQuit() {
@ -375,6 +444,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
qCDebug(glLogging) << "Building QML surface";
_renderControl = new QMyQuickRenderControl();
connect(_renderControl, &QQuickRenderControl::renderRequested, this, [this] { _render = true; });
connect(_renderControl, &QQuickRenderControl::sceneChanged, this, [this] { _render = _polish = true; });
QQuickWindow::setDefaultAlphaBuffer(true);
@ -385,7 +456,7 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
// so we wait until after its ctor to move object/context to this thread.
_quickWindow = new QQuickWindow(_renderControl);
_quickWindow->setColor(QColor(255, 255, 255, 0));
_quickWindow->setFlags(_quickWindow->flags() | static_cast<Qt::WindowFlags>(Qt::WA_TranslucentBackground));
_quickWindow->setClearBeforeRendering(false);
_renderControl->_renderWindow = _proxyWindow;
@ -398,32 +469,20 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
connect(_quickWindow, &QQuickWindow::focusObjectChanged, this, &OffscreenQmlSurface::onFocusObjectChanged);
// Create a QML engine.
_qmlEngine = new QQmlEngine;
auto qmlEngine = acquireEngine(_quickWindow);
_qmlContext = new QQmlContext(qmlEngine->rootContext());
_qmlEngine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory);
_qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
_qmlContext->setContextProperty("globalEventBridge", this);
_qmlContext->setContextProperty("webEntity", this);
auto importList = _qmlEngine->importPathList();
importList.insert(importList.begin(), PathUtils::resourcesPath());
_qmlEngine->setImportPathList(importList);
if (!_qmlEngine->incubationController()) {
_qmlEngine->setIncubationController(_quickWindow->incubationController());
}
_qmlComponent = new QQmlComponent(qmlEngine);
// FIXME
_glData = ::getGLContextData(); // Initialize JSON structure so that it can be filled in later and then used in QML.
_qmlEngine->rootContext()->setContextProperty("GL", _glData);
_qmlEngine->rootContext()->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
_qmlComponent = new QQmlComponent(_qmlEngine);
connect(_renderControl, &QQuickRenderControl::renderRequested, this, [this] { _render = true; });
connect(_renderControl, &QQuickRenderControl::sceneChanged, this, [this] { _render = _polish = true; });
if (!_canvas->makeCurrent()) {
qWarning("Failed to make context current for QML Renderer");
return;
}
_glData = ::getGLContextData();
_renderControl->initialize(_canvas->getContext());
// When Quick says there is a need to render, we will not render immediately. Instead,
@ -433,11 +492,6 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
_updateTimer.setTimerType(Qt::PreciseTimer);
_updateTimer.setInterval(MIN_TIMER_MS); // 5ms, Qt::PreciseTimer required
_updateTimer.start();
auto rootContext = getRootContext();
rootContext->setContextProperty("urlHandler", new UrlHandler());
rootContext->setContextProperty("resourceDirectoryUrl", QUrl::fromLocalFile(PathUtils::resourcesPath()));
rootContext->setContextProperty("pathToFonts", "../../");
}
static uvec2 clampSize(const uvec2& size, uint32_t maxDimension) {
@ -460,7 +514,7 @@ void OffscreenQmlSurface::resize(const QSize& newSize_, bool forceResize) {
return;
}
_qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize);
_qmlContext->setContextProperty("surfaceSize", newSize);
if (_rootItem) {
_rootItem->setSize(newSize);
@ -520,14 +574,19 @@ QQuickItem* OffscreenQmlSurface::getRootItem() {
}
void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
_qmlEngine->setBaseUrl(baseUrl);
_qmlContext->setBaseUrl(baseUrl);
}
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
// Synchronous loading may take a while; restart the deadlock timer
QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection);
_qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous);
if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) {
_qmlComponent->loadUrl(_qmlContext->resolvedUrl(qmlSource), QQmlComponent::PreferSynchronous);
} else {
_qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous);
}
if (_qmlComponent->isLoading()) {
connect(_qmlComponent, &QQmlComponent::statusChanged, this,
@ -541,10 +600,22 @@ QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQm
}
void OffscreenQmlSurface::clearCache() {
getRootContext()->engine()->clearComponentCache();
_qmlContext->engine()->clearComponentCache();
}
QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f) {
#if 0
if (!_rootItem) {
QQmlComponent component(_qmlContext->engine());
component.setData(R"QML(
import QtQuick 2.0
import QtWebChannel 1.0
Item { Component.onCompleted: globalEventBridge.WebChannel.id = "globalEventBridge"; }
)QML", QUrl());
QObject *helper = component.create(_qmlContext);
qDebug() << "Created helper";
}
#endif
disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, 0);
if (_qmlComponent->isError()) {
QList<QQmlError> errorList = _qmlComponent->errors();
@ -554,21 +625,8 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb
return nullptr;
}
// FIXME: Refactor with similar code in RenderableWebEntityItem
QString javaScriptToInject;
QFile webChannelFile(":qtwebchannel/qwebchannel.js");
QFile createGlobalEventBridgeFile(PathUtils::resourcesPath() + "/html/createGlobalEventBridge.js");
if (webChannelFile.open(QFile::ReadOnly | QFile::Text) &&
createGlobalEventBridgeFile.open(QFile::ReadOnly | QFile::Text)) {
QString webChannelStr = QTextStream(&webChannelFile).readAll();
QString createGlobalEventBridgeStr = QTextStream(&createGlobalEventBridgeFile).readAll();
javaScriptToInject = webChannelStr + createGlobalEventBridgeStr;
} else {
qCWarning(glLogging) << "Unable to find qwebchannel.js or createGlobalEventBridge.js";
}
QQmlContext* newContext = new QQmlContext(_qmlEngine, qApp);
QObject* newObject = _qmlComponent->beginCreate(newContext);
QObject* newObject = _qmlComponent->beginCreate(_qmlContext);
if (_qmlComponent->isError()) {
QList<QQmlError> errorList = _qmlComponent->errors();
foreach(const QQmlError& error, errorList)
@ -579,12 +637,10 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb
return nullptr;
}
_qmlEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
_qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
newObject->setProperty("eventBridge", QVariant::fromValue(this));
newContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject));
f(newContext, newObject);
f(_qmlContext, newObject);
_qmlComponent->completeCreate();
@ -735,7 +791,7 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
mouseEvent->screenPos(), mouseEvent->button(),
mouseEvent->buttons(), mouseEvent->modifiers());
if (event->type() == QEvent::MouseMove) {
_qmlEngine->rootContext()->setContextProperty("lastMousePosition", transformedPos);
_qmlContext->setContextProperty("lastMousePosition", transformedPos);
}
mappedEvent.ignore();
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
@ -762,9 +818,6 @@ void OffscreenQmlSurface::resume() {
if (getRootItem()) {
getRootItem()->setProperty("eventBridge", QVariant::fromValue(this));
}
if (getRootContext()) {
getRootContext()->setContextProperty("webEntity", this);
}
}
bool OffscreenQmlSurface::isPaused() const {
@ -790,8 +843,8 @@ QSize OffscreenQmlSurface::size() const {
return _quickWindow->geometry().size();
}
QQmlContext* OffscreenQmlSurface::getRootContext() {
return _qmlEngine->rootContext();
QQmlContext* OffscreenQmlSurface::getSurfaceContext() {
return _qmlContext;
}
Q_DECLARE_METATYPE(std::function<void()>);

View file

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

View file

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

View file

@ -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$>
// Generated on <$_SCRIBE_DATE$>
//
// hit_effect.vert
// vertex shader
// Draw the fed vertex position, pass straight as clip pos
// Output the clip position
//
// Created by Eric Levin on 7/20/15.
// Copyright 2015 High Fidelity, Inc.
// 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/Inputs.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
out vec2 varQuadPosition;
layout(location = 0) in vec4 inPosition;
void main(void) {
varQuadPosition = inPosition.xy;
gl_Position = inPosition;
}
}

View file

@ -2,15 +2,17 @@
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// drawOpaqueStencil.frag
// fragment shader
// Draw white
//
// Created by Sam Gateau on 9/29/15.
// Copyright 2015 High Fidelity, Inc.
// 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
//
out vec4 outFragColor;
void main(void) {
outFragColor = vec4(1.0);
}

View file

@ -16,6 +16,12 @@
#include "DrawTransformUnitQuad_vert.h"
#include "DrawTexcoordRectTransformUnitQuad_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 "DrawTextureOpaque_frag.h"
#include "DrawColoredTexture_frag.h"
@ -26,6 +32,10 @@ ShaderPointer StandardShaderLib::_drawUnitQuadTexcoordVS;
ShaderPointer StandardShaderLib::_drawTransformUnitQuadVS;
ShaderPointer StandardShaderLib::_drawTexcoordRectTransformUnitQuadVS;
ShaderPointer StandardShaderLib::_drawViewportQuadTransformTexcoordVS;
ShaderPointer StandardShaderLib::_drawVertexPositionVS;
ShaderPointer StandardShaderLib::_drawTransformVertexPositionVS;
ShaderPointer StandardShaderLib::_drawNadaPS;
ShaderPointer StandardShaderLib::_drawWhitePS;
ShaderPointer StandardShaderLib::_drawTexturePS;
ShaderPointer StandardShaderLib::_drawTextureOpaquePS;
ShaderPointer StandardShaderLib::_drawColoredTexturePS;
@ -85,6 +95,34 @@ ShaderPointer StandardShaderLib::getDrawViewportQuadTransformTexcoordVS() {
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() {
if (!_drawTexturePS) {
_drawTexturePS = gpu::Shader::createPixel(std::string(DrawTexture_frag));
@ -99,8 +137,6 @@ ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() {
return _drawTextureOpaquePS;
}
ShaderPointer StandardShaderLib::getDrawColoredTexturePS() {
if (!_drawColoredTexturePS) {
_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.
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 getDrawTextureOpaquePS();
static ShaderPointer getDrawColoredTexturePS();
@ -51,6 +60,12 @@ protected:
static ShaderPointer _drawTransformUnitQuadVS;
static ShaderPointer _drawTexcoordRectTransformUnitQuadVS;
static ShaderPointer _drawViewportQuadTransformTexcoordVS;
static ShaderPointer _drawVertexPositionVS;
static ShaderPointer _drawTransformVertexPositionVS;
static ShaderPointer _drawNadaPS;
static ShaderPointer _drawWhitePS;
static ShaderPointer _drawTexturePS;
static ShaderPointer _drawTextureOpaquePS;
static ShaderPointer _drawColoredTexturePS;

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() {
}
@ -256,3 +292,5 @@ Geometry::~Geometry() {
void Geometry::setMesh(const MeshPointer& mesh) {
_mesh = mesh;
}

View file

@ -65,6 +65,9 @@ public:
const gpu::BufferStream& getVertexStream() const { return _vertexStream; }
// Index Buffer
using Indices16 = std::vector<int16_t>;
using Indices32 = std::vector<int32_t>;
void setIndexBuffer(const BufferView& buffer);
const BufferView& getIndexBuffer() const { return _indexBuffer; }
size_t getNumIndices() const { return _indexBuffer.getNumElements(); }
@ -127,6 +130,9 @@ public:
std::function<void(glm::vec3)> normalFunc,
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:
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>();
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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -23,7 +23,7 @@ ProceduralSkybox::ProceduralSkybox() : model::Skybox() {
_procedural._fragmentSource = skybox_frag;
// Adjust the pipeline state for background using the stencil test
_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() {

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
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];
boneBaseCorners[0] = pose0 * ((uAxis * radius) + (vAxis * radius) + (wAxis * radius));

View file

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

View file

@ -18,6 +18,7 @@
#include <gpu/Batch.h>
#include <gpu/Context.h>
#include "StencilMaskPass.h"
#include "AbstractViewStateInterface.h"
#include "GeometryCache.h"
#include "TextureCache.h"
@ -27,18 +28,15 @@
#include "deferred_light_point_vert.h"
#include "deferred_light_spot_vert.h"
#include "directional_light_frag.h"
#include "directional_ambient_light_frag.h"
#include "directional_skybox_light_frag.h"
#include "directional_light_shadow_frag.h"
#include "directional_ambient_light_shadow_frag.h"
#include "directional_skybox_light_shadow_frag.h"
#include "local_lights_shading_frag.h"
#include "local_lights_drawOutline_frag.h"
#include "point_light_frag.h"
#include "spot_light_frag.h"
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 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() {
_directionalLightLocations = std::make_shared<LightLocations>();
_directionalAmbientSphereLightLocations = std::make_shared<LightLocations>();
_directionalSkyboxLightLocations = std::make_shared<LightLocations>();
_directionalLightShadowLocations = std::make_shared<LightLocations>();
_directionalAmbientSphereLightShadowLocations = std::make_shared<LightLocations>();
_directionalSkyboxLightShadowLocations = std::make_shared<LightLocations>();
_localLightLocations = 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_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_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations);
loadLightProgram(deferred_light_vert, local_lights_shading_frag, true, _localLight, _localLightLocations);
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
_lightStage = std::make_shared<LightStage>();
@ -160,11 +136,11 @@ void DeferredLightingEffect::init() {
lp->setAmbientIntensity(0.5f);
lp->setAmbientMap(_defaultSkyboxAmbientTexture);
auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance();
if (irradianceSH) {
lp->setAmbientSphere((*irradianceSH));
}
lp->setAmbientMap(_defaultSkyboxAmbientTexture);
auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance();
if (irradianceSH) {
lp->setAmbientSphere((*irradianceSH));
}
}
void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {
@ -267,7 +243,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
state->setColorWriteMask(true, true, true, false);
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_FRONT);
@ -280,7 +256,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
} else {
// 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);
// 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) {
/* auto globalLight = _allocatedLights.front();
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_DEPTH |
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
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);
}
auto& program = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadow : deferredLightingEffect->_directionalLight;
LightLocationsPtr locations = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadowLocations : deferredLightingEffect->_directionalLightLocations;
auto& program = deferredLightingEffect->_directionalSkyboxLight;
LightLocationsPtr locations = deferredLightingEffect->_directionalSkyboxLightLocations;
const auto& keyLight = deferredLightingEffect->_allocatedLights[deferredLightingEffect->_globalLights.front()];
// Setup the global directional pass pipeline

View file

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

View file

@ -24,6 +24,7 @@
#include "TextureCache.h"
#include "RenderUtilsLogging.h"
#include "StencilMaskPass.h"
#include "gpu/StandardShaderLib.h"
@ -1610,6 +1611,9 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const
state->setBlendFunction(true,
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);
PrepareStencil::testMask(*state);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("lineData"), LINE_DATA_SLOT));
gpu::Shader::makeProgram(*program, slotBindings);
@ -1663,11 +1667,14 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
// enable decal blend
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);
auto stateNoBlend = std::make_shared<gpu::State>();
PrepareStencil::testMaskDrawShape(*state);
auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS();
auto programNoBlend = gpu::Shader::createProgram(vs, noBlendPS);
gpu::Shader::makeProgram((*programNoBlend));
@ -1690,12 +1697,14 @@ void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bo
auto stateLayered = std::make_shared<gpu::State>();
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);
auto state = std::make_shared<gpu::State>(stateLayered->getValues());
const float DEPTH_BIAS = 0.001f;
state->setDepthBias(DEPTH_BIAS);
state->setDepthTest(true, false, gpu::LESS_EQUAL);
PrepareStencil::testMaskDrawShape(*state);
_gridPipeline = gpu::Pipeline::create(program, state);
}
@ -1773,6 +1782,11 @@ static void buildWebShader(const std::string& vertShaderText, const std::string&
state->setBlendFunction(blendEnable,
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);
if (blendEnable) {
PrepareStencil::testMask(*state);
} else {
PrepareStencil::testMaskDrawShape(*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::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::PipelinePointer pipeline = gpu::Pipeline::create(program, state);
_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 "StencilMaskPass.h"
#include "lightClusters_drawGrid_vert.h"
#include "lightClusters_drawGrid_frag.h"

View file

@ -27,12 +27,12 @@
#include <render/BlurTask.h>
#include "LightingModel.h"
#include "StencilMaskPass.h"
#include "DebugDeferredBuffer.h"
#include "DeferredFramebuffer.h"
#include "DeferredLightingEffect.h"
#include "SurfaceGeometryPass.h"
#include "FramebufferCache.h"
#include "HitEffect.h"
#include "TextureCache.h"
#include "ZoneRenderer.h"
@ -43,8 +43,6 @@
#include <gpu/StandardShaderLib.h>
#include "drawOpaqueStencil_frag.h"
using namespace render;
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 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
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying();
task.addJob<DrawStateSortDeferred>("DrawOpaqueDeferred", opaqueInputs, shapePlumber);
// Once opaque is all rendered create stencil background
task.addJob<DrawStencilDeferred>("DrawOpaqueStencil", deferredFramebuffer);
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) {
assert(renderContext->args);
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;
};
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 {
Q_OBJECT
Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged)

View file

@ -15,6 +15,7 @@
#include <gpu/Context.h>
#include <gpu/StandardShaderLib.h>
#include "StencilMaskPass.h"
#include "DeferredLightingEffect.h"
#include "TextureCache.h"
#include "render/DrawTask.h"
@ -330,6 +331,7 @@ void addPlumberPipeline(ShapePlumber& plumber,
bool isWireframed = (i & 4);
auto state = std::make_shared<gpu::State>();
PrepareStencil::testMaskDrawShape(*state);
// Depth test depends on transparency
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/StandardShaderLib.h>
#include "StencilMaskPass.h"
const int DepthLinearPass_FrameTransformSlot = 0;
const int DepthLinearPass_DepthMapSlot = 0;
@ -224,7 +224,7 @@ const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
// 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);
@ -250,6 +250,7 @@ const gpu::PipelinePointer& LinearDepthPass::getDownsamplePipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
PrepareStencil::testShape(*state);
state->setColorWriteMask(true, true, true, false);
@ -554,7 +555,7 @@ const gpu::PipelinePointer& SurfaceGeometryPass::getCurvaturePipeline() {
#ifdef USE_STENCIL_TEST
// 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
// Good to go add the brand new pipeline
_curvaturePipeline = gpu::Pipeline::create(program, state);

View file

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

View file

@ -17,6 +17,7 @@
#include <render/FilterTask.h>
#include <render/DrawTask.h>
#include "StencilMaskPass.h"
#include "DeferredLightingEffect.h"
#include "zone_drawKeyLight_frag.h"
@ -74,6 +75,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() {
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);
_keyLightPipeline = gpu::Pipeline::create(program, state);
}
@ -95,6 +97,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getAmbientPipeline() {
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);
_ambientPipeline = gpu::Pipeline::create(program, state);
}
@ -115,6 +118,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getBackgroundPipeline() {
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);
_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);
}

View file

@ -1,85 +0,0 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// point_light.frag
// fragment shader
//
// Created by Sam Gateau on 9/18/15.
// Copyright 2014 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
//
<!
// Everything about deferred buffer
<@include DeferredBufferRead.slh@>
<$declareDeferredCurvature()$>
// Everything about light
<@include model/Light.slh@>
<$declareLightBuffer()$>
<@include LightingModel.slh@>
<@include LightPoint.slh@>
<$declareLightingPoint(supportScattering)$>
uniform vec4 texcoordFrameTransform;
in vec4 _texCoord0;!>
out vec4 _fragColor;
void main(void) {
_fragColor = vec4(1.0, 1.0, 1.0, 1.0);
<!
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
// Grab the fragment data from the uv
vec2 texCoord = _texCoord0.st / _texCoord0.q;
texCoord *= texcoordFrameTransform.zw;
texCoord += texcoordFrameTransform.xy;
DeferredFragment frag = unpackDeferredFragment(deferredTransform, texCoord);
if (frag.mode == FRAG_MODE_UNLIT) {
discard;
}
// Need the light now
Light light = getLight();
// Frag pos in world
mat4 invViewMat = getViewInverse();
vec4 fragPos = invViewMat * frag.position;
// Clip againgst the light volume and Make the Light vector going from fragment to light center in world space
vec4 fragLightVecLen2;
if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) {
discard;
}
// Frag to eye vec
vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0);
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
vec3 diffuse;
vec3 specular;
vec4 midNormalCurvature;
vec4 lowNormalCurvature;
if (frag.mode == FRAG_MODE_SCATTERING) {
unpackMidLowNormalCurvature(texCoord, midNormalCurvature, lowNormalCurvature);
}
evalLightingPoint(diffuse, specular, light,
fragLightVecLen2.xyz, fragEyeDir, frag.normal, frag.roughness,
frag.metallic, frag.fresnel, frag.albedo, 1.0,
frag.scattering, midNormalCurvature, lowNormalCurvature);
_fragColor.rgb += diffuse;
_fragColor.rgb += specular;
!>
}

View file

@ -1,115 +0,0 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// spot_light.frag
// fragment shader
//
// Created by Sam Gateau on 9/18/15.
// Copyright 2014 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
//
// Everything about deferred buffer
<!<@include DeferredBufferRead.slh@>
<$declareDeferredCurvature()$>
// Everything about light
<@include model/Light.slh@>
<$declareLightBuffer(256)$>
uniform lightIndexBuffer {
int lightIndex[256];
};
<@include LightingModel.slh@>
<@include LightPoint.slh@>
<$declareLightingPoint(supportScattering)$>
<@include LightSpot.slh@>
<$declareLightingSpot(supportScattering)$>
//uniform vec4 texcoordFrameTransform;
!>
//in vec4 _texCoord0;
//flat in int instanceID;
out vec4 _fragColor;
void main(void) {
_fragColor = vec4(1.0, 1.0, 1.0, 1.0);
// DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
// Grab the fragment data from the uv
//vec2 texCoord = _texCoord0.st;/* / _texCoord0.q;
/*texCoord *= texcoordFrameTransform.zw;
texCoord += texcoordFrameTransform.xy;*/
/*
vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord);
DeferredFragment frag = unpackDeferredFragmentNoPosition(texCoord);
if (frag.mode == FRAG_MODE_UNLIT) {
discard;
}
// frag.depthVal = depthValue;
frag.position = fragPosition;
vec4 midNormalCurvature;
vec4 lowNormalCurvature;
if (frag.mode == FRAG_MODE_SCATTERING) {
unpackMidLowNormalCurvature(texCoord, midNormalCurvature, lowNormalCurvature);
}
// Frag pos in world
mat4 invViewMat = getViewInverse();
vec4 fragPos = invViewMat * fragPosition;
// Frag to eye vec
vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0);
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
int numLights = lightIndex[0];
for (int i = 0; i < numLights; i++) {
// Need the light now
Light light = getLight(lightIndex[i + 1]);
bool isSpot = light_isSpot(light);
// Clip againgst the light volume and Make the Light vector going from fragment to light center in world space
vec4 fragLightVecLen2;
vec4 fragLightDirLen;
float cosSpotAngle;
if (isSpot) {
if (!clipFragToLightVolumeSpot(light, fragPos.xyz, fragLightVecLen2, fragLightDirLen, cosSpotAngle)) {
continue;
}
} else {
if (!clipFragToLightVolumePoint(light, fragPos.xyz, fragLightVecLen2)) {
continue;
}
}
vec3 diffuse;
vec3 specular;
if (isSpot) {
evalLightingSpot(diffuse, specular, light,
fragLightDirLen.xyzw, cosSpotAngle, fragEyeDir, frag.normal, frag.roughness,
frag.metallic, frag.fresnel, frag.albedo, 1.0,
frag.scattering, midNormalCurvature, lowNormalCurvature);
} else {
evalLightingPoint(diffuse, specular, light,
fragLightVecLen2.xyz, fragEyeDir, frag.normal, frag.roughness,
frag.metallic, frag.fresnel, frag.albedo, 1.0,
frag.scattering, midNormalCurvature, lowNormalCurvature);
}
_fragColor.rgb += diffuse;
_fragColor.rgb += specular;
}
*/
}

View file

@ -0,0 +1,23 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// stencil_drawMask.slf
// fragment shader
//
// Created by Sam Gateau on 5/31/17.
// 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
//
in vec2 varTexCoord0;
float aspectRatio = 0.95;
void main(void) {
vec2 pos = varTexCoord0 * 2.0 - vec2(1.0);
pos.x = aspectRatio * (pos.x * (pos.x > 0.0 ? 2.0 : -2.0) - 1.0);
if (1.0 - dot(pos.xy, pos.xy) > 0.0 ) discard;
}

View file

@ -49,7 +49,7 @@ const mat4 Matrices::Z_180 { createMatFromQuatAndPos(Quaternions::Z_180, Vectors
glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) {
float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1;
// adjust signs if necessary
if (cosa < 0.0f) {
cosa = -cosa;
@ -58,19 +58,19 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) {
oz = -oz;
ow = -ow;
}
// calculate coefficients; if the angle is too close to zero, we must fall back
// to linear interpolation
if ((1.0f - cosa) > EPSILON) {
float angle = acosf(cosa), sina = sinf(angle);
s0 = sinf((1.0f - proportion) * angle) / sina;
s1 = sinf(proportion * angle) / sina;
} else {
s0 = 1.0f - proportion;
s1 = proportion;
}
return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz));
}
@ -105,10 +105,10 @@ int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm
int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) {
const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.0f);
uint16_t angleHolder = floorf((degrees + 180.0f) * ANGLE_CONVERSION_RATIO);
memcpy(buffer, &angleHolder, sizeof(uint16_t));
return sizeof(uint16_t);
}
@ -125,7 +125,7 @@ int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput
quatParts[1] = floorf((quatNormalized.y + 1.0f) * QUAT_PART_CONVERSION_RATIO);
quatParts[2] = floorf((quatNormalized.z + 1.0f) * QUAT_PART_CONVERSION_RATIO);
quatParts[3] = floorf((quatNormalized.w + 1.0f) * QUAT_PART_CONVERSION_RATIO);
memcpy(buffer, &quatParts, sizeof(quatParts));
return sizeof(quatParts);
}
@ -133,12 +133,12 @@ int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput
int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput) {
uint16_t quatParts[4];
memcpy(&quatParts, buffer, sizeof(quatParts));
quatOutput.x = ((quatParts[0] / (float) std::numeric_limits<uint16_t>::max()) * 2.0f) - 1.0f;
quatOutput.y = ((quatParts[1] / (float) std::numeric_limits<uint16_t>::max()) * 2.0f) - 1.0f;
quatOutput.z = ((quatParts[2] / (float) std::numeric_limits<uint16_t>::max()) * 2.0f) - 1.0f;
quatOutput.w = ((quatParts[3] / (float) std::numeric_limits<uint16_t>::max()) * 2.0f) - 1.0f;
return sizeof(quatParts);
}
@ -235,7 +235,7 @@ glm::vec3 safeEulerAngles(const glm::quat& q) {
atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)),
asinf(sy),
atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z)));
} else {
// not a unique solution; x + z = atan2(-m21, m11)
eulers = glm::vec3(
@ -250,7 +250,7 @@ glm::vec3 safeEulerAngles(const glm::quat& q) {
PI_OVER_TWO,
-atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)));
}
// adjust so that z, rather than y, is in [-pi/2, pi/2]
if (eulers.z < -PI_OVER_TWO) {
if (eulers.x < 0.0f) {
@ -265,7 +265,7 @@ glm::vec3 safeEulerAngles(const glm::quat& q) {
eulers.y -= PI;
}
eulers.z += PI;
} else if (eulers.z > PI_OVER_TWO) {
if (eulers.x < 0.0f) {
eulers.x += PI;
@ -320,7 +320,7 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) {
for (int i = 0; i < 10; i++) {
// store the results of the previous iteration
glm::mat3 previous = upper;
// compute average of the matrix with its inverse transpose
float sd00 = previous[1][1] * previous[2][2] - previous[2][1] * previous[1][2];
float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2];
@ -334,15 +334,15 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) {
upper[0][0] = +sd00 * hrdet + previous[0][0] * 0.5f;
upper[1][0] = -sd10 * hrdet + previous[1][0] * 0.5f;
upper[2][0] = +sd20 * hrdet + previous[2][0] * 0.5f;
upper[0][1] = -(previous[1][0] * previous[2][2] - previous[2][0] * previous[1][2]) * hrdet + previous[0][1] * 0.5f;
upper[1][1] = +(previous[0][0] * previous[2][2] - previous[2][0] * previous[0][2]) * hrdet + previous[1][1] * 0.5f;
upper[2][1] = -(previous[0][0] * previous[1][2] - previous[1][0] * previous[0][2]) * hrdet + previous[2][1] * 0.5f;
upper[0][2] = +(previous[1][0] * previous[2][1] - previous[2][0] * previous[1][1]) * hrdet + previous[0][2] * 0.5f;
upper[1][2] = -(previous[0][0] * previous[2][1] - previous[2][0] * previous[0][1]) * hrdet + previous[1][2] * 0.5f;
upper[2][2] = +(previous[0][0] * previous[1][1] - previous[1][0] * previous[0][1]) * hrdet + previous[2][2] * 0.5f;
// compute the difference; if it's small enough, we're done
glm::mat3 diff = upper - previous;
if (diff[0][0] * diff[0][0] + diff[1][0] * diff[1][0] + diff[2][0] * diff[2][0] + diff[0][1] * diff[0][1] +
@ -352,7 +352,7 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) {
}
}
}
// now that we have a nice orthogonal matrix, we can extract the rotation quaternion
// using the method described in http://en.wikipedia.org/wiki/Rotation_matrix#Conversions
float x2 = fabs(1.0f + upper[0][0] - upper[1][1] - upper[2][2]);
@ -473,7 +473,7 @@ glm::mat4 createMatFromScaleQuatAndPos(const glm::vec3& scale, const glm::quat&
glm::vec4(zAxis, 0.0f), glm::vec4(trans, 1.0f));
}
// cancel out roll
// cancel out roll
glm::quat cancelOutRoll(const glm::quat& q) {
glm::vec3 forward = q * Vectors::FRONT;
return glm::quat_cast(glm::inverse(glm::lookAt(Vectors::ZERO, forward, Vectors::UP)));
@ -538,17 +538,16 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda
uAxisOut = glm::normalize(primaryAxis);
glm::vec3 normSecondary = glm::normalize(secondaryAxis);
// if secondaryAxis is parallel with the primaryAxis, pick another axis.
// if normSecondary is parallel with the primaryAxis, pick another secondary.
const float EPSILON = 1.0e-4f;
if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > EPSILON) {
// pick a better secondaryAxis.
normSecondary = glm::vec3(1.0f, 0.0f, 0.0f);
if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > EPSILON) {
normSecondary = glm::vec3(0.0f, 1.0f, 0.0f);
if (fabsf(fabsf(glm::dot(uAxisOut, normSecondary)) - 1.0f) < EPSILON) {
normSecondary = Vectors::UNIT_X;
if (fabsf(fabsf(glm::dot(uAxisOut, normSecondary)) - 1.0f) < EPSILON) {
normSecondary = Vectors::UNIT_Y;
}
}
wAxisOut = glm::normalize(glm::cross(uAxisOut, secondaryAxis));
wAxisOut = glm::normalize(glm::cross(uAxisOut, normSecondary));
vAxisOut = glm::cross(wAxisOut, uAxisOut);
}

View file

@ -76,7 +76,7 @@ public:
class RenderArgs {
public:
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE };
enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT };
enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD };
enum DebugFlags {
RENDER_DEBUG_NONE = 0,
RENDER_DEBUG_HULLS = 1
@ -87,7 +87,7 @@ public:
float sizeScale = 1.0f,
int boundaryLevelAdjust = 0,
RenderMode renderMode = DEFAULT_RENDER_MODE,
RenderSide renderSide = MONO,
DisplayMode displayMode = MONO,
DebugFlags debugFlags = RENDER_DEBUG_NONE,
gpu::Batch* batch = nullptr) :
_context(context),
@ -95,7 +95,7 @@ public:
_sizeScale(sizeScale),
_boundaryLevelAdjust(boundaryLevelAdjust),
_renderMode(renderMode),
_renderSide(renderSide),
_displayMode(displayMode),
_debugFlags(debugFlags),
_batch(batch) {
}
@ -121,7 +121,7 @@ public:
float _sizeScale = 1.0f;
int _boundaryLevelAdjust = 0;
RenderMode _renderMode = DEFAULT_RENDER_MODE;
RenderSide _renderSide = MONO;
DisplayMode _displayMode = MONO;
DebugFlags _debugFlags = RENDER_DEBUG_NONE;
gpu::Batch* _batch = nullptr;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -642,6 +642,8 @@ var toolBar = (function () {
enabled: active
}));
isActive = active;
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
if (!isActive) {
entityListTool.setVisible(false);
gridTool.setVisible(false);
@ -650,8 +652,8 @@ var toolBar = (function () {
selectionManager.clearSelections();
cameraManager.disable();
selectionDisplay.triggerMapping.disable();
tablet.landscape = false;
} else {
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.loadQMLSource("Edit.qml");
UserActivityLogger.enabledEdit();
entityListTool.setVisible(true);
@ -659,6 +661,8 @@ var toolBar = (function () {
grid.setEnabled(true);
propertiesTool.setVisible(true);
selectionDisplay.triggerMapping.enable();
print("starting tablet in landscape mode")
tablet.landscape = true;
// Not sure what the following was meant to accomplish, but it currently causes
// everybody else to think that Interface has lost focus overall. fogbugzid:558
// Window.setFocus();

View file

@ -22,7 +22,9 @@ var DEFAULT_WIDTH = 0.4375;
var DEFAULT_VERTICAL_FIELD_OF_VIEW = 45; // degrees
var SENSOR_TO_ROOM_MATRIX = -2;
var CAMERA_MATRIX = -7;
var ROT_Y_180 = {x: 0, y: 1, z: 0, w: 0};
var ROT_Y_180 = {x: 0.0, y: 1.0, z: 0, w: 0};
var ROT_LANDSCAPE = {x: 1.0, y: 1.0, z: 0, w: 0};
var ROT_LANDSCAPE_WINDOW = {x: 0.0, y: 0.0, z: 0.0, w: 0};
var ROT_IDENT = {x: 0, y: 0, z: 0, w: 1};
var TABLET_TEXTURE_RESOLUTION = { x: 480, y: 706 };
var INCHES_TO_METERS = 1 / 39.3701;
@ -243,29 +245,29 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
};
WebTablet.prototype.getDimensions = function() {
if (this.landscape) {
return { x: this.width * 2, y: this.height, z: this.depth };
} else {
return { x: this.width, y: this.height, z: this.depth };
}
return { x: this.width, y: this.height, z: this.depth };
};
WebTablet.prototype.getTabletTextureResolution = function() {
if (this.landscape) {
return { x: TABLET_TEXTURE_RESOLUTION.x * 2, y: TABLET_TEXTURE_RESOLUTION.y };
return { x: TABLET_TEXTURE_RESOLUTION.y , y: TABLET_TEXTURE_RESOLUTION.x };
} else {
return TABLET_TEXTURE_RESOLUTION;
}
};
WebTablet.prototype.setLandscape = function(newLandscapeValue) {
if (this.landscape == newLandscapeValue) {
if (this.landscape === newLandscapeValue) {
return;
}
this.landscape = newLandscapeValue;
Overlays.editOverlay(this.tabletEntityID, { dimensions: this.getDimensions() });
Overlays.editOverlay(this.tabletEntityID,
{ rotation: this.landscape ? Quat.multiply(Camera.orientation, ROT_LANDSCAPE) :
Quat.multiply(Camera.orientation, ROT_Y_180) });
Overlays.editOverlay(this.webOverlayID, {
resolution: this.getTabletTextureResolution()
resolution: this.getTabletTextureResolution(),
rotation: Quat.multiply(Camera.orientation, ROT_LANDSCAPE_WINDOW)
});
};
@ -407,7 +409,7 @@ WebTablet.prototype.calculateWorldAttitudeRelativeToCamera = function (windowPos
return {
position: worldMousePosition,
rotation: Quat.multiply(Camera.orientation, ROT_Y_180)
rotation: this.landscape ? Quat.multiply(Camera.orientation, ROT_LANDSCAPE) : Quat.multiply(Camera.orientation, ROT_Y_180)
};
};

View file

@ -191,16 +191,12 @@
gTablet.updateAudioBar(currentMicLevel);
}
if (validCheckTime - now > MSECS_PER_SEC/4) {
//each 250ms should be just fine
if (now - validCheckTime > MSECS_PER_SEC) {
validCheckTime = now;
updateTabletWidthFromSettings();
if (UIWebTablet) {
UIWebTablet.setLandscape(landscape);
}
}
if (validCheckTime - now > MSECS_PER_SEC) {
validCheckTime = now;
if (tabletRezzed && UIWebTablet && !tabletIsValid()) {
// when we switch domains, the tablet entity gets destroyed and recreated. this causes
// the overlay to be deleted, but not recreated. If the overlay is deleted for this or any

View file

@ -31,13 +31,9 @@
#include <render-utils/deferred_light_point_vert.h>
#include <render-utils/deferred_light_spot_vert.h>
#include <render-utils/directional_light_frag.h>
#include <render-utils/directional_ambient_light_frag.h>
#include <render-utils/directional_skybox_light_frag.h>
#include <render-utils/point_light_frag.h>
#include <render-utils/spot_light_frag.h>
#include <render-utils/standardTransformPNTC_vert.h>
#include <render-utils/standardDrawTexture_frag.h>
@ -66,9 +62,6 @@
#include <entities-renderer/textured_particle_frag.h>
#include <entities-renderer/textured_particle_vert.h>
#include <render-utils/hit_effect_vert.h>
#include <render-utils/hit_effect_frag.h>
#include <render-utils/overlay3D_vert.h>
#include <render-utils/overlay3D_frag.h>
@ -155,11 +148,8 @@ void QTestWindow::draw() {
testShaderBuild(simple_vert, simple_frag);
testShaderBuild(simple_vert, simple_textured_frag);
testShaderBuild(simple_vert, simple_textured_unlit_frag);
testShaderBuild(deferred_light_vert, directional_light_frag);
testShaderBuild(deferred_light_vert, directional_ambient_light_frag);
testShaderBuild(deferred_light_vert, directional_skybox_light_frag);
testShaderBuild(deferred_light_point_vert, point_light_frag);
testShaderBuild(deferred_light_spot_vert, spot_light_frag);
testShaderBuild(standardTransformPNTC_vert, standardDrawTexture_frag);
testShaderBuild(standardTransformPNTC_vert, DrawTextureOpaque_frag);
@ -190,7 +180,6 @@ void QTestWindow::draw() {
testShaderBuild(ambient_occlusion_vert, ambient_occlusion_frag);
testShaderBuild(ambient_occlusion_vert, occlusion_blend_frag);
*/
testShaderBuild(hit_effect_vert, hit_effect_frag);
testShaderBuild(overlay3D_vert, overlay3D_frag);

View file

@ -140,3 +140,77 @@ void GLMHelpersTests::testSimd() {
}
qDebug() << "Done ";
}
void GLMHelpersTests::testGenerateBasisVectors() {
{ // very simple case: primary along X, secondary is linear combination of X and Y
glm::vec3 u(1.0f, 0.0f, 0.0f);
glm::vec3 v(1.0f, 1.0f, 0.0f);
glm::vec3 w;
generateBasisVectors(u, v, u, v, w);
QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_X, EPSILON);
QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_Y, EPSILON);
QCOMPARE_WITH_ABS_ERROR(w, Vectors::UNIT_Z, EPSILON);
}
{ // point primary along Y instead of X
glm::vec3 u(0.0f, 1.0f, 0.0f);
glm::vec3 v(1.0f, 1.0f, 0.0f);
glm::vec3 w;
generateBasisVectors(u, v, u, v, w);
QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_Y, EPSILON);
QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_X, EPSILON);
QCOMPARE_WITH_ABS_ERROR(w, -Vectors::UNIT_Z, EPSILON);
}
{ // pass bad data (both vectors along Y). The helper will guess X for secondary.
glm::vec3 u(0.0f, 1.0f, 0.0f);
glm::vec3 v(0.0f, 1.0f, 0.0f);
glm::vec3 w;
generateBasisVectors(u, v, u, v, w);
QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_Y, EPSILON);
QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_X, EPSILON);
QCOMPARE_WITH_ABS_ERROR(w, -Vectors::UNIT_Z, EPSILON);
}
{ // pass bad data (both vectors along X). The helper will guess X for secondary, fail, then guess Y.
glm::vec3 u(1.0f, 0.0f, 0.0f);
glm::vec3 v(1.0f, 0.0f, 0.0f);
glm::vec3 w;
generateBasisVectors(u, v, u, v, w);
QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_X, EPSILON);
QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_Y, EPSILON);
QCOMPARE_WITH_ABS_ERROR(w, Vectors::UNIT_Z, EPSILON);
}
{ // general case for arbitrary rotation
float angle = 1.234f;
glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f));
glm::quat rotation = glm::angleAxis(angle, axis);
// expected values
glm::vec3 x = rotation * Vectors::UNIT_X;
glm::vec3 y = rotation * Vectors::UNIT_Y;
glm::vec3 z = rotation * Vectors::UNIT_Z;
// primary is along x
// secondary is linear combination of x and y
// tertiary is unknown
glm::vec3 u = 1.23f * x;
glm::vec3 v = 2.34f * x + 3.45f * y;
glm::vec3 w;
generateBasisVectors(u, v, u, v, w);
QCOMPARE_WITH_ABS_ERROR(u, x, EPSILON);
QCOMPARE_WITH_ABS_ERROR(v, y, EPSILON);
QCOMPARE_WITH_ABS_ERROR(w, z, EPSILON);
}
}

View file

@ -21,6 +21,7 @@ private slots:
void testEulerDecomposition();
void testSixByteOrientationCompression();
void testSimd();
void testGenerateBasisVectors();
};
float getErrorDifference(const float& a, const float& b);

View file

@ -8,6 +8,8 @@
#include "StorageTests.h"
#include <memory>
QTEST_MAIN(StorageTests)
using namespace storage;
@ -32,8 +34,8 @@ void StorageTests::testConversion() {
QFileInfo fileInfo(_testFile);
QCOMPARE(fileInfo.exists(), false);
}
StoragePointer storagePointer = std::make_unique<MemoryStorage>(_testData.size(), _testData.data());
QCOMPARE(storagePointer->size(), (quint64)_testData.size());
StoragePointer storagePointer = std::unique_ptr<MemoryStorage>(new MemoryStorage(_testData.size(), _testData.data()));
QCOMPARE(storagePointer->size(), _testData.size());
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0);
// Convert to a file
storagePointer = storagePointer->toFileStorage(_testFile);
@ -42,12 +44,12 @@ void StorageTests::testConversion() {
QCOMPARE(fileInfo.exists(), true);
QCOMPARE(fileInfo.size(), (qint64)_testData.size());
}
QCOMPARE(storagePointer->size(), (quint64)_testData.size());
QCOMPARE(storagePointer->size(), _testData.size());
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0);
// Convert to memory
storagePointer = storagePointer->toMemoryStorage();
QCOMPARE(storagePointer->size(), (quint64)_testData.size());
QCOMPARE(storagePointer->size(), _testData.size());
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0);
{
// ensure the file is unaffected
@ -58,13 +60,13 @@ void StorageTests::testConversion() {
// truncate the data as a new memory object
auto newSize = _testData.size() / 2;
storagePointer = std::make_unique<MemoryStorage>(newSize, storagePointer->data());
QCOMPARE(storagePointer->size(), (quint64)newSize);
storagePointer = std::unique_ptr<Storage>(new MemoryStorage(newSize, storagePointer->data()));
QCOMPARE(storagePointer->size(), newSize);
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), newSize), 0);
// Convert back to file
storagePointer = storagePointer->toFileStorage(_testFile);
QCOMPARE(storagePointer->size(), (quint64)newSize);
QCOMPARE(storagePointer->size(), newSize);
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), newSize), 0);
{
// ensure the file is truncated