mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 11:37:58 +02:00
Merge branch 'tablet-ui' of github.com:highfidelity/hifi into tablet-ui
This commit is contained in:
commit
3f0860f9c3
23 changed files with 226 additions and 448 deletions
|
@ -12,7 +12,6 @@ import QtQuick 2.5
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
|
|
||||||
import "../dialogs"
|
import "../dialogs"
|
||||||
import "../menus"
|
|
||||||
import "../js/Utils.js" as Utils
|
import "../js/Utils.js" as Utils
|
||||||
|
|
||||||
// This is our primary 'desktop' object to which all VR dialogs and windows are childed.
|
// This is our primary 'desktop' object to which all VR dialogs and windows are childed.
|
||||||
|
@ -467,31 +466,6 @@ FocusScope {
|
||||||
return fileDialogBuilder.createObject(desktop, properties);
|
return fileDialogBuilder.createObject(desktop, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuMouseHandler { id: menuPopperUpper }
|
|
||||||
function popupMenu(point) {
|
|
||||||
menuPopperUpper.popup(desktop, rootMenu.items, point);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleMenu(point) {
|
|
||||||
menuPopperUpper.toggle(desktop, rootMenu.items, point);
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onEscapePressed: {
|
|
||||||
if (menuPopperUpper.closeLastMenu()) {
|
|
||||||
event.accepted = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
event.accepted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
|
||||||
if (menuPopperUpper.closeLastMenu()) {
|
|
||||||
event.accepted = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
event.accepted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function unfocusWindows() {
|
function unfocusWindows() {
|
||||||
// First find the active focus item, and unfocus it, all the way
|
// First find the active focus item, and unfocus it, all the way
|
||||||
// up the parent chain to the window
|
// up the parent chain to the window
|
||||||
|
|
|
@ -127,11 +127,19 @@ Item {
|
||||||
gradient: Gradient {
|
gradient: Gradient {
|
||||||
GradientStop {
|
GradientStop {
|
||||||
position: 0
|
position: 0
|
||||||
color: "#00b8ff"
|
color: "#2c8e72"
|
||||||
|
}
|
||||||
|
GradientStop {
|
||||||
|
position: 0.9
|
||||||
|
color: "#1fc6a6"
|
||||||
|
}
|
||||||
|
GradientStop {
|
||||||
|
position: 0.91
|
||||||
|
color: "#ea4c5f"
|
||||||
}
|
}
|
||||||
GradientStop {
|
GradientStop {
|
||||||
position: 1
|
position: 1
|
||||||
color: "#ff2d73"
|
color: "#ea4c5f"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
interface/resources/qml/hifi/tablet/TabletMenu.qml
Normal file
27
interface/resources/qml/hifi/tablet/TabletMenu.qml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQml 2.2
|
||||||
|
import "."
|
||||||
|
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: tabletMenu
|
||||||
|
objectName: "tabletMenu"
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
|
||||||
|
property var rootMenu: Menu { objectName:"rootMenu" }
|
||||||
|
property var point: Qt.point(50, 50)
|
||||||
|
|
||||||
|
TabletMouseHandler { id: menuPopperUpper }
|
||||||
|
|
||||||
|
function setRootMenu(menu) {
|
||||||
|
tabletMenu.rootMenu = menu
|
||||||
|
buildMenu()
|
||||||
|
}
|
||||||
|
function buildMenu() {
|
||||||
|
menuPopperUpper.popup(tabletMenu, rootMenu.items)
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,8 +12,8 @@ import QtQuick 2.5
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Controls.Styles 1.4
|
import QtQuick.Controls.Styles 1.4
|
||||||
|
|
||||||
import "../controls-uit"
|
import "../../controls-uit"
|
||||||
import "../styles-uit"
|
import "../../styles-uit"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
|
@ -12,7 +12,7 @@ import QtQuick 2.5
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Controls.Styles 1.4
|
import QtQuick.Controls.Styles 1.4
|
||||||
|
|
||||||
import "../styles-uit"
|
import "../../styles-uit"
|
||||||
|
|
||||||
FocusScope {
|
FocusScope {
|
||||||
id: root
|
id: root
|
||||||
|
@ -38,8 +38,8 @@ FocusScope {
|
||||||
ListView {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
x: 8; y: 8
|
x: 8; y: 8
|
||||||
width: 128
|
width: parent.width
|
||||||
height: count * 32
|
height: parent.height
|
||||||
topMargin: hifi.dimensions.menuPadding.y
|
topMargin: hifi.dimensions.menuPadding.y
|
||||||
onEnabledChanged: recalcSize();
|
onEnabledChanged: recalcSize();
|
||||||
onVisibleChanged: recalcSize();
|
onVisibleChanged: recalcSize();
|
||||||
|
@ -57,7 +57,7 @@ FocusScope {
|
||||||
color: hifi.colors.white
|
color: hifi.colors.white
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: VrMenuItem {
|
delegate: TabletMenuItem {
|
||||||
text: name
|
text: name
|
||||||
source: item
|
source: item
|
||||||
onImplicitHeightChanged: listView.recalcSize()
|
onImplicitHeightChanged: listView.recalcSize()
|
|
@ -16,11 +16,11 @@ import "."
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
objectName: "MouseMenuHandlerItem"
|
objectName: "tabletMenuHandlerItem"
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: menuRoot;
|
id: menuRoot;
|
||||||
objectName: "MouseMenuHandlerMouseArea"
|
objectName: "tabletMenuHandlerMouseArea"
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: d.topMenu !== null
|
enabled: d.topMenu !== null
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
@ -34,7 +34,7 @@ Item {
|
||||||
property var topMenu: null;
|
property var topMenu: null;
|
||||||
property var modelMaker: Component { ListModel { } }
|
property var modelMaker: Component { ListModel { } }
|
||||||
property var menuViewMaker: Component {
|
property var menuViewMaker: Component {
|
||||||
VrMenuView {
|
TabletMenuView {
|
||||||
id: subMenu
|
id: subMenu
|
||||||
onSelected: d.handleSelection(subMenu, currentItem, item)
|
onSelected: d.handleSelection(subMenu, currentItem, item)
|
||||||
}
|
}
|
||||||
|
@ -54,10 +54,11 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function toModel(items) {
|
function toModel(items) {
|
||||||
var result = modelMaker.createObject(desktop);
|
var result = modelMaker.createObject(tabletMenu);
|
||||||
for (var i = 0; i < items.length; ++i) {
|
for (var i = 0; i < items.length; ++i) {
|
||||||
var item = items[i];
|
var item = items[i];
|
||||||
if (!item.visible) continue;
|
if (!item.visible) continue;
|
||||||
|
console.log(item.title)
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case MenuItemType.Menu:
|
case MenuItemType.Menu:
|
||||||
result.append({"name": item.title, "item": item})
|
result.append({"name": item.title, "item": item})
|
||||||
|
@ -82,7 +83,7 @@ Item {
|
||||||
topMenu.focus = true;
|
topMenu.focus = true;
|
||||||
} else {
|
} else {
|
||||||
topMenu = null;
|
topMenu = null;
|
||||||
offscreenFlags.navigationFocused = false;
|
//offscreenFlags.navigationFocused = false;
|
||||||
menuRoot.enabled = false;
|
menuRoot.enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +92,7 @@ Item {
|
||||||
menuStack.push(newMenu);
|
menuStack.push(newMenu);
|
||||||
topMenu = newMenu;
|
topMenu = newMenu;
|
||||||
topMenu.focus = true;
|
topMenu.focus = true;
|
||||||
offscreenFlags.navigationFocused = true;
|
//offscreenFlags.navigationFocused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearMenus() {
|
function clearMenus() {
|
||||||
|
@ -118,12 +119,7 @@ Item {
|
||||||
function buildMenu(items, targetPosition) {
|
function buildMenu(items, targetPosition) {
|
||||||
var model = toModel(items);
|
var model = toModel(items);
|
||||||
// Menus must be childed to desktop for Z-ordering
|
// Menus must be childed to desktop for Z-ordering
|
||||||
var newMenu = menuViewMaker.createObject(desktop, { model: model, z: topMenu ? topMenu.z + 1 : desktop.zLevels.menu, isSubMenu: topMenu !== null });
|
var newMenu = menuViewMaker.createObject(tabletMenu, { model: model, isSubMenu: topMenu !== null });
|
||||||
if (targetPosition) {
|
|
||||||
newMenu.x = targetPosition.x
|
|
||||||
newMenu.y = targetPosition.y - newMenu.height / 3 * 1
|
|
||||||
}
|
|
||||||
clampMenuPosition(newMenu);
|
|
||||||
pushMenu(newMenu);
|
pushMenu(newMenu);
|
||||||
return newMenu;
|
return newMenu;
|
||||||
}
|
}
|
||||||
|
@ -150,20 +146,12 @@ Item {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function popup(parent, items, point) {
|
function popup(parent, items) {
|
||||||
d.clearMenus();
|
d.clearMenus();
|
||||||
menuRoot.enabled = true;
|
menuRoot.enabled = true;
|
||||||
d.buildMenu(items, point);
|
d.buildMenu(items, point);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggle(parent, items, point) {
|
|
||||||
if (d.topMenu) {
|
|
||||||
d.clearMenus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
popup(parent, items, point);
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeLastMenu() {
|
function closeLastMenu() {
|
||||||
if (d.menuStack.length) {
|
if (d.menuStack.length) {
|
||||||
d.popMenu();
|
d.popMenu();
|
|
@ -1059,10 +1059,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
DependencyManager::get<AudioClient>()->toggleMute();
|
DependencyManager::get<AudioClient>()->toggleMute();
|
||||||
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
||||||
cycleCamera();
|
cycleCamera();
|
||||||
} else if (action == controller::toInt(controller::Action::UI_NAV_SELECT)) {
|
|
||||||
if (!offscreenUi->navigationFocused()) {
|
|
||||||
toggleMenuUnderReticle();
|
|
||||||
}
|
|
||||||
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
|
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
|
||||||
toggleTabletUI();
|
toggleTabletUI();
|
||||||
} else if (action == controller::toInt(controller::Action::RETICLE_X)) {
|
} else if (action == controller::toInt(controller::Action::RETICLE_X)) {
|
||||||
|
@ -1580,17 +1576,6 @@ QString Application::getUserAgent() {
|
||||||
return userAgent;
|
return userAgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::toggleMenuUnderReticle() const {
|
|
||||||
// In HMD, if the menu is near the mouse but not under it, the reticle can be at a significantly
|
|
||||||
// different depth. When you focus on the menu, the cursor can appear to your crossed eyes as both
|
|
||||||
// on the menu and off.
|
|
||||||
// Even in 2D, it is arguable whether the user would want the menu to be to the side.
|
|
||||||
const float X_LEFT_SHIFT = 50.0;
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
|
||||||
auto reticlePosition = getApplicationCompositor().getReticlePosition();
|
|
||||||
offscreenUi->toggleMenu(QPoint(reticlePosition.x - X_LEFT_SHIFT, reticlePosition.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t lastTabletUIToggle { 0 };
|
uint64_t lastTabletUIToggle { 0 };
|
||||||
const uint64_t toggleTabletUILockout { 500000 };
|
const uint64_t toggleTabletUILockout { 500000 };
|
||||||
void Application::toggleTabletUI() const {
|
void Application::toggleTabletUI() const {
|
||||||
|
@ -2931,10 +2916,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
|
|
||||||
|
|
||||||
void Application::keyReleaseEvent(QKeyEvent* event) {
|
void Application::keyReleaseEvent(QKeyEvent* event) {
|
||||||
if (event->key() == Qt::Key_Alt && _altPressed && hasFocus()) {
|
|
||||||
toggleMenuUnderReticle();
|
|
||||||
}
|
|
||||||
|
|
||||||
_keysPressed.remove(event->key());
|
_keysPressed.remove(event->key());
|
||||||
|
|
||||||
_controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts
|
_controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts
|
||||||
|
@ -4076,11 +4057,13 @@ void Application::setKeyboardFocusOverlay(unsigned int overlayID) {
|
||||||
}
|
}
|
||||||
_lastAcceptedKeyPress = usecTimestampNow();
|
_lastAcceptedKeyPress = usecTimestampNow();
|
||||||
|
|
||||||
|
if (overlay->getProperty("showKeyboardFocusHighlight").toBool()) {
|
||||||
auto size = overlay->getSize() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR;
|
auto size = overlay->getSize() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR;
|
||||||
const float OVERLAY_DEPTH = 0.0105f;
|
const float OVERLAY_DEPTH = 0.0105f;
|
||||||
setKeyboardFocusHighlight(overlay->getPosition(), overlay->getRotation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH));
|
setKeyboardFocusHighlight(overlay->getPosition(), overlay->getRotation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::updateDialogs(float deltaTime) const {
|
void Application::updateDialogs(float deltaTime) const {
|
||||||
|
|
|
@ -484,7 +484,6 @@ private:
|
||||||
static void dragEnterEvent(QDragEnterEvent* event);
|
static void dragEnterEvent(QDragEnterEvent* event);
|
||||||
|
|
||||||
void maybeToggleMenuVisible(QMouseEvent* event) const;
|
void maybeToggleMenuVisible(QMouseEvent* event) const;
|
||||||
void toggleMenuUnderReticle() const;
|
|
||||||
void toggleTabletUI() const;
|
void toggleTabletUI() const;
|
||||||
|
|
||||||
MainWindow* _window;
|
MainWindow* _window;
|
||||||
|
|
|
@ -160,7 +160,7 @@ Menu::Menu() {
|
||||||
audioIO.data(), SLOT(toggleMute()));
|
audioIO.data(), SLOT(toggleMute()));
|
||||||
|
|
||||||
// Audio > Show Level Meter
|
// Audio > Show Level Meter
|
||||||
addCheckableActionToQMenuAndActionHash(audioMenu, MenuOption::AudioTools, 0, true);
|
addCheckableActionToQMenuAndActionHash(audioMenu, MenuOption::AudioTools, 0, false);
|
||||||
|
|
||||||
|
|
||||||
// Avatar menu ----------------------------------
|
// Avatar menu ----------------------------------
|
||||||
|
|
|
@ -50,7 +50,8 @@ Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) :
|
||||||
_url(Web3DOverlay->_url),
|
_url(Web3DOverlay->_url),
|
||||||
_scriptURL(Web3DOverlay->_scriptURL),
|
_scriptURL(Web3DOverlay->_scriptURL),
|
||||||
_dpi(Web3DOverlay->_dpi),
|
_dpi(Web3DOverlay->_dpi),
|
||||||
_resolution(Web3DOverlay->_resolution)
|
_resolution(Web3DOverlay->_resolution),
|
||||||
|
_showKeyboardFocusHighlight(Web3DOverlay->_showKeyboardFocusHighlight)
|
||||||
{
|
{
|
||||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||||
}
|
}
|
||||||
|
@ -351,6 +352,11 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
|
||||||
if (dpi.isValid()) {
|
if (dpi.isValid()) {
|
||||||
_dpi = dpi.toFloat();
|
_dpi = dpi.toFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto showKeyboardFocusHighlight = properties["showKeyboardFocusHighlight"];
|
||||||
|
if (showKeyboardFocusHighlight.isValid()) {
|
||||||
|
_showKeyboardFocusHighlight = showKeyboardFocusHighlight.toBool();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant Web3DOverlay::getProperty(const QString& property) {
|
QVariant Web3DOverlay::getProperty(const QString& property) {
|
||||||
|
@ -366,6 +372,9 @@ QVariant Web3DOverlay::getProperty(const QString& property) {
|
||||||
if (property == "dpi") {
|
if (property == "dpi") {
|
||||||
return _dpi;
|
return _dpi;
|
||||||
}
|
}
|
||||||
|
if (property == "showKeyboardFocusHighlight") {
|
||||||
|
return _showKeyboardFocusHighlight;
|
||||||
|
}
|
||||||
return Billboard3DOverlay::getProperty(property);
|
return Billboard3DOverlay::getProperty(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ private:
|
||||||
float _dpi;
|
float _dpi;
|
||||||
vec2 _resolution{ 640, 480 };
|
vec2 _resolution{ 640, 480 };
|
||||||
int _geometryId { 0 };
|
int _geometryId { 0 };
|
||||||
|
bool _showKeyboardFocusHighlight{ true };
|
||||||
|
|
||||||
bool _pressed{ false };
|
bool _pressed{ false };
|
||||||
QTouchDevice _touchDevice;
|
QTouchDevice _touchDevice;
|
||||||
|
|
|
@ -1308,7 +1308,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setActionData);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setActionData);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, setParentID);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, updateParentID);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(queryAACube, setQueryAACube);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(queryAACube, setQueryAACube);
|
||||||
|
|
||||||
|
@ -1565,6 +1565,14 @@ void EntityItem::updatePosition(const glm::vec3& value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityItem::updateParentID(const QUuid& value) {
|
||||||
|
if (_parentID != value) {
|
||||||
|
setParentID(value);
|
||||||
|
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; // children are forced to be kinematic
|
||||||
|
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EntityItem::updatePositionFromNetwork(const glm::vec3& value) {
|
void EntityItem::updatePositionFromNetwork(const glm::vec3& value) {
|
||||||
if (shouldSuppressLocationEdits()) {
|
if (shouldSuppressLocationEdits()) {
|
||||||
return;
|
return;
|
||||||
|
@ -1773,7 +1781,6 @@ void EntityItem::updateCreated(uint64_t value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const {
|
void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const {
|
||||||
// TODO: detect attachment status and adopt group of wearer
|
|
||||||
if (_collisionless) {
|
if (_collisionless) {
|
||||||
group = BULLET_COLLISION_GROUP_COLLISIONLESS;
|
group = BULLET_COLLISION_GROUP_COLLISIONLESS;
|
||||||
mask = 0;
|
mask = 0;
|
||||||
|
@ -1787,10 +1794,18 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t userMask = getCollisionMask();
|
uint8_t userMask = getCollisionMask();
|
||||||
|
// if this entity is a descendant of MyAvatar, don't collide with MyAvatar. This avoids the
|
||||||
|
// "bootstrapping" problem where you can shoot yourself across the room by grabbing something
|
||||||
|
// and holding it against your own avatar.
|
||||||
|
QUuid ancestorID = findAncestorOfType(NestableType::Avatar);
|
||||||
|
if (!ancestorID.isNull() && ancestorID == Physics::getSessionUUID()) {
|
||||||
|
userMask &= ~USER_COLLISION_GROUP_MY_AVATAR;
|
||||||
|
}
|
||||||
|
|
||||||
if ((bool)(userMask & USER_COLLISION_GROUP_MY_AVATAR) !=
|
if ((bool)(userMask & USER_COLLISION_GROUP_MY_AVATAR) !=
|
||||||
(bool)(userMask & USER_COLLISION_GROUP_OTHER_AVATAR)) {
|
(bool)(userMask & USER_COLLISION_GROUP_OTHER_AVATAR)) {
|
||||||
// asymmetric avatar collision mask bits
|
// asymmetric avatar collision mask bits
|
||||||
if (!getSimulatorID().isNull() && (!getSimulatorID().isNull()) && getSimulatorID() != Physics::getSessionUUID()) {
|
if (!getSimulatorID().isNull() && getSimulatorID() != Physics::getSessionUUID()) {
|
||||||
// someone else owns the simulation, so we toggle the avatar bits (swap interpretation)
|
// someone else owns the simulation, so we toggle the avatar bits (swap interpretation)
|
||||||
userMask ^= USER_COLLISION_MASK_AVATARS | ~userMask;
|
userMask ^= USER_COLLISION_MASK_AVATARS | ~userMask;
|
||||||
}
|
}
|
||||||
|
|
|
@ -339,6 +339,7 @@ public:
|
||||||
// updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags
|
// updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags
|
||||||
virtual void updateRegistrationPoint(const glm::vec3& value);
|
virtual void updateRegistrationPoint(const glm::vec3& value);
|
||||||
void updatePosition(const glm::vec3& value);
|
void updatePosition(const glm::vec3& value);
|
||||||
|
void updateParentID(const QUuid& value);
|
||||||
void updatePositionFromNetwork(const glm::vec3& value);
|
void updatePositionFromNetwork(const glm::vec3& value);
|
||||||
void updateDimensions(const glm::vec3& value);
|
void updateDimensions(const glm::vec3& value);
|
||||||
void updateRotation(const glm::quat& rotation);
|
void updateRotation(const glm::quat& rotation);
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
#include "ScriptEngineLogging.h"
|
#include "ScriptEngineLogging.h"
|
||||||
|
#include "DependencyManager.h"
|
||||||
|
#include "OffscreenUi.h"
|
||||||
|
|
||||||
TabletScriptingInterface::TabletScriptingInterface() {
|
TabletScriptingInterface::TabletScriptingInterface() {
|
||||||
qmlRegisterType<SoundEffect>("Hifi", 1, 0, "SoundEffect");
|
qmlRegisterType<SoundEffect>("Hifi", 1, 0, "SoundEffect");
|
||||||
|
@ -56,6 +58,7 @@ void TabletScriptingInterface::setQmlTabletRoot(QString tabletId, QQuickItem* qm
|
||||||
static const char* TABLET_SOURCE_URL = "Tablet.qml";
|
static const char* TABLET_SOURCE_URL = "Tablet.qml";
|
||||||
static const char* WEB_VIEW_SOURCE_URL = "TabletWebView.qml";
|
static const char* WEB_VIEW_SOURCE_URL = "TabletWebView.qml";
|
||||||
static const char* LOADER_SOURCE_PROPERTY_NAME = "LoaderSource";
|
static const char* LOADER_SOURCE_PROPERTY_NAME = "LoaderSource";
|
||||||
|
static const char* VRMENU_SOURCE_URL = "TabletMenu.qml";
|
||||||
|
|
||||||
TabletProxy::TabletProxy(QString name) : _name(name) {
|
TabletProxy::TabletProxy(QString name) : _name(name) {
|
||||||
;
|
;
|
||||||
|
@ -95,6 +98,15 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabletProxy::gotoMenuScreen() {
|
||||||
|
if (_qmlTabletRoot) {
|
||||||
|
_qmlTabletRoot->setProperty(LOADER_SOURCE_PROPERTY_NAME, VRMENU_SOURCE_URL);
|
||||||
|
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
||||||
|
QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen()));
|
||||||
|
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TabletProxy::gotoHomeScreen() {
|
void TabletProxy::gotoHomeScreen() {
|
||||||
if (_qmlTabletRoot) {
|
if (_qmlTabletRoot) {
|
||||||
QString tabletSource = _qmlTabletRoot->property(LOADER_SOURCE_PROPERTY_NAME).toString();
|
QString tabletSource = _qmlTabletRoot->property(LOADER_SOURCE_PROPERTY_NAME).toString();
|
||||||
|
@ -160,7 +172,7 @@ void TabletProxy::removeButton(QObject* tabletButtonProxy) {
|
||||||
void TabletProxy::updateAudioBar(const double micLevel) {
|
void TabletProxy::updateAudioBar(const double micLevel) {
|
||||||
auto tablet = getQmlTablet();
|
auto tablet = getQmlTablet();
|
||||||
if (!tablet) {
|
if (!tablet) {
|
||||||
qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
//qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
||||||
} else {
|
} else {
|
||||||
QMetaObject::invokeMethod(tablet, "setMicLevel", Qt::AutoConnection, Q_ARG(QVariant, QVariant(micLevel)));
|
QMetaObject::invokeMethod(tablet, "setMicLevel", Qt::AutoConnection, Q_ARG(QVariant, QVariant(micLevel)));
|
||||||
}
|
}
|
||||||
|
@ -186,6 +198,27 @@ void TabletProxy::addButtonsToHomeScreen() {
|
||||||
QObject::disconnect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen()));
|
QObject::disconnect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabletProxy::addButtonsToMenuScreen() {
|
||||||
|
if (!_qmlTabletRoot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
||||||
|
if (!loader) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QQuickItem* VrMenu = loader->findChild<QQuickItem*>("tabletMenu");
|
||||||
|
if (!VrMenu) {
|
||||||
|
qDebug() << "----------> could not find vr menu";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
|
QObject* menu = offscreenUi->getRootMenu();
|
||||||
|
QMetaObject::invokeMethod(VrMenu, "setRootMenu", Qt::AutoConnection, Q_ARG(QVariant, QVariant::fromValue(menu)));
|
||||||
|
}
|
||||||
|
|
||||||
void TabletProxy::removeButtonsFromHomeScreen() {
|
void TabletProxy::removeButtonsFromHomeScreen() {
|
||||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
for (auto& buttonProxy : _tabletButtonProxies) {
|
for (auto& buttonProxy : _tabletButtonProxies) {
|
||||||
|
|
|
@ -65,6 +65,8 @@ public:
|
||||||
|
|
||||||
void setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface);
|
void setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface);
|
||||||
|
|
||||||
|
Q_INVOKABLE void gotoMenuScreen();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* transition to the home screen
|
* transition to the home screen
|
||||||
* @function TabletProxy#gotoHomeScreen
|
* @function TabletProxy#gotoHomeScreen
|
||||||
|
@ -120,6 +122,7 @@ signals:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void addButtonsToHomeScreen();
|
void addButtonsToHomeScreen();
|
||||||
|
void addButtonsToMenuScreen();
|
||||||
protected:
|
protected:
|
||||||
void removeButtonsFromHomeScreen();
|
void removeButtonsFromHomeScreen();
|
||||||
QQuickItem* getQmlTablet() const;
|
QQuickItem* getQmlTablet() const;
|
||||||
|
|
|
@ -1015,7 +1015,7 @@ AACube SpatiallyNestable::getQueryAACube() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpatiallyNestable::hasAncestorOfType(NestableType nestableType) {
|
bool SpatiallyNestable::hasAncestorOfType(NestableType nestableType) const {
|
||||||
bool success;
|
bool success;
|
||||||
SpatiallyNestablePointer parent = getParentPointer(success);
|
SpatiallyNestablePointer parent = getParentPointer(success);
|
||||||
if (!success || !parent) {
|
if (!success || !parent) {
|
||||||
|
@ -1029,6 +1029,20 @@ bool SpatiallyNestable::hasAncestorOfType(NestableType nestableType) {
|
||||||
return parent->hasAncestorOfType(nestableType);
|
return parent->hasAncestorOfType(nestableType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QUuid SpatiallyNestable::findAncestorOfType(NestableType nestableType) const {
|
||||||
|
bool success;
|
||||||
|
SpatiallyNestablePointer parent = getParentPointer(success);
|
||||||
|
if (!success || !parent) {
|
||||||
|
return QUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->_nestableType == nestableType) {
|
||||||
|
return parent->getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent->findAncestorOfType(nestableType);
|
||||||
|
}
|
||||||
|
|
||||||
void SpatiallyNestable::getLocalTransformAndVelocities(
|
void SpatiallyNestable::getLocalTransformAndVelocities(
|
||||||
Transform& transform,
|
Transform& transform,
|
||||||
glm::vec3& velocity,
|
glm::vec3& velocity,
|
||||||
|
|
|
@ -163,7 +163,8 @@ public:
|
||||||
bool isParentIDValid() const { bool success = false; getParentPointer(success); return success; }
|
bool isParentIDValid() const { bool success = false; getParentPointer(success); return success; }
|
||||||
virtual SpatialParentTree* getParentTree() const { return nullptr; }
|
virtual SpatialParentTree* getParentTree() const { return nullptr; }
|
||||||
|
|
||||||
bool hasAncestorOfType(NestableType nestableType);
|
bool hasAncestorOfType(NestableType nestableType) const;
|
||||||
|
const QUuid findAncestorOfType(NestableType nestableType) const;
|
||||||
SpatiallyNestablePointer getParentPointer(bool& success) const;
|
SpatiallyNestablePointer getParentPointer(bool& success) const;
|
||||||
static SpatiallyNestablePointer findByID(QUuid id, bool& success);
|
static SpatiallyNestablePointer findByID(QUuid id, bool& success);
|
||||||
|
|
||||||
|
|
|
@ -524,6 +524,10 @@ QQuickItem* OffscreenUi::getDesktop() {
|
||||||
return _desktop;
|
return _desktop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QObject* OffscreenUi::getRootMenu() {
|
||||||
|
return getRootItem()->findChild<QObject*>("rootMenu");
|
||||||
|
}
|
||||||
|
|
||||||
QQuickItem* OffscreenUi::getToolWindow() {
|
QQuickItem* OffscreenUi::getToolWindow() {
|
||||||
return _toolWindow;
|
return _toolWindow;
|
||||||
}
|
}
|
||||||
|
@ -533,11 +537,6 @@ void OffscreenUi::unfocusWindows() {
|
||||||
Q_ASSERT(invokeResult);
|
Q_ASSERT(invokeResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenUi::toggleMenu(const QPoint& screenPosition) { // caller should already have mapped using getReticlePosition
|
|
||||||
emit showDesktop(); // we really only want to do this if you're showing the menu, but for now this works
|
|
||||||
QMetaObject::invokeMethod(_desktop, "toggleMenu", Q_ARG(QVariant, screenPosition));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class FileDialogListener : public ModalDialogListener {
|
class FileDialogListener : public ModalDialogListener {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
@ -45,7 +45,6 @@ public:
|
||||||
bool navigationFocused();
|
bool navigationFocused();
|
||||||
void setNavigationFocused(bool focused);
|
void setNavigationFocused(bool focused);
|
||||||
void unfocusWindows();
|
void unfocusWindows();
|
||||||
void toggleMenu(const QPoint& screenCoordinates);
|
|
||||||
|
|
||||||
|
|
||||||
// Setting pinned to true will hide all overlay elements on the desktop that don't have a pinned flag
|
// Setting pinned to true will hide all overlay elements on the desktop that don't have a pinned flag
|
||||||
|
@ -59,7 +58,7 @@ public:
|
||||||
QObject* getFlags();
|
QObject* getFlags();
|
||||||
QQuickItem* getDesktop();
|
QQuickItem* getDesktop();
|
||||||
QQuickItem* getToolWindow();
|
QQuickItem* getToolWindow();
|
||||||
|
QObject* getRootMenu();
|
||||||
enum Icon {
|
enum Icon {
|
||||||
ICON_NONE = 0,
|
ICON_NONE = 0,
|
||||||
ICON_QUESTION,
|
ICON_QUESTION,
|
||||||
|
|
|
@ -35,7 +35,8 @@ var DEFAULT_SCRIPTS = [
|
||||||
"system/snapshot.js",
|
"system/snapshot.js",
|
||||||
"system/help.js",
|
"system/help.js",
|
||||||
"system/bubble.js",
|
"system/bubble.js",
|
||||||
"system/tablet-ui/tabletUI.js"
|
"system/tablet-ui/tabletUI.js",
|
||||||
|
"system/menu.js"
|
||||||
];
|
];
|
||||||
|
|
||||||
// add a menu item for debugging
|
// add a menu item for debugging
|
||||||
|
|
|
@ -12,22 +12,22 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
/* global setEntityCustomData, getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings,
|
/* global getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings,
|
||||||
Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset, setGrabCommunications,
|
Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset, setGrabCommunications,
|
||||||
Menu */
|
Menu */
|
||||||
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
Script.include("../libraries/utils.js");
|
Script.include("/~/system/libraries/utils.js");
|
||||||
Script.include("../libraries/Xform.js");
|
Script.include("/~/system/libraries/Xform.js");
|
||||||
Script.include("../libraries/controllers.js");
|
Script.include("/~/system/libraries/controllers.js");
|
||||||
|
|
||||||
//
|
//
|
||||||
// add lines where the hand ray picking is happening
|
// add lines where the hand ray picking is happening
|
||||||
//
|
//
|
||||||
var WANT_DEBUG = false;
|
var WANT_DEBUG = false;
|
||||||
var WANT_DEBUG_STATE = false;
|
var WANT_DEBUG_STATE = true;
|
||||||
var WANT_DEBUG_SEARCH_NAME = null;
|
var WANT_DEBUG_SEARCH_NAME = null;
|
||||||
|
|
||||||
var FORCE_IGNORE_IK = false;
|
var FORCE_IGNORE_IK = false;
|
||||||
|
@ -41,8 +41,6 @@ var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smo
|
||||||
var TRIGGER_OFF_VALUE = 0.1;
|
var TRIGGER_OFF_VALUE = 0.1;
|
||||||
var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab
|
var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab
|
||||||
|
|
||||||
var COLLIDE_WITH_AV_AFTER_RELEASE_DELAY = 0.25; // seconds
|
|
||||||
|
|
||||||
var BUMPER_ON_VALUE = 0.5;
|
var BUMPER_ON_VALUE = 0.5;
|
||||||
|
|
||||||
var THUMB_ON_VALUE = 0.5;
|
var THUMB_ON_VALUE = 0.5;
|
||||||
|
@ -175,7 +173,6 @@ var GRABBABLE_PROPERTIES = [
|
||||||
];
|
];
|
||||||
|
|
||||||
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
|
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
|
||||||
var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js
|
|
||||||
|
|
||||||
var DEFAULT_GRABBABLE_DATA = {
|
var DEFAULT_GRABBABLE_DATA = {
|
||||||
disableReleaseVelocity: false
|
disableReleaseVelocity: false
|
||||||
|
@ -188,6 +185,15 @@ var blacklist = [];
|
||||||
var FORBIDDEN_GRAB_NAMES = ["Grab Debug Entity", "grab pointer"];
|
var FORBIDDEN_GRAB_NAMES = ["Grab Debug Entity", "grab pointer"];
|
||||||
var FORBIDDEN_GRAB_TYPES = ["Unknown", "Light", "PolyLine", "Zone"];
|
var FORBIDDEN_GRAB_TYPES = ["Unknown", "Light", "PolyLine", "Zone"];
|
||||||
|
|
||||||
|
var holdEnabled = true;
|
||||||
|
var nearGrabEnabled = true;
|
||||||
|
var farGrabEnabled = true;
|
||||||
|
var myAvatarScalingEnabled = true;
|
||||||
|
var objectScalingEnabled = true;
|
||||||
|
var mostRecentSearchingHand = RIGHT_HAND;
|
||||||
|
var DEFAULT_SPHERE_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/equip-Fresnel-3.fbx";
|
||||||
|
var HARDWARE_MOUSE_ID = 0; // Value reserved for hardware mouse.
|
||||||
|
|
||||||
// states for the state machine
|
// states for the state machine
|
||||||
var STATE_OFF = 0;
|
var STATE_OFF = 0;
|
||||||
var STATE_SEARCHING = 1;
|
var STATE_SEARCHING = 1;
|
||||||
|
@ -201,31 +207,8 @@ var STATE_ENTITY_LASER_TOUCHING = 8;
|
||||||
var STATE_OVERLAY_STYLUS_TOUCHING = 9;
|
var STATE_OVERLAY_STYLUS_TOUCHING = 9;
|
||||||
var STATE_OVERLAY_LASER_TOUCHING = 10;
|
var STATE_OVERLAY_LASER_TOUCHING = 10;
|
||||||
|
|
||||||
var holdEnabled = true;
|
|
||||||
var nearGrabEnabled = true;
|
|
||||||
var farGrabEnabled = true;
|
|
||||||
var myAvatarScalingEnabled = true;
|
|
||||||
var objectScalingEnabled = true;
|
|
||||||
|
|
||||||
// "collidesWith" is specified by comma-separated list of group names
|
|
||||||
// the possible group names are: static, dynamic, kinematic, myAvatar, otherAvatar
|
|
||||||
var COLLIDES_WITH_WHILE_GRABBED = "dynamic,otherAvatar";
|
|
||||||
|
|
||||||
var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC;
|
|
||||||
var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC;
|
|
||||||
|
|
||||||
var delayedDeactivateFunc;
|
|
||||||
var delayedDeactivateTimeout;
|
|
||||||
var delayedDeactivateEntityID;
|
|
||||||
|
|
||||||
var CONTROLLER_STATE_MACHINE = {};
|
var CONTROLLER_STATE_MACHINE = {};
|
||||||
|
|
||||||
var mostRecentSearchingHand = RIGHT_HAND;
|
|
||||||
|
|
||||||
var DEFAULT_SPHERE_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/equip-Fresnel-3.fbx";
|
|
||||||
|
|
||||||
var HARDWARE_MOUSE_ID = 0; // Value reserved for hardware mouse.
|
|
||||||
|
|
||||||
CONTROLLER_STATE_MACHINE[STATE_OFF] = {
|
CONTROLLER_STATE_MACHINE[STATE_OFF] = {
|
||||||
name: "off",
|
name: "off",
|
||||||
enterMethod: "offEnter",
|
enterMethod: "offEnter",
|
||||||
|
@ -491,17 +474,6 @@ function storeAttachPointForHotspotInSettings(hotspot, hand, offsetPosition, off
|
||||||
setAttachPointSettings(attachPointSettings);
|
setAttachPointSettings(attachPointSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeMyAvatarFromCollidesWith(origCollidesWith) {
|
|
||||||
var collidesWithSplit = origCollidesWith.split(",");
|
|
||||||
// remove myAvatar from the array
|
|
||||||
for (var i = collidesWithSplit.length - 1; i >= 0; i--) {
|
|
||||||
if (collidesWithSplit[i] === "myAvatar") {
|
|
||||||
collidesWithSplit.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return collidesWithSplit.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
|
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
|
||||||
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
|
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
|
||||||
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
|
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
|
||||||
|
@ -1271,11 +1243,6 @@ function MyController(hand) {
|
||||||
this.prevPotentialEquipHotspot = potentialEquipHotspot;
|
this.prevPotentialEquipHotspot = potentialEquipHotspot;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.heartBeatIsStale = function(data) {
|
|
||||||
var now = Date.now();
|
|
||||||
return data.heartBeat === undefined || now - data.heartBeat > HEART_BEAT_TIMEOUT;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Performs ray pick test from the hand controller into the world
|
// Performs ray pick test from the hand controller into the world
|
||||||
// @param {number} which hand to use, RIGHT_HAND or LEFT_HAND
|
// @param {number} which hand to use, RIGHT_HAND or LEFT_HAND
|
||||||
// @returns {object} returns object with two keys entityID and distance
|
// @returns {object} returns object with two keys entityID and distance
|
||||||
|
@ -1391,14 +1358,16 @@ function MyController(hand) {
|
||||||
|
|
||||||
this.hotspotIsEquippable = function(hotspot) {
|
this.hotspotIsEquippable = function(hotspot) {
|
||||||
var props = entityPropertiesCache.getProps(hotspot.entityID);
|
var props = entityPropertiesCache.getProps(hotspot.entityID);
|
||||||
var grabProps = entityPropertiesCache.getGrabProps(hotspot.entityID);
|
|
||||||
var debug = (WANT_DEBUG_SEARCH_NAME && props.name === WANT_DEBUG_SEARCH_NAME);
|
var debug = (WANT_DEBUG_SEARCH_NAME && props.name === WANT_DEBUG_SEARCH_NAME);
|
||||||
|
|
||||||
var refCount = ("refCount" in grabProps) ? grabProps.refCount : 0;
|
|
||||||
var okToEquipFromOtherHand = ((this.getOtherHandController().state == STATE_NEAR_GRABBING ||
|
var okToEquipFromOtherHand = ((this.getOtherHandController().state == STATE_NEAR_GRABBING ||
|
||||||
this.getOtherHandController().state == STATE_DISTANCE_HOLDING) &&
|
this.getOtherHandController().state == STATE_DISTANCE_HOLDING) &&
|
||||||
this.getOtherHandController().grabbedEntity == hotspot.entityID);
|
this.getOtherHandController().grabbedEntity == hotspot.entityID);
|
||||||
if (refCount > 0 && !this.heartBeatIsStale(grabProps) && !okToEquipFromOtherHand) {
|
var hasParent = true;
|
||||||
|
if (props.parentID === NULL_UUID) {
|
||||||
|
hasParent = false;
|
||||||
|
}
|
||||||
|
if ((hasParent || entityHasActions(hotspot.entityID)) && !okToEquipFromOtherHand) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
print("equip is skipping '" + props.name + "': grabbed by someone else");
|
print("equip is skipping '" + props.name + "': grabbed by someone else");
|
||||||
}
|
}
|
||||||
|
@ -1410,29 +1379,13 @@ function MyController(hand) {
|
||||||
|
|
||||||
this.entityIsGrabbable = function(entityID) {
|
this.entityIsGrabbable = function(entityID) {
|
||||||
var grabbableProps = entityPropertiesCache.getGrabbableProps(entityID);
|
var grabbableProps = entityPropertiesCache.getGrabbableProps(entityID);
|
||||||
var grabProps = entityPropertiesCache.getGrabProps(entityID);
|
|
||||||
var props = entityPropertiesCache.getProps(entityID);
|
var props = entityPropertiesCache.getProps(entityID);
|
||||||
if (!props) {
|
if (!props) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var physical = propsArePhysical(props);
|
|
||||||
var grabbable = false;
|
|
||||||
var debug = (WANT_DEBUG_SEARCH_NAME && props.name === WANT_DEBUG_SEARCH_NAME);
|
var debug = (WANT_DEBUG_SEARCH_NAME && props.name === WANT_DEBUG_SEARCH_NAME);
|
||||||
var refCount = ("refCount" in grabProps) ? grabProps.refCount : 0;
|
var grabbable = propsArePhysical(props);
|
||||||
|
if (grabbableProps.hasOwnProperty("grabbable")) {
|
||||||
if (physical) {
|
|
||||||
// physical things default to grabbable
|
|
||||||
grabbable = true;
|
|
||||||
} else {
|
|
||||||
// non-physical things default to non-grabbable unless they are already grabbed
|
|
||||||
if (refCount > 0) {
|
|
||||||
grabbable = true;
|
|
||||||
} else {
|
|
||||||
grabbable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (grabbableProps.hasOwnProperty("grabbable") && refCount === 0) {
|
|
||||||
grabbable = grabbableProps.grabbable;
|
grabbable = grabbableProps.grabbable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1640,18 +1593,11 @@ function MyController(hand) {
|
||||||
} else {
|
} else {
|
||||||
// If near something grabbable, grab it!
|
// If near something grabbable, grab it!
|
||||||
if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) {
|
if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) {
|
||||||
|
this.setState(STATE_NEAR_GRABBING, "near grab '" + name + "'");
|
||||||
var props = entityPropertiesCache.getProps(entity);
|
var props = entityPropertiesCache.getProps(entity);
|
||||||
var grabProps = entityPropertiesCache.getGrabProps(entity);
|
|
||||||
var refCount = grabProps.refCount ? grabProps.refCount : 0;
|
|
||||||
if (refCount >= 1) {
|
|
||||||
// if another person is holding the object, remember to restore the
|
|
||||||
// parent info, when we are finished grabbing it.
|
|
||||||
this.shouldResetParentOnRelease = true;
|
this.shouldResetParentOnRelease = true;
|
||||||
this.previousParentID = props.parentID;
|
this.previousParentID = props.parentID;
|
||||||
this.previousParentJointIndex = props.parentJointIndex;
|
this.previousParentJointIndex = props.parentJointIndex;
|
||||||
}
|
|
||||||
|
|
||||||
this.setState(STATE_NEAR_GRABBING, "near grab '" + name + "'");
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// potentialNearGrabEntity = entity;
|
// potentialNearGrabEntity = entity;
|
||||||
|
@ -2039,7 +1985,6 @@ function MyController(hand) {
|
||||||
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
|
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
|
||||||
|
|
||||||
if (this.actionID !== null) {
|
if (this.actionID !== null) {
|
||||||
this.activateEntity(this.grabbedEntity, grabbedProperties, false, true);
|
|
||||||
this.callEntityMethodOnGrabbed("startDistanceGrab");
|
this.callEntityMethodOnGrabbed("startDistanceGrab");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2063,12 +2008,11 @@ function MyController(hand) {
|
||||||
Entities.editEntity(this.grabbedEntity, { velocity: velocity });
|
Entities.editEntity(this.grabbedEntity, { velocity: velocity });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.release();
|
||||||
this.setState(STATE_OFF, "trigger released");
|
this.setState(STATE_OFF, "trigger released");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.heartBeat(this.grabbedEntity);
|
|
||||||
|
|
||||||
var controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
var controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||||
var worldControllerPosition = controllerLocation.position;
|
var worldControllerPosition = controllerLocation.position;
|
||||||
var worldControllerRotation = controllerLocation.orientation;
|
var worldControllerRotation = controllerLocation.orientation;
|
||||||
|
@ -2101,8 +2045,6 @@ function MyController(hand) {
|
||||||
disableMoveWithHead: false
|
disableMoveWithHead: false
|
||||||
};
|
};
|
||||||
|
|
||||||
var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData);
|
|
||||||
|
|
||||||
// Update radialVelocity
|
// Update radialVelocity
|
||||||
var lastVelocity = Vec3.multiply(worldHandDelta, 1.0 / deltaObjectTime);
|
var lastVelocity = Vec3.multiply(worldHandDelta, 1.0 / deltaObjectTime);
|
||||||
var delta = Vec3.normalize(Vec3.subtract(grabbedProperties.position, worldControllerPosition));
|
var delta = Vec3.normalize(Vec3.subtract(grabbedProperties.position, worldControllerPosition));
|
||||||
|
@ -2133,6 +2075,7 @@ function MyController(hand) {
|
||||||
newTargetPosition = Vec3.sum(newTargetPosition, worldControllerPosition);
|
newTargetPosition = Vec3.sum(newTargetPosition, worldControllerPosition);
|
||||||
|
|
||||||
var objectToAvatar = Vec3.subtract(this.currentObjectPosition, MyAvatar.position);
|
var objectToAvatar = Vec3.subtract(this.currentObjectPosition, MyAvatar.position);
|
||||||
|
var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData);
|
||||||
if (handControllerData.disableMoveWithHead !== true) {
|
if (handControllerData.disableMoveWithHead !== true) {
|
||||||
// mix in head motion
|
// mix in head motion
|
||||||
if (MOVE_WITH_HEAD) {
|
if (MOVE_WITH_HEAD) {
|
||||||
|
@ -2280,12 +2223,10 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
||||||
this.activateEntity(this.grabbedEntity, grabbedProperties, false, false);
|
|
||||||
|
|
||||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
|
||||||
if (FORCE_IGNORE_IK) {
|
if (FORCE_IGNORE_IK) {
|
||||||
this.ignoreIK = true;
|
this.ignoreIK = true;
|
||||||
} else {
|
} else {
|
||||||
|
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||||
this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true;
|
this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2372,17 +2313,9 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Entities.editEntity(this.grabbedEntity, {
|
Entities.editEntity(this.grabbedEntity, {
|
||||||
velocity: {
|
velocity: { x: 0, y: 0, z: 0 },
|
||||||
x: 0,
|
angularVelocity: { x: 0, y: 0, z: 0 },
|
||||||
y: 0,
|
// dynamic: false
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
angularVelocity: {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
dynamic: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.state == STATE_NEAR_GRABBING) {
|
if (this.state == STATE_NEAR_GRABBING) {
|
||||||
|
@ -2408,6 +2341,7 @@ function MyController(hand) {
|
||||||
|
|
||||||
if (this.state == STATE_NEAR_GRABBING && (!this.triggerClicked && this.secondaryReleased())) {
|
if (this.state == STATE_NEAR_GRABBING && (!this.triggerClicked && this.secondaryReleased())) {
|
||||||
this.callEntityMethodOnGrabbed("releaseGrab");
|
this.callEntityMethodOnGrabbed("releaseGrab");
|
||||||
|
this.release();
|
||||||
this.setState(STATE_OFF, "trigger released");
|
this.setState(STATE_OFF, "trigger released");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2425,8 +2359,8 @@ function MyController(hand) {
|
||||||
// we have an equipped object and the secondary trigger was released
|
// we have an equipped object and the secondary trigger was released
|
||||||
// short-circuit the other checks and release it
|
// short-circuit the other checks and release it
|
||||||
this.preparingHoldRelease = false;
|
this.preparingHoldRelease = false;
|
||||||
|
|
||||||
this.release();
|
this.release();
|
||||||
|
this.setState(STATE_OFF, "equipping ended via secondary press");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2466,14 +2400,13 @@ function MyController(hand) {
|
||||||
this.prevDropDetected = dropDetected;
|
this.prevDropDetected = dropDetected;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.heartBeat(this.grabbedEntity);
|
|
||||||
|
|
||||||
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID",
|
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID",
|
||||||
"position", "rotation", "dimensions",
|
"position", "rotation", "dimensions",
|
||||||
"registrationPoint"]);
|
"registrationPoint"]);
|
||||||
if (!props.position) {
|
if (!props.position) {
|
||||||
// server may have reset, taking our equipped entity with it. move back to "off" state
|
// server may have reset, taking our equipped entity with it. move back to "off" state
|
||||||
this.callEntityMethodOnGrabbed("releaseGrab");
|
this.callEntityMethodOnGrabbed("releaseGrab");
|
||||||
|
this.release();
|
||||||
this.setState(STATE_OFF, "entity has no position property");
|
this.setState(STATE_OFF, "entity has no position property");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2508,6 +2441,7 @@ function MyController(hand) {
|
||||||
} else { // this.state == STATE_HOLD
|
} else { // this.state == STATE_HOLD
|
||||||
this.callEntityMethodOnGrabbed("releaseEquip");
|
this.callEntityMethodOnGrabbed("releaseEquip");
|
||||||
}
|
}
|
||||||
|
this.release();
|
||||||
this.setState(STATE_OFF, "held object too far away");
|
this.setState(STATE_OFF, "held object too far away");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2902,7 +2836,6 @@ function MyController(hand) {
|
||||||
this.release = function() {
|
this.release = function() {
|
||||||
this.turnOffVisualizations();
|
this.turnOffVisualizations();
|
||||||
|
|
||||||
var noVelocity = false;
|
|
||||||
if (this.grabbedEntity !== null) {
|
if (this.grabbedEntity !== null) {
|
||||||
if (this.state === STATE_HOLD) {
|
if (this.state === STATE_HOLD) {
|
||||||
this.callEntityMethodOnGrabbed("releaseEquip");
|
this.callEntityMethodOnGrabbed("releaseEquip");
|
||||||
|
@ -2910,26 +2843,16 @@ function MyController(hand) {
|
||||||
|
|
||||||
// Make a small release haptic pulse if we really were holding something
|
// Make a small release haptic pulse if we really were holding something
|
||||||
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
|
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
|
||||||
|
|
||||||
// If this looks like the release after adjusting something still held in the other hand, print the position
|
|
||||||
// and rotation of the held thing to help content creators set the userData.
|
|
||||||
var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, {});
|
|
||||||
this.printNewOffsets = (grabData.refCount > 1);
|
|
||||||
|
|
||||||
if (this.actionID !== null) {
|
if (this.actionID !== null) {
|
||||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
||||||
// sometimes we want things to stay right where they are when we let go.
|
|
||||||
var releaseVelocityData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
|
||||||
if (releaseVelocityData.disableReleaseVelocity === true ||
|
|
||||||
// this next line allowed both:
|
|
||||||
// (1) far-grab, pull to self, near grab, then throw
|
|
||||||
// (2) equip something physical and adjust it with a other-hand grab without the thing drifting
|
|
||||||
grabData.refCount > 1) {
|
|
||||||
noVelocity = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.deactivateEntity(this.grabbedEntity, noVelocity);
|
if (this.shouldResetParentOnRelease) {
|
||||||
|
Entities.editEntity(this.grabbedEntity, {
|
||||||
|
parentID: this.previousParentID,
|
||||||
|
parentJointIndex: this.previousParentJointIndex
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||||
action: 'release',
|
action: 'release',
|
||||||
|
@ -2953,96 +2876,6 @@ function MyController(hand) {
|
||||||
this.grabPointSphereOff();
|
this.grabPointSphereOff();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.heartBeat = function(entityID) {
|
|
||||||
var now = Date.now();
|
|
||||||
if (now - this.lastHeartBeat > HEART_BEAT_INTERVAL) {
|
|
||||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
|
||||||
data.heartBeat = now;
|
|
||||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
|
||||||
this.lastHeartBeat = now;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.resetAbandonedGrab = function(entityID) {
|
|
||||||
print("cleaning up abandoned grab on " + entityID);
|
|
||||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
|
||||||
data.refCount = 1;
|
|
||||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
|
||||||
this.deactivateEntity(entityID, false);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.activateEntity = function(entityID, grabbedProperties, wasLoaded, collideWithStatic) {
|
|
||||||
this.autoUnequipCounter = 0;
|
|
||||||
|
|
||||||
if (this.entityActivated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.entityActivated = true;
|
|
||||||
|
|
||||||
if (delayedDeactivateTimeout && delayedDeactivateEntityID == entityID) {
|
|
||||||
// we have a timeout waiting to set collisions with myAvatar back on (so that when something
|
|
||||||
// is thrown it doesn't collide with the avatar's capsule the moment it's released). We've
|
|
||||||
// regrabbed the entity before the timeout fired, so cancel the timeout, run the function now
|
|
||||||
// and adjust the grabbedProperties. This will make the saved set of properties (the ones that
|
|
||||||
// get re-instated after all the grabs have been released) be correct.
|
|
||||||
Script.clearTimeout(delayedDeactivateTimeout);
|
|
||||||
delayedDeactivateTimeout = null;
|
|
||||||
grabbedProperties.collidesWith = delayedDeactivateFunc();
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
|
||||||
var now = Date.now();
|
|
||||||
|
|
||||||
if (wasLoaded) {
|
|
||||||
data.refCount = 1;
|
|
||||||
} else {
|
|
||||||
data.refCount = data.refCount ? data.refCount + 1 : 1;
|
|
||||||
|
|
||||||
// zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done
|
|
||||||
if (data.refCount == 1) {
|
|
||||||
data.heartBeat = now;
|
|
||||||
this.lastHeartBeat = now;
|
|
||||||
|
|
||||||
this.isInitialGrab = true;
|
|
||||||
data.gravity = grabbedProperties.gravity;
|
|
||||||
data.collidesWith = grabbedProperties.collidesWith;
|
|
||||||
data.collisionless = grabbedProperties.collisionless;
|
|
||||||
data.dynamic = grabbedProperties.dynamic;
|
|
||||||
data.parentID = wasLoaded ? NULL_UUID : grabbedProperties.parentID;
|
|
||||||
data.parentJointIndex = grabbedProperties.parentJointIndex;
|
|
||||||
|
|
||||||
var whileHeldProperties = {
|
|
||||||
gravity: { x: 0, y: 0, z: 0 },
|
|
||||||
"collidesWith": collideWithStatic ?
|
|
||||||
COLLIDES_WITH_WHILE_GRABBED + ",static" :
|
|
||||||
COLLIDES_WITH_WHILE_GRABBED
|
|
||||||
};
|
|
||||||
Entities.editEntity(entityID, whileHeldProperties);
|
|
||||||
} else if (data.refCount > 1) {
|
|
||||||
if (this.heartBeatIsStale(data)) {
|
|
||||||
// this entity has userData suggesting it is grabbed, but nobody is updating the hearbeat.
|
|
||||||
// deactivate it before grabbing.
|
|
||||||
this.resetAbandonedGrab(entityID);
|
|
||||||
grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
|
||||||
return this.activateEntity(entityID, grabbedProperties, wasLoaded, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isInitialGrab = false;
|
|
||||||
// if an object is being grabbed by more than one person (or the same person twice, but nevermind), switch
|
|
||||||
// the collision groups so that it wont collide with "other" avatars. This avoids a situation where two
|
|
||||||
// people are holding something and one of them will be able (if the other releases at the right time) to
|
|
||||||
// bootstrap themselves with the held object. This happens because the meaning of "otherAvatar" in
|
|
||||||
// the collision mask hinges on who the physics simulation owner is.
|
|
||||||
Entities.editEntity(entityID, {
|
|
||||||
// "collidesWith": removeAvatarsFromCollidesWith(grabbedProperties.collidesWith)
|
|
||||||
collisionless: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.checkForStrayChildren = function() {
|
this.checkForStrayChildren = function() {
|
||||||
// sometimes things can get parented to a hand and this script is unaware. Search for such entities and
|
// sometimes things can get parented to a hand and this script is unaware. Search for such entities and
|
||||||
// unhook them.
|
// unhook them.
|
||||||
|
@ -3060,147 +2893,6 @@ function MyController(hand) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.delayedDeactivateEntity = function(entityID, collidesWith) {
|
|
||||||
// If, before the grab started, the held entity collided with myAvatar, we do the deactivation in
|
|
||||||
// two parts. Most of it is done in deactivateEntity(), but the final collidesWith and refcount
|
|
||||||
// are delayed a bit. This keeps thrown things from colliding with the avatar's capsule so often.
|
|
||||||
// The refcount is handled in this delayed fashion so things don't get confused if someone else
|
|
||||||
// grabs the entity before the timeout fires.
|
|
||||||
Entities.editEntity(entityID, {
|
|
||||||
collidesWith: collidesWith
|
|
||||||
});
|
|
||||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
|
||||||
if (data && data.refCount) {
|
|
||||||
data.refCount = data.refCount - 1;
|
|
||||||
if (data.refCount < 1) {
|
|
||||||
data = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.deactivateEntity = function(entityID, noVelocity, delayed) {
|
|
||||||
var deactiveProps;
|
|
||||||
|
|
||||||
if (!this.entityActivated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.entityActivated = false;
|
|
||||||
|
|
||||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
|
||||||
var doDelayedDeactivate = false;
|
|
||||||
if (data && data.refCount) {
|
|
||||||
data.refCount = data.refCount - 1;
|
|
||||||
if (data.refCount < 1) {
|
|
||||||
deactiveProps = {
|
|
||||||
gravity: data.gravity,
|
|
||||||
// don't set collidesWith myAvatar back right away, because thrown things tend to bounce off the
|
|
||||||
// avatar's capsule.
|
|
||||||
collidesWith: removeMyAvatarFromCollidesWith(data.collidesWith),
|
|
||||||
collisionless: data.collisionless,
|
|
||||||
dynamic: data.dynamic,
|
|
||||||
parentID: data.parentID,
|
|
||||||
parentJointIndex: data.parentJointIndex
|
|
||||||
};
|
|
||||||
|
|
||||||
doDelayedDeactivate = (data.collidesWith.indexOf("myAvatar") >= 0);
|
|
||||||
|
|
||||||
if (doDelayedDeactivate) {
|
|
||||||
var delayedCollidesWith = data.collidesWith;
|
|
||||||
var delayedEntityID = entityID;
|
|
||||||
delayedDeactivateFunc = function() {
|
|
||||||
// set collidesWith back to original value a bit later than the rest
|
|
||||||
delayedDeactivateTimeout = null;
|
|
||||||
_this.delayedDeactivateEntity(delayedEntityID, delayedCollidesWith);
|
|
||||||
return delayedCollidesWith;
|
|
||||||
};
|
|
||||||
delayedDeactivateTimeout =
|
|
||||||
Script.setTimeout(delayedDeactivateFunc, COLLIDE_WITH_AV_AFTER_RELEASE_DELAY * MSECS_PER_SEC);
|
|
||||||
delayedDeactivateEntityID = entityID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// things that are held by parenting and dropped with no velocity will end up as "static" in bullet. If
|
|
||||||
// it looks like the dropped thing should fall, give it a little velocity.
|
|
||||||
var props = Entities.getEntityProperties(entityID, ["parentID", "velocity", "dynamic", "shapeType"]);
|
|
||||||
var parentID = props.parentID;
|
|
||||||
|
|
||||||
if (!noVelocity &&
|
|
||||||
parentID == MyAvatar.sessionUUID &&
|
|
||||||
Vec3.length(data.gravity) > 0.0 &&
|
|
||||||
data.dynamic &&
|
|
||||||
data.parentID == NULL_UUID &&
|
|
||||||
!data.collisionless) {
|
|
||||||
deactiveProps.velocity = this.currentVelocity;
|
|
||||||
}
|
|
||||||
if (noVelocity) {
|
|
||||||
deactiveProps.velocity = {
|
|
||||||
x: 0.0,
|
|
||||||
y: 0.0,
|
|
||||||
z: 0.0
|
|
||||||
};
|
|
||||||
deactiveProps.angularVelocity = {
|
|
||||||
x: 0.0,
|
|
||||||
y: 0.0,
|
|
||||||
z: 0.0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Entities.editEntity(entityID, deactiveProps);
|
|
||||||
data = null;
|
|
||||||
} else if (this.shouldResetParentOnRelease) {
|
|
||||||
// we parent-grabbed this from another parent grab. try to put it back where we found it.
|
|
||||||
deactiveProps = {
|
|
||||||
parentID: this.previousParentID,
|
|
||||||
parentJointIndex: this.previousParentJointIndex,
|
|
||||||
velocity: {
|
|
||||||
x: 0.0,
|
|
||||||
y: 0.0,
|
|
||||||
z: 0.0
|
|
||||||
},
|
|
||||||
angularVelocity: {
|
|
||||||
x: 0.0,
|
|
||||||
y: 0.0,
|
|
||||||
z: 0.0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Entities.editEntity(entityID, deactiveProps);
|
|
||||||
|
|
||||||
if (this.printNewOffsets) {
|
|
||||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "localRotation"]);
|
|
||||||
if (grabbedProperties && grabbedProperties.localPosition && grabbedProperties.localRotation) {
|
|
||||||
print((this.hand === RIGHT_HAND ? '"LeftHand"' : '"RightHand"') + ":" +
|
|
||||||
'[{"x":' + grabbedProperties.localPosition.x + ', "y":' + grabbedProperties.localPosition.y +
|
|
||||||
', "z":' + grabbedProperties.localPosition.z + '}, {"x":' + grabbedProperties.localRotation.x +
|
|
||||||
', "y":' + grabbedProperties.localRotation.y + ', "z":' + grabbedProperties.localRotation.z +
|
|
||||||
', "w":' + grabbedProperties.localRotation.w + '}]');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (noVelocity) {
|
|
||||||
Entities.editEntity(entityID, {
|
|
||||||
velocity: {
|
|
||||||
x: 0.0,
|
|
||||||
y: 0.0,
|
|
||||||
z: 0.0
|
|
||||||
},
|
|
||||||
angularVelocity: {
|
|
||||||
x: 0.0,
|
|
||||||
y: 0.0,
|
|
||||||
z: 0.0
|
|
||||||
},
|
|
||||||
dynamic: data.dynamic
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data = null;
|
|
||||||
}
|
|
||||||
if (!doDelayedDeactivate) {
|
|
||||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getOtherHandController = function() {
|
this.getOtherHandController = function() {
|
||||||
return (this.hand === RIGHT_HAND) ? leftController : rightController;
|
return (this.hand === RIGHT_HAND) ? leftController : rightController;
|
||||||
};
|
};
|
||||||
|
|
|
@ -90,7 +90,8 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
|
||||||
color: { red: 255, green: 255, blue: 255 },
|
color: { red: 255, green: 255, blue: 255 },
|
||||||
alpha: 1.0,
|
alpha: 1.0,
|
||||||
parentID: this.tabletEntityID,
|
parentID: this.tabletEntityID,
|
||||||
parentJointIndex: -1
|
parentJointIndex: -1,
|
||||||
|
showKeyboardFocusHighlight: false
|
||||||
});
|
});
|
||||||
|
|
||||||
var HOME_BUTTON_Y_OFFSET = -0.25;
|
var HOME_BUTTON_Y_OFFSET = -0.25;
|
||||||
|
|
30
scripts/system/menu.js
Normal file
30
scripts/system/menu.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// menu.js
|
||||||
|
// scripts/system/
|
||||||
|
//
|
||||||
|
// Created by Dante Ruiz on 5 Jun 2017
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
var button = tablet.addButton({
|
||||||
|
icon: "icons/tablet-icons/menu-i.svg",
|
||||||
|
text: "Menu"
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function onClicked() {
|
||||||
|
tablet.gotoMenuScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
button.clicked.connect(onClicked);
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function () {
|
||||||
|
button.clicked.disconnect(onClicked);
|
||||||
|
tablet.removeButton(button);
|
||||||
|
})
|
||||||
|
}());
|
Loading…
Reference in a new issue