don't allow PC keyboard in HMD login/fix sign up password

This commit is contained in:
Wayne Chen 2018-12-05 18:14:59 -08:00
commit 037abd9b5e
112 changed files with 2573 additions and 1793 deletions
assignment-client/src
interface
libraries
plugins/openvr/src
scripts

View file

@ -656,6 +656,8 @@ void Agent::queryAvatars() {
ViewFrustum view;
view.setPosition(scriptedAvatar->getWorldPosition());
view.setOrientation(scriptedAvatar->getHeadOrientation());
view.setProjection(DEFAULT_FIELD_OF_VIEW_DEGREES, DEFAULT_ASPECT_RATIO,
DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP);
view.calculate();
ConicalViewFrustum conicalView { view };
@ -876,18 +878,30 @@ void Agent::aboutToFinish() {
DependencyManager::destroy<AudioInjectorManager>();
// destroy all other created dependencies
DependencyManager::destroy<ScriptCache>();
DependencyManager::destroy<ResourceCacheSharedItems>();
DependencyManager::destroy<SoundCacheScriptingInterface>();
DependencyManager::destroy<SoundCache>();
DependencyManager::destroy<AudioScriptingInterface>();
DependencyManager::destroy<RecordingScriptingInterface>();
DependencyManager::destroy<AnimationCacheScriptingInterface>();
DependencyManager::destroy<EntityScriptingInterface>();
DependencyManager::destroy<ResourceScriptingInterface>();
DependencyManager::destroy<UserActivityLoggerScriptingInterface>();
DependencyManager::destroy<ScriptCache>();
DependencyManager::destroy<SoundCache>();
DependencyManager::destroy<AnimationCache>();
DependencyManager::destroy<recording::Deck>();
DependencyManager::destroy<recording::Recorder>();
DependencyManager::destroy<recording::ClipCache>();
DependencyManager::destroy<AvatarHashMap>();
DependencyManager::destroy<AssignmentParentFinder>();
DependencyManager::destroy<MessagesClient>();
DependencyManager::destroy<ResourceManager>();
DependencyManager::destroy<ResourceCacheSharedItems>();
// drop our shared pointer to the script engine, then ask ScriptEngines to shutdown scripting
// this ensures that the ScriptEngine goes down before ScriptEngines
_scriptEngine.clear();

View file

@ -129,17 +129,12 @@ void AssignmentClient::stopAssignmentClient() {
QThread* currentAssignmentThread = _currentAssignment->thread();
// ask the current assignment to stop
BLOCKING_INVOKE_METHOD(_currentAssignment, "stop");
QMetaObject::invokeMethod(_currentAssignment, "stop");
// ask the current assignment to delete itself on its thread
_currentAssignment->deleteLater();
// when this thread is destroyed we don't need to run our assignment complete method
disconnect(currentAssignmentThread, &QThread::destroyed, this, &AssignmentClient::assignmentCompleted);
// wait on the thread from that assignment - it will be gone once the current assignment deletes
currentAssignmentThread->quit();
currentAssignmentThread->wait();
auto PROCESS_EVENTS_INTERVAL_MS = 100;
while (!currentAssignmentThread->wait(PROCESS_EVENTS_INTERVAL_MS)) {
QCoreApplication::processEvents();
}
}
}

View file

@ -337,6 +337,13 @@ void AudioMixerClientData::removeAgentAvatarAudioStream() {
if (it != _audioStreams.end()) {
_audioStreams.erase(it);
// Clear mixing structures so that they get recreated with up to date
// data if the stream comes back
setHasReceivedFirstMix(false);
_streams.skipped.clear();
_streams.inactive.clear();
_streams.active.clear();
}
}

View file

@ -21,7 +21,7 @@
#include <GLMHelpers.h>
ScriptableAvatar::ScriptableAvatar() {
_clientTraitsHandler = std::unique_ptr<ClientTraitsHandler>(new ClientTraitsHandler(this));
_clientTraitsHandler.reset(new ClientTraitsHandler(this));
}
QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) {

View file

@ -583,15 +583,29 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> mess
void EntityScriptServer::aboutToFinish() {
shutdownScriptEngine();
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);
DependencyManager::get<ResourceManager>()->cleanup();
DependencyManager::destroy<AudioScriptingInterface>();
DependencyManager::destroy<SoundCacheScriptingInterface>();
DependencyManager::destroy<ResourceScriptingInterface>();
DependencyManager::destroy<EntityScriptingInterface>();
DependencyManager::destroy<SoundCache>();
DependencyManager::destroy<ScriptCache>();
DependencyManager::destroy<ResourceManager>();
DependencyManager::destroy<ResourceCacheSharedItems>();
DependencyManager::destroy<MessagesClient>();
DependencyManager::destroy<AssignmentDynamicFactory>();
DependencyManager::destroy<AssignmentParentFinder>();
DependencyManager::destroy<AvatarHashMap>();
DependencyManager::get<ResourceManager>()->cleanup();
DependencyManager::destroy<PluginManager>();
DependencyManager::destroy<ResourceScriptingInterface>();
DependencyManager::destroy<EntityScriptingInterface>();
// cleanup the AudioInjectorManager (and any still running injectors)
DependencyManager::destroy<AudioInjectorManager>();

View file

@ -0,0 +1,78 @@
{
"name": "Standard to Action (No Movement)",
"channels": [
{ "from": "Standard.LT", "to": "Actions.LeftHandClick" },
{ "from": "Standard.RT", "to": "Actions.RightHandClick" },
{ "from": "Standard.LeftHand", "to": "Actions.LeftHand" },
{ "from": "Standard.LeftHandThumb1", "to": "Actions.LeftHandThumb1"},
{ "from": "Standard.LeftHandThumb2", "to": "Actions.LeftHandThumb2"},
{ "from": "Standard.LeftHandThumb3", "to": "Actions.LeftHandThumb3"},
{ "from": "Standard.LeftHandThumb4", "to": "Actions.LeftHandThumb4"},
{ "from": "Standard.LeftHandIndex1", "to": "Actions.LeftHandIndex1"},
{ "from": "Standard.LeftHandIndex2", "to": "Actions.LeftHandIndex2"},
{ "from": "Standard.LeftHandIndex3", "to": "Actions.LeftHandIndex3"},
{ "from": "Standard.LeftHandIndex4", "to": "Actions.LeftHandIndex4"},
{ "from": "Standard.LeftHandMiddle1", "to": "Actions.LeftHandMiddle1"},
{ "from": "Standard.LeftHandMiddle2", "to": "Actions.LeftHandMiddle2"},
{ "from": "Standard.LeftHandMiddle3", "to": "Actions.LeftHandMiddle3"},
{ "from": "Standard.LeftHandMiddle4", "to": "Actions.LeftHandMiddle4"},
{ "from": "Standard.LeftHandRing1", "to": "Actions.LeftHandRing1"},
{ "from": "Standard.LeftHandRing2", "to": "Actions.LeftHandRing2"},
{ "from": "Standard.LeftHandRing3", "to": "Actions.LeftHandRing3"},
{ "from": "Standard.LeftHandRing4", "to": "Actions.LeftHandRing4"},
{ "from": "Standard.LeftHandPinky1", "to": "Actions.LeftHandPinky1"},
{ "from": "Standard.LeftHandPinky2", "to": "Actions.LeftHandPinky2"},
{ "from": "Standard.LeftHandPinky3", "to": "Actions.LeftHandPinky3"},
{ "from": "Standard.LeftHandPinky4", "to": "Actions.LeftHandPinky4"},
{ "from": "Standard.RightHand", "to": "Actions.RightHand" },
{ "from": "Standard.RightHandThumb1", "to": "Actions.RightHandThumb1"},
{ "from": "Standard.RightHandThumb2", "to": "Actions.RightHandThumb2"},
{ "from": "Standard.RightHandThumb3", "to": "Actions.RightHandThumb3"},
{ "from": "Standard.RightHandThumb4", "to": "Actions.RightHandThumb4"},
{ "from": "Standard.RightHandIndex1", "to": "Actions.RightHandIndex1"},
{ "from": "Standard.RightHandIndex2", "to": "Actions.RightHandIndex2"},
{ "from": "Standard.RightHandIndex3", "to": "Actions.RightHandIndex3"},
{ "from": "Standard.RightHandIndex4", "to": "Actions.RightHandIndex4"},
{ "from": "Standard.RightHandMiddle1", "to": "Actions.RightHandMiddle1"},
{ "from": "Standard.RightHandMiddle2", "to": "Actions.RightHandMiddle2"},
{ "from": "Standard.RightHandMiddle3", "to": "Actions.RightHandMiddle3"},
{ "from": "Standard.RightHandMiddle4", "to": "Actions.RightHandMiddle4"},
{ "from": "Standard.RightHandRing1", "to": "Actions.RightHandRing1"},
{ "from": "Standard.RightHandRing2", "to": "Actions.RightHandRing2"},
{ "from": "Standard.RightHandRing3", "to": "Actions.RightHandRing3"},
{ "from": "Standard.RightHandRing4", "to": "Actions.RightHandRing4"},
{ "from": "Standard.RightHandPinky1", "to": "Actions.RightHandPinky1"},
{ "from": "Standard.RightHandPinky2", "to": "Actions.RightHandPinky2"},
{ "from": "Standard.RightHandPinky3", "to": "Actions.RightHandPinky3"},
{ "from": "Standard.RightHandPinky4", "to": "Actions.RightHandPinky4"},
{ "from": "Standard.LeftFoot", "to": "Actions.LeftFoot" },
{ "from": "Standard.RightFoot", "to": "Actions.RightFoot" },
{ "from": "Standard.Hips", "to": "Actions.Hips" },
{ "from": "Standard.Spine2", "to": "Actions.Spine2" },
{ "from": "Standard.Head", "to": "Actions.Head" },
{ "from": "Standard.LeftArm", "to": "Actions.LeftArm" },
{ "from": "Standard.RightArm", "to": "Actions.RightArm" },
{ "from": "Standard.TrackedObject00", "to" : "Actions.TrackedObject00" },
{ "from": "Standard.TrackedObject01", "to" : "Actions.TrackedObject01" },
{ "from": "Standard.TrackedObject02", "to" : "Actions.TrackedObject02" },
{ "from": "Standard.TrackedObject03", "to" : "Actions.TrackedObject03" },
{ "from": "Standard.TrackedObject04", "to" : "Actions.TrackedObject04" },
{ "from": "Standard.TrackedObject05", "to" : "Actions.TrackedObject05" },
{ "from": "Standard.TrackedObject06", "to" : "Actions.TrackedObject06" },
{ "from": "Standard.TrackedObject07", "to" : "Actions.TrackedObject07" },
{ "from": "Standard.TrackedObject08", "to" : "Actions.TrackedObject08" },
{ "from": "Standard.TrackedObject09", "to" : "Actions.TrackedObject09" },
{ "from": "Standard.TrackedObject10", "to" : "Actions.TrackedObject10" },
{ "from": "Standard.TrackedObject11", "to" : "Actions.TrackedObject11" },
{ "from": "Standard.TrackedObject12", "to" : "Actions.TrackedObject12" },
{ "from": "Standard.TrackedObject13", "to" : "Actions.TrackedObject13" },
{ "from": "Standard.TrackedObject14", "to" : "Actions.TrackedObject14" },
{ "from": "Standard.TrackedObject15", "to" : "Actions.TrackedObject15" }
]
}

View file

@ -1,9 +1,8 @@
//
// LoginDialog.qml
//
// Created by Wayne Chen
// Copyright 2018 High Fidelity, Inc.
//
// Created by David Rowe on 3 Jun 2015
// 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
//
@ -37,6 +36,8 @@ FocusScope {
property string title: ""
property string text: ""
property int titleWidth: 0
property alias bannerWidth: banner.width
property alias bannerHeight: banner.height
function tryDestroy() {
root.destroy()
@ -51,10 +52,36 @@ FocusScope {
}
Image {
z: -10
id: loginDialogBackground
source: "LoginDialog/background.png"
source: "LoginDialog/background.jpg"
anchors.fill: parent
z: -2
}
Rectangle {
z: -6
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.5
color: "black"
}
Item {
z: -5
id: bannerContainer
width: parent.width
height: banner.height
anchors {
top: parent.top
topMargin: 0.18 * parent.height
}
Image {
id: banner
anchors.centerIn: parent
source: "../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
Keys.onPressed: {
@ -92,6 +119,6 @@ FocusScope {
}
Component.onCompleted: {
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
}
}

View file

@ -56,29 +56,6 @@ Item {
anchors.fill: parent
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Rectangle {
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.9
color: "black"
}
Item {
id: bannerContainer
width: parent.width
height: banner.height
anchors {
bottom: textContainer.top
bottomMargin: 0.125 * parent.height
}
Image {
id: banner
anchors.centerIn: parent
source: "../../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
Item {
id: textContainer
width: parent.width
@ -131,7 +108,7 @@ Item {
horizontalAlignment: Text.AlignHCenter
Component.onCompleted: {
bodyText.text = root.isTablet ? qsTr("Please navigate to your default browser\nto recover your account.\nIf you are in a VR headset, please take it off.") :
qsTr("Please navigate to your default browser to recover your account.\nIf you are in a VR headset, please take it off.");
qsTr("Please navigate to your default browser to recover your account.\nIf you are in a VR headset,\nplease take it off.");
bodyTextMetrics.text = bodyText.text;
bodyText
bodyText.anchors.leftMargin = (parent.width - bodyTextMetrics.width) / 2;

View file

@ -26,14 +26,15 @@ Item {
readonly property int fontSize: 15
readonly property bool fontBold: true
readonly property bool withSteam: withSteam
property string errorString: errorString
QtObject {
id: d
readonly property int minWidth: 480
// readonly property int minWidthButton: !root.isTablet ? 256 : 174
readonly property int minWidthButton: 36
readonly property int minWidthButton: !root.isTablet ? 256 : 174
property int maxWidth: root.isTablet ? 1280 : root.width
readonly property int minHeight: 120
// readonly property int minHeightButton: !root.isTablet ? 56 : 42
readonly property int minHeightButton: 36
property int maxHeight: root.isTablet ? 720 : root.height
@ -56,29 +57,6 @@ Item {
height: root.height
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Rectangle {
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.9
color: "black"
}
Item {
id: bannerContainer
width: parent.width
height: banner.height
anchors {
top: parent.top
topMargin: 85
}
Image {
id: banner
anchors.centerIn: parent
source: "../../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
Item {
id: contentItem
anchors.fill: parent
@ -94,78 +72,42 @@ Item {
// above buttons.
anchors.topMargin: (parent.height - additionalTextContainer.height) / 2 - hifi.dimensions.contentSpacing.y - profileButton.height
anchors.left: parent.left;
anchors.leftMargin: (parent.width - loginErrorMessageTextMetrics.width) / 2;
color: "red";
font.family: "Cairo"
font.pixelSize: 12
text: ""
font.family: completeProfileBody.fontFamily
font.pixelSize: completeProfileBody.fontSize
text: completeProfileBody.errorString
visible: true
}
HifiStylesUit.HiFiGlyphs {
id: loggedInGlyph;
text: hifi.glyphs.steamSquare;
// color
color: "white"
// Size
size: 78;
// Anchors
anchors.left: parent.left;
anchors.leftMargin: (parent.width - loggedInGlyph.size) / 2;
anchors.top: loginErrorMessage.bottom
anchors.topMargin: 2 * hifi.dimensions.contentSpacing.y
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
visible: false;
}
Item {
id: buttons
width: Math.max(banner.width, cancelContainer.width + profileButton.width)
width: root.bannerWidth
height: d.minHeightButton
anchors {
top: parent.top
topMargin: (parent.height - additionalTextContainer.height) / 2 - hifi.dimensions.contentSpacing.y
left: parent.left
leftMargin: (parent.width - banner.width) / 2
leftMargin: (parent.width - root.bannerWidth) / 2
}
Item {
id: cancelContainer
width: cancelText.width
height: d.minHeightButton
HifiControlsUit.Button {
id: cancelButton
anchors {
top: parent.top
left: parent.left
}
Text {
id: cancelText
text: qsTr("Cancel");
width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
lineHeight: 1
color: "white"
font.family: completeProfileBody.fontFamily
font.pixelSize: completeProfileBody.fontSize
font.capitalization: Font.AllUppercase;
font.bold: completeProfileBody.fontBold
lineHeightMode: Text.ProportionalHeight
anchors.centerIn: parent
text: qsTr("CANCEL")
color: hifi.buttons.noneBorderlessWhite
fontFamily: completeProfileBody.fontFamily
fontSize: completeProfileBody.fontSize
fontBold: completeProfileBody.fontBold
onClicked: {
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
}
MouseArea {
id: cancelArea
anchors.fill: parent
hoverEnabled: true
onEntered: {
Tablet.playSound(TabletEnums.ButtonHover);
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
}
}
TextMetrics {
id: profileButtonTextMetrics
font: cancelText.font
text: qsTr("CREATE YOUR PROFILE")
}
HifiControlsUit.Button {
id: profileButton
@ -173,7 +115,7 @@ Item {
top: parent.top
right: parent.right
}
width: Math.max(profileButtonTextMetrics.width + 2 * hifi.dimensions.contentSpacing.x, d.minWidthButton)
width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
text: qsTr("Create your profile")
@ -185,8 +127,6 @@ Item {
onClicked: {
loginErrorMessage.visible = false;
loginDialog.createAccountFromSteam();
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
"withSteam": true, "fromBody": "CompleteProfileBody" })
}
}
}
@ -212,7 +152,7 @@ Item {
onLinkActivated: {
loginDialog.isLogIn = true;
bodyLoader.setSource("SignInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "" });
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "", "linkSteam": true });
}
}
@ -246,11 +186,26 @@ Item {
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
onLinkActivated: loginDialog.openUrl(link)
onLinkActivated: loginDialog.openUrl(link);
}
}
}
Connections {
target: loginDialog
onHandleCreateCompleted: {
console.log("Create Succeeded")
loginDialog.loginThroughSteam();
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": true, "linkSteam": false });
}
onHandleCreateFailed: {
console.log("Create Failed: " + error);
bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
}
}
Component.onCompleted: {
//but rise Tablet's one instead for Tablet interface
if (root.isTablet || root.isOverlay) {

View file

@ -35,6 +35,7 @@ Item {
property bool punctuationMode: false
property bool withSteam: false
property bool linkSteam: linkSteam
property bool withOculus: false
property string errorString: errorString
@ -44,7 +45,6 @@ Item {
readonly property int minWidthButton: !root.isTablet ? 256 : 174
property int maxWidth: root.isTablet ? 1280 : root.width
readonly property int minHeight: 120
// readonly property int minHeightButton: !root.isTablet ? 56 : 42
readonly property int minHeightButton: 36
property int maxHeight: root.isTablet ? 720 : root.height
@ -65,7 +65,7 @@ Item {
function login() {
loginDialog.login(emailField.text, passwordField.text);
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": false, "withOculus": false, "fromBody": "" });
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": false, "withOculus": false, "linkSteam": linkAccountBody.linkSteam });
}
function init() {
@ -73,11 +73,19 @@ Item {
loginDialog.isLogIn = true;
loginErrorMessage.text = linkAccountBody.errorString;
loginErrorMessage.visible = (linkAccountBody.errorString !== "");
loginButton.text = "Log In";
loginButton.text = !linkAccountBody.linkSteam ? "Log In" : "Link Account";
loginButton.color = hifi.buttons.blue;
emailField.placeholderText = "Username or Email";
var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");
emailField.text = keepMeLoggedInCheckbox.checked ? savedUsername === "Unknown user" ? "" : savedUsername : "";
if (linkAccountBody.linkSteam) {
steamInfoText.anchors.top = passwordField.bottom;
keepMeLoggedInCheckbox.anchors.top = steamInfoText.bottom;
loginButton.width = (passwordField.width - hifi.dimensions.contentSpacing.x) / 2;
loginButton.anchors.right = emailField.right;
} else {
loginButton.anchors.left = emailField.left;
}
loginContainer.visible = true;
}
@ -88,36 +96,13 @@ Item {
height: root.height
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Rectangle {
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.9
color: "black"
}
Item {
id: bannerContainer
width: parent.width
height: banner.height
anchors {
bottom: loginContainer.top
bottomMargin: 0.12 * parent.height
}
Image {
id: banner
anchors.centerIn: parent
source: "../../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
Item {
id: loginContainer
width: emailField.width
height: 0.45 * parent.height
anchors {
top: parent.top
topMargin: bannerContainer.height + 0.25 * parent.height
topMargin: root.bannerHeight + 0.25 * parent.height
left: parent.left
leftMargin: (parent.width - emailField.width) / 2
}
@ -149,15 +134,15 @@ Item {
HifiControlsUit.TextField {
id: emailField
width: banner.width
width: root.bannerWidth
height: linkAccountBody.textFieldHeight
font.pixelSize: linkAccountBody.textFieldFontSize
styleRenderType: Text.QtRendering
anchors {
top: parent.top
topMargin: loginErrorMessage.height
topMargin: errorContainer.height
}
placeholderText: "Username or Email"
focus: true
activeFocusOnPress: true
Keys.onPressed: {
switch (event.key) {
@ -181,14 +166,17 @@ Item {
}
onFocusChanged: {
root.text = "";
root.isPassword = !focus;
if (focus) {
root.isPassword = false;
}
}
}
HifiControlsUit.TextField {
id: passwordField
width: banner.width
width: root.bannerWidth
height: linkAccountBody.textFieldHeight
font.pixelSize: linkAccountBody.textFieldFontSize
styleRenderType: Text.QtRendering
placeholderText: "Password"
activeFocusOnPress: true
echoMode: passwordFieldMouseArea.showPassword ? TextInput.Normal : TextInput.Password
@ -269,16 +257,30 @@ Item {
}
onCheckedChanged: {
Settings.setValue("keepMeLoggedIn", checked);
if (checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", Account.username);
var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");
emailField.text = savedUsername === "Unknown user" ? "" : savedUsername;
} else {
Settings.setValue("keepMeLoggedIn/savedUsername", "");
}
}
Component.onDestruction: {
Settings.setValue("keepMeLoggedIn", checked);
if (checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text);
}
}
}
HifiControlsUit.Button {
id: cancelButton
width: (passwordField.width - hifi.dimensions.contentSpacing.x) / 2;
height: d.minHeightButton
text: qsTr("Cancel")
fontFamily: linkAccountBody.fontFamily
fontSize: linkAccountBody.fontSize
fontBold: linkAccountBody.fontBold
color: hifi.buttons.noneBorderlessWhite;
visible: linkAccountBody.linkSteam
anchors {
top: keepMeLoggedInCheckbox.bottom
topMargin: hifi.dimensions.contentSpacing.y
}
onClicked: {
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "errorString": "" });
}
}
HifiControlsUit.Button {
@ -292,22 +294,38 @@ Item {
anchors {
top: keepMeLoggedInCheckbox.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: emailField.left
}
onClicked: {
linkAccountBody.login()
}
}
Text {
id: steamInfoText
visible: linkAccountBody.linkSteam
anchors {
top: loginButton.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: emailField.left
}
font.family: linkAccountBody.fontFamily
font.pixelSize: linkAccountBody.textFieldFontSize
color: "white"
text: qsTr("Your Steam account information will not be exposed to others.");
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
HifiStylesUit.ShortcutText {
id: cantAccessText
z: 10
visible: !linkAccountBody.linkSteam
anchors {
top: loginButton.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: emailField.left
}
font.family: linkAccountBody.fontFamily
font.pixelSize: 18
font.pixelSize: linkAccountBody.textFieldFontSize
text: "<a href='https://highfidelity.com/users/password/new'> Can't access your account?</a>"
@ -337,28 +355,33 @@ Item {
buttonGlyph: hifi.glyphs.steamSquare
buttonGlyphRightMargin: 10
onClicked: {
if (loginDialog.isOculusStoreRunning()) {
linkAccountBody.withOculus = true;
loginDialog.loginThroughSteam();
} else if (loginDialog.isSteamRunning()) {
// if (loginDialog.isOculusStoreRunning()) {
// linkAccountBody.withOculus = true;
// loginDialog.loginThroughSteam();
// } else
if (loginDialog.isSteamRunning()) {
linkAccountBody.withSteam = true;
loginDialog.loginThroughSteam();
}
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
"withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "fromBody": "LinkAccountBody" });
"withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam });
}
Component.onCompleted: {
if (loginDialog.isOculusStoreRunning()) {
continueButton.text = qsTr("CONTINUE WITH OCULUS");
continueButton.buttonGlyph = hifi.glyphs.oculus;
} else if (loginDialog.isSteamRunning()) {
if (linkAccountBody.linkSteam) {
continueButton.visible = false;
return;
}
// if (loginDialog.isOculusStoreRunning()) {
// continueButton.text = qsTr("CONTINUE WITH OCULUS");
// continueButton.buttonGlyph = hifi.glyphs.oculus;
// } else
if (loginDialog.isSteamRunning()) {
continueButton.text = qsTr("CONTINUE WITH STEAM");
continueButton.buttonGlyph = hifi.glyphs.steamSquare;
} else {
continueButton.visible = false;
}
}
}
}
@ -366,10 +389,11 @@ Item {
id: signUpContainer
width: loginContainer.width
height: signUpTextMetrics.height
visible: !linkAccountBody.linkSteam
anchors {
left: loginContainer.left
top: loginContainer.bottom
// topMargin: 0.25 * parent.height
topMargin: 0.05 * parent.height
}
TextMetrics {
id: signUpTextMetrics
@ -406,7 +430,7 @@ Item {
onLinkActivated: {
Tablet.playSound(TabletEnums.ButtonClick);
bodyLoader.setSource("SignUpBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
"errorString": "" });
"errorString": "", "linkSteam": linkAccountBody.linkSteam });
}
}
}
@ -430,7 +454,7 @@ Item {
fontFamily: linkAccountBody.fontFamily
fontSize: linkAccountBody.fontSize
fontBold: linkAccountBody.fontBold
visible: loginDialog.getLoginDialogPoppedUp()
visible: loginDialog.getLoginDialogPoppedUp() && !linkAccountBody.linkSteam;
onClicked: {
if (loginDialog.getLoginDialogPoppedUp()) {
console.log("[ENCOURAGELOGINDIALOG]: user dismissed login screen")
@ -445,6 +469,15 @@ Item {
}
}
Connections {
target: loginDialog
onFocusEnabled: {
Qt.callLater(function() {
emailField.forceActiveFocus();
})
}
}
Component.onCompleted: {
//but rise Tablet's one instead for Tablet interface
root.keyboardEnabled = HMD.active;
@ -466,10 +499,6 @@ Item {
Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text);
linkAccountBody.login();
break;
case Qt.Key_Escape:
event.accepted = true;
root.tryDestroy();
break;
}
}
}

View file

@ -26,7 +26,7 @@ Item {
property bool fontBold: true
property bool withSteam: withSteam
property bool withOculus: withOculus
property string fromBody: fromBody
property bool linkSteam: linkSteam
QtObject {
id: d
@ -68,16 +68,13 @@ Item {
function init() {
// For the process of logging in.
loggingInText.wrapMode = Text.NoWrap;
print("withSteam " + loggingInBody.withSteam);
print("withOculus " + loggingInBody.withOculus);
if (loggingInBody.withSteam) {
loggingInGlyph.visible = true;
loggingInText.text = "Logging in to Steam";
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
} else if (loggingInBody.withOculus) {
loggingInGlyph.visible = true;
loggingInGlyph.text = hifi.glyphs.oculus;
loggingInGlyph.visible = true;
loggingInText.text = "Logging in to Oculus";
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
} else {
@ -89,19 +86,20 @@ Item {
}
function loadingSuccess() {
loggingInSpinner.visible = false;
if (loggingInBody.linkSteam) {
loggingInText.text = "Linking to Steam";
loginDialog.linkSteam();
return;
}
if (loggingInBody.withSteam) {
// reset the flag.
loggingInGlyph.visible = false;
loggingInText.text = "You are now logged into Steam!"
loggingInText.anchors.centerIn = loggingInHeader;
loggingInText.anchors.bottom = loggingInHeader.bottom;
loggingInText.text = "You are now logged into Steam!";
loggedInGlyph.visible = true;
} else if (loggingInBody.withOculus) {
// reset the flag.
loggingInGlyph.visible = false;
loggingInText.text = "You are now logged into Oculus!"
loggingInText.anchors.centerIn = loggingInHeader;
loggingInText.anchors.bottom = loggingInHeader.bottom;
loggingInText.text = "You are now logged into Oculus!";
loggedInGlyph.text = hifi.glyphs.oculus;
loggedInGlyph.visible = true;
} else {
@ -116,30 +114,6 @@ Item {
height: root.height
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Rectangle {
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.9
color: "black"
}
Item {
id: bannerContainer
width: parent.width
height: banner.height
anchors {
top: parent.top
topMargin: 85
}
Image {
id: banner
anchors.centerIn: parent
source: "../../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
Item {
id: loggingInContainer
width: parent.width
@ -173,7 +147,7 @@ Item {
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
visible: loggingInBody.withSteam;
visible: loggingInBody.withSteam || loggingInBody.withOculus;
}
TextMetrics {
@ -207,7 +181,7 @@ Item {
}
AnimatedImage {
id: loggingInSpinner
source: "../../icons/loader-snake-64-w.gif"
source: "images/loader-snake-298-b.gif"
width: 128
height: width
anchors.left: parent.left;
@ -248,10 +222,19 @@ Item {
Connections {
target: loginDialog
onHandleLinkCompleted: {
console.log("Link Succeeded");
loggingInBody.linkSteam = false;
loggingInBody.loadingSuccess();
}
onHandleLinkFailed: {
console.log("Link Failed: " + error);
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": true, "errorString": error });
}
onHandleLoginCompleted: {
console.log("Login Succeeded")
loadingSuccess();
console.log("Login Succeeded");
loggingInBody.loadingSuccess();
}
onHandleLoginFailed: {
@ -260,8 +243,8 @@ Item {
var errorString = "";
if (loggingInBody.withSteam) {
loggingInGlyph.visible = false;
errorString = "Your Steam authentication has failed. Please make sure you are logged into Steam and try again."
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString });
errorString = "Your Steam authentication has failed. Please make sure you are logged into Steam and try again.";
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "errorString": errorString });
} else if (loggingInBody.withOculus) {
loggingInGlyph.visible = false;
errorString = "Your Oculus authentication has failed. Please make sure you are logged into Oculus and try again."
@ -269,11 +252,7 @@ Item {
}
else {
errorString = "Username or password is incorrect.";
if (loginDialog.isLogIn && loggingInBody.withSteam) {
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
} else {
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString });
}
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString });
}
}
}

View file

@ -1,5 +1,5 @@
//
// signUpBody.qml
// SignUpBody.qml
//
// Created by Stephen Birarda on 7 Dec 2016
// Copyright 2016 High Fidelity, Inc.
@ -37,6 +37,7 @@ Item {
onKeyboardRaisedChanged: d.resize();
property string errorString: errorString
property bool linkSteam: linkSteam
QtObject {
id: d
@ -44,7 +45,6 @@ Item {
readonly property int minWidthButton: !root.isTablet ? 256 : 174
property int maxWidth: root.isTablet ? 1280 : root.width
readonly property int minHeight: 120
// readonly property int minHeightButton: !root.isTablet ? 56 : 42
readonly property int minHeightButton: 36
property int maxHeight: root.isTablet ? 720 : root.height
@ -64,22 +64,14 @@ Item {
}
}
function login() {
function signup() {
loginDialog.signup(emailField.text, usernameField.text, passwordField.text);
return;
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": false, "withOculus": false, "fromBody": "" });
}
function init() {
// going to/from sign in/up dialog.
loginDialog.isLogIn = false;
loginErrorMessage.visible = (signUpBody.errorString !== "");
if (signUpBody.errorString !== "") {
loginErrorMessage.text = signUpBody.errorString;
errorContainer.anchors.bottom = usernameField.top;
errorContainer.anchors.bottomMargin = hifi.dimensions.contentSpacing.y;
errorContainer.anchors.left = usernameField.left;
}
emailField.placeholderText = "Email";
emailField.text = "";
emailField.anchors.top = usernameField.bottom;
@ -95,37 +87,13 @@ Item {
height: root.height
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Rectangle {
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.9
color: "black"
}
Item {
id: bannerContainer
width: parent.width
height: banner.height
anchors {
bottom: loginContainer.top
bottomMargin: 0.12 * parent.height
}
Image {
id: banner
anchors.centerIn: parent
source: "../../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
Item {
id: loginContainer
width: usernameField.width
height: parent.height - bannerContainer.height
height: parent.height
anchors {
top: parent.top
topMargin: bannerContainer.height + 0.25 * parent.height
topMargin: root.bannerHeight + 0.25 * parent.height
left: parent.left
leftMargin: (parent.width - usernameField.width) / 2
}
@ -133,7 +101,7 @@ Item {
Item {
id: errorContainer
width: loginErrorMessageTextMetrics.width
width: parent.width
height: loginErrorMessageTextMetrics.height
anchors {
bottom: usernameField.top;
@ -147,6 +115,7 @@ Item {
}
Text {
id: loginErrorMessage;
width: root.bannerWidth
color: "red";
font.family: signUpBody.fontFamily
font.pixelSize: 18
@ -159,10 +128,11 @@ Item {
HifiControlsUit.TextField {
id: usernameField
width: banner.width
width: root.bannerWidth
height: signUpBody.textFieldHeight
placeholderText: "Username"
font.pixelSize: signUpBody.textFieldFontSize
styleRenderType: Text.QtRendering
anchors {
top: parent.top
topMargin: loginErrorMessage.height
@ -191,25 +161,28 @@ Item {
if (keepMeLoggedInCheckbox.checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
}
signUpBody.login();
signUpBody.signup();
break;
}
}
onFocusChanged: {
root.text = "";
root.isPassword = !focus;
if (focus) {
root.isPassword = false;
}
}
}
HifiControlsUit.TextField {
id: emailField
width: banner.width
width: root.bannerWidth
height: signUpBody.textFieldHeight
anchors {
top: parent.top
}
placeholderText: "Username or Email"
font.pixelSize: signUpBody.textFieldFontSize
styleRenderType: Text.QtRendering
activeFocusOnPress: true
Keys.onPressed: {
switch (event.key) {
@ -233,21 +206,24 @@ Item {
if (keepMeLoggedInCheckbox.checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
}
signUpBody.login();
signUpBody.signup();
break;
}
}
onFocusChanged: {
root.text = "";
root.isPassword = !focus;
if (focus) {
root.isPassword = false;
}
}
}
HifiControlsUit.TextField {
id: passwordField
width: banner.width
width: root.bannerWidth
height: signUpBody.textFieldHeight
placeholderText: "Password"
font.pixelSize: signUpBody.textFieldFontSize
styleRenderType: Text.QtRendering
activeFocusOnPress: true
echoMode: passwordFieldMouseArea.showPassword ? TextInput.Normal : TextInput.Password
anchors {
@ -316,7 +292,7 @@ Item {
if (keepMeLoggedInCheckbox.checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
}
signUpBody.login();
signUpBody.signup();
break;
}
}
@ -336,16 +312,12 @@ Item {
}
onCheckedChanged: {
Settings.setValue("keepMeLoggedIn", checked);
if (checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", Account.username);
var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");
usernameField.text = savedUsername === "Unknown user" ? "" : savedUsername;
} else {
Settings.setValue("keepMeLoggedIn/savedUsername", "");
}
}
Component.onDestruction: {
Settings.setValue("keepMeLoggedIn", checked);
if (checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text);
}
}
}
@ -369,7 +341,7 @@ Item {
fontSize: signUpBody.fontSize
fontBold: signUpBody.fontBold
onClicked: {
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": signUpBody.linkSteam });
}
}
HifiControlsUit.Button {
@ -387,7 +359,7 @@ Item {
}
onClicked: {
signUpBody.login()
signUpBody.signup();
}
}
}
@ -433,7 +405,7 @@ Item {
console.log("Sign Up Completed");
loginDialog.login(usernameField.text, passwordField.text);
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": false, "fromBody": "" });
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": false, "linkSteam": false });
}
onHandleSignupFailed: {
console.log("Sign Up Failed")
@ -442,6 +414,13 @@ Item {
loginErrorMessage.visible = (errorStringEdited !== "");
if (errorStringEdited !== "") {
loginErrorMessage.text = errorStringEdited;
loginErrorMessageTextMetrics.text = errorStringEdited;
if (loginErrorMessageTextMetrics.width > 350 && root.isTablet) {
loginErrorMessage.wrapMode = Text.WordWrap;
loginErrorMessage.verticalAlignment = Text.AlignLeft;
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
errorContainer.height = 2 * loginErrorMessageTextMetrics.height;
}
errorContainer.anchors.bottom = usernameField.top;
errorContainer.anchors.left = usernameField.left;
}

View file

@ -25,12 +25,9 @@ Item {
readonly property int fontSize: 15
readonly property bool fontBold: true
readonly property string errorString: errorString
function create() {
mainTextContainer.visible = false
loginDialog.createAccountFromSteam(textField.text)
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": true, "fromBody": "UsernameCollisionBody" });
loginDialog.createAccountFromSteam(textField.text);
}
property bool keyboardEnabled: false
@ -45,7 +42,6 @@ Item {
readonly property int minWidthButton: !root.isTablet ? 256 : 174
property int maxWidth: root.isTablet ? 1280 : root.width
readonly property int minHeight: 120
// readonly property int minHeightButton: !root.isTablet ? 56 : 42
readonly property int minHeightButton: 36
property int maxHeight: root.isTablet ? 720 : root.height
@ -70,30 +66,6 @@ Item {
onHeightChanged: d.resize(); onWidthChanged: d.resize();
anchors.fill: parent
Rectangle {
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.9
color: "black"
}
Item {
id: bannerContainer
width: parent.width
height: banner.height
anchors {
top: parent.top
topMargin: 85
}
Image {
id: banner
anchors.centerIn: parent
source: "../../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
TextMetrics {
id: mainTextContainerTextMetrics
font: mainTextContainer.font
@ -110,9 +82,9 @@ Item {
}
font.family: usernameCollisionBody.fontFamily
font.pixelSize: usernameCollisionBody.fontSize - 10
font.pixelSize: usernameCollisionBody.fontSize
font.bold: usernameCollisionBody.fontBold
text: qsTr("Your Steam username is not available.")
text: qsTr("Your Steam username is not available.");
wrapMode: Text.WordWrap
color: hifi.colors.redAccent
lineHeight: 1
@ -130,9 +102,10 @@ Item {
topMargin: hifi.dimensions.contentSpacing.y
}
font.family: "Fira Sans"
font.pixelSize: usernameCollisionBody.fontSize - 10
font.pixelSize: usernameCollisionBody.fontSize
styleRenderType: Text.QtRendering
font.bold: usernameCollisionBody.fontBold
width: banner.width
width: root.bannerWidth
placeholderText: "Choose your own"
@ -170,54 +143,33 @@ Item {
Item {
id: buttons
width: Math.max(banner.width, cancelContainer.width + profileButton.width)
width: root.bannerWidth
height: d.minHeightButton
anchors {
top: textField.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: parent.left
leftMargin: (parent.width - banner.width) / 2
leftMargin: (parent.width - root.bannerWidth) / 2
}
Item {
id: cancelContainer
width: cancelText.width
height: d.minHeightButton
HifiControlsUit.Button {
id: cancelButton
anchors {
top: parent.top
left: parent.left
}
Text {
id: cancelText
text: qsTr("Cancel");
width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
lineHeight: 1
color: "white"
font.family: usernameCollisionBody.fontFamily
font.pixelSize: usernameCollisionBody.fontSize
font.capitalization: Font.AllUppercase;
font.bold: usernameCollisionBody.fontBold
lineHeightMode: Text.ProportionalHeight
anchors.centerIn: parent
text: qsTr("CANCEL")
color: hifi.buttons.noneBorderlessWhite
fontFamily: usernameCollisionBody.fontFamily
fontSize: usernameCollisionBody.fontSize
fontBold: usernameCollisionBody.fontBold
onClicked: {
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "" });
}
MouseArea {
id: cancelArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onEntered: {
Tablet.playSound(TabletEnums.ButtonHover);
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
}
}
}
TextMetrics {
id: profileButtonTextMetrics
font: cancelText.font
text: qsTr("CREATE YOUR PROFILE")
}
HifiControlsUit.Button {
id: profileButton
@ -225,7 +177,7 @@ Item {
top: parent.top
right: parent.right
}
width: Math.max(profileButtonTextMetrics.width + 2 * hifi.dimensions.contentSpacing.x, d.minWidthButton)
width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
text: qsTr("Create your profile")
@ -241,36 +193,18 @@ Item {
}
}
Component.onCompleted: {
//dont rise local keyboard
keyboardEnabled = !root.isTablet && HMD.active;
//but rise Tablet's one instead for Tablet interface
if (root.isTablet || root.isOverlay) {
root.keyboardEnabled = HMD.active;
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
}
root.text = "";
d.resize();
textField.focus = true;
if (usernameCollisionBody.errorString !== "") {
mainTextContainer.visible = true;
mainTextContainer.text = usernameCollisionBody.errorString;
}
}
Connections {
target: loginDialog
onHandleCreateCompleted: {
console.log("Create Succeeded")
console.log("Create Succeeded");
loginDialog.loginThroughSteam();
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": true, "fromBody": "UsernameCollisionBody" })
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": true, "linkSteam": false })
}
onHandleCreateFailed: {
console.log("Create Failed: " + error)
mainTextContainer.visible = true
mainTextContainer.text = "\"" + textField.text + qsTr("\" is invalid or already taken.")
mainTextContainer.text = "\"" + textField.text + qsTr("\" is invalid or already taken.");
}
onHandleLoginCompleted: {
console.log("Login Succeeded");

Binary file not shown.

After

(image error) Size: 315 KiB

Binary file not shown.

Before

(image error) Size: 22 KiB

Binary file not shown.

After

(image error) Size: 272 KiB

Binary file not shown.

Before

(image error) Size: 58 KiB

Binary file not shown.

After

(image error) Size: 281 KiB

Binary file not shown.

Before

(image error) Size: 49 KiB

View file

@ -36,6 +36,8 @@ FocusScope {
property string title: ""
property int titleWidth: 0
property alias text: loginKeyboard.mirroredText
property alias bannerWidth: banner.width
property alias bannerHeight: banner.height
function tryDestroy() {
root.destroy()
@ -51,10 +53,36 @@ FocusScope {
}
Image {
z: -10
id: loginDialogBackground
source: "LoginDialog/background.png"
source: "LoginDialog/background.jpg"
anchors.fill: parent
z: -2
}
Rectangle {
z: -6
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.5
color: "black"
}
Item {
z: -5
id: bannerContainer
width: parent.width
height: banner.height
anchors {
top: parent.top
topMargin: 0.18 * parent.height
}
Image {
id: banner
anchors.centerIn: parent
source: "../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
Timer {
@ -121,6 +149,6 @@ FocusScope {
Component.onCompleted: {
keyboardTimer.start();
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": ""});
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
}
}

View file

@ -44,20 +44,18 @@ Rectangle {
onPasswordChanged: {
var use3DKeyboard = (typeof MenuInterface === "undefined") ? false : MenuInterface.isOptionChecked("Use 3D Keyboard");
var use3DKeyboard = (typeof KeyboardScriptingInterface === "undefined") ? false : KeyboardScriptingInterface.use3DKeyboard;
if (use3DKeyboard) {
KeyboardScriptingInterface.password = password;
}
}
onRaisedChanged: {
console.log("raising keyboard to " + raised);
var use3DKeyboard = (typeof MenuInterface === "undefined") ? false : MenuInterface.isOptionChecked("Use 3D Keyboard");
var use3DKeyboard = (typeof KeyboardScriptingInterface === "undefined") ? false : KeyboardScriptingInterface.use3DKeyboard;
if (!use3DKeyboard) {
keyboardBase.height = raised ? raisedHeight : 0;
keyboardBase.visible = raised;
} else {
console.log("raising 3d keyboard to " + raised);
KeyboardScriptingInterface.raised = raised;
KeyboardScriptingInterface.password = raised ? password : false;
}

View file

@ -31,6 +31,7 @@ TextField {
property bool hasClearButton: false;
property string leftPermanentGlyph: "";
property string centerPlaceholderGlyph: "";
property int styleRenderType: Text.NativeRendering
placeholderText: textField.placeholderText
@ -44,8 +45,8 @@ TextField {
// workaround for https://bugreports.qt.io/browse/QTBUG-49297
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Return:
case Qt.Key_Enter:
case Qt.Key_Return:
case Qt.Key_Enter:
event.accepted = true;
// emit accepted signal manually
@ -156,6 +157,7 @@ TextField {
selectionColor: hifi.colors.primaryHighlight
padding.left: hasRoundedBorder ? textField.height / 2 : ((isSearchField || textField.leftPermanentGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding
padding.right: (hasClearButton ? textField.height - 2 : 0) + hifi.dimensions.textPadding
renderType: textField.styleRenderType
}
HifiControls.Label {

View file

@ -39,6 +39,8 @@ FocusScope {
property alias text: loginKeyboard.mirroredText
property int titleWidth: 0
property alias bannerWidth: banner.width
property alias bannerHeight: banner.height
property string iconText: hifi.glyphs.avatar
property int iconSize: 35
@ -90,10 +92,36 @@ FocusScope {
}
Image {
z: -10
id: loginDialogBackground
source: "../LoginDialog/background.png"
source: "../LoginDialog/background_tablet.jpg"
anchors.fill: parent
z: -2
}
Item {
z: -5
id: bannerContainer
width: parent.width
height: banner.height
anchors {
top: parent.top
topMargin: 0.18 * parent.height
}
Image {
id: banner
anchors.centerIn: parent
source: "../../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
Rectangle {
z: -6
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.5
color: "black"
}
HifiControlsUit.Keyboard {
@ -143,7 +171,7 @@ FocusScope {
}
Component.onCompleted: {
bodyLoader.setSource("../LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
keyboardTimer.start();
bodyLoader.setSource("../LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
}
}

View file

@ -1,84 +0,0 @@
//
// LoginScreenDialog.qml
//
// Created by Wayne Chen on 2018/10/9
// Copyright 2018 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
//
import Hifi 1.0
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 as OriginalStyles
import "qrc:///controls-uit" as HifiControlsUit
import "qrc:///styles-uit" as HifiStylesUit
LoginDialog {
id: loginDialog
Loader {
id: bodyLoader
Item {
function login() {
flavorText.visible = false
mainTextContainer.visible = false
toggleLoading(true)
loginDialog.login(usernameField.text, passwordField.text)
}
Connections {
target: loginScreenDialog
onHandleLoginCompleted: {
console.log("Login Succeeded, linking steam account")
var poppedUp = Settings.getValue("loginDialogPoppedUp", false);
if (poppedUp) {
console.log("[ENCOURAGELOGINDIALOG]: logging in")
var data = {
"action": "user logged in"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
Settings.setValue("loginDialogPoppedUp", false);
}
if (loginDialog.isSteamRunning()) {
loginDialog.linkSteam()
} else {
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
onHandleLoginFailed: {
console.log("Login Failed")
var poppedUp = Settings.getValue("loginDialogPoppedUp", false);
if (poppedUp) {
console.log("[ENCOURAGELOGINDIALOG]: failed logging in")
var data = {
"action": "user failed logging in"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
Settings.setValue("loginDialogPoppedUp", false);
}
flavorText.visible = true
mainTextContainer.visible = true
toggleLoading(false)
}
onHandleLinkCompleted: {
console.log("Link Succeeded")
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
onHandleLinkFailed: {
console.log("Link Failed")
toggleLoading(false)
}
}
}
}
}

View file

@ -207,12 +207,12 @@ Flickable {
width: 112
label: "Y Offset"
suffix: " cm"
minimumValue: -10
minimumValue: -50
maximumValue: 50
realStepSize: 1
realValue: -5
colorScheme: hifi.colorSchemes.dark
onEditingFinished: {
onRealValueChanged: {
sendConfigurationSettings();
openVrConfiguration.forceActiveFocus();
}
@ -223,14 +223,14 @@ Flickable {
id: headZOffset
width: 112
label: "Z Offset"
minimumValue: -10
minimumValue: -50
maximumValue: 50
realStepSize: 1
decimals: 1
suffix: " cm"
realValue: -5
colorScheme: hifi.colorSchemes.dark
onEditingFinished: {
onRealValueChanged: {
sendConfigurationSettings();
openVrConfiguration.forceActiveFocus();
}
@ -319,11 +319,12 @@ Flickable {
width: 112
suffix: " cm"
label: "Y Offset"
minimumValue: -10
minimumValue: -30
maximumValue: 30
realStepSize: 1
colorScheme: hifi.colorSchemes.dark
onEditingFinished: {
onRealValueChanged: {
sendConfigurationSettings();
openVrConfiguration.forceActiveFocus();
}
@ -335,12 +336,13 @@ Flickable {
width: 112
label: "Z Offset"
suffix: " cm"
minimumValue: -10
minimumValue: -30
maximumValue: 30
realStepSize: 1
decimals: 1
colorScheme: hifi.colorSchemes.dark
onEditingFinished: {
onRealValueChanged: {
sendConfigurationSettings();
openVrConfiguration.forceActiveFocus();
}
@ -574,7 +576,7 @@ Flickable {
colorScheme: hifi.colorSchemes.dark
realValue: 33.0
onEditingFinished: {
onRealValueChanged: {
sendConfigurationSettings();
openVrConfiguration.forceActiveFocus();
}
@ -592,7 +594,7 @@ Flickable {
colorScheme: hifi.colorSchemes.dark
realValue: 48
onEditingFinished: {
onRealValueChanged: {
sendConfigurationSettings();
openVrConfiguration.forceActiveFocus();
}
@ -771,7 +773,7 @@ Flickable {
realStepSize: 1.0
colorScheme: hifi.colorSchemes.dark
onEditingFinished: {
onRealValueChanged: {
calibrationTimer.interval = realValue * 1000;
openVrConfiguration.countDown = realValue;
numberAnimation.duration = calibrationTimer.interval;
@ -977,6 +979,13 @@ Flickable {
var configurationType = settings["trackerConfiguration"];
displayTrackerConfiguration(configurationType);
// default offset for user wearing puck on the center of their forehead.
headYOffset.realValue = 4; // (cm), puck is above the head joint.
headZOffset.realValue = 8; // (cm), puck is in front of the head joint.
// defaults for user wearing the pucks on the backs of their palms.
handYOffset.realValue = 8; // (cm), puck is past the the hand joint. (set this to zero if puck is on the wrist)
handZOffset.realValue = -4; // (cm), puck is on above hand joint.
var HmdHead = settings["HMDHead"];
var viveController = settings["handController"];

View file

@ -61,7 +61,7 @@ Item {
RalewaySemiBold {
text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in")
horizontalAlignment: Text.AlignRight
anchors.right: parent.right
Layout.alignment: Qt.AlignRight
font.pixelSize: 20
color: "#afafaf"
}
@ -71,7 +71,7 @@ Item {
height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0
text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : ""
horizontalAlignment: Text.AlignRight
anchors.right: parent.right
Layout.alignment: Qt.AlignRight
font.pixelSize: 20
color: "#afafaf"
}

View file

@ -87,7 +87,6 @@
#include <FramebufferCache.h>
#include <gpu/Batch.h>
#include <gpu/Context.h>
#include <gpu/gl/GLBackend.h>
#include <InfoView.h>
#include <input-plugins/InputPlugin.h>
#include <controllers/UserInputMapper.h>
@ -122,8 +121,6 @@
#include <plugins/SteamClientPlugin.h>
#include <plugins/InputConfiguration.h>
#include <RecordingScriptingInterface.h>
#include <UpdateSceneTask.h>
#include <RenderViewTask.h>
#include <render/EngineStats.h>
#include <SecondaryCamera.h>
#include <ResourceCache.h>
@ -264,54 +261,7 @@ extern "C" {
#include "AndroidHelper.h"
#endif
enum ApplicationEvent {
// Execute a lambda function
Lambda = QEvent::User + 1,
// Trigger the next render
Render,
// Trigger the next idle
Idle,
};
class RenderEventHandler : public QObject {
using Parent = QObject;
Q_OBJECT
public:
RenderEventHandler() {
// Transfer to a new thread
moveToNewNamedThread(this, "RenderThread", [](QThread* renderThread) {
hifi::qt::addBlockingForbiddenThread("Render", renderThread);
qApp->_lastTimeRendered.start();
}, std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority);
}
private:
void initialize() {
setObjectName("Render");
PROFILE_SET_THREAD_NAME("Render");
setCrashAnnotation("render_thread_id", std::to_string((size_t)QThread::currentThreadId()));
}
void render() {
if (qApp->shouldPaint()) {
qApp->paintGL();
}
}
bool event(QEvent* event) override {
switch ((int)event->type()) {
case ApplicationEvent::Render:
render();
qApp->_pendingRenderEvent.store(false);
return true;
default:
break;
}
return Parent::event(event);
}
};
#include "graphics/RenderEventHandler.h"
Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse")
@ -374,8 +324,6 @@ static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SI
static const int ENTITY_SERVER_ADDED_TIMEOUT = 5000;
static const int ENTITY_SERVER_CONNECTION_TIMEOUT = 5000;
static const uint32_t INVALID_FRAME = UINT32_MAX;
static const float INITIAL_QUERY_RADIUS = 10.0f; // priority radius for entities before physics enabled
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
@ -385,6 +333,10 @@ Setting::Handle<int> maxOctreePacketsPerSecond{"maxOctreePPS", DEFAULT_MAX_OCTRE
Setting::Handle<bool> loginDialogPoppedUp{"loginDialogPoppedUp", false};
static const QUrl OVERLAY_LOGIN_DIALOG_URL(PathUtils::qmlUrl("OverlayLoginDialog.qml"));
static const QString STANDARD_TO_ACTION_MAPPING_NAME = "Standard to Action";
static const QString NO_MOVEMENT_MAPPING_NAME = "Standard to Action (No Movement)";
static const QString NO_MOVEMENT_MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/standard_nomovement.json";
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";
@ -1813,6 +1765,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
userInputMapper->registerDevice(_touchscreenVirtualPadDevice->getInputDevice());
}
QString scriptsSwitch = QString("--").append(SCRIPTS_SWITCH);
_defaultScriptsLocation = getCmdOption(argc, constArgv, scriptsSwitch.toStdString().c_str());
// Make sure we don't time out during slow operations at startup
updateHeartbeat();
@ -1834,8 +1789,18 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(offscreenUi.data(), &OffscreenUi::keyboardFocusActive, [this]() {
#if !defined(Q_OS_ANDROID)
// Do not show login dialog if requested not to on the command line
QString hifiNoLoginCommandLineKey = QString("--").append(HIFI_NO_LOGIN_COMMAND_LINE_KEY);
int index = arguments().indexOf(hifiNoLoginCommandLineKey);
if (index != -1) {
resumeAfterLoginDialogActionTaken();
return;
}
// only for non-android. QML is ready to be shown at this time.
showLoginScreen();
#else
resumeAfterLoginDialogActionTaken();
#endif
});
@ -2071,7 +2036,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
auto displayPlugin = qApp->getActiveDisplayPlugin();
properties["render_rate"] = _renderLoopCounter.rate();
properties["render_rate"] = getRenderLoopRate();
properties["target_render_rate"] = getTargetRenderFrameRate();
properties["present_rate"] = displayPlugin->presentRate();
properties["new_frame_present_rate"] = displayPlugin->newFramePresentRate();
@ -2360,7 +2325,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
DependencyManager::get<Keyboard>()->createKeyboard();
_pendingIdleEvent = false;
_pendingRenderEvent = false;
_graphicsEngine.startup();
qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID());
@ -2369,17 +2334,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(&AndroidHelper::instance(), &AndroidHelper::enterBackground, this, &Application::enterBackground);
connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground);
AndroidHelper::instance().notifyLoadComplete();
#else
#if !defined(DISABLE_QML)
// Do not show login dialog if requested not to on the command line
const QString HIFI_NO_LOGIN_COMMAND_LINE_KEY = "--no-login-suggestion";
int index = arguments().indexOf(HIFI_NO_LOGIN_COMMAND_LINE_KEY);
if (index == -1) {
// request not found
pauseUntilLoginDetermined();
}
#endif
#endif
pauseUntilLoginDetermined();
}
void Application::updateVerboseLogging() {
@ -2544,6 +2500,8 @@ void Application::cleanupBeforeQuit() {
QString webengineRemoteDebugging = QProcessEnvironment::systemEnvironment().value("QTWEBENGINE_REMOTE_DEBUGGING", "false");
qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebugging;
DependencyManager::prepareToExit();
if (tracing::enabled()) {
auto tracer = DependencyManager::get<tracing::Tracer>();
tracer->stopTracing();
@ -2612,11 +2570,6 @@ void Application::cleanupBeforeQuit() {
// Cleanup all overlays after the scripts, as scripts might add more
_overlays.cleanupAllOverlays();
// The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual
// removal of the items.
// See https://highfidelity.fogbugz.com/f/cases/5328
_main3DScene->enqueueFrame(); // flush all the transactions
_main3DScene->processTransactionQueue(); // process and apply deletions
// first stop all timers directly or by invokeMethod
// depending on what thread they run in
@ -2631,7 +2584,6 @@ void Application::cleanupBeforeQuit() {
}
_window->saveGeometry();
_gpuContext->shutdown();
// Destroy third party processes after scripts have finished using them.
#ifdef HAVE_DDE
@ -2656,6 +2608,7 @@ void Application::cleanupBeforeQuit() {
// destroy Audio so it and its threads have a chance to go down safely
// this must happen after QML, as there are unexplained audio crashes originating in qtwebengine
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "stop");
DependencyManager::destroy<AudioClient>();
DependencyManager::destroy<AudioInjectorManager>();
DependencyManager::destroy<AudioScriptingInterface>();
@ -2688,10 +2641,9 @@ Application::~Application() {
_shapeManager.collectGarbage();
assert(_shapeManager.getNumShapes() == 0);
// shutdown render engine
_main3DScene = nullptr;
_renderEngine = nullptr;
// shutdown graphics engine
_graphicsEngine.shutdown();
_gameWorkload.shutdown();
DependencyManager::destroy<Preferences>();
@ -2747,10 +2699,8 @@ Application::~Application() {
// quit the thread used by the closure event sender
closeEventSender->thread()->quit();
// Can't log to file passed this point, FileLogger about to be deleted
// Can't log to file past this point, FileLogger about to be deleted
qInstallMessageHandler(LogHandler::verboseMessageHandler);
_renderEventHandler->deleteLater();
}
void Application::initializeGL() {
@ -2840,26 +2790,13 @@ void Application::initializeGL() {
#endif
_renderEventHandler = new RenderEventHandler();
// Build an offscreen GL context for the main thread.
_glWidget->makeCurrent();
glClearColor(0.2f, 0.2f, 0.2f, 1);
glClear(GL_COLOR_BUFFER_BIT);
_glWidget->swapBuffers();
// Create the GPU backend
// Requires the window context, because that's what's used in the actual rendering
// and the GPU backend will make things like the VAO which cannot be shared across
// contexts
_glWidget->makeCurrent();
gpu::Context::init<gpu::gl::GLBackend>();
_glWidget->makeCurrent();
_gpuContext = std::make_shared<gpu::Context>();
DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext);
_graphicsEngine.initializeGPU(_glWidget);
}
static const QString SPLASH_SKYBOX{ "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" };
@ -2873,7 +2810,7 @@ void Application::initializeDisplayPlugins() {
// Once time initialization code
DisplayPluginPointer targetDisplayPlugin;
foreach(auto displayPlugin, displayPlugins) {
displayPlugin->setContext(_gpuContext);
displayPlugin->setContext(_graphicsEngine.getGPUContext());
if (displayPlugin->getName() == lastActiveDisplayPluginName) {
targetDisplayPlugin = displayPlugin;
}
@ -2943,18 +2880,7 @@ void Application::initializeDisplayPlugins() {
void Application::initializeRenderEngine() {
// FIXME: on low end systems os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread.
DeadlockWatchdogThread::withPause([&] {
// Set up the render engine
render::CullFunctor cullFunctor = LODManager::shouldRender;
_renderEngine->addJob<UpdateSceneTask>("UpdateScene");
#ifndef Q_OS_ANDROID
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
#endif
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
_renderEngine->load();
_renderEngine->registerScene(_main3DScene);
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
_graphicsEngine.initializeRender(DISABLE_DEFERRED);
DependencyManager::get<Keyboard>()->registerKeyboardHighlighting();
});
}
@ -2965,6 +2891,7 @@ static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, in
#endif
void Application::showLoginScreen() {
#if !defined(DISABLE_QML)
auto accountManager = DependencyManager::get<AccountManager>();
auto dialogsManager = DependencyManager::get<DialogsManager>();
if (!accountManager->isLoggedIn()) {
@ -2983,6 +2910,9 @@ void Application::showLoginScreen() {
}
_loginDialogPoppedUp = !accountManager->isLoggedIn();
loginDialogPoppedUp.set(_loginDialogPoppedUp);
#else
resumeAfterLoginDialogActionTaken();
#endif
}
void Application::initializeUi() {
@ -3176,7 +3106,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
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("FrameTimings", &_graphicsEngine._frameTimingsScriptingInterface);
surfaceContext->setContextProperty("Rates", new RatesScriptingInterface(this));
surfaceContext->setContextProperty("TREE_SCALE", TREE_SCALE);
@ -3225,7 +3155,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
surfaceContext->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
surfaceContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
surfaceContext->setContextProperty("Scene", DependencyManager::get<SceneScriptingInterface>().data());
surfaceContext->setContextProperty("Render", _renderEngine->getConfiguration().get());
surfaceContext->setContextProperty("Render", _graphicsEngine.getRenderEngine()->getConfiguration().get());
surfaceContext->setContextProperty("Workload", _gameWorkload._engine->getConfiguration().get());
surfaceContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
surfaceContext->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
@ -3513,7 +3443,7 @@ void Application::resizeGL() {
auto renderResolutionScale = getRenderResolutionScale();
if (displayPlugin->getRenderResolutionScale() != renderResolutionScale) {
auto renderConfig = _renderEngine->getConfiguration();
auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
assert(renderConfig);
auto mainView = renderConfig->getConfig("RenderMainView.RenderDeferredTask");
assert(mainView);
@ -3763,8 +3693,8 @@ void Application::onPresent(quint32 frameCount) {
postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority);
}
expected = false;
if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEvent.compare_exchange_strong(expected, true)) {
postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render));
if (_graphicsEngine.checkPendingRenderEvent() && !isAboutToQuit()) {
postEvent(_graphicsEngine._renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render));
}
}
@ -3859,7 +3789,7 @@ bool Application::event(QEvent* event) {
}
// Allow focused Entities and Overlays to handle keyboard input
if (isKeyEvent(event->type()) && handleKeyEventForFocusedEntityOrOverlay(event)) {
if (isKeyEvent(event->type()) && handleKeyEventForFocusedEntityOrOverlay(event) && !qApp->getLoginDialogPoppedUp()) {
return true;
}
@ -3972,6 +3902,10 @@ bool Application::eventFilter(QObject* object, QEvent* event) {
static bool _altPressed{ false };
void Application::keyPressEvent(QKeyEvent* event) {
if (isHMDMode() && qApp->getLoginDialogPoppedUp()) {
return;
}
_altPressed = event->key() == Qt::Key_Alt;
if (!event->isAutoRepeat()) {
@ -4215,6 +4149,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
}
void Application::keyReleaseEvent(QKeyEvent* event) {
if (isHMDMode() && qApp->getLoginDialogPoppedUp()) {
return;
}
if (!event->isAutoRepeat()) {
_keysPressed.remove(event->key());
}
@ -4579,39 +4517,6 @@ bool Application::acceptSnapshot(const QString& urlString) {
return true;
}
static uint32_t _renderedFrameIndex { INVALID_FRAME };
bool Application::shouldPaint() const {
if (_aboutToQuit || _window->isMinimized()) {
return false;
}
auto displayPlugin = getActiveDisplayPlugin();
#ifdef DEBUG_PAINT_DELAY
static uint64_t paintDelaySamples{ 0 };
static uint64_t paintDelayUsecs{ 0 };
paintDelayUsecs += displayPlugin->getPaintDelayUsecs();
static const int PAINT_DELAY_THROTTLE = 1000;
if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) {
qCDebug(interfaceapp).nospace() <<
"Paint delay (" << paintDelaySamples << " samples): " <<
(float)paintDelaySamples / paintDelayUsecs << "us";
}
#endif
// Throttle if requested
if (displayPlugin->isThrottled() && (_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
return false;
}
// Sync up the _renderedFrameIndex
_renderedFrameIndex = displayPlugin->presentCount();
return true;
}
#ifdef Q_OS_WIN
#include <Windows.h>
#include <TCHAR.h>
@ -4865,26 +4770,13 @@ void Application::idle() {
if (displayPlugin) {
PROFILE_COUNTER_IF_CHANGED(app, "present", float, displayPlugin->presentRate());
}
PROFILE_COUNTER_IF_CHANGED(app, "renderLoopRate", float, _renderLoopCounter.rate());
PROFILE_COUNTER_IF_CHANGED(app, "currentDownloads", uint32_t, ResourceCache::getLoadingRequestCount());
PROFILE_COUNTER_IF_CHANGED(app, "renderLoopRate", float, getRenderLoopRate());
PROFILE_COUNTER_IF_CHANGED(app, "currentDownloads", uint32_t, ResourceCache::getLoadingRequests().length());
PROFILE_COUNTER_IF_CHANGED(app, "pendingDownloads", uint32_t, ResourceCache::getPendingRequestCount());
PROFILE_COUNTER_IF_CHANGED(app, "currentProcessing", int, DependencyManager::get<StatTracker>()->getStat("Processing").toInt());
PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, DependencyManager::get<StatTracker>()->getStat("PendingProcessing").toInt());
auto renderConfig = _renderEngine->getConfiguration();
PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_gpuContext->getFrameTimerGPUAverage());
auto opaqueRangeTimer = renderConfig->getConfig("OpaqueRangeTimer");
auto linearDepth = renderConfig->getConfig("LinearDepth");
auto surfaceGeometry = renderConfig->getConfig("SurfaceGeometry");
auto renderDeferred = renderConfig->getConfig("RenderDeferred");
auto toneAndPostRangeTimer = renderConfig->getConfig("ToneAndPostRangeTimer");
PROFILE_COUNTER(render_detail, "gpuTimes", {
{ "OpaqueRangeTimer", opaqueRangeTimer ? opaqueRangeTimer->property("gpuRunTime") : 0 },
{ "LinearDepth", linearDepth ? linearDepth->property("gpuRunTime") : 0 },
{ "SurfaceGeometry", surfaceGeometry ? surfaceGeometry->property("gpuRunTime") : 0 },
{ "RenderDeferred", renderDeferred ? renderDeferred->property("gpuRunTime") : 0 },
{ "ToneAndPostRangeTimer", toneAndPostRangeTimer ? toneAndPostRangeTimer->property("gpuRunTime") : 0 }
});
auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_graphicsEngine.getGPUContext()->getFrameTimerGPUAverage());
PROFILE_RANGE(app, __FUNCTION__);
@ -5258,9 +5150,6 @@ void Application::init() {
#if !defined(DISABLE_QML)
DependencyManager::get<DialogsManager>()->toggleLoginDialog();
#endif
if (!DISABLE_DEFERRED) {
DependencyManager::get<DeferredLightingEffect>()->init();
}
DependencyManager::get<AvatarManager>()->init();
_timerStart.start();
@ -5329,7 +5218,7 @@ void Application::init() {
}
}, Qt::QueuedConnection);
_gameWorkload.startup(getEntities()->getWorkloadSpace(), _main3DScene, _entitySimulation);
_gameWorkload.startup(getEntities()->getWorkloadSpace(), _graphicsEngine.getRenderScene(), _entitySimulation);
_entitySimulation->setWorkloadSpace(getEntities()->getWorkloadSpace());
}
@ -5340,7 +5229,14 @@ void Application::pauseUntilLoginDetermined() {
}
getMyAvatar()->setEnableMeshVisible(false);
_controllerScriptingInterface->disableMapping("Standard to Action");
_controllerScriptingInterface->disableMapping(STANDARD_TO_ACTION_MAPPING_NAME);
{
auto userInputMapper = DependencyManager::get<UserInputMapper>();
if (userInputMapper->loadMapping(NO_MOVEMENT_MAPPING_JSON)) {
_controllerScriptingInterface->enableMapping(NO_MOVEMENT_MAPPING_NAME);
}
}
const auto& nodeList = DependencyManager::get<NodeList>();
// save interstitial mode setting until resuming.
@ -5371,7 +5267,7 @@ void Application::resumeAfterLoginDialogActionTaken() {
return;
}
if (!isHMDMode()) {
if (!isHMDMode() && getDesktopTabletBecomesToolbarSetting()) {
auto toolbar = DependencyManager::get<ToolbarScriptingInterface>()->getToolbar("com.highfidelity.interface.toolbar.system");
toolbar->writeProperty("visible", true);
} else {
@ -5381,8 +5277,13 @@ void Application::resumeAfterLoginDialogActionTaken() {
updateSystemTabletMode();
{
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->unloadMapping(NO_MOVEMENT_MAPPING_JSON);
_controllerScriptingInterface->disableMapping(NO_MOVEMENT_MAPPING_NAME);
}
getMyAvatar()->setEnableMeshVisible(true);
_controllerScriptingInterface->enableMapping("Standard to Action");
_controllerScriptingInterface->enableMapping(STANDARD_TO_ACTION_MAPPING_NAME);
const auto& nodeList = DependencyManager::get<NodeList>();
nodeList->getDomainHandler().setInterstitialModeEnabled(_interstitialModeEnabled);
@ -5391,7 +5292,12 @@ void Application::resumeAfterLoginDialogActionTaken() {
// this will force the model the look at the correct directory (weird order of operations issue)
scriptEngines->reloadLocalFiles();
scriptEngines->loadScripts();
if (!_defaultScriptsLocation.exists()) {
scriptEngines->loadDefaultScripts();
scriptEngines->defaultScriptsLocationOverridden(true);
} else {
scriptEngines->loadScripts();
}
}
if (_firstRun.get()) {
@ -5466,7 +5372,7 @@ void Application::updateLOD(float deltaTime) const {
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
if (!isThrottleRendering()) {
float presentTime = getActiveDisplayPlugin()->getAveragePresentTime();
float engineRunTime = (float)(_renderEngine->getConfiguration().get()->getCPURunTime());
float engineRunTime = (float)(_graphicsEngine.getRenderEngine()->getConfiguration().get()->getCPURunTime());
float gpuTime = getGPUContext()->getFrameTimerGPUAverage();
float batchTime = getGPUContext()->getFrameTimerBatchAverage();
auto lodManager = DependencyManager::get<LODManager>();
@ -5846,6 +5752,9 @@ void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) {
_keyboardFocusHighlight->setVisible(false);
}
}
if (overlayID == _loginDialogOverlayID) {
emit loginDialogFocusEnabled();
}
}
}
@ -5867,7 +5776,7 @@ void Application::updateSecondaryCameraViewFrustum() {
// camera should be.
// Code based on SecondaryCameraJob
auto renderConfig = _renderEngine->getConfiguration();
auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
assert(renderConfig);
auto camera = dynamic_cast<SecondaryCameraJobConfig*>(renderConfig->getConfig("SecondaryCamera"));
@ -5936,7 +5845,7 @@ void Application::updateSecondaryCameraViewFrustum() {
static bool domainLoadingInProgress = false;
void Application::update(float deltaTime) {
PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_renderFrameCount + 1);
PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_graphicsEngine._renderFrameCount + 1);
if (_aboutToQuit) {
return;
@ -6355,7 +6264,7 @@ void Application::update(float deltaTime) {
// TODO: Fix this by modeling the way the secondary camera works on how the main camera works
// ie. Use a camera object stored in the game logic and informs the Engine on where the secondary
// camera should be.
updateSecondaryCameraViewFrustum();
// updateSecondaryCameraViewFrustum();
}
quint64 now = usecTimestampNow();
@ -6431,13 +6340,6 @@ void Application::update(float deltaTime) {
updateRenderArgs(deltaTime);
// HACK
// load the view frustum
// FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering.
// Then we can move this logic into the Avatar::simulate call.
myAvatar->preDisplaySide(&_appRenderArgs._renderArgs);
{
PerformanceTimer perfTimer("AnimDebugDraw");
AnimDebugDraw::getInstance().update();
@ -6448,10 +6350,15 @@ void Application::update(float deltaTime) {
PerformanceTimer perfTimer("enqueueFrame");
getMain3DScene()->enqueueFrame();
}
// If the display plugin is inactive then the frames won't be processed so process them here.
if (!getActiveDisplayPlugin()->isActive()) {
getMain3DScene()->processTransactionQueue();
}
}
void Application::updateRenderArgs(float deltaTime) {
editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) {
_graphicsEngine.editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) {
PerformanceTimer perfTimer("editRenderArgs");
appRenderArgs._headPose = getHMDSensorPose();
@ -6480,7 +6387,7 @@ void Application::updateRenderArgs(float deltaTime) {
_viewFrustum.setProjection(adjustedProjection);
_viewFrustum.calculate();
}
appRenderArgs._renderArgs = RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(),
appRenderArgs._renderArgs = RenderArgs(_graphicsEngine.getGPUContext(), lodManager->getOctreeSizeScale(),
lodManager->getBoundaryLevelAdjust(), lodManager->getLODAngleHalfTan(), RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
appRenderArgs._renderArgs._scene = getMain3DScene();
@ -6565,6 +6472,13 @@ void Application::updateRenderArgs(float deltaTime) {
QMutexLocker viewLocker(&_viewMutex);
appRenderArgs._renderArgs.setViewFrustum(_displayViewFrustum);
}
// HACK
// load the view frustum
// FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering.
// Then we can move this logic into the Avatar::simulate call.
myAvatar->preDisplaySide(&appRenderArgs._renderArgs);
});
}
@ -7168,7 +7082,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerFunction("HMD", "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0);
scriptEngine->registerGlobalObject("Scene", DependencyManager::get<SceneScriptingInterface>().data());
scriptEngine->registerGlobalObject("Render", _renderEngine->getConfiguration().get());
scriptEngine->registerGlobalObject("Render", _graphicsEngine.getRenderEngine()->getConfiguration().get());
scriptEngine->registerGlobalObject("Workload", _gameWorkload._engine->getConfiguration().get());
GraphicsScriptingInterface::registerMetaTypes(scriptEngine.data());
@ -8741,6 +8655,7 @@ void Application::createLoginDialogOverlay() {
overlays.editOverlay(keyboard->getAnchorID(), properties);
keyboard->setResetKeyboardPositionOnRaise(false);
}
setKeyboardFocusOverlay(_loginDialogOverlayID);
getApplicationCompositor().getReticleInterface()->setAllowMouseCapture(false);
getApplicationCompositor().getReticleInterface()->setVisible(false);
if (!_loginStateManager.isSetUp()) {
@ -8749,11 +8664,13 @@ void Application::createLoginDialogOverlay() {
}
void Application::updateLoginDialogOverlayPosition() {
auto overlayPosition = getOverlays().getProperty(_loginDialogOverlayID, "position");
const float LOOK_AWAY_THRESHOLD_ANGLE = 40.0f;
auto& overlays = getOverlays();
auto overlayPosition = overlays.getProperty(_loginDialogOverlayID, "position");
auto overlayPositionVec = vec3FromVariant(overlayPosition.value);
auto cameraPositionVec = _myCamera.getPosition();
auto cameraOrientation = _myCamera.getOrientation();
cameraOrientation = cancelOutRollAndPitch(cameraOrientation);
cameraOrientation = cancelOutRoll(cameraOrientation);
auto headLookVec = (cameraOrientation * Vectors::FRONT);
auto overlayToHeadVec = overlayPositionVec - cameraPositionVec;
auto pointAngle = (glm::acos(glm::dot(glm::normalize(overlayToHeadVec), glm::normalize(headLookVec))) * 180.0f / PI);
@ -8762,12 +8679,12 @@ void Application::updateLoginDialogOverlayPosition() {
auto newOverlayPositionVec = (cameraPositionVec + offset) + (upVec * -0.1f);
auto newOverlayOrientation = glm::inverse(glm::quat_cast(glm::lookAt(newOverlayPositionVec, cameraPositionVec, upVec))) * Quaternions::Y_180;
if (pointAngle > 40.0f) {
if (pointAngle > LOOK_AWAY_THRESHOLD_ANGLE) {
QVariantMap properties {
{"position", vec3toVariant(newOverlayPositionVec)},
{"orientation", quatToVariant(newOverlayOrientation)}
};
getOverlays().editOverlay(_loginDialogOverlayID, properties);
overlays.editOverlay(_loginDialogOverlayID, properties);
}
}

View file

@ -71,11 +71,11 @@
#include "ui/overlays/Overlays.h"
#include "workload/GameWorkload.h"
#include "graphics/GraphicsEngine.h"
#include <procedural/ProceduralSkybox.h>
#include <graphics/Skybox.h>
#include <ModelScriptingInterface.h>
#include "FrameTimingsScriptingInterface.h"
#include "Sound.h"
@ -98,6 +98,8 @@ static const UINT UWM_SHOW_APPLICATION =
#endif
static const QString RUNNING_MARKER_FILENAME = "Interface.running";
static const QString SCRIPTS_SWITCH = "scripts";
static const QString HIFI_NO_LOGIN_COMMAND_LINE_KEY = "no-login-suggestion";
class Application;
#if defined(qApp)
@ -153,7 +155,6 @@ public:
void updateSecondaryCameraViewFrustum();
void updateCamera(RenderArgs& renderArgs, float deltaTime);
void paintGL();
void resizeGL();
bool event(QEvent* event) override;
@ -203,8 +204,8 @@ public:
Overlays& getOverlays() { return _overlays; }
size_t getRenderFrameCount() const { return _renderFrameCount; }
float getRenderLoopRate() const { return _renderLoopCounter.rate(); }
size_t getRenderFrameCount() const { return _graphicsEngine.getRenderFrameCount(); }
float getRenderLoopRate() const { return _graphicsEngine.getRenderLoopRate(); }
float getNumCollisionObjects() const;
float getTargetRenderFrameRate() const; // frames/second
@ -275,10 +276,10 @@ public:
void setMaxOctreePacketsPerSecond(int maxOctreePPS);
int getMaxOctreePacketsPerSecond() const;
render::ScenePointer getMain3DScene() override { return _main3DScene; }
const render::ScenePointer& getMain3DScene() const { return _main3DScene; }
render::EnginePointer getRenderEngine() override { return _renderEngine; }
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
render::ScenePointer getMain3DScene() override { return _graphicsEngine.getRenderScene(); }
render::EnginePointer getRenderEngine() override { return _graphicsEngine.getRenderEngine(); }
gpu::ContextPointer getGPUContext() const { return _graphicsEngine.getGPUContext(); }
const GameWorkload& getGameWorkload() const { return _gameWorkload; }
@ -344,6 +345,8 @@ signals:
void interstitialModeChanged(bool isInInterstitialMode);
void loginDialogFocusEnabled();
void miniTabletEnabledChanged(bool enabled);
public slots:
@ -526,7 +529,6 @@ private:
bool handleFileOpenEvent(QFileOpenEvent* event);
void cleanupBeforeQuit();
bool shouldPaint() const;
void idle();
void update(float deltaTime);
@ -546,8 +548,6 @@ private:
void initializeAcceptedFiles();
void runRenderFrame(RenderArgs* renderArgs/*, Camera& whichCamera, bool selfAvatarOnly = false*/);
bool importJSONFromURL(const QString& urlString);
bool importSVOFromURL(const QString& urlString);
bool importFromZIP(const QString& filePath);
@ -597,18 +597,12 @@ private:
bool _activatingDisplayPlugin { false };
uint32_t _renderFrameCount { 0 };
// Frame Rate Measurement
RateCounter<500> _renderLoopCounter;
RateCounter<500> _gameLoopCounter;
FrameTimingsScriptingInterface _frameTimingsScriptingInterface;
QTimer _minimizedWindowTimer;
QElapsedTimer _timerStart;
QElapsedTimer _lastTimeUpdated;
QElapsedTimer _lastTimeRendered;
int _minimumGPUTextureMemSizeStabilityCount { 30 };
@ -672,6 +666,7 @@ private:
ControllerScriptingInterface* _controllerScriptingInterface{ nullptr };
QPointer<LogDialog> _logDialog;
QPointer<EntityScriptServerLogDialog> _entityScriptServerLogDialog;
QDir _defaultScriptsLocation;
FileLogger* _logger;
@ -703,29 +698,9 @@ private:
quint64 _lastFaceTrackerUpdate;
render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) };
render::EnginePointer _renderEngine{ new render::RenderEngine() };
gpu::ContextPointer _gpuContext; // initialized during window creation
GameWorkload _gameWorkload;
mutable QMutex _renderArgsMutex{ QMutex::Recursive };
struct AppRenderArgs {
render::Args _renderArgs;
glm::mat4 _eyeToWorld;
glm::mat4 _view;
glm::mat4 _eyeOffsets[2];
glm::mat4 _eyeProjections[2];
glm::mat4 _headPose;
glm::mat4 _sensorToWorld;
float _sensorToWorldScale { 1.0f };
bool _isStereo{ false };
};
AppRenderArgs _appRenderArgs;
using RenderArgsEditor = std::function <void (AppRenderArgs&)>;
void editRenderArgs(RenderArgsEditor editor);
GraphicsEngine _graphicsEngine;
void updateRenderArgs(float deltaTime);
@ -771,8 +746,6 @@ private:
bool _keyboardDeviceHasFocus { true };
QString _returnFromFullScreenMirrorTo;
ConnectionMonitor _connectionMonitor;
QTimer _addAssetToWorldResizeTimer;
@ -806,12 +779,8 @@ private:
QUrl _avatarOverrideUrl;
bool _saveAvatarOverrideUrl { false };
QObject* _renderEventHandler{ nullptr };
friend class RenderEventHandler;
std::atomic<bool> _pendingIdleEvent { true };
std::atomic<bool> _pendingRenderEvent { true };
bool quitWhenFinished { false };

View file

@ -19,220 +19,207 @@
#include "Util.h"
// Statically provided display and input plugins
extern DisplayPluginList getDisplayPlugins();
void Application::editRenderArgs(RenderArgsEditor editor) {
QMutexLocker renderLocker(&_renderArgsMutex);
editor(_appRenderArgs);
}
void Application::paintGL() {
// Some plugins process message events, allowing paintGL to be called reentrantly.
_renderFrameCount++;
_lastTimeRendered.start();
auto lastPaintBegin = usecTimestampNow();
PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_renderFrameCount);
PerformanceTimer perfTimer("paintGL");
if (nullptr == _displayPlugin) {
return;
}
DisplayPluginPointer displayPlugin;
{
PROFILE_RANGE(render, "/getActiveDisplayPlugin");
displayPlugin = getActiveDisplayPlugin();
}
{
PROFILE_RANGE(render, "/pluginBeginFrameRender");
// If a display plugin loses it's underlying support, it
// needs to be able to signal us to not use it
if (!displayPlugin->beginFrameRender(_renderFrameCount)) {
QMetaObject::invokeMethod(this, "updateDisplayMode");
return;
}
}
RenderArgs renderArgs;
glm::mat4 HMDSensorPose;
glm::mat4 eyeToWorld;
glm::mat4 sensorToWorld;
bool isStereo;
glm::mat4 stereoEyeOffsets[2];
glm::mat4 stereoEyeProjections[2];
{
QMutexLocker viewLocker(&_renderArgsMutex);
renderArgs = _appRenderArgs._renderArgs;
// don't render if there is no context.
if (!_appRenderArgs._renderArgs._context) {
return;
}
HMDSensorPose = _appRenderArgs._headPose;
eyeToWorld = _appRenderArgs._eyeToWorld;
sensorToWorld = _appRenderArgs._sensorToWorld;
isStereo = _appRenderArgs._isStereo;
for_each_eye([&](Eye eye) {
stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye];
stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye];
});
}
{
PROFILE_RANGE(render, "/gpuContextReset");
_gpuContext->beginFrame(_appRenderArgs._view, HMDSensorPose);
// Reset the gpu::Context Stages
// Back to the default framebuffer;
gpu::doInBatch("Application_render::gpuContextReset", _gpuContext, [&](gpu::Batch& batch) {
batch.resetStages();
});
}
{
PROFILE_RANGE(render, "/renderOverlay");
PerformanceTimer perfTimer("renderOverlay");
// NOTE: There is no batch associated with this renderArgs
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
renderArgs._viewport = glm::ivec4(0, 0, getDeviceSize());
_applicationOverlay.renderOverlay(&renderArgs);
}
{
PROFILE_RANGE(render, "/updateCompositor");
getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld);
}
gpu::FramebufferPointer finalFramebuffer;
QSize finalFramebufferSize;
{
PROFILE_RANGE(render, "/getOutputFramebuffer");
// Primary rendering pass
auto framebufferCache = DependencyManager::get<FramebufferCache>();
finalFramebufferSize = framebufferCache->getFrameBufferSize();
// Final framebuffer that will be handed to the display-plugin
finalFramebuffer = framebufferCache->getFramebuffer();
}
{
if (isStereo) {
renderArgs._context->enableStereo(true);
renderArgs._context->setStereoProjections(stereoEyeProjections);
renderArgs._context->setStereoViews(stereoEyeOffsets);
}
renderArgs._hudOperator = displayPlugin->getHUDOperator();
renderArgs._hudTexture = _applicationOverlay.getOverlayTexture();
renderArgs._blitFramebuffer = finalFramebuffer;
runRenderFrame(&renderArgs);
}
auto frame = _gpuContext->endFrame();
frame->frameIndex = _renderFrameCount;
frame->framebuffer = finalFramebuffer;
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
auto frameBufferCache = DependencyManager::get<FramebufferCache>();
if (frameBufferCache) {
frameBufferCache->releaseFramebuffer(framebuffer);
}
};
// deliver final scene rendering commands to the display plugin
{
PROFILE_RANGE(render, "/pluginOutput");
PerformanceTimer perfTimer("pluginOutput");
_renderLoopCounter.increment();
displayPlugin->submitFrame(frame);
}
// Reset the framebuffer and stereo state
renderArgs._blitFramebuffer.reset();
renderArgs._context->enableStereo(false);
#if !defined(DISABLE_QML)
{
auto stats = Stats::getInstance();
if (stats) {
stats->setRenderDetails(renderArgs._details);
}
}
#endif
uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
_frameTimingsScriptingInterface.addValue(lastPaintDuration);
}
//void Application::paintGL() {
// // Some plugins process message events, allowing paintGL to be called reentrantly.
//
// _renderFrameCount++;
// // SG: Moved into the RenderEventHandler
// //_lastTimeRendered.start();
//
// auto lastPaintBegin = usecTimestampNow();
// PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_renderFrameCount);
// PerformanceTimer perfTimer("paintGL");
//
// if (nullptr == _displayPlugin) {
// return;
// }
//
// DisplayPluginPointer displayPlugin;
// {
// PROFILE_RANGE(render, "/getActiveDisplayPlugin");
// displayPlugin = getActiveDisplayPlugin();
// }
//
// {
// PROFILE_RANGE(render, "/pluginBeginFrameRender");
// // If a display plugin loses it's underlying support, it
// // needs to be able to signal us to not use it
// if (!displayPlugin->beginFrameRender(_renderFrameCount)) {
// QMetaObject::invokeMethod(this, "updateDisplayMode");
// return;
// }
// }
//
// RenderArgs renderArgs;
// glm::mat4 HMDSensorPose;
// glm::mat4 eyeToWorld;
// glm::mat4 sensorToWorld;
//
// bool isStereo;
// glm::mat4 stereoEyeOffsets[2];
// glm::mat4 stereoEyeProjections[2];
//
// {
// QMutexLocker viewLocker(&_renderArgsMutex);
// renderArgs = _appRenderArgs._renderArgs;
//
// // don't render if there is no context.
// if (!_appRenderArgs._renderArgs._context) {
// return;
// }
//
// HMDSensorPose = _appRenderArgs._headPose;
// eyeToWorld = _appRenderArgs._eyeToWorld;
// sensorToWorld = _appRenderArgs._sensorToWorld;
// isStereo = _appRenderArgs._isStereo;
// for_each_eye([&](Eye eye) {
// stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye];
// stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye];
// });
// }
//
// {
// PROFILE_RANGE(render, "/gpuContextReset");
// _graphicsEngine.getGPUContext()->beginFrame(_appRenderArgs._view, HMDSensorPose);
// // Reset the gpu::Context Stages
// // Back to the default framebuffer;
// gpu::doInBatch("Application_render::gpuContextReset", _graphicsEngine.getGPUContext(), [&](gpu::Batch& batch) {
// batch.resetStages();
// });
// }
//
//
// {
// PROFILE_RANGE(render, "/renderOverlay");
// PerformanceTimer perfTimer("renderOverlay");
// // NOTE: There is no batch associated with this renderArgs
// // the ApplicationOverlay class assumes it's viewport is setup to be the device size
// renderArgs._viewport = glm::ivec4(0, 0, getDeviceSize() * getRenderResolutionScale());
// _applicationOverlay.renderOverlay(&renderArgs);
// }
//
// {
// PROFILE_RANGE(render, "/updateCompositor");
// getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld);
// }
//
// gpu::FramebufferPointer finalFramebuffer;
// QSize finalFramebufferSize;
// {
// PROFILE_RANGE(render, "/getOutputFramebuffer");
// // Primary rendering pass
// auto framebufferCache = DependencyManager::get<FramebufferCache>();
// finalFramebufferSize = framebufferCache->getFrameBufferSize();
// // Final framebuffer that will be handled to the display-plugin
// finalFramebuffer = framebufferCache->getFramebuffer();
// }
//
// {
// if (isStereo) {
// renderArgs._context->enableStereo(true);
// renderArgs._context->setStereoProjections(stereoEyeProjections);
// renderArgs._context->setStereoViews(stereoEyeOffsets);
// }
//
// renderArgs._hudOperator = displayPlugin->getHUDOperator();
// renderArgs._hudTexture = _applicationOverlay.getOverlayTexture();
// renderArgs._blitFramebuffer = finalFramebuffer;
// _graphicsEngine.render_runRenderFrame(&renderArgs);
// }
//
// auto frame = _graphicsEngine.getGPUContext()->endFrame();
// frame->frameIndex = _renderFrameCount;
// frame->framebuffer = finalFramebuffer;
// frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
// auto frameBufferCache = DependencyManager::get<FramebufferCache>();
// if (frameBufferCache) {
// frameBufferCache->releaseFramebuffer(framebuffer);
// }
// };
// // deliver final scene rendering commands to the display plugin
// {
// PROFILE_RANGE(render, "/pluginOutput");
// PerformanceTimer perfTimer("pluginOutput");
// _renderLoopCounter.increment();
// displayPlugin->submitFrame(frame);
// }
//
// // Reset the framebuffer and stereo state
// renderArgs._blitFramebuffer.reset();
// renderArgs._context->enableStereo(false);
//
// {
// Stats::getInstance()->setRenderDetails(renderArgs._details);
// }
//
// uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
// _frameTimingsScriptingInterface.addValue(lastPaintDuration);
//}
// WorldBox Render Data & rendering functions
class WorldBoxRenderData {
public:
typedef render::Payload<WorldBoxRenderData> Payload;
typedef Payload::DataPointer Pointer;
int _val = 0;
static render::ItemID _item; // unique WorldBoxRenderData
};
render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
namespace render {
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
PerformanceTimer perfTimer("worldBox");
auto& batch = *args->_batch;
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
renderWorldBox(args, batch);
}
}
}
void Application::runRenderFrame(RenderArgs* renderArgs) {
PROFILE_RANGE(render, __FUNCTION__);
PerformanceTimer perfTimer("display");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::runRenderFrame()");
// The pending changes collecting the changes here
render::Transaction transaction;
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
// render models...
PerformanceTimer perfTimer("entities");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::runRenderFrame() ... entities...");
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
renderArgs->_debugFlags = renderDebugFlags;
}
// Make sure the WorldBox is in the scene
// For the record, this one RenderItem is the first one we created and added to the scene.
// We could move that code elsewhere but you know...
if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
auto worldBoxRenderData = std::make_shared<WorldBoxRenderData>();
auto worldBoxRenderPayload = std::make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
WorldBoxRenderData::_item = _main3DScene->allocateID();
transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
_main3DScene->enqueueTransaction(transaction);
}
{
PerformanceTimer perfTimer("EngineRun");
_renderEngine->getRenderContext()->args = renderArgs;
_renderEngine->run();
}
}
//
//class WorldBoxRenderData {
//public:
// typedef render::Payload<WorldBoxRenderData> Payload;
// typedef Payload::DataPointer Pointer;
//
// int _val = 0;
// static render::ItemID _item; // unique WorldBoxRenderData
//};
//
//render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
//
//namespace render {
// template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
// template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
// template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
// if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
// PerformanceTimer perfTimer("worldBox");
//
// auto& batch = *args->_batch;
// DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
// renderWorldBox(args, batch);
// }
// }
//}
//
//void Application::runRenderFrame(RenderArgs* renderArgs) {
// PROFILE_RANGE(render, __FUNCTION__);
// PerformanceTimer perfTimer("display");
// PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::runRenderFrame()");
//
// // The pending changes collecting the changes here
// render::Transaction transaction;
//
// if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
// // render models...
// PerformanceTimer perfTimer("entities");
// PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
// "Application::runRenderFrame() ... entities...");
//
// RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
//
// renderArgs->_debugFlags = renderDebugFlags;
// }
//
// // Make sure the WorldBox is in the scene
// // For the record, this one RenderItem is the first one we created and added to the scene.
// // We could move that code elsewhere but you know...
// if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
// auto worldBoxRenderData = std::make_shared<WorldBoxRenderData>();
// auto worldBoxRenderPayload = std::make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
//
// WorldBoxRenderData::_item = _main3DScene->allocateID();
//
// transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
// _main3DScene->enqueueTransaction(transaction);
// }
//
// {
// PerformanceTimer perfTimer("EngineRun");
// _renderEngine->getRenderContext()->args = renderArgs;
// _renderEngine->run();
// }
//}

View file

@ -247,25 +247,35 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() {
bookmark.insert(ENTRY_AVATAR_URL, avatarUrl);
bookmark.insert(ENTRY_AVATAR_SCALE, avatarScale);
QScriptEngine scriptEngine;
QVariantList wearableEntities;
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
auto avatarEntities = myAvatar->getAvatarEntityData();
for (auto entityID : avatarEntities.keys()) {
auto entity = entityTree->findEntityByID(entityID);
if (!entity || !isWearableEntity(entity)) {
continue;
if (entityTree) {
QScriptEngine scriptEngine;
auto avatarEntities = myAvatar->getAvatarEntityData();
for (auto entityID : avatarEntities.keys()) {
auto entity = entityTree->findEntityByID(entityID);
if (!entity || !isWearableEntity(entity)) {
continue;
}
QVariantMap avatarEntityData;
EncodeBitstreamParams params;
auto desiredProperties = entity->getEntityProperties(params);
desiredProperties += PROP_LOCAL_POSITION;
desiredProperties += PROP_LOCAL_ROTATION;
desiredProperties -= PROP_JOINT_ROTATIONS_SET;
desiredProperties -= PROP_JOINT_ROTATIONS;
desiredProperties -= PROP_JOINT_TRANSLATIONS_SET;
desiredProperties -= PROP_JOINT_TRANSLATIONS;
EntityItemProperties entityProperties = entity->getProperties(desiredProperties);
QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties);
avatarEntityData["properties"] = scriptProperties.toVariant();
wearableEntities.append(QVariant(avatarEntityData));
}
QVariantMap avatarEntityData;
EncodeBitstreamParams params;
auto desiredProperties = entity->getEntityProperties(params);
desiredProperties += PROP_LOCAL_POSITION;
desiredProperties += PROP_LOCAL_ROTATION;
EntityItemProperties entityProperties = entity->getProperties(desiredProperties);
QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties);
avatarEntityData["properties"] = scriptProperties.toVariant();
wearableEntities.append(QVariant(avatarEntityData));
}
bookmark.insert(ENTRY_AVATAR_ENTITIES, wearableEntities);
return bookmark;

View file

@ -368,8 +368,6 @@ Menu::Menu() {
qApp->setHmdTabletBecomesToolbarSetting(action->isChecked());
});
addCheckableActionToQMenuAndActionHash(uiOptionsMenu, MenuOption::Use3DKeyboard, 0, true);
// Developer > Render >>>
MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render");

View file

@ -117,7 +117,7 @@ namespace MenuOption {
const QString FrameTimer = "Show Timer";
const QString FullscreenMirror = "Mirror";
const QString Help = "Help...";
const QString HomeLocation = "Home";
const QString HomeLocation = "Home ";
const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode";
const QString ActionMotorControl = "Enable Default Motor Control";
@ -213,7 +213,6 @@ namespace MenuOption {
const QString TurnWithHead = "Turn using Head";
const QString UseAudioForMouth = "Use Audio for Mouth";
const QString UseCamera = "Use Camera";
const QString Use3DKeyboard = "Use 3D Keyboard";
const QString VelocityFilter = "Velocity Filter";
const QString VisibleToEveryone = "Everyone";
const QString VisibleToFriends = "Friends";

View file

@ -19,7 +19,6 @@
#include <QStandardPaths>
static const QString AVATAR_HEAD_AND_BODY_STRING = "Avatar Body with Head";
static const QString AVATAR_ATTACHEMENT_STRING = "Avatar Attachment";
static const QString ENTITY_MODEL_STRING = "Entity Model";
ModelSelector::ModelSelector() {

View file

@ -171,7 +171,7 @@ void SecondaryCameraJobConfig::setOrientation(glm::quat orient) {
}
void SecondaryCameraJobConfig::enableSecondaryCameraRenderConfigs(bool enabled) {
qApp->getRenderEngine()->getConfiguration()->getConfig<SecondaryCameraRenderTask>()->setEnabled(enabled);
qApp->getRenderEngine()->getConfiguration()->getConfig<SecondaryCameraRenderTask>("SecondaryCameraJob")->setEnabled(enabled);
setEnabled(enabled);
}
@ -187,11 +187,13 @@ public:
void run(const render::RenderContextPointer& renderContext, const RenderArgsPointer& cachedArgs) {
auto args = renderContext->args;
if (cachedArgs) {
args->_blitFramebuffer = cachedArgs->_blitFramebuffer;
args->_viewport = cachedArgs->_viewport;
args->popViewFrustum();
args->_displayMode = cachedArgs->_displayMode;
args->_renderMode = cachedArgs->_renderMode;
}
args->popViewFrustum();
gpu::doInBatch("EndSecondaryCameraFrame::run", args->_context, [&](gpu::Batch& batch) {
batch.restoreContextStereo();

View file

@ -36,114 +36,6 @@
using namespace std;
void renderWorldBox(RenderArgs* args, gpu::Batch& batch) {
auto geometryCache = DependencyManager::get<GeometryCache>();
// Show center of world
static const glm::vec3 RED(1.0f, 0.0f, 0.0f);
static const glm::vec3 GREEN(0.0f, 1.0f, 0.0f);
static const glm::vec3 BLUE(0.0f, 0.0f, 1.0f);
static const glm::vec3 GREY(0.5f, 0.5f, 0.5f);
static const glm::vec4 GREY4(0.5f, 0.5f, 0.5f, 1.0f);
static const glm::vec4 DASHED_RED(1.0f, 0.0f, 0.0f, 1.0f);
static const glm::vec4 DASHED_GREEN(0.0f, 1.0f, 0.0f, 1.0f);
static const glm::vec4 DASHED_BLUE(0.0f, 0.0f, 1.0f, 1.0f);
static const float DASH_LENGTH = 1.0f;
static const float GAP_LENGTH = 1.0f;
auto transform = Transform{};
static std::array<int, 18> geometryIds;
static std::once_flag initGeometryIds;
std::call_once(initGeometryIds, [&] {
for (size_t i = 0; i < geometryIds.size(); ++i) {
geometryIds[i] = geometryCache->allocateID();
}
});
batch.setModelTransform(transform);
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(HALF_TREE_SCALE, 0.0f, 0.0f), RED, geometryIds[0]);
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-HALF_TREE_SCALE, 0.0f, 0.0f), DASHED_RED,
DASH_LENGTH, GAP_LENGTH, geometryIds[1]);
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, HALF_TREE_SCALE, 0.0f), GREEN, geometryIds[2]);
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, -HALF_TREE_SCALE, 0.0f), DASHED_GREEN,
DASH_LENGTH, GAP_LENGTH, geometryIds[3]);
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, HALF_TREE_SCALE), BLUE, geometryIds[4]);
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, -HALF_TREE_SCALE), DASHED_BLUE,
DASH_LENGTH, GAP_LENGTH, geometryIds[5]);
// X center boundaries
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f), GREY,
geometryIds[6]);
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
geometryIds[7]);
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f),
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
geometryIds[8]);
geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
geometryIds[9]);
// Z center boundaries
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, -HALF_TREE_SCALE),
glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
geometryIds[10]);
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, -HALF_TREE_SCALE),
glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE), GREY,
geometryIds[11]);
geometryCache->renderLine(batch, glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE),
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
geometryIds[12]);
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE),
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
geometryIds[13]);
// Center boundaries
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
geometryIds[14]);
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE), GREY,
geometryIds[15]);
geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
geometryIds[16]);
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE),
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
geometryIds[17]);
geometryCache->renderWireCubeInstance(args, batch, GREY4);
// Draw meter markers along the 3 axis to help with measuring things
const float MARKER_DISTANCE = 1.0f;
const float MARKER_RADIUS = 0.05f;
transform = Transform().setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(args, batch, RED);
transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(args, batch, RED);
transform = Transform().setTranslation(glm::vec3(0.0f, MARKER_DISTANCE, 0.0f)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(args, batch, GREEN);
transform = Transform().setTranslation(glm::vec3(0.0f, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(args, batch, BLUE);
transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(args, batch, GREY);
}
// Do some basic timing tests and report the results
void runTimingTests() {
// How long does it take to make a call to get the time?

View file

@ -15,14 +15,9 @@
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <gpu/Batch.h>
#include <render/Forward.h>
class ShapeEntityItem;
class ShapeInfo;
void renderWorldBox(RenderArgs* args, gpu::Batch& batch);
void runTimingTests();
void runUnitTests();

View file

@ -139,7 +139,7 @@ MyAvatar::MyAvatar(QThread* thread) :
_flyingHMDSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "flyingHMD", _flyingPrefHMD),
_avatarEntityCountSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "avatarEntityData" << "size", 0)
{
_clientTraitsHandler = std::unique_ptr<ClientTraitsHandler>(new ClientTraitsHandler(this));
_clientTraitsHandler.reset(new ClientTraitsHandler(this));
// give the pointer to our head to inherited _headData variable from AvatarData
_headData = new MyHead(this);

View file

@ -0,0 +1,301 @@
//
// GraphicsEngine.cpp
//
// Created by Sam Gateau on 29/6/2018.
// Copyright 2018 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 "GraphicsEngine.h"
#include <shared/GlobalAppProperties.h>
#include "WorldBox.h"
#include "LODManager.h"
#include <GeometryCache.h>
#include <TextureCache.h>
#include <FramebufferCache.h>
#include <UpdateSceneTask.h>
#include <RenderViewTask.h>
#include <SecondaryCamera.h>
#include "RenderEventHandler.h"
#include <gpu/Batch.h>
#include <gpu/Context.h>
#include <gpu/gl/GLBackend.h>
#include <display-plugins/DisplayPlugin.h>
#include <display-plugins/CompositorHelper.h>
#include <QMetaObject>
#include "ui/Stats.h"
#include "Application.h"
GraphicsEngine::GraphicsEngine() {
}
GraphicsEngine::~GraphicsEngine() {
}
void GraphicsEngine::initializeGPU(GLWidget* glwidget) {
_renderEventHandler = new RenderEventHandler(
[this]() { return this->shouldPaint(); },
[this]() { this->render_performFrame(); }
);
// Requires the window context, because that's what's used in the actual rendering
// and the GPU backend will make things like the VAO which cannot be shared across
// contexts
glwidget->makeCurrent();
gpu::Context::init<gpu::gl::GLBackend>();
glwidget->makeCurrent();
_gpuContext = std::make_shared<gpu::Context>();
DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext);
}
void GraphicsEngine::initializeRender(bool disableDeferred) {
// Set up the render engine
render::CullFunctor cullFunctor = LODManager::shouldRender;
_renderEngine->addJob<UpdateSceneTask>("UpdateScene");
#ifndef Q_OS_ANDROID
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !disableDeferred);
#endif
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !disableDeferred, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
_renderEngine->load();
_renderEngine->registerScene(_renderScene);
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
}
void GraphicsEngine::startup() {
static_cast<RenderEventHandler*>(_renderEventHandler)->resumeThread();
}
void GraphicsEngine::shutdown() {
// The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual
// removal of the items.
// See https://highfidelity.fogbugz.com/f/cases/5328
_renderScene->enqueueFrame(); // flush all the transactions
_renderScene->processTransactionQueue(); // process and apply deletions
_gpuContext->shutdown();
// shutdown render engine
_renderScene = nullptr;
_renderEngine = nullptr;
_renderEventHandler->deleteLater();
}
void GraphicsEngine::render_runRenderFrame(RenderArgs* renderArgs) {
PROFILE_RANGE(render, __FUNCTION__);
PerformanceTimer perfTimer("render");
// Make sure the WorldBox is in the scene
// For the record, this one RenderItem is the first one we created and added to the scene.
// We could move that code elsewhere but you know...
if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
render::Transaction transaction;
auto worldBoxRenderData = std::make_shared<WorldBoxRenderData>();
auto worldBoxRenderPayload = std::make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
WorldBoxRenderData::_item = _renderScene->allocateID();
transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
_renderScene->enqueueTransaction(transaction);
}
{
_renderEngine->getRenderContext()->args = renderArgs;
_renderEngine->run();
}
}
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
bool GraphicsEngine::shouldPaint() const {
auto displayPlugin = qApp->getActiveDisplayPlugin();
#ifdef DEBUG_PAINT_DELAY
static uint64_t paintDelaySamples{ 0 };
static uint64_t paintDelayUsecs{ 0 };
paintDelayUsecs += displayPlugin->getPaintDelayUsecs();
static const int PAINT_DELAY_THROTTLE = 1000;
if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) {
qCDebug(interfaceapp).nospace() <<
"Paint delay (" << paintDelaySamples << " samples): " <<
(float)paintDelaySamples / paintDelayUsecs << "us";
}
#endif
// Throttle if requested
//if (displayPlugin->isThrottled() && (_graphicsEngine._renderEventHandler->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
if ( displayPlugin->isThrottled() &&
(static_cast<RenderEventHandler*>(_renderEventHandler)->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
return false;
}
return true;
}
bool GraphicsEngine::checkPendingRenderEvent() {
bool expected = false;
return (_renderEventHandler && static_cast<RenderEventHandler*>(_renderEventHandler)->_pendingRenderEvent.compare_exchange_strong(expected, true));
}
void GraphicsEngine::render_performFrame() {
// Some plugins process message events, allowing paintGL to be called reentrantly.
_renderFrameCount++;
auto lastPaintBegin = usecTimestampNow();
PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_renderFrameCount);
PerformanceTimer perfTimer("paintGL");
DisplayPluginPointer displayPlugin;
{
PROFILE_RANGE(render, "/getActiveDisplayPlugin");
displayPlugin = qApp->getActiveDisplayPlugin();
}
{
PROFILE_RANGE(render, "/pluginBeginFrameRender");
// If a display plugin loses it's underlying support, it
// needs to be able to signal us to not use it
if (!displayPlugin->beginFrameRender(_renderFrameCount)) {
QMetaObject::invokeMethod(qApp, "updateDisplayMode");
return;
}
}
RenderArgs renderArgs;
glm::mat4 HMDSensorPose;
glm::mat4 eyeToWorld;
glm::mat4 sensorToWorld;
bool isStereo;
glm::mat4 stereoEyeOffsets[2];
glm::mat4 stereoEyeProjections[2];
{
QMutexLocker viewLocker(&_renderArgsMutex);
renderArgs = _appRenderArgs._renderArgs;
// don't render if there is no context.
if (!_appRenderArgs._renderArgs._context) {
return;
}
HMDSensorPose = _appRenderArgs._headPose;
eyeToWorld = _appRenderArgs._eyeToWorld;
sensorToWorld = _appRenderArgs._sensorToWorld;
isStereo = _appRenderArgs._isStereo;
for_each_eye([&](Eye eye) {
stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye];
stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye];
});
}
{
PROFILE_RANGE(render, "/gpuContextReset");
getGPUContext()->beginFrame(_appRenderArgs._view, HMDSensorPose);
// Reset the gpu::Context Stages
// Back to the default framebuffer;
gpu::doInBatch("Application_render::gpuContextReset", getGPUContext(), [&](gpu::Batch& batch) {
batch.resetStages();
});
}
{
PROFILE_RANGE(render, "/renderOverlay");
PerformanceTimer perfTimer("renderOverlay");
// NOTE: There is no batch associated with this renderArgs
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
renderArgs._viewport = glm::ivec4(0, 0, qApp->getDeviceSize());
qApp->getApplicationOverlay().renderOverlay(&renderArgs);
}
{
PROFILE_RANGE(render, "/updateCompositor");
qApp->getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld);
}
gpu::FramebufferPointer finalFramebuffer;
QSize finalFramebufferSize;
{
PROFILE_RANGE(render, "/getOutputFramebuffer");
// Primary rendering pass
auto framebufferCache = DependencyManager::get<FramebufferCache>();
finalFramebufferSize = framebufferCache->getFrameBufferSize();
// Final framebuffer that will be handled to the display-plugin
finalFramebuffer = framebufferCache->getFramebuffer();
}
{
if (isStereo) {
renderArgs._context->enableStereo(true);
renderArgs._context->setStereoProjections(stereoEyeProjections);
renderArgs._context->setStereoViews(stereoEyeOffsets);
}
renderArgs._hudOperator = displayPlugin->getHUDOperator();
renderArgs._hudTexture = qApp->getApplicationOverlay().getOverlayTexture();
renderArgs._blitFramebuffer = finalFramebuffer;
render_runRenderFrame(&renderArgs);
}
auto frame = getGPUContext()->endFrame();
frame->frameIndex = _renderFrameCount;
frame->framebuffer = finalFramebuffer;
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
auto frameBufferCache = DependencyManager::get<FramebufferCache>();
if (frameBufferCache) {
frameBufferCache->releaseFramebuffer(framebuffer);
}
};
// deliver final scene rendering commands to the display plugin
{
PROFILE_RANGE(render, "/pluginOutput");
PerformanceTimer perfTimer("pluginOutput");
_renderLoopCounter.increment();
displayPlugin->submitFrame(frame);
}
// Reset the framebuffer and stereo state
renderArgs._blitFramebuffer.reset();
renderArgs._context->enableStereo(false);
{
auto stats = Stats::getInstance();
if (stats) {
stats->setRenderDetails(renderArgs._details);
}
}
uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
_frameTimingsScriptingInterface.addValue(lastPaintDuration);
}
void GraphicsEngine::editRenderArgs(RenderArgsEditor editor) {
QMutexLocker renderLocker(&_renderArgsMutex);
editor(_appRenderArgs);
}

View file

@ -0,0 +1,90 @@
//
// GraphicsEngine.h
//
// Created by Sam Gateau on 29/6/2018.
// Copyright 2018 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
//
#ifndef hifi_GraphicsEngine_h
#define hifi_GraphicsEngine_h
#include <gl/OffscreenGLCanvas.h>
#include <gl/GLWidget.h>
#include <qmutex.h>
#include <render/Engine.h>
#include <OctreeConstants.h>
#include <shared/RateCounter.h>
#include "FrameTimingsScriptingInterface.h"
struct AppRenderArgs {
render::Args _renderArgs;
glm::mat4 _eyeToWorld;
glm::mat4 _view;
glm::mat4 _eyeOffsets[2];
glm::mat4 _eyeProjections[2];
glm::mat4 _headPose;
glm::mat4 _sensorToWorld;
float _sensorToWorldScale{ 1.0f };
bool _isStereo{ false };
};
using RenderArgsEditor = std::function <void(AppRenderArgs&)>;
class GraphicsEngine {
public:
GraphicsEngine();
~GraphicsEngine();
void initializeGPU(GLWidget*);
void initializeRender(bool disableDeferred);
void startup();
void shutdown();
render::ScenePointer getRenderScene() const { return _renderScene; }
render::EnginePointer getRenderEngine() const { return _renderEngine; }
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
// Same as the one in application
bool shouldPaint() const;
bool checkPendingRenderEvent();
size_t getRenderFrameCount() const { return _renderFrameCount; }
float getRenderLoopRate() const { return _renderLoopCounter.rate(); }
// Feed GRaphics Engine with new frame configuration
void editRenderArgs(RenderArgsEditor editor);
private:
// Thread specific calls
void render_performFrame();
void render_runRenderFrame(RenderArgs* renderArgs);
protected:
mutable QMutex _renderArgsMutex{ QMutex::Recursive };
AppRenderArgs _appRenderArgs;
RateCounter<500> _renderLoopCounter;
uint32_t _renderFrameCount{ 0 };
render::ScenePointer _renderScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) };
render::EnginePointer _renderEngine{ new render::RenderEngine() };
gpu::ContextPointer _gpuContext; // initialized during window creation
QObject* _renderEventHandler{ nullptr };
friend class RenderEventHandler;
FrameTimingsScriptingInterface _frameTimingsScriptingInterface;
friend class Application;
};
#endif // hifi_GraphicsEngine_h

View file

@ -0,0 +1,58 @@
//
// RenderEventHandler.cpp
//
// Created by Bradley Austin Davis on 29/6/2018.
// Copyright 2018 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 "RenderEventHandler.h"
#include "Application.h"
#include <shared/GlobalAppProperties.h>
#include <shared/QtHelpers.h>
#include "CrashHandler.h"
RenderEventHandler::RenderEventHandler(CheckCall checkCall, RenderCall renderCall) :
_checkCall(checkCall),
_renderCall(renderCall)
{
// Transfer to a new thread
moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) {
hifi::qt::addBlockingForbiddenThread("Render", renderThread);
_lastTimeRendered.start();
}, std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority);
}
void RenderEventHandler::initialize() {
setObjectName("Render");
PROFILE_SET_THREAD_NAME("Render");
setCrashAnnotation("render_thread_id", std::to_string((size_t)QThread::currentThreadId()));
}
void RenderEventHandler::resumeThread() {
_pendingRenderEvent = false;
}
void RenderEventHandler::render() {
if (_checkCall()) {
_lastTimeRendered.start();
_renderCall();
}
}
bool RenderEventHandler::event(QEvent* event) {
switch ((int)event->type()) {
case ApplicationEvent::Render:
render();
_pendingRenderEvent.store(false);
return true;
default:
break;
}
return Parent::event(event);
}

View file

@ -0,0 +1,52 @@
//
// RenderEventHandler.h
//
// Created by Bradley Austin Davis on 29/6/2018.
// Copyright 2018 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
//
#ifndef hifi_RenderEventHandler_h
#define hifi_RenderEventHandler_h
#include <QEvent>
#include <QElapsedTimer>
#include "gl/OffscreenGLCanvas.h"
enum ApplicationEvent {
// Execute a lambda function
Lambda = QEvent::User + 1,
// Trigger the next render
Render,
// Trigger the next idle
Idle,
};
class RenderEventHandler : public QObject {
using Parent = QObject;
Q_OBJECT
public:
using CheckCall = std::function <bool()>;
using RenderCall = std::function <void()>;
CheckCall _checkCall;
RenderCall _renderCall;
RenderEventHandler(CheckCall checkCall, RenderCall renderCall);
QElapsedTimer _lastTimeRendered;
std::atomic<bool> _pendingRenderEvent{ true };
void resumeThread();
private:
void initialize();
void render();
bool event(QEvent* event) override;
};
#endif // #include hifi_RenderEventHandler_h

View file

@ -0,0 +1,138 @@
//
// WorldBox.cpp
//
// Created by Sam Gateau on 01/07/2018.
// Copyright 2018 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 "WorldBox.h"
#include "OctreeConstants.h"
render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
namespace render {
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
PerformanceTimer perfTimer("worldBox");
auto& batch = *args->_batch;
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
WorldBoxRenderData::renderWorldBox(args, batch);
}
}
}
void WorldBoxRenderData::renderWorldBox(RenderArgs* args, gpu::Batch& batch) {
auto geometryCache = DependencyManager::get<GeometryCache>();
// Show center of world
static const glm::vec3 RED(1.0f, 0.0f, 0.0f);
static const glm::vec3 GREEN(0.0f, 1.0f, 0.0f);
static const glm::vec3 BLUE(0.0f, 0.0f, 1.0f);
static const glm::vec3 GREY(0.5f, 0.5f, 0.5f);
static const glm::vec4 GREY4(0.5f, 0.5f, 0.5f, 1.0f);
static const glm::vec4 DASHED_RED(1.0f, 0.0f, 0.0f, 1.0f);
static const glm::vec4 DASHED_GREEN(0.0f, 1.0f, 0.0f, 1.0f);
static const glm::vec4 DASHED_BLUE(0.0f, 0.0f, 1.0f, 1.0f);
static const float DASH_LENGTH = 1.0f;
static const float GAP_LENGTH = 1.0f;
auto transform = Transform{};
static std::array<int, 18> geometryIds;
static std::once_flag initGeometryIds;
std::call_once(initGeometryIds, [&] {
for (size_t i = 0; i < geometryIds.size(); ++i) {
geometryIds[i] = geometryCache->allocateID();
}
});
batch.setModelTransform(transform);
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(HALF_TREE_SCALE, 0.0f, 0.0f), RED, geometryIds[0]);
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-HALF_TREE_SCALE, 0.0f, 0.0f), DASHED_RED,
DASH_LENGTH, GAP_LENGTH, geometryIds[1]);
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, HALF_TREE_SCALE, 0.0f), GREEN, geometryIds[2]);
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, -HALF_TREE_SCALE, 0.0f), DASHED_GREEN,
DASH_LENGTH, GAP_LENGTH, geometryIds[3]);
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, HALF_TREE_SCALE), BLUE, geometryIds[4]);
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, -HALF_TREE_SCALE), DASHED_BLUE,
DASH_LENGTH, GAP_LENGTH, geometryIds[5]);
// X center boundaries
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f), GREY,
geometryIds[6]);
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
geometryIds[7]);
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f),
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
geometryIds[8]);
geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
geometryIds[9]);
// Z center boundaries
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, -HALF_TREE_SCALE),
glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
geometryIds[10]);
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, -HALF_TREE_SCALE),
glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE), GREY,
geometryIds[11]);
geometryCache->renderLine(batch, glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE),
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
geometryIds[12]);
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE),
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
geometryIds[13]);
// Center boundaries
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
geometryIds[14]);
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE), GREY,
geometryIds[15]);
geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
geometryIds[16]);
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE),
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
geometryIds[17]);
geometryCache->renderWireCubeInstance(args, batch, GREY4);
// Draw meter markers along the 3 axis to help with measuring things
const float MARKER_DISTANCE = 1.0f;
const float MARKER_RADIUS = 0.05f;
transform = Transform().setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(args, batch, RED);
transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(args, batch, RED);
transform = Transform().setTranslation(glm::vec3(0.0f, MARKER_DISTANCE, 0.0f)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(args, batch, GREEN);
transform = Transform().setTranslation(glm::vec3(0.0f, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(args, batch, BLUE);
transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(args, batch, GREY);
}

View file

@ -0,0 +1,43 @@
//
// WorldBox.h
//
// Created by Sam Gateau on 01/07/2018.
// Copyright 2018 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
//
#ifndef hifi_WorldBox_h
#define hifi_WorldBox_h
#include <PerfStat.h>
#include <gpu/Batch.h>
#include <render/Forward.h>
#include <render/Item.h>
#include <GeometryCache.h>
#include "Menu.h"
class WorldBoxRenderData {
public:
typedef render::Payload<WorldBoxRenderData> Payload;
typedef Payload::DataPointer Pointer;
int _val = 0;
static render::ItemID _item; // unique WorldBoxRenderData
static void renderWorldBox(RenderArgs* args, gpu::Batch& batch);
};
namespace render {
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff);
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff);
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args);
}
#endif // hifi_WorldBox_h

View file

@ -72,6 +72,7 @@ int main(int argc, const char* argv[]) {
QCommandLineOption serverContentPathOption("serverContentPath", "Where to find server content", "serverContentPath");
QCommandLineOption allowMultipleInstancesOption("allowMultipleInstances", "Allow multiple instances to run");
QCommandLineOption overrideAppLocalDataPathOption("cache", "set test cache <dir>", "dir");
QCommandLineOption overrideScriptsPathOption(SCRIPTS_SWITCH, "set scripts <path>", "path");
parser.addOption(urlOption);
parser.addOption(noUpdaterOption);
@ -79,6 +80,7 @@ int main(int argc, const char* argv[]) {
parser.addOption(runServerOption);
parser.addOption(serverContentPathOption);
parser.addOption(overrideAppLocalDataPathOption);
parser.addOption(overrideScriptsPathOption);
parser.addOption(allowMultipleInstancesOption);
if (!parser.parse(arguments)) {
@ -165,6 +167,15 @@ int main(int argc, const char* argv[]) {
if (allowMultipleInstances) {
instanceMightBeRunning = false;
}
// this needs to be done here in main, as the mechanism for setting the
// scripts directory appears not to work. See the bug report
// https://highfidelity.fogbugz.com/f/cases/5759/Issues-changing-scripts-directory-in-ScriptsEngine
if (parser.isSet(overrideScriptsPathOption)) {
QDir scriptsPath(parser.value(overrideScriptsPathOption));
if (scriptsPath.exists()) {
PathUtils::defaultScriptsLocation(scriptsPath.path());
}
}
if (instanceMightBeRunning) {
// Try to connect and send message to existing interface instance

View file

@ -32,3 +32,7 @@ void KeyboardScriptingInterface::setPassword(bool password) {
void KeyboardScriptingInterface::loadKeyboardFile(const QString& keyboardFile) {
DependencyManager::get<Keyboard>()->loadKeyboardFile(keyboardFile);
}
bool KeyboardScriptingInterface::getUse3DKeyboard() {
return DependencyManager::get<Keyboard>()->getUse3DKeyboard();
}

View file

@ -31,6 +31,7 @@ class KeyboardScriptingInterface : public QObject, public Dependency {
Q_OBJECT
Q_PROPERTY(bool raised READ isRaised WRITE setRaised)
Q_PROPERTY(bool password READ isPassword WRITE setPassword)
Q_PROPERTY(bool use3DKeyboard READ getUse3DKeyboard);
public:
Q_INVOKABLE void loadKeyboardFile(const QString& string);
@ -41,5 +42,7 @@ private:
bool isPassword();
void setPassword(bool password);
bool getUse3DKeyboard();
};
#endif

View file

@ -55,8 +55,6 @@ ApplicationOverlay::~ApplicationOverlay() {
// Renders the overlays either to a texture or to the screen
void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
PROFILE_RANGE(render, __FUNCTION__);
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
buildFramebufferObject();
if (!_overlayFramebuffer) {

View file

@ -241,6 +241,17 @@ void Keyboard::registerKeyboardHighlighting() {
selection->enableListToScene(KEY_PRESSED_HIGHLIGHT);
}
bool Keyboard::getUse3DKeyboard() const {
return _use3DKeyboardLock.resultWithReadLock<bool>([&] {
return _use3DKeyboard.get();
});
}
void Keyboard::setUse3DKeyboard(bool use) {
_use3DKeyboardLock.withWriteLock([&] {
_use3DKeyboard.set(use);
});
}
void Keyboard::createKeyboard() {
auto pointerManager = DependencyManager::get<PointerManager>();

View file

@ -23,6 +23,7 @@
#include <Sound.h>
#include <AudioInjector.h>
#include <shared/ReadWriteLockable.h>
#include <SettingHandle.h>
#include "ui/overlays/Overlay.h"
@ -93,11 +94,12 @@ public:
void registerKeyboardHighlighting();
bool isRaised() const;
void setRaised(bool raised);
void setResetKeyboardPositionOnRaise(bool reset);
bool isPassword() const;
void setPassword(bool password);
void setResetKeyboardPositionOnRaise(bool reset);
bool getUse3DKeyboard() const;
void setUse3DKeyboard(bool use);
void loadKeyboardFile(const QString& keyboardFile);
QVector<OverlayID> getKeysID();
@ -147,6 +149,9 @@ private:
SharedSoundPointer _keySound { nullptr };
std::shared_ptr<QTimer> _layerSwitchTimer { std::make_shared<QTimer>() };
mutable ReadWriteLockable _use3DKeyboardLock;
Setting::Handle<bool> _use3DKeyboard { "use3DKeyboard", true };
QString _typedCharacters;
TextDisplay _textDisplay;
Anchor _anchor;

View file

@ -42,8 +42,9 @@ LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) {
this, &LoginDialog::handleLoginCompleted);
connect(accountManager.data(), &AccountManager::loginFailed,
this, &LoginDialog::handleLoginFailed);
#endif
connect(qApp, SIGNAL(loginDialogFocusEnabled()), this, SLOT(onFocusEnabled()));
connect(this, SIGNAL(dismissedLoginDialog()), qApp, SLOT(onDismissedLoginDialog()));
#endif
}
LoginDialog::~LoginDialog() {
@ -121,6 +122,25 @@ void LoginDialog::login(const QString& username, const QString& password) const
DependencyManager::get<AccountManager>()->requestAccessToken(username, password);
}
void LoginDialog::loginThroughOculus() {
qDebug() << "Attempting to login through Oculus";
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
steamClient->requestTicket([this](Ticket ticket) {
if (ticket.isNull()) {
emit handleLoginFailed();
return;
}
DependencyManager::get<AccountManager>()->requestAccessTokenWithSteam(ticket);
});
}
}
void LoginDialog::linkOculus() {
qDebug() << "Attempting to link Oculus account";
}
void LoginDialog::loginThroughSteam() {
qDebug() << "Attempting to login through Steam";
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
@ -288,3 +308,8 @@ void LoginDialog::signupFailed(QNetworkReply* reply) {
emit handleSignupFailed(DEFAULT_SIGN_UP_FAILURE_MESSAGE);
}
}
void LoginDialog::onFocusEnabled() {
forceActiveFocus();
emit focusEnabled();
}

View file

@ -48,6 +48,8 @@ signals:
// occurs upon dismissing the encouraging log in.
void dismissedLoginDialog();
void focusEnabled();
public slots:
void linkCompleted(QNetworkReply* reply);
void linkFailed(QNetworkReply* reply);
@ -58,6 +60,8 @@ public slots:
void signupCompleted(QNetworkReply* reply);
void signupFailed(QNetworkReply* reply);
void onFocusEnabled();
protected slots:
Q_INVOKABLE void dismissLoginDialog();
@ -65,6 +69,8 @@ protected slots:
Q_INVOKABLE bool isOculusStoreRunning() const;
Q_INVOKABLE void login(const QString& username, const QString& password) const;
Q_INVOKABLE void loginThroughOculus();
Q_INVOKABLE void linkOculus();
Q_INVOKABLE void loginThroughSteam();
Q_INVOKABLE void linkSteam();
Q_INVOKABLE void createAccountFromSteam(QString username = QString());

View file

@ -24,6 +24,7 @@
#include "Snapshot.h"
#include "SnapshotAnimated.h"
#include "UserActivityLogger.h"
#include "ui/Keyboard.h"
void setupPreferences() {
auto preferences = DependencyManager::get<Preferences>();
@ -119,6 +120,12 @@ void setupPreferences() {
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use reticle cursor instead of arrow", getter, setter));
}
{
auto getter = []()->bool { return DependencyManager::get<Keyboard>()->getUse3DKeyboard(); };
auto setter = [](bool value) { DependencyManager::get<Keyboard>()->setUse3DKeyboard(value); };
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use Virtual Keyboard", getter, setter));
}
{
auto getter = []()->bool { return qApp->getMiniTabletEnabled(); };
auto setter = [](bool value) { qApp->setMiniTabletEnabled(value); };

View file

@ -302,7 +302,6 @@ void AudioClient::customDeleter() {
#if defined(Q_OS_ANDROID)
_shouldRestartInputSetup = false;
#endif
stop();
deleteLater();
}

View file

@ -51,7 +51,7 @@
#include <xmmintrin.h>
// convert float to int using round-to-nearest
FORCEINLINE static int32_t floatToInt(float x) {
return _mm_cvt_ss2si(_mm_load_ss(&x));
return _mm_cvt_ss2si(_mm_set_ss(x));
}
#else
@ -150,7 +150,7 @@ static const int IEEE754_EXPN_BIAS = 127;
//
// Peak detection and -log2(x) for float input (mono)
// x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff
// x > 2^LOG2_HEADROOM undefined
// x > 2^LOG2_HEADROOM returns 0
//
FORCEINLINE static int32_t peaklog2(float* input) {
@ -161,12 +161,12 @@ FORCEINLINE static int32_t peaklog2(float* input) {
uint32_t peak = u & IEEE754_FABS_MASK;
// split into e and x - 1.0
int e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM;
int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM;
int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff;
// saturate
if (e > 31) {
return 0x7fffffff;
// saturate when e > 31 or e < 0
if ((uint32_t)e > 31) {
return 0x7fffffff & ~(e >> 31);
}
int k = x >> (31 - LOG2_TABBITS);
@ -186,7 +186,7 @@ FORCEINLINE static int32_t peaklog2(float* input) {
//
// Peak detection and -log2(x) for float input (stereo)
// x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff
// x > 2^LOG2_HEADROOM undefined
// x > 2^LOG2_HEADROOM returns 0
//
FORCEINLINE static int32_t peaklog2(float* input0, float* input1) {
@ -200,12 +200,12 @@ FORCEINLINE static int32_t peaklog2(float* input0, float* input1) {
uint32_t peak = MAX(u0, u1);
// split into e and x - 1.0
int e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM;
int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM;
int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff;
// saturate
if (e > 31) {
return 0x7fffffff;
// saturate when e > 31 or e < 0
if ((uint32_t)e > 31) {
return 0x7fffffff & ~(e >> 31);
}
int k = x >> (31 - LOG2_TABBITS);
@ -225,7 +225,7 @@ FORCEINLINE static int32_t peaklog2(float* input0, float* input1) {
//
// Peak detection and -log2(x) for float input (quad)
// x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff
// x > 2^LOG2_HEADROOM undefined
// x > 2^LOG2_HEADROOM returns 0
//
FORCEINLINE static int32_t peaklog2(float* input0, float* input1, float* input2, float* input3) {
@ -243,12 +243,12 @@ FORCEINLINE static int32_t peaklog2(float* input0, float* input1, float* input2,
uint32_t peak = MAX(MAX(u0, u1), MAX(u2, u3));
// split into e and x - 1.0
int e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM;
int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM;
int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff;
// saturate
if (e > 31) {
return 0x7fffffff;
// saturate when e > 31 or e < 0
if ((uint32_t)e > 31) {
return 0x7fffffff & ~(e >> 31);
}
int k = x >> (31 - LOG2_TABBITS);

View file

@ -447,9 +447,9 @@ AudioInjectorPointer AudioInjector::playSound(SharedSoundPointer sound, const A
using AudioConstants::AudioSample;
using AudioConstants::SAMPLE_RATE;
const int standardRate = SAMPLE_RATE;
// limit to 4 octaves
const int pitch = glm::clamp(options.pitch, 1 / 16.0f, 16.0f);
const int resampledRate = SAMPLE_RATE / pitch;
// limit pitch to 4 octaves
const float pitch = glm::clamp(options.pitch, 1 / 16.0f, 16.0f);
const int resampledRate = glm::round(SAMPLE_RATE / pitch);
auto audioData = sound->getAudioData();
auto numChannels = audioData->getNumChannels();
@ -499,9 +499,9 @@ AudioInjectorPointer AudioInjector::playSound(AudioDataPointer audioData, const
using AudioConstants::AudioSample;
using AudioConstants::SAMPLE_RATE;
const int standardRate = SAMPLE_RATE;
// limit to 4 octaves
const int pitch = glm::clamp(options.pitch, 1 / 16.0f, 16.0f);
const int resampledRate = SAMPLE_RATE / pitch;
// limit pitch to 4 octaves
const float pitch = glm::clamp(options.pitch, 1 / 16.0f, 16.0f);
const int resampledRate = glm::round(SAMPLE_RATE / pitch);
auto numChannels = audioData->getNumChannels();
auto numFrames = audioData->getNumFrames();

View file

@ -1490,7 +1490,7 @@ protected:
bool _isClientAvatar { false };
// null unless MyAvatar or ScriptableAvatar sending traits data to mixer
std::unique_ptr<ClientTraitsHandler> _clientTraitsHandler;
std::unique_ptr<ClientTraitsHandler, LaterDeleter> _clientTraitsHandler;
template <typename T, typename F>
T readLockWithNamedJointIndex(const QString& name, const T& defaultValue, F f) const {

View file

@ -22,7 +22,7 @@ ClientTraitsHandler::ClientTraitsHandler(AvatarData* owningAvatar) :
_owningAvatar(owningAvatar)
{
auto nodeList = DependencyManager::get<NodeList>();
QObject::connect(nodeList.data(), &NodeList::nodeAdded, [this](SharedNodePointer addedNode){
QObject::connect(nodeList.data(), &NodeList::nodeAdded, this, [this](SharedNodePointer addedNode) {
if (addedNode->getType() == NodeType::AvatarMixer) {
resetForNewMixer();
}

View file

@ -534,18 +534,26 @@ void OpenGLDisplayPlugin::updateFrameData() {
}
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> OpenGLDisplayPlugin::getHUDOperator() {
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) {
if (_hudPipeline && hudTexture) {
auto hudPipeline = _hudPipeline;
auto hudMirrorPipeline = _mirrorHUDPipeline;
auto hudStereo = isStereo();
auto hudCompositeFramebufferSize = _compositeFramebuffer->getSize();
std::array<glm::ivec4, 2> hudEyeViewports;
for_each_eye([&](Eye eye) {
hudEyeViewports[eye] = eyeViewport(eye);
});
return [=](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) {
if (hudPipeline && hudTexture) {
batch.enableStereo(false);
batch.setPipeline(mirror ? _mirrorHUDPipeline : _hudPipeline);
batch.setPipeline(mirror ? hudMirrorPipeline : hudPipeline);
batch.setResourceTexture(0, hudTexture);
if (isStereo()) {
if (hudStereo) {
for_each_eye([&](Eye eye) {
batch.setViewportTransform(eyeViewport(eye));
batch.setViewportTransform(hudEyeViewports[eye]);
batch.draw(gpu::TRIANGLE_STRIP, 4);
});
} else {
batch.setViewportTransform(ivec4(uvec2(0), _compositeFramebuffer->getSize()));
batch.setViewportTransform(ivec4(uvec2(0), hudCompositeFramebufferSize));
batch.draw(gpu::TRIANGLE_STRIP, 4);
}
}

View file

@ -420,18 +420,26 @@ void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> HmdDisplayPlugin::HUDRenderer::render(HmdDisplayPlugin& plugin) {
updatePipeline();
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) {
if (pipeline && hudTexture) {
batch.setPipeline(pipeline);
batch.setInputFormat(format);
gpu::BufferView posView(vertices, VERTEX_OFFSET, vertices->getSize(), VERTEX_STRIDE, format->getAttributes().at(gpu::Stream::POSITION)._element);
gpu::BufferView uvView(vertices, TEXTURE_OFFSET, vertices->getSize(), VERTEX_STRIDE, format->getAttributes().at(gpu::Stream::TEXCOORD)._element);
auto hudPipeline = pipeline;
auto hudFormat = format;
auto hudVertices = vertices;
auto hudIndices = indices;
auto hudUniformBuffer = uniformsBuffer;
auto hudUniforms = uniforms;
auto hudIndexCount = indexCount;
return [=](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) {
if (hudPipeline && hudTexture) {
batch.setPipeline(hudPipeline);
batch.setInputFormat(hudFormat);
gpu::BufferView posView(hudVertices, VERTEX_OFFSET, hudVertices->getSize(), VERTEX_STRIDE, hudFormat->getAttributes().at(gpu::Stream::POSITION)._element);
gpu::BufferView uvView(hudVertices, TEXTURE_OFFSET, hudVertices->getSize(), VERTEX_STRIDE, hudFormat->getAttributes().at(gpu::Stream::TEXCOORD)._element);
batch.setInputBuffer(gpu::Stream::POSITION, posView);
batch.setInputBuffer(gpu::Stream::TEXCOORD, uvView);
batch.setIndexBuffer(gpu::UINT16, indices, 0);
uniformsBuffer->setSubData(0, uniforms);
batch.setUniformBuffer(0, uniformsBuffer);
batch.setIndexBuffer(gpu::UINT16, hudIndices, 0);
hudUniformBuffer->setSubData(0, hudUniforms);
batch.setUniformBuffer(0, hudUniformBuffer);
auto compositorHelper = DependencyManager::get<CompositorHelper>();
glm::mat4 modelTransform = compositorHelper->getUiTransform();
@ -441,7 +449,7 @@ std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> HmdDis
batch.setModelTransform(modelTransform);
batch.setResourceTexture(0, hudTexture);
batch.drawIndexed(gpu::TRIANGLES, indexCount);
batch.drawIndexed(gpu::TRIANGLES, hudIndexCount);
}
};
}

View file

@ -486,6 +486,8 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
propertiesWithSimID.setLastEditedBy(sessionID);
propertiesWithSimID.setActionData(QByteArray());
bool scalesWithParent = propertiesWithSimID.getScalesWithParent();
propertiesWithSimID = convertPropertiesFromScriptSemantics(propertiesWithSimID, scalesWithParent);
@ -830,6 +832,8 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
properties.setClientOnly(entity->getClientOnly());
properties.setOwningAvatarID(entity->getOwningAvatarID());
properties.setActionData(entity->getDynamicData());
// make sure the properties has a type, so that the encode can know which properties to include
properties.setType(entity->getType());

View file

@ -180,9 +180,7 @@ void Deck::processFrames() {
#ifdef WANT_RECORDING_DEBUG
qCDebug(recordingLog) << "Setting timer for next processing " << nextInterval;
#endif
_timer.singleShot(nextInterval, [this] {
processFrames();
});
_timer.singleShot(nextInterval, this, &Deck::processFrames);
}
void Deck::removeClip(const ClipConstPointer& clip) {

View file

@ -303,7 +303,7 @@ AmbientOcclusionEffect::AmbientOcclusionEffect() {
}
void AmbientOcclusionEffect::configure(const Config& config) {
DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(config.enabled);
DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(config.isEnabled());
bool shouldUpdateBlurs = false;
bool shouldUpdateTechnique = false;

View file

@ -78,7 +78,6 @@ using AmbientOcclusionFramebufferPointer = std::shared_ptr<AmbientOcclusionFrame
class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
Q_PROPERTY(bool horizonBased MEMBER horizonBased NOTIFY dirty)
Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty)
Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty)

View file

@ -282,7 +282,7 @@ void BloomEffect::configure(const Config& config) {
for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) {
blurName.back() = '0' + i;
auto blurConfig = config.getConfig<render::BlurGaussian>(blurName);
blurConfig->setProperty("filterScale", 1.0f);
blurConfig->filterScale = 1.0f;
}
}

View file

@ -25,7 +25,6 @@
class DebugDeferredBufferConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled)
Q_PROPERTY(int mode MEMBER mode WRITE setMode)
Q_PROPERTY(glm::vec4 size MEMBER size NOTIFY dirty)
public:

View file

@ -606,11 +606,16 @@ void RenderDeferredCleanup::run(const render::RenderContextPointer& renderContex
}
}
RenderDeferred::RenderDeferred(bool renderShadows):
_renderShadows(renderShadows)
{
DependencyManager::get<DeferredLightingEffect>()->init();
}
void RenderDeferred::configure(const Config& config) {
}
void RenderDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs) {
PROFILE_RANGE(render, "DeferredLighting");
auto deferredTransform = inputs.get0();
auto deferredFramebuffer = inputs.get1();

View file

@ -189,8 +189,7 @@ public:
using Config = RenderDeferredConfig;
using JobModel = render::Job::ModelI<RenderDeferred, Inputs, Config>;
RenderDeferred() {}
RenderDeferred(bool renderShadows) : _renderShadows(renderShadows) {}
RenderDeferred(bool renderShadows = false);
void configure(const Config& config);

View file

@ -444,10 +444,12 @@ LightStageSetup::LightStageSetup() {
}
void LightStageSetup::run(const render::RenderContextPointer& renderContext) {
auto stage = renderContext->_scene->getStage(LightStage::getName());
if (!stage) {
stage = std::make_shared<LightStage>();
renderContext->_scene->resetStage(LightStage::getName(), stage);
if (renderContext->_scene) {
auto stage = renderContext->_scene->getStage(LightStage::getName());
if (!stage) {
stage = std::make_shared<LightStage>();
renderContext->_scene->resetStage(LightStage::getName(), stage);
}
}
}

View file

@ -38,7 +38,7 @@ using namespace render;
extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter);
void RenderShadowTask::configure(const Config& configuration) {
DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.enabled);
DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.isEnabled());
// This is a task, so must still propogate configure() to its Jobs
// Task::configure(configuration);
}

View file

@ -38,7 +38,6 @@ protected:
class RenderShadowTaskConfig : public render::Task::Config::Persistent {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
public:
RenderShadowTaskConfig() : render::Task::Config::Persistent(QStringList() << "Render" << "Engine" << "Shadows", true) {}

View file

@ -64,7 +64,6 @@ private:
class ToneMappingConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled)
Q_PROPERTY(float exposure MEMBER exposure WRITE setExposure);
Q_PROPERTY(int curve MEMBER curve WRITE setCurve);
public:

View file

@ -20,7 +20,6 @@
namespace render {
class DrawSceneOctreeConfig : public Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty())
Q_PROPERTY(bool showVisibleCells READ getShowVisibleCells WRITE setShowVisibleCells NOTIFY dirty())
Q_PROPERTY(bool showEmptyCells READ getShowEmptyCells WRITE setShowEmptyCells NOTIFY dirty())
Q_PROPERTY(int numAllocatedCells READ getNumAllocatedCells)
@ -77,7 +76,6 @@ namespace render {
class DrawItemSelectionConfig : public Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty())
Q_PROPERTY(bool showInsideItems READ getShowInsideItems WRITE setShowInsideItems NOTIFY dirty())
Q_PROPERTY(bool showInsideSubcellItems READ getShowInsideSubcellItems WRITE setShowInsideSubcellItems NOTIFY dirty())
Q_PROPERTY(bool showPartialItems READ getShowPartialItems WRITE setShowPartialItems NOTIFY dirty())

View file

@ -26,7 +26,7 @@
using namespace render;
void DrawStatusConfig::dirtyHelper() {
enabled = showNetwork || showDisplay;
_isEnabled = showNetwork || showDisplay;
emit dirty();
}

View file

@ -319,10 +319,6 @@ void ScriptEngines::loadScripts() {
// loads all saved scripts
auto runningScripts = runningScriptsHandle.get();
if (runningScripts.empty()) {
loadDefaultScripts();
return;
}
for (auto script : runningScripts) {
auto string = script.toString();

View file

@ -74,6 +74,9 @@ public:
#endif
return hashCode;
}
static void prepareToExit() { manager()._exiting = true; }
private:
static DependencyManager& manager();
@ -84,6 +87,8 @@ private:
QHash<size_t, QSharedPointer<Dependency>> _instanceHash;
QHash<size_t, size_t> _inheritanceHash;
bool _exiting { false };
};
template <typename T>
@ -95,9 +100,17 @@ QSharedPointer<T> DependencyManager::get() {
instance = qSharedPointerCast<T>(manager().safeGet(hashCode));
#ifndef QT_NO_DEBUG
// debug builds...
if (instance.isNull()) {
qWarning() << "DependencyManager::get(): No instance available for" << typeid(T).name();
}
#else
// for non-debug builds, don't print "No instance available" during shutdown, because
// the act of printing this often causes crashes (because the LogHandler has-been/is-being
// deleted).
if (!manager()._exiting && instance.isNull()) {
qWarning() << "DependencyManager::get(): No instance available for" << typeid(T).name();
}
#endif
}

View file

@ -113,6 +113,13 @@ void doEvery(quint64& lastReportUsecs, quint64 secs, F lamdba) {
// Maximum accuracy in msecs
float secTimestampNow();
// Custom deleter for QObjects that calls deleteLater
struct LaterDeleter {
void operator()(QObject* ptr) {
ptr->deleteLater();
}
};
float randFloat();
int randIntInRange (int min, int max);
float randFloatInRange (float min,float max);

View file

@ -18,6 +18,17 @@
using namespace task;
JobConfig::~JobConfig() {
}
void JobConfig::setEnabled(bool enable) {
if (_isEnabled != enable) {
_isEnabled = enable;
emit dirtyEnabled();
}
}
void JobConfig::setPresetList(const QJsonObject& object) {
for (auto it = object.begin(); it != object.end(); it++) {
JobConfig* child = findChild<JobConfig*>(it.key(), Qt::FindDirectChildrenOnly);
@ -68,3 +79,57 @@ void TaskConfig::refresh() {
_task->applyConfiguration();
}
TaskConfig* TaskConfig::getRootConfig(const std::string& jobPath, std::string& jobName) const {
TaskConfig* root = const_cast<TaskConfig*> (this);
std::list<std::string> tokens;
std::size_t pos = 0, sepPos;
while ((sepPos = jobPath.find_first_of('.', pos)) != std::string::npos) {
std::string token = jobPath.substr(pos, sepPos - pos);
if (!token.empty()) {
tokens.push_back(token);
}
pos = sepPos + 1;
}
{
std::string token = jobPath.substr(pos, sepPos - pos);
if (!token.empty()) {
tokens.push_back(token);
}
}
if (tokens.empty()) {
return root;
}
else {
while (tokens.size() > 1) {
auto taskName = tokens.front();
tokens.pop_front();
root = root->findChild<TaskConfig*>((taskName.empty() ? QString() : QString(taskName.c_str())));
if (!root) {
return nullptr;
}
}
jobName = tokens.front();
}
return root;
}
JobConfig* TaskConfig::getJobConfig(const std::string& jobPath) const {
std::string jobName;
auto root = getRootConfig(jobPath, jobName);
if (!root) {
return nullptr;
}
if (jobName.empty()) {
return root;
} else {
auto found = root->findChild<JobConfig*>((jobName.empty() ? QString() : QString(jobName.c_str())));
if (!found) {
return nullptr;
}
return found;
}
}

View file

@ -50,12 +50,10 @@ public:
_default = toJsonValue(*this).toObject().toVariantMap();
_presets.unite(list.toVariantMap());
if (C::alwaysEnabled || C::enabled) {
if (C::isEnabled()) {
_presets.insert(DEFAULT, _default);
}
if (!C::alwaysEnabled) {
_presets.insert(NONE, QVariantMap{{ "enabled", false }});
}
_presets.insert(NONE, QVariantMap{{ "enabled", false }});
auto preset = _preset.get();
if (preset != _preset.getDefault() && _presets.contains(preset)) {
@ -92,17 +90,21 @@ class JobConfig : public QObject {
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY dirtyEnabled())
double _msCPURunTime{ 0.0 };
protected:
friend class TaskConfig;
bool _isEnabled{ true };
public:
using Persistent = PersistentConfig<JobConfig>;
JobConfig() = default;
JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {}
JobConfig(bool enabled): _isEnabled{ enabled } {}
~JobConfig();
bool isEnabled() { return alwaysEnabled || enabled; }
void setEnabled(bool enable) { enabled = alwaysEnabled || enable; emit dirtyEnabled(); }
bool alwaysEnabled{ true };
bool enabled{ true };
bool isEnabled() const { return _isEnabled; }
void setEnabled(bool enable);
virtual void setPresetList(const QJsonObject& object);
@ -200,6 +202,7 @@ public:
*/
class TaskConfig : public JobConfig {
Q_OBJECT
public:
using Persistent = PersistentConfig<TaskConfig>;
@ -221,27 +224,13 @@ public:
//
// getter for qml integration, prefer the templated getter
Q_INVOKABLE QObject* getConfig(const QString& name) { return getConfig<TConfigProxy>(name.toStdString()); }
// getter for cpp (strictly typed), prefer this getter
template <class T> typename T::Config* getConfig(std::string job = "") const {
const TaskConfig* root = this;
QString path = (job.empty() ? QString() : QString(job.c_str())); // an empty string is not a null string
auto tokens = path.split('.', QString::SkipEmptyParts);
TaskConfig* getRootConfig(const std::string& jobPath, std::string& jobName) const;
JobConfig* getJobConfig(const std::string& jobPath) const;
if (tokens.empty()) {
tokens.push_back(QString());
}
else {
while (tokens.size() > 1) {
auto name = tokens.front();
tokens.pop_front();
root = QObject::findChild<TaskConfig*>(name);
if (!root) {
return nullptr;
}
}
}
return root->findChild<typename T::Config*>(tokens.front());
template <class T> typename T::Config* getConfig(std::string jobPath = "") const {
return dynamic_cast<typename T::Config*>(getJobConfig(jobPath));
}
Q_INVOKABLE bool isTask() const override { return true; }

View file

@ -164,7 +164,7 @@ public:
void run(const ContextPointer& jobContext) override {
jobContext->jobConfig = std::static_pointer_cast<Config>(Concept::_config);
if (jobContext->jobConfig->alwaysEnabled || jobContext->jobConfig->isEnabled()) {
if (jobContext->jobConfig->isEnabled()) {
jobRun(_data, jobContext, _input.get<I>(), _output.edit<O>());
}
jobContext->jobConfig.reset();
@ -340,7 +340,7 @@ public:
void run(const ContextPointer& jobContext) override {
auto config = std::static_pointer_cast<C>(Concept::_config);
if (config->alwaysEnabled || config->enabled) {
if (config->isEnabled()) {
for (auto job : TaskConcept::_jobs) {
job.run(jobContext);
if (jobContext->taskFlow.doAbortTask()) {

View file

@ -149,6 +149,11 @@ protected:
int findPositionOfMenuItem(MenuWrapper* menu, const QString& searchMenuItem);
int positionBeforeSeparatorIfNeeded(MenuWrapper* menu, int requestedPosition);
// There is a design flaw here -- _actionHash is system-wide and hashes the names of menu-items to their
// QActions. The path (parent submenu name etc) isn't included in the hash key. This generally works,
// but we add "Home" twice -- once for "go home" and once for "set startup location to home". Anytime
// a user bookmarks a place and gives it a name like an existing menu-item, something will go wrong.
// TODO: change the js api to require the full path when referring to a specific menu item.
QHash<QString, QAction*> _actionHash;
bool isValidGrouping(const QString& grouping) const { return grouping == "Advanced" || grouping == "Developer"; }

View file

@ -892,7 +892,7 @@ glm::mat4 ViveControllerManager::InputDevice::calculateDefaultToReferenceForHead
glm::vec3 x = glm::normalize(glm::cross(Vectors::UNIT_Y, forward));
glm::vec3 z = glm::normalize(glm::cross(x, Vectors::UNIT_Y));
glm::mat3 centerEyeRotMat(x, Vectors::UNIT_Y, z);
glm::vec3 centerEyeTrans = headPuckPose.translation + centerEyeRotMat * glm::vec3(0.0f, _headPuckYOffset, _headPuckZOffset);
glm::vec3 centerEyeTrans = headPuckPose.translation + centerEyeRotMat * -glm::vec3(0.0f, _headPuckYOffset, _headPuckZOffset);
glm::mat4 E_s(glm::vec4(centerEyeRotMat[0], 0.0f),
glm::vec4(centerEyeRotMat[1], 0.0f),
@ -1056,7 +1056,7 @@ void ViveControllerManager::InputDevice::hapticsHelper(float deltaTime, bool lef
float hapticTime = strength * MAX_HAPTIC_TIME;
if (hapticTime < duration * 1000.0f) {
_system->TriggerHapticPulse(deviceIndex, 0, hapticTime);
}
}
float remainingHapticTime = duration - (hapticTime / 1000.0f + deltaTime * 1000.0f); // in milliseconds
if (leftHand) {
@ -1077,23 +1077,20 @@ void ViveControllerManager::InputDevice::calibrateLeftHand(const glm::mat4& defa
}
// This allows the user to not have to match the t-pose exactly. We assume that the y facing of the hand lies in the plane of the puck.
// Where the plane of the puck is defined by the the local z-axis of the puck, which is facing out of the vive logo/power button.
// Where the plane of the puck is defined by the the local z-axis of the puck, which is pointing out of the camera mount on the bottom of the puck.
glm::vec3 zPrime = handPoseZAxis;
glm::vec3 xPrime = glm::normalize(glm::cross(referenceHandYAxis, handPoseZAxis));
glm::vec3 yPrime = glm::normalize(glm::cross(zPrime, xPrime));
glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f),
glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
glm::vec3 translationOffset = glm::vec3(0.0f, _handPuckYOffset, _handPuckZOffset);
glm::quat initialRotation = handPose.getRotation();
glm::quat finalRotation = glmExtractRotation(newHandMat);
glm::quat rotationOffset = glm::inverse(initialRotation) * finalRotation;
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
glm::quat initialRot = handPose.getRotation();
glm::quat postOffsetRot = glm::inverse(initialRot) * glmExtractRotation(newHandMat);
glm::vec3 postOffsetTrans = postOffsetRot * -glm::vec3(0.0f, _handPuckYOffset, _handPuckZOffset);
glm::mat4 postOffsetMat = createMatFromQuatAndPos(postOffsetRot, postOffsetTrans);
_jointToPuckMap[controller::LEFT_HAND] = handPair.first;
_pucksPostOffset[handPair.first] = offsetMat;
_pucksPostOffset[handPair.first] = postOffsetMat;
}
void ViveControllerManager::InputDevice::calibrateRightHand(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) {
@ -1113,16 +1110,13 @@ void ViveControllerManager::InputDevice::calibrateRightHand(const glm::mat4& def
glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f),
glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
glm::vec3 translationOffset = glm::vec3(0.0f, _handPuckYOffset, _handPuckZOffset);
glm::quat initialRotation = handPose.getRotation();
glm::quat finalRotation = glmExtractRotation(newHandMat);
glm::quat rotationOffset = glm::inverse(initialRotation) * finalRotation;
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
glm::quat initialRot = handPose.getRotation();
glm::quat postOffsetRot = glm::inverse(initialRot) * glmExtractRotation(newHandMat);
glm::vec3 postOffsetTrans = postOffsetRot * -glm::vec3(0.0f, _handPuckYOffset, _handPuckZOffset);
glm::mat4 postOffsetMat = createMatFromQuatAndPos(postOffsetRot, postOffsetTrans);
_jointToPuckMap[controller::RIGHT_HAND] = handPair.first;
_pucksPostOffset[handPair.first] = offsetMat;
_pucksPostOffset[handPair.first] = postOffsetMat;
}

View file

@ -73,6 +73,121 @@ function job_print_functor(printout, showProps, maxDepth) {
}
}
// Use this function to create a functor that will build a tree datastructure of the Job visited
function job_tree_model_array_functor(jobTreeArray, newNodeFunctor) {
var jobsRoot;
var numJobs = 0;
var jobTreePath = []
if (newNodeFunctor === undefined) newNodeFunctor = function (node) {}
return function (job, depth, index) {
var id = numJobs
var newItem = {"name": job.objectName, "level": depth, "index": index, "id": id, "subNode": [], "path": ""}
if (depth == 0) {
newNodeFunctor(newItem)
jobTreeArray.push(newItem)
numJobs++
jobsRoot = jobTreeArray[0].subNode;
} else {
if (jobTreePath.length < depth) {
var node = jobsRoot;
var path;
for (var n = 0; n < jobTreePath.length; n++) {
newItem.path += (n > 0 ? "." : "") + node[jobTreePath[n]].name
node = node[jobTreePath[n]].subNode
}
newNodeFunctor(newItem)
node.push((newItem))
numJobs++
jobTreePath.push(0);
} else if (jobTreePath.length >= depth) {
var node = jobsRoot;
for (var n = 0; n < (depth - 1); n++) {
newItem.path += (n > 0 ? "." : "") + node[jobTreePath[n]].name
node = node[jobTreePath[n]].subNode
}
newNodeFunctor(newItem)
node.push((newItem))
numJobs++
jobTreePath[depth-1] = index;
while (jobTreePath.length > depth) {
jobTreePath.pop();
}
}
}
return true;
}
}
function job_tree_model_functor(jobTreeModel, maxLevel, newNodeFunctor) {
var jobsRoot;
var numJobs = 0;
var jobTreePath = []
if (newNodeFunctor === undefined) newNodeFunctor = function (node) {}
return function (job, depth, index) {
var id = numJobs
var newItem = {"name": job.objectName, "level": depth, "index": index, "id": id, "subNode": [], "path": "", "init": (depth < maxLevel), "ud": {}}
if (depth == 0) {
newNodeFunctor(newItem)
jobTreeModel.append(newItem)
numJobs++
jobsRoot = jobTreeModel.get(0).subNode;
} else {
if (jobTreePath.length < depth) {
var node = jobsRoot;
var path;
for (var n = 0; n < jobTreePath.length; n++) {
newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name
node = node.get(jobTreePath[n]).subNode
}
newNodeFunctor(newItem)
node.append((newItem))
numJobs++
jobTreePath.push(0);
} else if (jobTreePath.length >= depth) {
var node = jobsRoot;
for (var n = 0; n < (depth - 1); n++) {
newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name
node = node.get(jobTreePath[n]).subNode
}
newNodeFunctor(newItem)
node.append((newItem))
numJobs++
jobTreePath[depth-1] = index;
while (jobTreePath.length > depth) {
jobTreePath.pop();
}
}
}
return true;
}
}
// Traverse the jobTreenode data structure created above
function job_traverseTreeNode(root, functor, depth) {
if (root.subNode.length) {
depth++;
for (var i = 0; i <root.subNode.length; i++) {
var sub = root.subNode[i];
if (functor(sub, depth, i)) {
job_traverseTreeNode(sub, functor, depth, 0)
}
}
}
}
function job_traverseTreeNodeRoot(root, functor) {
if (functor(root, 0, 0)) {
job_traverseTreeNode(root, functor, 0)
}
}
// Expose functions for regular js including this files through the 'Jet' object
/*Jet = {}
Jet.task_traverse = task_traverse

View file

@ -19,56 +19,23 @@ import "../jet.js" as Jet
Rectangle {
HifiConstants { id: hifi;}
color: hifi.colors.baseGray;
color: Qt.rgba(hifi.colors.baseGray.r, hifi.colors.baseGray.g, hifi.colors.baseGray.b, 0.8);
id: root;
property var rootConfig : Workload
property var myArray : []
Component.onCompleted: {
var message = ""
var maxDepth = 3;
var jobTreePath = []
var jobsRoot;
var functor = function (job, depth, index) {
var newItem = {"name": job.objectName, "level": depth, "index": index, "subNode": [], "init": depth < maxDepth, "path": ""}
if (depth == 0) {
jobsModel.append(newItem)
jobsRoot = jobsModel.get(0).subNode;
} else {
if (jobTreePath.length < depth) {
var node = jobsRoot;
var path;
for (var n = 0; n < jobTreePath.length; n++) {
newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name
node = node.get(jobTreePath[n]).subNode
}
node.append(newItem)
jobTreePath.push(0);
} else if (jobTreePath.length >= depth) {
var node = jobsRoot;
for (var n = 0; n < (depth - 1); n++) {
newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name
node = node.get(jobTreePath[n]).subNode
}
node.append(newItem)
jobTreePath[depth-1] = index;
while (jobTreePath.length > depth) {
jobTreePath.pop();
}
}
}
return true;
}
var functor = Jet.job_tree_model_functor(jobsModel, 3, function(node) {
node["cpuT"] = 0.0
})
Jet.task_traverseTree(rootConfig, functor);
}
ListModel {
id: jobsModel
property var engineJobItemModel : []
}
Component {
@ -77,30 +44,46 @@ Rectangle {
id: objRecursiveColumn
clip: true
visible: model.init
MouseArea {
width: objRow.implicitWidth
height: objRow.implicitHeight
onDoubleClicked: {
for(var i = 1; i < parent.children.length - 1; ++i) {
parent.children[i].visible = !parent.children[i].visible
}
function switchFold() {
for(var i = 1; i < children.length - 1; ++i) {
children[i].visible = !children[i].visible
}
Row {
id: objRow
Item {
height: 1
width: model.level * 15
}
Row {
id: objRow
Item {
height: 1
width: model.level * 15
}
HifiControls.CheckBox {
id: objCheck
property var config: root.rootConfig.getConfig(model.path + "." + model.name);
text: " "
checked: root.rootConfig.getConfig(model.path + "." + model.name).enabled
onCheckedChanged: { root.rootConfig.getConfig(model.path + "." + model.name).enabled = checked }
}
MouseArea {
width: objLabel.implicitWidth
height: objLabel.implicitHeight
onDoubleClicked: {
parent.parent.switchFold()
}
HifiControls.CheckBox {
property var config: root.rootConfig.getConfig(model.path + "." + model.name);
HifiControls.Label {
id: objLabel
colorScheme: (root.rootConfig.getConfig(model.path + "." + model.name) ? hifi.colorSchemes.dark : hifi.colorSchemes.light)
text: (objRecursiveColumn.children.length > 2 ?
objRecursiveColumn.children[1].visible ?
qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name + " ms=" + config.cpuRunTime.toFixed(2)
checked: config.enabled
qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name
+ " id=" + model.id
}
}
}
Repeater {
model: subNode
delegate: objRecursiveDelegate

View file

@ -0,0 +1,265 @@
//
// jet/TaskTimeFrameView.qml
//
// Created by Sam Gateau, 2018/06/15
// Copyright 2018 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
//
import QtQuick 2.7
import QtQuick.Controls 1.4 as Original
import QtQuick.Controls.Styles 1.4
import "qrc:///qml/styles-uit"
import "qrc:///qml/controls-uit" as HifiControls
import "../jet.js" as Jet
Rectangle {
HifiConstants { id: hifi;}
color: Qt.rgba(hifi.colors.baseGray.r, hifi.colors.baseGray.g, hifi.colors.baseGray.b, 0.8);
id: root;
property var rootConfig : Workload
property var jobsTree
property var jobsArray
Component.onCompleted: {
if (!jobsTree) { jobsTree = new Array(); }
if (!jobsArray) { jobsArray = new Array(); }
var tfunctor = Jet.job_tree_model_array_functor(jobsTree, function(node) {
var job = { "fullpath": (node.path + "." + node.name), "cpuT": 0.0, "depth": node.level, "name": node.name }
jobsArray.push(job)
})
Jet.task_traverseTree(rootConfig, tfunctor);
for (var j = 0; j <jobsArray.length; j++) {
jobsArray[j].cpuT = Render.getConfig(jobsArray[j].fullpath).cpuRunTime
// print("job" + j + ": " + jobsArray[j].cpuT)
}
}
Component.onDestruction: {
myCanvasTimer.stop();
console.log("stopping timer!!!!");
}
Timer {
id: myCanvasTimer
interval: 100; running: true; repeat: true
onTriggered: pullFreshValues()
}
function pullFreshValues() {
for (var j = 0; j <jobsArray.length; j++) {
jobsArray[j].cpuT = Render.getConfig(jobsArray[j].fullpath).cpuRunTime
// jobsArray[j].cpuT = root.rootConfig.getConfig(jobsArray[j].fullpath).cpuRunTime
}
mycanvas.requestPaint()
}
property var frameScale : 10
Row {
id: myHeaderRow
anchors.top:parent.top
anchors.left:parent.left
anchors.right:parent.right
HifiControls.Button {
id: myTimerPlayPause
text: (myCanvasTimer.running ? "||" : "|>")
height: 24
width: 24
onClicked: {
print("list of highlight styles")
myCanvasTimer.running = !myCanvasTimer.running
}
}
}
Canvas {
id: mycanvas
anchors.top:myHeaderRow.bottom
anchors.bottom:parent.bottom
anchors.left:parent.left
anchors.right:parent.right
property var frameDuration: 10
property var frameViewBegin: 0
property var frameViewRange: width
function reset() {
frameViewBegin = 0
frameViewRange = width
}
function checkView() {
if (frameViewBegin > width * 0.9) {
frameViewBegin = width * 0.9
} else if (frameViewBegin + frameViewRange < width * 0.1) {
frameViewBegin = width * 0.1 -frameViewRange
}
}
function drag(deltaX) {
frameViewBegin -= deltaX
checkView()
}
function pivotScale(pivotX, deltaX) {
var newRange = frameViewRange + 2 * deltaX
if (newRange <= 1) {
newRange = 2;
}
frameViewBegin = pivotX - frameViewRange * (pivotX - frameViewBegin) / newRange
frameViewRange = newRange
print( "pivot= " + pivotX + " deltaX= " + (deltaX))
checkView()
}
onPaint: {
// print("mycanvasOnPaint " + jobsArray.length)
var lineHeight = 12;
function getXFromTime(t) {
return (t / mycanvas.frameDuration) * mycanvas.frameViewRange - (mycanvas.frameViewBegin)
}
function getWFromDuration(d) {
return (d / mycanvas.frameDuration) * mycanvas.frameViewRange
}
function displayBackground(ctx) {
ctx.fillStyle = Qt.rgba(0, 0, 0, root.backgroundOpacity);
ctx.fillRect(0, 0, width, height);
ctx.strokeStyle= "grey";
ctx.lineWidth="2";
ctx.beginPath();
ctx.moveTo(0, lineHeight + 1);
ctx.lineTo(width, lineHeight + 1);
ctx.moveTo(0, height);
ctx.lineTo(width, height);
var x0 = getXFromTime(0)
ctx.moveTo(x0, 0);
ctx.lineTo(x0, height);
x0 = getXFromTime(5)
ctx.moveTo(x0, 0);
ctx.lineTo(x0, height);
x0 = getXFromTime(10)
ctx.moveTo(x0, 0);
ctx.lineTo(x0, height);
ctx.stroke();
}
function drawJob(ctx, depth, index, duration, timeOffset) {
//print(root.jobsArray[index].cpuT)
ctx.fillStyle = ( depth % 2 ? ( index % 2 ? "blue" : "yellow") : ( index % 2 ? "green" : "red"))
ctx.fillRect(getXFromTime(timeOffset), lineHeight * 2 * depth,getWFromDuration(duration), lineHeight);
if (depth,getWFromDuration(duration) >= width * 0.1) {
ctx.fillStyle = "grey";
ctx.textAlign = "center";
ctx.fillText( root.jobsArray[index].name, getXFromTime(timeOffset + duration * 0.5), lineHeight * 2 * depth);
}
}
var ctx = getContext("2d");
ctx.clearRect(0, 0, width, height);
ctx.font="12px Verdana";
displayBackground(ctx);
if (jobsArray.length > 0) {
mycanvas.frameDuration = Math.max(jobsArray[0].cpuT, 1)
var rangeStack =new Array()
rangeStack.push( { "b": 0.0, "e": mycanvas.frameDuration } )
drawJob(ctx, 0, 0, jobsArray[0].cpuT, 0)
for (var i = 1; i <jobsArray.length; i++) {
var lastDepth = rangeStack.length - 1;
var depth = jobsArray[i].depth;
var timeOffset = 0.0
var duration = jobsArray[i].cpuT;
if (depth > lastDepth) {
timeOffset = rangeStack[lastDepth].b
while(rangeStack.length <= depth) {
rangeStack.push( { "b": timeOffset, "e": timeOffset + duration } )
}
} else {
if (depth < lastDepth) {
while(rangeStack.length != (depth + 1)) {
rangeStack.pop()
}
}
timeOffset = rangeStack[depth].e
rangeStack[depth].b = timeOffset
rangeStack[depth].e = timeOffset + duration
}
if (duration > 0.0) {
drawJob(ctx, depth, i, duration, timeOffset)
}
}
}
}
}
MouseArea {
id: hitbox
anchors.fill: mycanvas
acceptedButtons: Qt.LeftButton | Qt.RightButton
property var pivotX
property var dragPos
onPressed: {
dragPos = { "x":mouse.x, "y":mouse.y }
pivotX = mouse.x
}
onPositionChanged: {
if (dragPos !== undefined) {
var delta = mouse.x - dragPos.x
if (mouse.buttons & Qt.LeftButton) {
mycanvas.drag(delta)
}
if (mouse.buttons & Qt.RightButton) {
mycanvas.pivotScale(pivotX, delta)
}
dragPos.x = mouse.x
dragPos.y = mouse.y
mycanvas.requestPaint()
}
}
onReleased: {
dragPos = undefined
}
onWheel: {
mycanvas.pivotScale(wheel.x, mycanvas.frameViewRange * 0.02 * (wheel.angleDelta.y / 120.0))
mycanvas.requestPaint()
}
onDoubleClicked: {
mycanvas.reset()
mycanvas.requestPaint()
}
}
}

View file

@ -1,2 +1,3 @@
TaskList 1.0 TaskList.qml
TaskViewList 1.0 TaskViewList.qml
TaskTimeFrameView 1.0 TaskTimeFrameView.qml

View file

@ -1,13 +1,57 @@
function openEngineTaskView() {
// Set up the qml ui
var qml = Script.resolvePath('engineInspector.qml');
var window = new OverlayWindow({
title: 'Render Engine',
source: qml,
width: 300,
height: 400
(function() {
var TABLET_BUTTON_NAME = "Inspector";
var QMLAPP_URL = Script.resolvePath("./engineInspector.qml");
var ICON_URL = Script.resolvePath("../../../system/assets/images/luci-i.svg");
var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/luci-a.svg");
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({
text: TABLET_BUTTON_NAME,
icon: ICON_URL,
activeIcon: ACTIVE_ICON_URL
});
window.setPosition(200, 50);
//window.closed.connect(function() { Script.stop(); });
}
openEngineTaskView();
Script.scriptEnding.connect(function () {
killWindow()
button.clicked.disconnect(onClicked);
tablet.removeButton(button);
});
button.clicked.connect(onClicked);
var onScreen = false;
var window;
function onClicked() {
if (onScreen) {
killWindow()
} else {
createWindow()
}
}
function createWindow() {
var qml = Script.resolvePath(QMLAPP_URL);
window = new OverlayWindow({
title: 'Render Engine Inspector',
source: qml,
width: 250,
height: 500
});
window.setPosition(200, 50);
window.closed.connect(killWindow);
onScreen = true
button.editProperties({isActive: true});
}
function killWindow() {
if (window !== undefined) {
window.closed.disconnect(killWindow);
window.close()
window = undefined
}
onScreen = false
button.editProperties({isActive: false})
}
}());

View file

@ -1,7 +1,7 @@
//
// deferredLighting.qml
// EngineInspector.qml
//
// Created by Sam Gateau on 6/6/2016
// Created by Sam Gateau on 06/07/2018
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
@ -18,13 +18,13 @@ import "../lib/jet/qml" as Jet
Item {
HifiConstants { id: hifi;}
id: render;
id: root;
anchors.fill: parent
property var mainViewTask: Render.getConfig("RenderMainView")
property var rootConfig: Render.getConfig("")
Jet.TaskListView {
rootConfig: Render
anchors.fill: render
rootConfig: root.rootConfig
anchors.fill: root
}
}

View file

@ -0,0 +1,59 @@
(function() {
var TABLET_BUTTON_NAME = "Profiler";
var QMLAPP_URL = Script.resolvePath("./engineProfiler.qml");
var ICON_URL = Script.resolvePath("../../../system/assets/images/luci-i.svg");
var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/luci-a.svg");
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({
text: TABLET_BUTTON_NAME,
icon: ICON_URL,
activeIcon: ACTIVE_ICON_URL
});
Script.scriptEnding.connect(function () {
killWindow()
button.clicked.disconnect(onClicked);
tablet.removeButton(button);
});
button.clicked.connect(onClicked);
var onScreen = false;
var window;
function onClicked() {
if (onScreen) {
killWindow()
} else {
createWindow()
}
}
function createWindow() {
var qml = Script.resolvePath(QMLAPP_URL);
window = Desktop.createWindow(Script.resolvePath(QMLAPP_URL), {
title: 'Render Engine Profiler',
flags: Desktop.ALWAYS_ON_TOP,
presentationMode: Desktop.PresentationMode.NATIVE,
size: {x: 500, y: 100}
});
window.setPosition(200, 50);
window.closed.connect(killWindow);
onScreen = true
button.editProperties({isActive: true});
}
function killWindow() {
if (window !== undefined) {
window.closed.disconnect(killWindow);
window.close()
window = undefined
}
onScreen = false
button.editProperties({isActive: false})
}
}());

View file

@ -0,0 +1,31 @@
//
// EngineProfiler.qml
//
// Created by Sam Gateau on 06/07/2018
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3
import "qrc:///qml/styles-uit"
import "qrc:///qml/controls-uit" as HifiControls
import "../lib/jet/qml" as Jet
Item {
HifiConstants { id: hifi;}
id: root;
anchors.fill: parent
property var rootConfig: Render.getConfig("")
Jet.TaskTimeFrameView {
rootConfig: root.rootConfig
anchors.fill: root
}
}

View file

@ -615,7 +615,9 @@ function notificationPollCallbackHistory(historyArray) {
ui.notificationDisplayBanner(message);
} else {
for (var i = 0; i < notificationCount; i++) {
message = '"' + (historyArray[i].message) + '" ' +
var historyMessage = historyArray[i].message;
var sanitizedHistoryMessage = historyMessage.replace(/<\/?[^>]+(>|$)/g, "");
message = '"' + sanitizedHistoryMessage + '" ' +
"Open INVENTORY to see all activity.";
ui.notificationDisplayBanner(message);
}

View file

@ -129,9 +129,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
return getControllerWorldLocation(Controller.Standard.RightHand, true);
};
Selection.enableListHighlight(DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE);
Selection.enableListToScene(DISPATCHER_HOVERING_LIST);
this.updateTimings = function () {
_this.intervalCount++;
var thisInterval = Date.now();
@ -525,7 +522,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Controller.disableMapping(MAPPING_NAME);
_this.pointerManager.removePointers();
Pointers.removePointer(this.mouseRayPick);
Selection.disableListHighlight(DISPATCHER_HOVERING_LIST);
};
}

View file

@ -459,13 +459,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
this.dropGestureReset();
this.clearEquipHaptics();
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
unhighlightTargetEntity(this.targetEntityID);
var message = {
hand: this.hand,
entityID: this.targetEntityID
};
Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message));
var grabbedProperties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES);
var grabData = getGrabbableData(grabbedProperties);

View file

@ -84,7 +84,6 @@ Script.include("/~/system/libraries/controllers.js");
this.entityWithContextOverlay = false;
this.contextOverlayTimer = false;
this.locked = false;
this.highlightedEntity = null;
this.reticleMinX = MARGIN;
this.reticleMaxX = null;
this.reticleMinY = MARGIN;
@ -410,9 +409,6 @@ Script.include("/~/system/libraries/controllers.js");
if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE ||
(this.notPointingAtEntity(controllerData) && Window.isPhysicsEnabled()) || this.targetIsNull()) {
this.endFarGrabAction();
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
this.highlightedEntity = null;
this.restoreIgnoredEntities();
return makeRunningValues(false, [], []);
}
@ -466,9 +462,6 @@ Script.include("/~/system/libraries/controllers.js");
if (rayPickInfo.type === Picks.INTERSECTED_ENTITY) {
if (controllerData.triggerClicks[this.hand]) {
var entityID = rayPickInfo.objectID;
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
this.highlightedEntity = null;
var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
if (targetProps.href !== "") {
AddressManager.handleLookupString(targetProps.href);
@ -513,66 +506,43 @@ Script.include("/~/system/libraries/controllers.js");
this.startFarGrabAction(controllerData, targetProps);
}
}
} else {
var targetEntityID = rayPickInfo.objectID;
if (this.highlightedEntity !== targetEntityID) {
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity",
this.highlightedEntity);
var selectionTargetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES);
} else if (!this.entityWithContextOverlay) {
var _this = this;
var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps);
selectionTargetObject.parentProps = getEntityParents(selectionTargetProps);
var selectionTargetEntity = selectionTargetObject.getTargetEntity();
if (entityIsGrabbable(selectionTargetEntity.props) ||
entityIsGrabbable(selectionTargetObject.entityProps)) {
Selection.addToSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", rayPickInfo.objectID);
if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) {
if (_this.contextOverlayTimer) {
Script.clearTimeout(_this.contextOverlayTimer);
}
this.highlightedEntity = rayPickInfo.objectID;
_this.contextOverlayTimer = false;
_this.potentialEntityWithContextOverlay = rayPickInfo.objectID;
}
if (!this.entityWithContextOverlay) {
var _this = this;
if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) {
if (_this.contextOverlayTimer) {
Script.clearTimeout(_this.contextOverlayTimer);
if (!_this.contextOverlayTimer) {
_this.contextOverlayTimer = Script.setTimeout(function () {
if (!_this.entityWithContextOverlay &&
_this.contextOverlayTimer &&
_this.potentialEntityWithContextOverlay === rayPickInfo.objectID) {
var props = Entities.getEntityProperties(rayPickInfo.objectID, DISPATCHER_PROPERTIES);
var pointerEvent = {
type: "Move",
id: _this.hand + 1, // 0 is reserved for hardware mouse
pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID,
rayPickInfo.intersection, props),
pos3D: rayPickInfo.intersection,
normal: rayPickInfo.surfaceNormal,
direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal),
button: "Secondary"
};
if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) {
_this.entityWithContextOverlay = rayPickInfo.objectID;
}
}
_this.contextOverlayTimer = false;
_this.potentialEntityWithContextOverlay = rayPickInfo.objectID;
}
if (!_this.contextOverlayTimer) {
_this.contextOverlayTimer = Script.setTimeout(function () {
if (!_this.entityWithContextOverlay &&
_this.contextOverlayTimer &&
_this.potentialEntityWithContextOverlay === rayPickInfo.objectID) {
var props = Entities.getEntityProperties(rayPickInfo.objectID, DISPATCHER_PROPERTIES);
var pointerEvent = {
type: "Move",
id: _this.hand + 1, // 0 is reserved for hardware mouse
pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID,
rayPickInfo.intersection, props),
pos3D: rayPickInfo.intersection,
normal: rayPickInfo.surfaceNormal,
direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal),
button: "Secondary"
};
if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) {
_this.entityWithContextOverlay = rayPickInfo.objectID;
}
}
_this.contextOverlayTimer = false;
}, 500);
}
}, 500);
}
}
} else if (this.distanceRotating) {
this.distanceRotate(otherFarGrabModule);
} else if (this.highlightedEntity) {
Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity);
this.highlightedEntity = null;
}
}
return this.exitIfDisabled(controllerData);

View file

@ -61,6 +61,8 @@ Script.include("/~/system/libraries/controllers.js");
this.reticleMinY = MARGIN;
this.reticleMaxY = 0;
this.lastUnexpectedChildrenCheckTime = 0;
this.endedGrab = 0;
this.MIN_HAPTIC_PULSE_INTERVAL = 500; // ms
var FAR_GRAB_JOINTS = [65527, 65528]; // FARGRAB_LEFTHAND_INDEX, FARGRAB_RIGHTHAND_INDEX
@ -144,7 +146,12 @@ Script.include("/~/system/libraries/controllers.js");
// compute the mass for the purpose of energy and how quickly to move object
this.mass = this.getMass(grabbedProperties.dimensions, grabbedProperties.density);
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
// Debounce haptic pules. Can occur as near grab controller module vacillates between being ready or not due to
// changing positions and floating point rounding.
if (Date.now() - this.endedGrab > this.MIN_HAPTIC_PULSE_INTERVAL) {
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
}
unhighlightTargetEntity(this.targetEntityID);
var message = {
hand: this.hand,
@ -256,7 +263,7 @@ Script.include("/~/system/libraries/controllers.js");
};
this.endFarParentGrab = function (controllerData) {
this.hapticTargetID = null;
this.endedGrab = Date.now();
// var endProps = controllerData.nearbyEntityPropertiesByID[this.targetEntityID];
var endProps = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES);
if (this.thisFarGrabJointIsParent(endProps)) {
@ -410,11 +417,6 @@ Script.include("/~/system/libraries/controllers.js");
if (targetEntity) {
var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES);
if (entityIsGrabbable(gtProps)) {
// give haptic feedback
if (gtProps.id !== this.hapticTargetID) {
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
this.hapticTargetID = gtProps.id;
}
// if we've attempted to grab a child, roll up to the root of the tree
var groupRootProps = findGroupParent(controllerData, gtProps);
if (entityIsGrabbable(groupRootProps)) {

View file

@ -1,155 +0,0 @@
//
// highlightNearbyEntities.js
//
// Created by Dante Ruiz 2018-4-10
// 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
/* global Script, MyAvatar, entityIsCloneable, Messages, print */
"use strict";
(function () {
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Script.include("/~/system/libraries/controllers.js");
Script.include("/~/system/libraries/cloneEntityUtils.js");
var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
function differenceInArrays(firstArray, secondArray) {
var differenceArray = firstArray.filter(function(element) {
return secondArray.indexOf(element) < 0;
});
return differenceArray;
}
function HighlightNearbyEntities(hand) {
this.hand = hand;
this.otherHand = hand === dispatcherUtils.RIGHT_HAND ? dispatcherUtils.LEFT_HAND :
dispatcherUtils.RIGHT_HAND;
this.highlightedEntities = [];
this.parameters = dispatcherUtils.makeDispatcherModuleParameters(
480,
this.hand === dispatcherUtils.RIGHT_HAND ? ["rightHand"] : ["leftHand"],
[],
100);
this.isGrabable = function(controllerData, props) {
var canGrabEntity = false;
if (dispatcherUtils.entityIsGrabbable(props) || entityIsCloneable(props)) {
// if we've attempted to grab a child, roll up to the root of the tree
var groupRootProps = dispatcherUtils.findGroupParent(controllerData, props);
canGrabEntity = true;
if (!dispatcherUtils.entityIsGrabbable(groupRootProps)) {
canGrabEntity = false;
}
}
return canGrabEntity;
};
this.clearAll = function() {
this.highlightedEntities.forEach(function(entity) {
dispatcherUtils.unhighlightTargetEntity(entity);
});
};
this.hasHyperLink = function(props) {
return (props.href !== "" && props.href !== undefined);
};
this.removeEntityFromHighlightList = function(entityID) {
var index = this.highlightedEntities.indexOf(entityID);
if (index > -1) {
this.highlightedEntities.splice(index, 1);
}
};
this.getOtherModule = function() {
var otherModule = this.hand === dispatcherUtils.RIGHT_HAND ? leftHighlightNearbyEntities :
rightHighlightNearbyEntities;
return otherModule;
};
this.getOtherHandHighlightedEntities = function() {
return this.getOtherModule().highlightedEntities;
};
this.highlightEntities = function(controllerData) {
var nearbyEntitiesProperties = controllerData.nearbyEntityProperties[this.hand];
var otherHandHighlightedEntities = this.getOtherHandHighlightedEntities();
var newHighlightedEntities = [];
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
for (var i = 0; i < nearbyEntitiesProperties.length; i++) {
var props = nearbyEntitiesProperties[i];
if (props.distance > dispatcherUtils.NEAR_GRAB_RADIUS * sensorScaleFactor) {
continue;
}
if (this.isGrabable(controllerData, props) || this.hasHyperLink(props)) {
dispatcherUtils.highlightTargetEntity(props.id);
if (newHighlightedEntities.indexOf(props.id) < 0) {
newHighlightedEntities.push(props.id);
}
}
}
var unhighlightEntities = differenceInArrays(this.highlightedEntities, newHighlightedEntities);
unhighlightEntities.forEach(function(entityID) {
if (otherHandHighlightedEntities.indexOf(entityID) < 0 ) {
dispatcherUtils.unhighlightTargetEntity(entityID);
}
});
this.highlightedEntities = newHighlightedEntities;
};
this.isReady = function(controllerData) {
this.highlightEntities(controllerData);
return dispatcherUtils.makeRunningValues(false, [], []);
};
this.run = function(controllerData) {
return this.isReady(controllerData);
};
}
var handleMessage = function(channel, message, sender) {
var data;
if (sender === MyAvatar.sessionUUID) {
if (channel === 'Hifi-unhighlight-entity') {
try {
data = JSON.parse(message);
var hand = data.hand;
if (hand === dispatcherUtils.LEFT_HAND) {
leftHighlightNearbyEntities.removeEntityFromHighlightList(data.entityID);
} else if (hand === dispatcherUtils.RIGHT_HAND) {
rightHighlightNearbyEntities.removeEntityFromHighlightList(data.entityID);
}
} catch (e) {
print("highlightNearbyEntities -- Failed to parse message: " + JSON.stringify(message));
}
} else if (channel === 'Hifi-unhighlight-all') {
leftHighlightNearbyEntities.clearAll();
rightHighlightNearbyEntities.clearAll();
}
}
};
var leftHighlightNearbyEntities = new HighlightNearbyEntities(dispatcherUtils.LEFT_HAND);
var rightHighlightNearbyEntities = new HighlightNearbyEntities(dispatcherUtils.RIGHT_HAND);
dispatcherUtils.enableDispatcherModule("LeftHighlightNearbyEntities", leftHighlightNearbyEntities);
dispatcherUtils.enableDispatcherModule("RightHighlightNearbyEntities", rightHighlightNearbyEntities);
function cleanup() {
dispatcherUtils.disableDispatcherModule("LeftHighlightNearbyEntities");
dispatcherUtils.disableDispatcherModule("RightHighlightNearbyEntities");
}
Messages.subscribe('Hifi-unhighlight-entity');
Messages.subscribe('Hifi-unhighlight-all');
Messages.messageReceived.connect(handleMessage);
Script.scriptEnding.connect(cleanup);
}());

View file

@ -1,104 +0,0 @@
//
// mouseHighlightEntities.js
//
// scripts/system/controllers/controllerModules/
//
// Created by Dante Ruiz 2018-4-11
// 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
//
/* jslint bitwise: true */
/* global Script, print, Entities, Messages, Picks, HMD, MyAvatar, isInEditMode, DISPATCHER_PROPERTIES */
(function() {
Script.include("/~/system/libraries/utils.js");
var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
function MouseHighlightEntities() {
this.highlightedEntity = null;
this.grabbedEntity = null;
this.parameters = dispatcherUtils.makeDispatcherModuleParameters(
5,
["mouse"],
[],
100);
this.setGrabbedEntity = function(entity) {
this.grabbedEntity = entity;
this.highlightedEntity = null;
};
this.isReady = function(controllerData) {
if (HMD.active) {
if (this.highlightedEntity) {
dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity);
this.highlightedEntity = null;
}
} else if (!this.grabbedEntity && !isInEditMode()) {
var pickResult = controllerData.mouseRayPick;
if (pickResult.type === Picks.INTERSECTED_ENTITY) {
var targetEntityID = pickResult.objectID;
if (this.highlightedEntity !== targetEntityID) {
var targetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES);
if (this.highlightedEntity) {
dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity);
this.highlightedEntity = null;
}
if (dispatcherUtils.entityIsGrabbable(targetProps)) {
// highlight entity
dispatcherUtils.highlightTargetEntity(targetEntityID);
this.highlightedEntity = targetEntityID;
}
}
} else if (this.highlightedEntity) {
dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity);
this.highlightedEntity = null;
}
}
return dispatcherUtils.makeRunningValues(false, [], []);
};
this.run = function(controllerData) {
return this.isReady(controllerData);
};
}
var mouseHighlightEntities = new MouseHighlightEntities();
dispatcherUtils.enableDispatcherModule("MouseHighlightEntities", mouseHighlightEntities);
var handleMessage = function(channel, message, sender) {
var data;
if (sender === MyAvatar.sessionUUID) {
if (channel === 'Hifi-Object-Manipulation') {
try {
data = JSON.parse(message);
if (data.action === 'grab') {
var grabbedEntity = data.grabbedEntity;
mouseHighlightEntities.setGrabbedEntity(grabbedEntity);
} else if (data.action === 'release') {
mouseHighlightEntities.setGrabbedEntity(null);
}
} catch (e) {
print("Warning: mouseHighlightEntities -- error parsing Hifi-Object-Manipulation: " + message);
}
}
}
};
function cleanup() {
dispatcherUtils.disableDispatcherModule("MouseHighlightEntities");
}
Messages.subscribe('Hifi-Object-Manipulation');
Messages.messageReceived.connect(handleMessage);
Script.scriptEnding.connect(cleanup);
})();

View file

@ -24,7 +24,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
this.hand = hand;
this.targetEntityID = null;
this.actionID = null; // action this script created...
this.hapticTargetID = null;
this.parameters = makeDispatcherModuleParameters(
500,
@ -115,13 +114,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(this.targetEntityID, "startNearGrab", args);
unhighlightTargetEntity(this.targetEntityID);
var message = {
hand: this.hand,
entityID: this.targetEntityID
};
Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message));
};
// this is for when the action is going to time-out
@ -171,10 +163,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
break;
}
if (entityIsGrabbable(props) || entityIsCloneable(props)) {
if (props.id !== this.hapticTargetID) {
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
this.hapticTargetID = props.id;
}
if (!entityIsCloneable(props)) {
// if we've attempted to grab a non-cloneable child, roll up to the root of the tree
var groupRootProps = findGroupParent(controllerData, props);
@ -206,7 +194,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
return makeRunningValues(true, [this.targetEntityID], []);
}
} else {
this.hapticTargetID = null;
return makeRunningValues(false, [], []);
}
};
@ -216,7 +203,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE &&
controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
this.endNearGrabAction();
this.hapticTargetID = null;
return makeRunningValues(false, [], []);
}

View file

@ -11,7 +11,7 @@
TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS,
findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH,
HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, findHandChildEntities, TEAR_AWAY_DISTANCE, MSECS_PER_SEC, TEAR_AWAY_CHECK_TIME,
TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, highlightTargetEntity, unhighlightTargetEntity,
TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, NEAR_GRAB_DISTANCE,
distanceBetweenEntityLocalPositionAndBoundingBox, getGrabbableData, getGrabPointSphereOffset, DISPATCHER_PROPERTIES
*/
@ -24,15 +24,6 @@ Script.include("/~/system/libraries/controllers.js");
// XXX this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true;
// XXX this.kinematicGrab = (grabbableData.kinematic !== undefined) ? grabbableData.kinematic : NEAR_GRABBING_KINEMATIC;
// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral
function getGrabOffset(handController) {
var offset = getGrabPointSphereOffset(handController, true);
offset.y = -offset.y;
return Vec3.multiply(MyAvatar.sensorToWorldScale, offset);
}
function NearParentingGrabEntity(hand) {
this.hand = hand;
this.targetEntityID = null;
@ -40,12 +31,10 @@ Script.include("/~/system/libraries/controllers.js");
this.previousParentID = {};
this.previousParentJointIndex = {};
this.previouslyUnhooked = {};
this.hapticTargetID = null;
this.lastUnequipCheckTime = 0;
this.autoUnequipCounter = 0;
this.lastUnexpectedChildrenCheckTime = 0;
this.robbed = false;
this.highlightedEntity = null;
this.cloneAllowed = true;
this.parameters = makeDispatcherModuleParameters(
@ -95,14 +84,7 @@ Script.include("/~/system/libraries/controllers.js");
this.startNearParentingGrabEntity = function (controllerData, targetProps) {
var grabData = getGrabbableData(targetProps);
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
unhighlightTargetEntity(this.targetEntityID);
this.highlightedEntity = null;
var message = {
hand: this.hand,
entityID: this.targetEntityID
};
Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message));
var handJointIndex;
if (grabData.grabFollowsController) {
handJointIndex = getControllerJointIndex(this.hand);
@ -146,7 +128,6 @@ Script.include("/~/system/libraries/controllers.js");
};
this.endNearParentingGrabEntity = function (controllerData) {
this.hapticTargetID = null;
var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID];
if (this.thisHandIsParent(props) && !this.robbed) {
Entities.editEntity(this.targetEntityID, {
@ -164,8 +145,7 @@ Script.include("/~/system/libraries/controllers.js");
grabbedEntity: this.targetEntityID,
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
}));
unhighlightTargetEntity(this.targetEntityID);
this.highlightedEntity = null;
this.grabbing = false;
this.targetEntityID = null;
this.robbed = false;
@ -178,8 +158,10 @@ Script.include("/~/system/libraries/controllers.js");
this.lastUnequipCheckTime = now;
if (props.parentID === MyAvatar.SELF_ID) {
var tearAwayDistance = TEAR_AWAY_DISTANCE * MyAvatar.sensorToWorldScale;
var controllerIndex = (this.hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand);
var controllerGrabOffset = getGrabOffset(controllerIndex);
var controllerIndex =
this.hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand;
var controllerGrabOffset = getGrabPointSphereOffset(controllerIndex, true);
controllerGrabOffset = Vec3.multiply(-MyAvatar.sensorToWorldScale, controllerGrabOffset);
var distance = distanceBetweenEntityLocalPositionAndBoundingBox(props, controllerGrabOffset);
if (distance > tearAwayDistance) {
this.autoUnequipCounter++;
@ -242,21 +224,18 @@ Script.include("/~/system/libraries/controllers.js");
// nearbyEntityProperties is already sorted by length from controller
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
var nearGrabDistance = NEAR_GRAB_DISTANCE * sensorScaleFactor;
var nearGrabRadius = NEAR_GRAB_RADIUS * sensorScaleFactor;
for (var i = 0; i < nearbyEntityProperties.length; i++) {
var props = nearbyEntityProperties[i];
var handPosition = controllerData.controllerLocations[this.hand].position;
var dist = distanceBetweenPointAndEntityBoundingBox(handPosition, props);
var distance = Vec3.distance(handPosition, props.position);
if ((dist > TEAR_AWAY_DISTANCE) ||
(distance > NEAR_GRAB_RADIUS * sensorScaleFactor)) {
var grabPosition = controllerData.controllerLocations[this.hand].position; // Is offset from hand position.
var dist = distanceBetweenPointAndEntityBoundingBox(grabPosition, props);
var distance = Vec3.distance(grabPosition, props.position);
if ((dist > nearGrabDistance) ||
(distance > nearGrabRadius)) { // Only smallish entities can be near grabbed.
continue;
}
if (entityIsGrabbable(props) || entityIsCloneable(props)) {
// give haptic feedback
if (props.id !== this.hapticTargetID) {
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
this.hapticTargetID = props.id;
}
if (!entityIsCloneable(props)) {
// if we've attempted to grab a non-cloneable child, roll up to the root of the tree
var groupRootProps = findGroupParent(controllerData, props);
@ -290,16 +269,9 @@ Script.include("/~/system/libraries/controllers.js");
return makeRunningValues(false, [], []); // let nearActionGrabEntity handle it
} else {
this.targetEntityID = targetProps.id;
this.highlightedEntity = this.targetEntityID;
highlightTargetEntity(this.targetEntityID);
return makeRunningValues(true, [this.targetEntityID], []);
}
} else {
if (this.highlightedEntity) {
unhighlightTargetEntity(this.highlightedEntity);
this.highlightedEntity = null;
}
this.hapticTargetID = null;
this.robbed = false;
return makeRunningValues(false, [], []);
}
@ -316,11 +288,8 @@ Script.include("/~/system/libraries/controllers.js");
var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID];
if (!props) {
// entity was deleted
unhighlightTargetEntity(this.targetEntityID);
this.highlightedEntity = null;
this.grabbing = false;
this.targetEntityID = null;
this.hapticTargetID = null;
this.robbed = false;
return makeRunningValues(false, [], []);
}
@ -335,12 +304,10 @@ Script.include("/~/system/libraries/controllers.js");
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(this.targetEntityID, "continueNearGrab", args);
} else {
// still searching / highlighting
// still searching
var readiness = this.isReady(controllerData);
if (!readiness.active) {
this.robbed = false;
unhighlightTargetEntity(this.highlightedEntity);
this.highlightedEntity = null;
return readiness;
}
if (controllerData.triggerClicks[this.hand] || controllerData.secondaryValues[this.hand] > BUMPER_ON_VALUE) {

View file

@ -7,7 +7,7 @@
/* global Script, Entities, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, getGrabbableData,
Vec3, TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, makeRunningValues, NEAR_GRAB_RADIUS, unhighlightTargetEntity
Vec3, TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, makeRunningValues, NEAR_GRAB_RADIUS
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@ -55,7 +55,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
this.startNearTrigger = function (controllerData) {
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(this.targetEntityID, "startNearTrigger", args);
unhighlightTargetEntity(this.targetEntityID);
};
this.continueNearTrigger = function (controllerData) {

View file

@ -35,9 +35,7 @@ var CONTOLLER_SCRIPTS = [
"controllerModules/hudOverlayPointer.js",
"controllerModules/mouseHMD.js",
"controllerModules/scaleEntity.js",
"controllerModules/highlightNearbyEntities.js",
"controllerModules/nearGrabHyperLinkEntity.js",
"controllerModules/mouseHighlightEntities.js",
"controllerModules/nearTabletHighlight.js"
];

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