From f159d4c91dae39f9f05c9009e10a6dd44da2abec Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Tue, 31 Jan 2017 20:45:35 +0000 Subject: [PATCH 01/20] create nameTag.js script Running the script creates a text entity that will hover over the users head showing their display name. --- scripts/system/nameTag.js | 98 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 scripts/system/nameTag.js diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js new file mode 100644 index 0000000000..adaab83297 --- /dev/null +++ b/scripts/system/nameTag.js @@ -0,0 +1,98 @@ +"use strict"; + +/*jslint vars: true, plusplus: true*/ +/*global Entities, Script, Quat, Vec3, MyAvatar, print*/ +// nameTag.js +// +// Created by Triplelexx on 17/01/31 +// 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 + +const NAMETAG_DIMENSIONS = { + x: 1.0, + y: 0.2, + z: 1.0 +} + +const CLIENTONLY = false; +const NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; +const ENTITY_CHECK_INTERVAL = 5000; // ms = 5 seconds +const STARTUP_DELAY = 2000; // ms = 2 second +const OLD_AGE = 3500; // we recreate the entity if older than this time in seconds +const TTL = 2; // time to live in seconds if script is not running +const HEIGHT_ABOVE_HEAD = 0.2; +const HEAD_OFFSET = -0.025; + +var nametagEntityID = NULL_UUID; +var lastCheckForEntity = 0; + +// create the name tag entity after a brief delay +Script.setTimeout(function() { + addNameTag(); +}, STARTUP_DELAY); + +function addNameTag() { + var nametagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); + nametagPosition.y += HEIGHT_ABOVE_HEAD; + var modelNameTagProperties = { + type: 'Text', + text: MyAvatar.displayName, + parentID: MyAvatar.sessionUUID, + dimensions: NAMETAG_DIMENSIONS, + position: nametagPosition + } + nametagEntityID = Entities.addEntity(modelNameTagProperties, CLIENTONLY); +} + +function deleteNameTag() { + if(nametagEntityID !== NULL_UUID) { + Entities.deleteEntity(nametagEntityID); + nametagEntityID = NULL_UUID; + } +} + +// cleanup on ending +Script.scriptEnding.connect(cleanup); +function cleanup() { + deleteNameTag(); +} + +Script.update.connect(update); +function update() { + // bail if no entity + if(nametagEntityID == NULL_UUID) { + return; + } + + if(Date.now() - lastCheckForEntity > ENTITY_CHECK_INTERVAL) { + checkForEntity(); + lastCheckForEntity = Date.now(); + } +} + +function checkForEntity() { + var nametagProps = Entities.getEntityProperties(nametagEntityID); + + // it is possible for the age to not be a valid number, we check for this and bail accordingly + if(nametagProps.age < 1) { + return; + } + + // it's too old make a new one, otherwise update + if(nametagProps.age > OLD_AGE || nametagProps.age == undefined) { + deleteNameTag(); + addNameTag(); + } else { + var nametagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); + nametagPosition.y += HEIGHT_ABOVE_HEAD; + Entities.editEntity(nametagEntityID, { + position: nametagPosition, + // lifetime is in seconds we add TTL on top of the next poll time + lifetime: Math.round(nametagProps.age) + (ENTITY_CHECK_INTERVAL / 1000) + TTL, + text: MyAvatar.displayName + }); + } +} From be68f84100ed073266722f22b7df556f07060504 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Tue, 31 Jan 2017 22:14:39 +0000 Subject: [PATCH 02/20] update nameTag.js comments --- scripts/system/nameTag.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js index adaab83297..cd8df2c477 100644 --- a/scripts/system/nameTag.js +++ b/scripts/system/nameTag.js @@ -7,6 +7,7 @@ // Created by Triplelexx on 17/01/31 // Copyright 2017 High Fidelity, Inc. // +// Running the script creates a text entity that will hover over the user's head showing their display name. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -38,6 +39,7 @@ function addNameTag() { var nametagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); nametagPosition.y += HEIGHT_ABOVE_HEAD; var modelNameTagProperties = { + name: MyAvatar.displayName + ' Name Tag', type: 'Text', text: MyAvatar.displayName, parentID: MyAvatar.sessionUUID, @@ -62,7 +64,7 @@ function cleanup() { Script.update.connect(update); function update() { - // bail if no entity + // if no entity we return if(nametagEntityID == NULL_UUID) { return; } @@ -76,12 +78,12 @@ function update() { function checkForEntity() { var nametagProps = Entities.getEntityProperties(nametagEntityID); - // it is possible for the age to not be a valid number, we check for this and bail accordingly + // it is possible for the age to not be a valid number, we check for this and return accordingly if(nametagProps.age < 1) { return; } - // it's too old make a new one, otherwise update + // it's too old or we receive undefined make a new one, otherwise update if(nametagProps.age > OLD_AGE || nametagProps.age == undefined) { deleteNameTag(); addNameTag(); From b5d2926605f57b78137a12f9ca7493b3a8448290 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Wed, 1 Feb 2017 12:49:41 +0000 Subject: [PATCH 03/20] make text entity smaller and allow dynamic resizing based on name length --- scripts/system/nameTag.js | 74 ++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js index cd8df2c477..ceb7583a2e 100644 --- a/scripts/system/nameTag.js +++ b/scripts/system/nameTag.js @@ -12,12 +12,6 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -const NAMETAG_DIMENSIONS = { - x: 1.0, - y: 0.2, - z: 1.0 -} - const CLIENTONLY = false; const NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; const ENTITY_CHECK_INTERVAL = 5000; // ms = 5 seconds @@ -26,8 +20,11 @@ const OLD_AGE = 3500; // we recreate the entity if older than this time in secon const TTL = 2; // time to live in seconds if script is not running const HEIGHT_ABOVE_HEAD = 0.2; const HEAD_OFFSET = -0.025; +const SIZE_Y = 0.075; +const LETTER_OFFSET = 0.0225; +const LINE_HEIGHT = 0.05; -var nametagEntityID = NULL_UUID; +var nameTagEntityID = NULL_UUID; var lastCheckForEntity = 0; // create the name tag entity after a brief delay @@ -36,26 +33,53 @@ Script.setTimeout(function() { }, STARTUP_DELAY); function addNameTag() { - var nametagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); - nametagPosition.y += HEIGHT_ABOVE_HEAD; + var nameTagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); + nameTagPosition.y += HEIGHT_ABOVE_HEAD; var modelNameTagProperties = { name: MyAvatar.displayName + ' Name Tag', type: 'Text', text: MyAvatar.displayName, + lineHeight: LINE_HEIGHT, parentID: MyAvatar.sessionUUID, - dimensions: NAMETAG_DIMENSIONS, - position: nametagPosition + dimensions: dimensionsFromName(), + position: nameTagPosition } - nametagEntityID = Entities.addEntity(modelNameTagProperties, CLIENTONLY); + nameTagEntityID = Entities.addEntity(modelNameTagProperties, CLIENTONLY); } +function updateNameTag() { + var nameTagProps = Entities.getEntityProperties(nameTagEntityID); + var nameTagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); + nameTagPosition.y += HEIGHT_ABOVE_HEAD; + + Entities.editEntity(nameTagEntityID, { + position: nameTagPosition, + dimensions: dimensionsFromName(), + // lifetime is in seconds we add TTL on top of the next poll time + lifetime: Math.round(nameTagProps.age) + (ENTITY_CHECK_INTERVAL / 1000) + TTL, + text: MyAvatar.displayName + }); +}; + function deleteNameTag() { - if(nametagEntityID !== NULL_UUID) { - Entities.deleteEntity(nametagEntityID); - nametagEntityID = NULL_UUID; + if(nameTagEntityID !== NULL_UUID) { + Entities.deleteEntity(nameTagEntityID); + nameTagEntityID = NULL_UUID; } } +function dimensionsFromName() { + var nameTagDimensions = { + x: 0.0, + y: SIZE_Y, + z: 0.0 + } + for(var letter in MyAvatar.displayName) { + nameTagDimensions.x += LETTER_OFFSET; + } + return nameTagDimensions; +}; + // cleanup on ending Script.scriptEnding.connect(cleanup); function cleanup() { @@ -65,7 +89,7 @@ function cleanup() { Script.update.connect(update); function update() { // if no entity we return - if(nametagEntityID == NULL_UUID) { + if(nameTagEntityID == NULL_UUID) { return; } @@ -76,25 +100,17 @@ function update() { } function checkForEntity() { - var nametagProps = Entities.getEntityProperties(nametagEntityID); - + var nameTagProps = Entities.getEntityProperties(nameTagEntityID); // it is possible for the age to not be a valid number, we check for this and return accordingly - if(nametagProps.age < 1) { + if(nameTagProps.age < 1) { return; } - + // it's too old or we receive undefined make a new one, otherwise update - if(nametagProps.age > OLD_AGE || nametagProps.age == undefined) { + if(nameTagProps.age > OLD_AGE || nameTagProps.age == undefined) { deleteNameTag(); addNameTag(); } else { - var nametagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); - nametagPosition.y += HEIGHT_ABOVE_HEAD; - Entities.editEntity(nametagEntityID, { - position: nametagPosition, - // lifetime is in seconds we add TTL on top of the next poll time - lifetime: Math.round(nametagProps.age) + (ENTITY_CHECK_INTERVAL / 1000) + TTL, - text: MyAvatar.displayName - }); + updateNameTag(); } } From 5bf29f46570c92c392047d5bdf7824e5e17d783c Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Wed, 1 Feb 2017 12:59:40 +0000 Subject: [PATCH 04/20] improve dimensionsFromName implementation --- scripts/system/nameTag.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js index ceb7583a2e..c95db0e647 100644 --- a/scripts/system/nameTag.js +++ b/scripts/system/nameTag.js @@ -69,15 +69,11 @@ function deleteNameTag() { } function dimensionsFromName() { - var nameTagDimensions = { - x: 0.0, + return { + x: LETTER_OFFSET * MyAvatar.displayName.length, y: SIZE_Y, z: 0.0 - } - for(var letter in MyAvatar.displayName) { - nameTagDimensions.x += LETTER_OFFSET; - } - return nameTagDimensions; + }; }; // cleanup on ending From 1a58dad3adc3525bd79c754b297412c35f781b41 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Thu, 2 Feb 2017 01:12:55 +0000 Subject: [PATCH 05/20] change age check check for equal to -1 instead of < 1, think this would be more suitable if undefined is returned. --- scripts/system/nameTag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js index c95db0e647..88f7ab1f89 100644 --- a/scripts/system/nameTag.js +++ b/scripts/system/nameTag.js @@ -98,7 +98,7 @@ function update() { function checkForEntity() { var nameTagProps = Entities.getEntityProperties(nameTagEntityID); // it is possible for the age to not be a valid number, we check for this and return accordingly - if(nameTagProps.age < 1) { + if(nameTagProps.age == -1) { return; } From f8e6bd8c6b1524cfdcf9e15c552863269c7affbb Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 3 Feb 2017 10:53:26 -0800 Subject: [PATCH 06/20] Allow multiple instances to run if environment variable is set If the environment variable HIFI_ALLOW_MULTIPLE_INSTANCES is present, the value is ignored, then you can have multiple copies of interface running on the same machine. --- interface/src/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index d33dba535e..39b37e3d19 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -74,6 +74,11 @@ int main(int argc, const char* argv[]) { instanceMightBeRunning = !sharedMemory.create(1, QSharedMemory::ReadOnly); #endif + // allow multiple interfaces to run if this environment variable is set. + if (QProcessEnvironment::systemEnvironment().contains("HIFI_ALLOW_MULTIPLE_INSTANCES")) { + instanceMightBeRunning = false; + } + if (instanceMightBeRunning) { // Try to connect and send message to existing interface instance QLocalSocket socket; From 6738c0eadebaedf925f78593e1d2919db4bd6df3 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 3 Feb 2017 12:05:30 -0800 Subject: [PATCH 07/20] More consistent haptics on web overlays and entities --- .../system/controllers/handControllerGrab.js | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index d2c9fdc05a..f62acb985a 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -27,7 +27,7 @@ Script.include("/~/system/libraries/controllers.js"); // add lines where the hand ray picking is happening // var WANT_DEBUG = false; -var WANT_DEBUG_STATE = false; +var WANT_DEBUG_STATE = true; var WANT_DEBUG_SEARCH_NAME = null; var FORCE_IGNORE_IK = false; @@ -53,6 +53,13 @@ var HAPTIC_TEXTURE_DISTANCE = 0.002; var HAPTIC_DEQUIP_STRENGTH = 0.75; var HAPTIC_DEQUIP_DURATION = 50.0; +// triggered when stylus presses a web overlay/entity +var HAPTIC_STYLUS_STRENGTH = 1.0; +var HAPTIC_STYLUS_DURATION = 20.0; + +// triggerd when ui laser presses a web overlay/entity +var HAPTIC_LASER_UI_STRENGTH = 1.0; +var HAPTIC_LASER_UI_DURATION = 20.0; var HAND_HEAD_MIX_RATIO = 0.0; // 0 = only use hands for search/move. 1 = only use head for search/move. @@ -122,7 +129,6 @@ var GRAB_POINT_SPHERE_RADIUS = NEAR_GRAB_RADIUS; var GRAB_POINT_SPHERE_COLOR = { red: 240, green: 240, blue: 240 }; var GRAB_POINT_SPHERE_ALPHA = 0.85; - // // other constants // @@ -1248,7 +1254,7 @@ function MyController(hand) { if (homeButton === hmdHomeButton) { if (this.homeButtonTouched === false) { this.homeButtonTouched = true; - Controller.triggerHapticPulse(1, 20, this.hand); + Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, this.hand); Messages.sendLocalMessage("home", homeButton); } } else { @@ -1266,7 +1272,7 @@ function MyController(hand) { if (homeButton === hmdHomeButton) { if (this.homeButtonTouched === false) { this.homeButtonTouched = true; - Controller.triggerHapticPulse(1, 20, this.hand); + Controller.triggerHapticPulse(HAPTIC_LASER_UI_STRENGTH, HAPTIC_LASER_UI_DURATION, this.hand); Messages.sendLocalMessage("home", homeButton); } } else { @@ -1754,7 +1760,6 @@ function MyController(hand) { Entities.sendHoverOverEntity(entity, pointerEvent); } - this.grabbedEntity = entity; this.setState(STATE_ENTITY_STYLUS_TOUCHING, "begin touching entity '" + name + "'"); return true; @@ -1775,11 +1780,6 @@ function MyController(hand) { var pointerEvent; if (rayPickInfo.overlayID) { var overlay = rayPickInfo.overlayID; - - if (!this.homeButtonTouched) { - Controller.triggerHapticPulse(1, 20, this.hand); - } - if (Overlays.keyboardFocusOverlay != overlay) { Entities.keyboardFocusEntity = null; Overlays.keyboardFocusOverlay = overlay; @@ -2710,6 +2710,12 @@ function MyController(hand) { var theta = this.state === STATE_ENTITY_STYLUS_TOUCHING ? STYLUS_PRESS_TO_MOVE_DEADSPOT_ANGLE : LASER_PRESS_TO_MOVE_DEADSPOT_ANGLE; this.deadspotRadius = Math.tan(theta) * intersectInfo.distance; // dead spot radius in meters } + + if (this.state == STATE_ENTITY_STYLUS_TOUCHING) { + Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, this.hand); + } else if (this.state == STATE_ENTITY_LASER_TOUCHING) { + Controller.triggerHapticPulse(HAPTIC_LASER_UI_STRENGTH, HAPTIC_LASER_UI_DURATION, this.hand); + } }; this.entityTouchingExit = function() { @@ -2829,6 +2835,12 @@ function MyController(hand) { var theta = this.state === STATE_OVERLAY_STYLUS_TOUCHING ? STYLUS_PRESS_TO_MOVE_DEADSPOT_ANGLE : LASER_PRESS_TO_MOVE_DEADSPOT_ANGLE; this.deadspotRadius = Math.tan(theta) * intersectInfo.distance; // dead spot radius in meters } + + if (this.state == STATE_OVERLAY_STYLUS_TOUCHING) { + Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, this.hand); + } else if (this.state == STATE_OVERLAY_LASER_TOUCHING) { + Controller.triggerHapticPulse(HAPTIC_LASER_UI_STRENGTH, HAPTIC_LASER_UI_DURATION, this.hand); + } }; this.overlayTouchingExit = function () { From 0c28776ea2f3fd494d9d0e6c3df9f1cf6d0b7309 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Sat, 4 Feb 2017 00:13:39 +0000 Subject: [PATCH 08/20] some tweaks to users and menus got tablet --- interface/resources/qml/hifi/tablet/TabletMouseHandler.qml | 7 ++++++- scripts/system/tablet-users.js | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml index 32e34e279b..258a4c2f12 100644 --- a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml +++ b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml @@ -87,7 +87,11 @@ Item { if (topMenu.objectName === "") { breadcrumbText.text = "Menu"; } else { - breadcrumbText.text = topMenu.objectName; + if (menuStack.length === 1) { + breadcrumbText.text = "Menu"; + } else { + breadcrumbText.text = topMenu.objectName; + } } } else { breadcrumbText.text = "Menu"; @@ -164,6 +168,7 @@ Item { d.popMenu(); return true; } + return false; } diff --git a/scripts/system/tablet-users.js b/scripts/system/tablet-users.js index 0fad0c56f3..a47e4c8c5c 100644 --- a/scripts/system/tablet-users.js +++ b/scripts/system/tablet-users.js @@ -12,6 +12,7 @@ (function() { // BEGIN LOCAL_SCOPE var USERS_URL = "https://hifi-content.s3.amazonaws.com/faye/tablet-dev/users.html"; + var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; var FRIENDS_WINDOW_URL = "https://metaverse.highfidelity.com/user/friends"; var FRIENDS_WINDOW_WIDTH = 290; @@ -39,6 +40,10 @@ }); function onClicked() { + var tabletEntity = HMD.tabletID; + if (tabletEntity) { + Entities.editEntity(tabletEntity, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})}); + } tablet.gotoWebScreen(USERS_URL); } From dd8f095bd8463a157737ae20ab87192c5587429e Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Sat, 4 Feb 2017 00:36:41 +0000 Subject: [PATCH 09/20] minimize diff --- interface/resources/qml/hifi/tablet/TabletMouseHandler.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml index 258a4c2f12..17a00eccde 100644 --- a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml +++ b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml @@ -168,7 +168,6 @@ Item { d.popMenu(); return true; } - return false; } From 3311df5e1f5b99f1971e59a8c362d8f1f5e6e0f3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Feb 2017 14:23:37 -0800 Subject: [PATCH 10/20] fix default value in new row --- domain-server/resources/web/settings/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 3ed7d02364..4f8ca0eec4 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1417,7 +1417,7 @@ function addTableRow(row) { input_clone.children('td').each(function () { if ($(this).attr("name") !== keepField) { - $(this).find("input").val($(this).attr('data-default')); + $(this).find("input").val($(this).children('input').attr('data-default')); } }); From 5c46cecf6a28d24ebadbca16fcdd412e1488dfcf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Feb 2017 14:32:02 -0800 Subject: [PATCH 11/20] handle empty initial groups when comparing --- domain-server/resources/web/settings/js/settings.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 4f8ca0eec4..c5f055bed0 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1306,7 +1306,9 @@ function badgeSidebarForDifferences(changedElement) { var isGrouped = $('#' + panelParentID).hasClass('grouped'); if (isGrouped) { - var initialPanelJSON = Settings.initialValues[panelParentID]; + var initialPanelJSON = Settings.initialValues[panelParentID] + ? Settings.initialValues[panelParentID] + : {}; // get a JSON representation of that section var panelJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID]; @@ -1595,7 +1597,11 @@ function updateDataChangedForSiblingRows(row, forceTrue) { // get a JSON representation of that section var panelSettingJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID][tableShortName] - var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName] + if (Settings.initialValues[panelParentID]) { + var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName] + } else { + var initialPanelSettingJSON = {}; + } // if they are equal, we don't need data-changed isTrue = !_.isEqual(panelSettingJSON, initialPanelSettingJSON) From 2952be5fc89f86d67a67e3d58bd54980e4e66e63 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 7 Feb 2017 12:02:41 -0800 Subject: [PATCH 12/20] Added MouseX and MouseY axes to Keyboard device. --- .../input-plugins/src/input-plugins/KeyboardMouseDevice.cpp | 6 ++++++ .../input-plugins/src/input-plugins/KeyboardMouseDevice.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index 3308ba36ab..ddb2f482a1 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -25,6 +25,9 @@ void KeyboardMouseDevice::pluginUpdate(float deltaTime, const controller::InputC auto userInputMapper = DependencyManager::get(); userInputMapper->withLock([&, this]() { _inputDevice->update(deltaTime, inputCalibrationData); + + _inputDevice->_axisStateMap[MOUSE_AXIS_X] = _lastCursor.x(); + _inputDevice->_axisStateMap[MOUSE_AXIS_Y] = _lastCursor.y(); }); // For touch event, we need to check that the last event is not too long ago @@ -249,6 +252,9 @@ controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInp availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_POS), "MouseMoveUp")); availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_NEG), "MouseMoveDown")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X), "MouseX")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y), "MouseY")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "MouseWheelRight")); availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "MouseWheelLeft")); availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "MouseWheelUp")); diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h index f38b43c107..3570ec7193 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h @@ -47,6 +47,8 @@ public: MOUSE_AXIS_X_NEG, MOUSE_AXIS_Y_POS, MOUSE_AXIS_Y_NEG, + MOUSE_AXIS_X, + MOUSE_AXIS_Y, MOUSE_AXIS_WHEEL_Y_POS, MOUSE_AXIS_WHEEL_Y_NEG, MOUSE_AXIS_WHEEL_X_POS, From 7d630f6c9a083b0c25caad5c51b83c486e406194 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 7 Feb 2017 12:03:28 -0800 Subject: [PATCH 13/20] Added Mat4.createFromColumns --- libraries/script-engine/src/Mat4.cpp | 4 ++++ libraries/script-engine/src/Mat4.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/libraries/script-engine/src/Mat4.cpp b/libraries/script-engine/src/Mat4.cpp index bb65cb1e26..52b9690321 100644 --- a/libraries/script-engine/src/Mat4.cpp +++ b/libraries/script-engine/src/Mat4.cpp @@ -26,6 +26,10 @@ glm::mat4 Mat4::createFromScaleRotAndTrans(const glm::vec3& scale, const glm::qu return createMatFromScaleQuatAndPos(scale, rot, trans); } +glm::mat4 Mat4::createFromColumns(const glm::vec4& col0, const glm::vec4& col1, const glm::vec4& col2, const glm::vec4& col3) const { + return glm::mat4(col0, col1, col2, col3); +} + glm::vec3 Mat4::extractTranslation(const glm::mat4& m) const { return ::extractTranslation(m); } diff --git a/libraries/script-engine/src/Mat4.h b/libraries/script-engine/src/Mat4.h index 047bf56079..8b2a8aa8c1 100644 --- a/libraries/script-engine/src/Mat4.h +++ b/libraries/script-engine/src/Mat4.h @@ -23,8 +23,10 @@ class Mat4 : public QObject { public slots: glm::mat4 multiply(const glm::mat4& m1, const glm::mat4& m2) const; + glm::mat4 createFromRotAndTrans(const glm::quat& rot, const glm::vec3& trans) const; glm::mat4 createFromScaleRotAndTrans(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) const; + glm::mat4 createFromColumns(const glm::vec4& col0, const glm::vec4& col1, const glm::vec4& col2, const glm::vec4& col3) const; glm::vec3 extractTranslation(const glm::mat4& m) const; glm::quat extractRotation(const glm::mat4& m) const; From 9a44f63b742756d8130eb41daa83a82a58264425 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 7 Feb 2017 13:14:15 -0800 Subject: [PATCH 14/20] update crowd-agent and summon for bubble, avatar-mixin optimizations. --- .../tests/performance/crowd-agent.js | 5 ++++- scripts/developer/tests/performance/summon.js | 22 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/scripts/developer/tests/performance/crowd-agent.js b/scripts/developer/tests/performance/crowd-agent.js index b87d418643..9db4a112f3 100644 --- a/scripts/developer/tests/performance/crowd-agent.js +++ b/scripts/developer/tests/performance/crowd-agent.js @@ -16,7 +16,7 @@ var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd"; -print('crowd-agent version 4'); +print('crowd-agent version 5'); /* Observations: - File urls for AC scripts silently fail. Use a local server (e.g., python SimpleHTTPServer) for development. @@ -84,6 +84,9 @@ function startAgent(parameters) { // Can also be used to update. clearStopper(); var wasOff = !Agent.isAvatar; Agent.isAvatar = true; + if (parameters.displayName !== undefined) { + Avatar.displayName = parameters.displayName; + } if (parameters.position) { Avatar.position = parameters.position; } diff --git a/scripts/developer/tests/performance/summon.js b/scripts/developer/tests/performance/summon.js index 69bf0860ae..8e888fe9bc 100644 --- a/scripts/developer/tests/performance/summon.js +++ b/scripts/developer/tests/performance/summon.js @@ -13,7 +13,7 @@ // // See crowd-agent.js -var version = 2; +var version = 3; var label = "summon"; function debug() { print.apply(null, [].concat.apply([label, version], [].map.call(arguments, JSON.stringify))); @@ -23,6 +23,9 @@ var MINIMUM_AVATARS = 25; // We will summon agents to produce this many total. ( var N_LISTENING = MINIMUM_AVATARS - 1; var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND_DATA at once. +var initialBubble = Users.getIgnoreRadiusEnabled(); +debug('startup seeking:', MINIMUM_AVATARS, 'listening:', N_LISTENING, 'chattering:', AVATARS_CHATTERING_AT_ONCE, 'had bubble:', initialBubble); + // If we add or remove things too quickly, we get problems (e.g., audio, fogbugz 2095). // For now, spread them out this timing apart. var SPREAD_TIME_MS = 500; @@ -66,7 +69,7 @@ function messageHandler(channel, messageString, senderID) { if (MyAvatar.sessionUUID === senderID) { // ignore my own return; } - var message = {}, avatarIdentifiers; + var message = {}; try { message = JSON.parse(messageString); } catch (e) { @@ -76,9 +79,10 @@ function messageHandler(channel, messageString, senderID) { case "hello": Script.setTimeout(function () { // There can be avatars we've summoned that do not yet appear in the AvatarList. - avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents); + var avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents); + var nSummoned = summonedAgents.length; debug('present', avatarIdentifiers, summonedAgents); - if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS ) { + if ((nSummoned + avatarIdentifiers.length) < MINIMUM_AVATARS ) { var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE; var listen = nListening < N_LISTENING; if (chatter) { @@ -91,6 +95,7 @@ function messageHandler(channel, messageString, senderID) { messageSend({ key: 'SUMMON', rcpt: senderID, + displayName: "crowd " + nSummoned + " " + senderID, position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}), orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0), soundData: chatter && SOUND_DATA, @@ -100,7 +105,7 @@ function messageHandler(channel, messageString, senderID) { }); } }, accumulatedDelay); - accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello respsponses more or less together. + accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello responses more or less together. break; case "finishedSound": // Give someone else a chance. chattering = without(chattering, [senderID]); @@ -123,6 +128,8 @@ Messages.subscribe(MESSAGE_CHANNEL); Messages.messageReceived.connect(messageHandler); Script.scriptEnding.connect(function () { debug('stopping agents', summonedAgents); + Users.requestsDomainListData = false; + if (initialBubble && !Users.getIgnoreRadiusEnabled()) { Users.toggleIgnoreRadius(); } Messages.messageReceived.disconnect(messageHandler); // don't respond to any messages during shutdown accumulatedDelay = 0; summonedAgents.forEach(function (id) { @@ -134,14 +141,17 @@ Script.scriptEnding.connect(function () { debug('unsubscribed'); }); +Users.requestsDomainListData = true; // Get avatar data for the whole domain, even if not in our view. +if (initialBubble) { Users.toggleIgnoreRadius(); } messageSend({key: 'HELO'}); // Ask agents to report in now. Script.setTimeout(function () { var total = AvatarList.getAvatarIdentifiers().length; if (0 === summonedAgents.length) { Window.alert("No agents reported.\n\Please run " + MINIMUM_AVATARS + " instances of\n\ -http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js\n\ +http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js?v=someDate\n\ on your domain server."); } else if (total < MINIMUM_AVATARS) { Window.alert("Only " + summonedAgents.length + " agents reported. Now missing " + (MINIMUM_AVATARS - total) + " avatars, total."); } + Users.requestsDomainListData = false; }, MINIMUM_AVATARS * SPREAD_TIME_MS ) From e7244b47a9e9b6f96e66390f5194af847dd5a307 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Tue, 7 Feb 2017 21:55:55 +0000 Subject: [PATCH 15/20] increase LETTER_OFFSET value allow more room for characters, could be improved by detecting each one --- scripts/system/nameTag.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js index 88f7ab1f89..e25db69064 100644 --- a/scripts/system/nameTag.js +++ b/scripts/system/nameTag.js @@ -21,7 +21,7 @@ const TTL = 2; // time to live in seconds if script is not running const HEIGHT_ABOVE_HEAD = 0.2; const HEAD_OFFSET = -0.025; const SIZE_Y = 0.075; -const LETTER_OFFSET = 0.0225; +const LETTER_OFFSET = 0.03; // arbitrary value to dynamically change width, could be more accurate by detecting characters const LINE_HEIGHT = 0.05; var nameTagEntityID = NULL_UUID; @@ -35,7 +35,7 @@ Script.setTimeout(function() { function addNameTag() { var nameTagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); nameTagPosition.y += HEIGHT_ABOVE_HEAD; - var modelNameTagProperties = { + var nameTagProperties = { name: MyAvatar.displayName + ' Name Tag', type: 'Text', text: MyAvatar.displayName, @@ -44,7 +44,7 @@ function addNameTag() { dimensions: dimensionsFromName(), position: nameTagPosition } - nameTagEntityID = Entities.addEntity(modelNameTagProperties, CLIENTONLY); + nameTagEntityID = Entities.addEntity(nameTagProperties, CLIENTONLY); } function updateNameTag() { @@ -73,7 +73,7 @@ function dimensionsFromName() { x: LETTER_OFFSET * MyAvatar.displayName.length, y: SIZE_Y, z: 0.0 - }; + } }; // cleanup on ending From 3bd11978aaa33de3799809e52747855b10b4bbab Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 7 Feb 2017 15:59:38 -0800 Subject: [PATCH 16/20] low-hanging fruit on pal performance --- scripts/system/pal.js | 45 +++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 9e9c49b1a0..7e451a39fb 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -11,6 +11,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + // hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed // something, will revisit as this is sorta horrible. const UNSELECTED_TEXTURES = {"idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png"), @@ -27,7 +29,7 @@ const UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6}; const SELECTED_COLOR = {red: 0xF3, green: 0x91, blue: 0x29}; const HOVER_COLOR = {red: 0xD0, green: 0xD0, blue: 0xD0}; // almost white for now -(function() { // BEGIN LOCAL_SCOPE +var conserveResources = true; Script.include("/~/system/libraries/controllers.js"); @@ -265,15 +267,16 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like function addAvatarNode(id) { var selected = ExtendedOverlay.isSelected(id); return new ExtendedOverlay(id, "sphere", { - drawInFront: true, - solid: true, - alpha: 0.8, - color: color(selected, false, 0.0), - ignoreRayIntersection: false}, selected, true); + drawInFront: true, + solid: true, + alpha: 0.8, + color: color(selected, false, 0.0), + ignoreRayIntersection: false}, selected, !conserveResources); } function populateUserList(selectData) { - var data = []; - AvatarList.getAvatarIdentifiers().sort().forEach(function (id) { // sorting the identifiers is just an aid for debugging + var data = [], avatars = AvatarList.getAvatarIdentifiers(); + conserveResources = avatars.length > 20; + avatars.forEach(function (id) { // sorting the identifiers is just an aid for debugging var avatar = AvatarList.getAvatar(id); var avatarPalDatum = { displayName: avatar.sessionDisplayName, @@ -498,6 +501,7 @@ if (Settings.getValue("HUDUIEnabled")) { }); } var isWired = false; +var audioTimer; function off() { if (isWired) { // It is not ok to disconnect these twice, hence guard. Script.update.disconnect(updateOverlays); @@ -505,6 +509,7 @@ function off() { Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); isWired = false; } + if (audioTimer) { Script.clearInterval(audioTimer); } triggerMapping.disable(); // It's ok if we disable twice. triggerPressMapping.disable(); // see above removeOverlays(); @@ -521,7 +526,7 @@ function onClicked() { Controller.mouseMoveEvent.connect(handleMouseMoveEvent); triggerMapping.enable(); triggerPressMapping.enable(); - createAudioInterval(); + audioTimer = createAudioInterval(AUDIO_LEVEL_UPDATE_INTERVAL_MS / (conserveResources ? 3 : 1)); } else { off(); } @@ -591,21 +596,19 @@ function getAudioLevel(id) { return audioLevel; } -function createAudioInterval() { +function createAudioInterval(interval) { // we will update the audioLevels periodically // TODO: tune for efficiency - expecially with large numbers of avatars return Script.setInterval(function () { - if (pal.visible) { - var param = {}; - AvatarList.getAvatarIdentifiers().forEach(function (id) { - var level = getAudioLevel(id); - // qml didn't like an object with null/empty string for a key, so... - var userId = id || 0; - param[userId] = level; - }); - pal.sendToQml({method: 'updateAudioLevel', params: param}); - } - }, AUDIO_LEVEL_UPDATE_INTERVAL_MS); + var param = {}; + AvatarList.getAvatarIdentifiers().forEach(function (id) { + var level = getAudioLevel(id); + // qml didn't like an object with null/empty string for a key, so... + var userId = id || 0; + param[userId] = level; + }); + pal.sendToQml({method: 'updateAudioLevel', params: param}); + }, interval); } function avatarDisconnected(nodeID) { From 2e88f1ab1fa6aecaf8b34e693a8f977e139bb5b2 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 7 Feb 2017 16:21:14 -0800 Subject: [PATCH 17/20] conserving audio interval --- scripts/system/pal.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 7e451a39fb..adbde0ef5c 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -502,6 +502,8 @@ if (Settings.getValue("HUDUIEnabled")) { } var isWired = false; var audioTimer; +var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too) +var AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS = 300; function off() { if (isWired) { // It is not ok to disconnect these twice, hence guard. Script.update.disconnect(updateOverlays); @@ -526,7 +528,7 @@ function onClicked() { Controller.mouseMoveEvent.connect(handleMouseMoveEvent); triggerMapping.enable(); triggerPressMapping.enable(); - audioTimer = createAudioInterval(AUDIO_LEVEL_UPDATE_INTERVAL_MS / (conserveResources ? 3 : 1)); + audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); } else { off(); } @@ -562,9 +564,7 @@ var AVERAGING_RATIO = 0.05; var LOUDNESS_FLOOR = 11.0; var LOUDNESS_SCALE = 2.8 / 5.0; var LOG2 = Math.log(2.0); -var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too) var myData = {}; // we're not includied in ExtendedOverlay.get. -var audioInterval; function getAudioLevel(id) { // the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged From cb58c567b837f1dff257afd4e921c1af940aff0e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 7 Feb 2017 18:18:34 -0800 Subject: [PATCH 18/20] In desktop mode create tablet near mouse click location. But prevent the tablet from being displayed off screen. --- scripts/system/libraries/WebTablet.js | 75 +++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 0cd7d26854..74bbd788be 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // /* global getControllerWorldLocation, setEntityCustomData, Tablet, WebTablet:true, HMD, Settings, Script, - Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform */ + Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform, clamp */ Script.include(Script.resolvePath("../libraries/utils.js")); Script.include(Script.resolvePath("../libraries/controllers.js")); @@ -118,7 +118,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { }; // compute position, rotation & parentJointIndex of the tablet - this.calculateTabletAttachmentProperties(hand, tabletProperties); + this.calculateTabletAttachmentProperties(hand, true, tabletProperties); this.cleanUpOldTablets(); this.tabletEntityID = Entities.addEntity(tabletProperties, clientOnly); @@ -252,31 +252,78 @@ WebTablet.prototype.destroy = function () { WebTablet.prototype.geometryChanged = function (geometry) { if (!HMD.active) { var tabletProperties = {}; + // compute position, rotation & parentJointIndex of the tablet - this.calculateTabletAttachmentProperties(NO_HANDS, tabletProperties); + this.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties); Entities.editEntity(this.tabletEntityID, tabletProperties); } }; +function gluPerspective(fovy, aspect, zNear, zFar) { + var cotan = 1 / Math.tan(fovy / 2); + var alpha = -(zFar + zNear) / (zFar - zNear); + var beta = -(2 * zFar * zNear) / (zFar - zNear); + var col0 = {x: cotan / aspect, y: 0, z: 0, w: 0}; + var col1 = {x: 0, y: cotan, z: 0, w: 0}; + var col2 = {x: 0, y: 0, z: alpha, w: -1}; + var col3 = {x: 0, y: 0, z: beta, w: 0}; + return Mat4.createFromColumns(col0, col1, col2, col3); +} + // calclulate the appropriate position of the tablet in world space, such that it fits in the center of the screen. // with a bit of padding on the top and bottom. -WebTablet.prototype.calculateWorldAttitudeRelativeToCamera = function () { +// windowPos is used to position the center of the tablet at the given position. +WebTablet.prototype.calculateWorldAttitudeRelativeToCamera = function (windowPos) { + var DEFAULT_DESKTOP_TABLET_SCALE = 75; var DESKTOP_TABLET_SCALE = Settings.getValue("desktopTabletScale") || DEFAULT_DESKTOP_TABLET_SCALE; + + // clamp window pos so 2d tablet is not off-screen. + var TABLET_TEXEL_PADDING = {x: 60, y: 90}; + var X_CLAMP = (DESKTOP_TABLET_SCALE / 100) * ((TABLET_TEXTURE_RESOLUTION.x / 2) + TABLET_TEXEL_PADDING.x); + var Y_CLAMP = (DESKTOP_TABLET_SCALE / 100) * ((TABLET_TEXTURE_RESOLUTION.y / 2) + TABLET_TEXEL_PADDING.y); + windowPos.x = clamp(windowPos.x, X_CLAMP, Window.innerWidth - X_CLAMP); + windowPos.y = clamp(windowPos.y, Y_CLAMP, Window.innerHeight - Y_CLAMP); + var fov = (Settings.getValue('fieldOfView') || DEFAULT_VERTICAL_FIELD_OF_VIEW) * (Math.PI / 180); var MAX_PADDING_FACTOR = 2.2; var PADDING_FACTOR = Math.min(Window.innerHeight / TABLET_TEXTURE_RESOLUTION.y, MAX_PADDING_FACTOR); var TABLET_HEIGHT = (TABLET_TEXTURE_RESOLUTION.y / this.dpi) * INCHES_TO_METERS; var WEB_ENTITY_Z_OFFSET = (this.depth / 2); + + // calcualte distance from camera var dist = (PADDING_FACTOR * TABLET_HEIGHT) / (2 * Math.tan(fov / 2) * (DESKTOP_TABLET_SCALE / 100)) - WEB_ENTITY_Z_OFFSET; + + var Z_NEAR = 0.01; + var Z_FAR = 100.0; + + // calculate mouse position in clip space + var alpha = -(Z_FAR + Z_NEAR) / (Z_FAR - Z_NEAR); + var beta = -(2 * Z_FAR * Z_NEAR) / (Z_FAR - Z_NEAR); + var clipZ = (beta / dist) - alpha; + var clipMousePosition = {x: (2 * windowPos.x / Window.innerWidth) - 1, + y: (2 * ((Window.innerHeight - windowPos.y) / Window.innerHeight)) - 1, + z: clipZ}; + + // calculate projection matrix + var aspect = Window.innerWidth / Window.innerHeight; + var projMatrix = gluPerspective(fov, aspect, Z_NEAR, Z_FAR); + + // transform mouse clip position into view coordinates. + var viewMousePosition = Mat4.transformPoint(Mat4.inverse(projMatrix), clipMousePosition); + + // transform view mouse position into world coordinates. + var viewToWorldMatrix = Mat4.createFromRotAndTrans(Camera.orientation, Camera.position); + var worldMousePosition = Mat4.transformPoint(viewToWorldMatrix, viewMousePosition); + return { - position: Vec3.sum(Camera.position, Vec3.multiply(dist, Quat.getFront(Camera.orientation))), + position: worldMousePosition, rotation: Quat.multiply(Camera.orientation, ROT_Y_180) }; }; // compute position, rotation & parentJointIndex of the tablet -WebTablet.prototype.calculateTabletAttachmentProperties = function (hand, tabletProperties) { +WebTablet.prototype.calculateTabletAttachmentProperties = function (hand, useMouse, tabletProperties) { if (HMD.active) { // in HMD mode, the tablet should be relative to the sensor to world matrix. tabletProperties.parentJointIndex = SENSOR_TO_ROOM_MATRIX; @@ -289,8 +336,16 @@ WebTablet.prototype.calculateTabletAttachmentProperties = function (hand, tablet // in desktop mode, the tablet should be relative to the camera tabletProperties.parentJointIndex = CAMERA_MATRIX; - // compute the appropriate postion of the tablet such that it fits in the center of the screen nicely. - var attitude = this.calculateWorldAttitudeRelativeToCamera(); + var windowPos; + if (useMouse) { + // compute the appropriate postion of the tablet such that it fits in the center of the screen nicely. + windowPos = {x: Controller.getValue(Controller.Hardware.Keyboard.MouseX), + y: Controller.getValue(Controller.Hardware.Keyboard.MouseY)}; + } else { + windowPos = {x: Window.innerWidth / 2, + y: Window.innerHeight / 2}; + } + var attitude = this.calculateWorldAttitudeRelativeToCamera(windowPos); tabletProperties.position = attitude.position; tabletProperties.rotation = attitude.rotation; } @@ -310,7 +365,7 @@ WebTablet.prototype.onHmdChanged = function () { var tabletProperties = {}; // compute position, rotation & parentJointIndex of the tablet - this.calculateTabletAttachmentProperties(NO_HANDS, tabletProperties); + this.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties); Entities.editEntity(this.tabletEntityID, tabletProperties); // Full scene FXAA should be disabled on the overlay when the tablet in desktop mode. @@ -398,7 +453,7 @@ WebTablet.prototype.cameraModeChanged = function (newMode) { var self = this; var tabletProperties = {}; // compute position, rotation & parentJointIndex of the tablet - self.calculateTabletAttachmentProperties(NO_HANDS, tabletProperties); + self.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties); Entities.editEntity(self.tabletEntityID, tabletProperties); } }; From 6cba2049ddc259b5c013d2adc1183a77764078b8 Mon Sep 17 00:00:00 2001 From: mike Date: Tue, 7 Feb 2017 19:46:16 -0800 Subject: [PATCH 19/20] Made jumping easier on the Vive --- interface/resources/controllers/standard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index c9e91c8666..04a3f560b6 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -22,7 +22,7 @@ "to": "Actions.Up", "filters": [ - { "type": "deadZone", "min": 0.95 }, + { "type": "deadZone", "min": 0.6 }, "invert" ] }, From 244437d971c9fc2a92da662497daec39ab17f23c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 7 Feb 2017 23:50:06 -0800 Subject: [PATCH 20/20] set WANT_DEBUG_STATE back to false --- scripts/system/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index f62acb985a..b6429d619f 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -27,7 +27,7 @@ Script.include("/~/system/libraries/controllers.js"); // add lines where the hand ray picking is happening // var WANT_DEBUG = false; -var WANT_DEBUG_STATE = true; +var WANT_DEBUG_STATE = false; var WANT_DEBUG_SEARCH_NAME = null; var FORCE_IGNORE_IK = false;