mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 17:56:43 +02:00
Merge branch 'tablet-ui-edit-js' of github.com:sethalves/hifi into menuFix
This commit is contained in:
commit
73c337efd0
29 changed files with 592 additions and 247 deletions
|
@ -384,6 +384,8 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
if (includeThisAvatar) {
|
if (includeThisAvatar) {
|
||||||
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
|
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
|
||||||
numAvatarDataBytes += avatarPacketList->write(bytes);
|
numAvatarDataBytes += avatarPacketList->write(bytes);
|
||||||
|
|
||||||
|
if (detail != AvatarData::NoData) {
|
||||||
_stats.numOthersIncluded++;
|
_stats.numOthersIncluded++;
|
||||||
|
|
||||||
// increment the number of avatars sent to this reciever
|
// increment the number of avatars sent to this reciever
|
||||||
|
@ -395,7 +397,7 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
|
|
||||||
// remember the last time we sent details about this other node to the receiver
|
// remember the last time we sent details about this other node to the receiver
|
||||||
nodeData->setLastBroadcastTime(otherNode->getUUID(), start);
|
nodeData->setLastBroadcastTime(otherNode->getUUID(), start);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
avatarPacketList->endSegment();
|
avatarPacketList->endSegment();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
import QtQuick 2.5
|
import QtQuick 2.5
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
|
import Qt.labs.settings 1.0
|
||||||
import "../styles-uit"
|
import "../styles-uit"
|
||||||
import "../controls-uit" as HifiControls
|
import "../controls-uit" as HifiControls
|
||||||
|
|
||||||
|
@ -29,7 +30,9 @@ Rectangle {
|
||||||
property int myCardHeight: 90
|
property int myCardHeight: 90
|
||||||
property int rowHeight: 70
|
property int rowHeight: 70
|
||||||
property int actionButtonWidth: 55
|
property int actionButtonWidth: 55
|
||||||
property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4 : 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth
|
property int actionButtonAllowance: actionButtonWidth * 2
|
||||||
|
property int minNameCardWidth: palContainer.width - (actionButtonAllowance * 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth
|
||||||
|
property int nameCardWidth: minNameCardWidth + (iAmAdmin ? 0 : actionButtonAllowance)
|
||||||
property var myData: ({displayName: "", userName: "", audioLevel: 0.0, admin: true}) // valid dummy until set
|
property var myData: ({displayName: "", userName: "", audioLevel: 0.0, admin: true}) // valid dummy until set
|
||||||
property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring.
|
property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring.
|
||||||
property var userModelData: [] // This simple list is essentially a mirror of the userModel listModel without all the extra complexities.
|
property var userModelData: [] // This simple list is essentially a mirror of the userModel listModel without all the extra complexities.
|
||||||
|
@ -52,6 +55,16 @@ Rectangle {
|
||||||
letterboxMessage.visible = true
|
letterboxMessage.visible = true
|
||||||
letterboxMessage.popupRadius = 0
|
letterboxMessage.popupRadius = 0
|
||||||
}
|
}
|
||||||
|
Settings {
|
||||||
|
id: settings
|
||||||
|
category: "pal"
|
||||||
|
property bool filtered: false
|
||||||
|
property int nearDistance: 30
|
||||||
|
}
|
||||||
|
function refreshWithFilter() {
|
||||||
|
// We should just be able to set settings.filtered to filter.checked, but see #3249, so send to .js for saving.
|
||||||
|
pal.sendToScript({method: 'refresh', params: {filter: filter.checked && {distance: settings.nearDistance}}});
|
||||||
|
}
|
||||||
|
|
||||||
// This is the container for the PAL
|
// This is the container for the PAL
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -88,11 +101,32 @@ Rectangle {
|
||||||
audioLevel: myData.audioLevel
|
audioLevel: myData.audioLevel
|
||||||
isMyCard: true
|
isMyCard: true
|
||||||
// Size
|
// Size
|
||||||
width: nameCardWidth
|
width: minNameCardWidth
|
||||||
height: parent.height
|
height: parent.height
|
||||||
// Anchors
|
// Anchors
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
}
|
}
|
||||||
|
Row {
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
id: filter
|
||||||
|
checked: settings.filtered
|
||||||
|
text: "in view"
|
||||||
|
boxSize: reload.height * 0.70
|
||||||
|
onCheckedChanged: refreshWithFilter()
|
||||||
|
}
|
||||||
|
HifiControls.GlyphButton {
|
||||||
|
id: reload
|
||||||
|
glyph: hifi.glyphs.reload
|
||||||
|
width: reload.height
|
||||||
|
onClicked: refreshWithFilter()
|
||||||
|
}
|
||||||
|
spacing: 50
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
top: parent.top
|
||||||
|
topMargin: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Rectangles used to cover up rounded edges on bottom of MyInfo Rectangle
|
// Rectangles used to cover up rounded edges on bottom of MyInfo Rectangle
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -306,45 +340,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Refresh button
|
|
||||||
Rectangle {
|
|
||||||
// Size
|
|
||||||
width: hifi.dimensions.tableHeaderHeight-1
|
|
||||||
height: hifi.dimensions.tableHeaderHeight-1
|
|
||||||
// Anchors
|
|
||||||
anchors.left: table.left
|
|
||||||
anchors.leftMargin: 4
|
|
||||||
anchors.top: table.top
|
|
||||||
// Style
|
|
||||||
color: hifi.colors.tableBackgroundLight
|
|
||||||
// Actual refresh icon
|
|
||||||
HiFiGlyphs {
|
|
||||||
id: reloadButton
|
|
||||||
text: hifi.glyphs.reloadSmall
|
|
||||||
// Size
|
|
||||||
size: parent.width*1.5
|
|
||||||
// Anchors
|
|
||||||
anchors.fill: parent
|
|
||||||
// Style
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
color: hifi.colors.darkGray
|
|
||||||
}
|
|
||||||
MouseArea {
|
|
||||||
id: reloadButtonArea
|
|
||||||
// Anchors
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
// Everyone likes a responsive refresh button!
|
|
||||||
// So use onPressed instead of onClicked
|
|
||||||
onPressed: {
|
|
||||||
reloadButton.color = hifi.colors.lightGrayText
|
|
||||||
pal.sendToScript({method: 'refresh'})
|
|
||||||
}
|
|
||||||
onReleased: reloadButton.color = (containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.darkGray)
|
|
||||||
onEntered: reloadButton.color = hifi.colors.baseGrayHighlight
|
|
||||||
onExited: reloadButton.color = (pressed ? hifi.colors.lightGrayText: hifi.colors.darkGray)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Separator between user and admin functions
|
// Separator between user and admin functions
|
||||||
Rectangle {
|
Rectangle {
|
||||||
// Size
|
// Size
|
||||||
|
@ -501,7 +497,7 @@ Rectangle {
|
||||||
if (alreadyRefreshed === true) {
|
if (alreadyRefreshed === true) {
|
||||||
letterbox('', '', 'The last editor of this object is either you or not among this list of users.');
|
letterbox('', '', 'The last editor of this object is either you or not among this list of users.');
|
||||||
} else {
|
} else {
|
||||||
pal.sendToScript({method: 'refresh', params: message.params});
|
pal.sendToScript({method: 'refresh', params: {selected: message.params}});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If we've already refreshed the PAL and found the avatar in the model
|
// If we've already refreshed the PAL and found the avatar in the model
|
||||||
|
|
|
@ -548,6 +548,7 @@ const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 100.0f;
|
||||||
const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f;
|
const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f;
|
||||||
const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true;
|
const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true;
|
||||||
const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false;
|
const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false;
|
||||||
|
const bool DEFAULT_TABLET_VISIBLE_TO_OTHERS = false;
|
||||||
|
|
||||||
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) :
|
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) :
|
||||||
QApplication(argc, argv),
|
QApplication(argc, argv),
|
||||||
|
@ -570,6 +571,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
_desktopTabletScale("desktopTabletScale", DEFAULT_DESKTOP_TABLET_SCALE_PERCENT),
|
_desktopTabletScale("desktopTabletScale", DEFAULT_DESKTOP_TABLET_SCALE_PERCENT),
|
||||||
_desktopTabletBecomesToolbarSetting("desktopTabletBecomesToolbar", DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR),
|
_desktopTabletBecomesToolbarSetting("desktopTabletBecomesToolbar", DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR),
|
||||||
_hmdTabletBecomesToolbarSetting("hmdTabletBecomesToolbar", DEFAULT_HMD_TABLET_BECOMES_TOOLBAR),
|
_hmdTabletBecomesToolbarSetting("hmdTabletBecomesToolbar", DEFAULT_HMD_TABLET_BECOMES_TOOLBAR),
|
||||||
|
_tabletVisibleToOthersSetting("tabletVisibleToOthers", DEFAULT_TABLET_VISIBLE_TO_OTHERS),
|
||||||
_constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true),
|
_constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true),
|
||||||
_scaleMirror(1.0f),
|
_scaleMirror(1.0f),
|
||||||
_rotateMirror(0.0f),
|
_rotateMirror(0.0f),
|
||||||
|
@ -2356,6 +2358,11 @@ void Application::setHmdTabletBecomesToolbarSetting(bool value) {
|
||||||
updateSystemTabletMode();
|
updateSystemTabletMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::setTabletVisibleToOthersSetting(bool value) {
|
||||||
|
_tabletVisibleToOthersSetting.set(value);
|
||||||
|
updateSystemTabletMode();
|
||||||
|
}
|
||||||
|
|
||||||
void Application::setSettingConstrainToolbarPosition(bool setting) {
|
void Application::setSettingConstrainToolbarPosition(bool setting) {
|
||||||
_constrainToolbarPosition.set(setting);
|
_constrainToolbarPosition.set(setting);
|
||||||
DependencyManager::get<OffscreenUi>()->setConstrainToolbarToCenterX(setting);
|
DependencyManager::get<OffscreenUi>()->setConstrainToolbarToCenterX(setting);
|
||||||
|
@ -3098,17 +3105,23 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
|
||||||
if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() ||
|
if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() ||
|
||||||
getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_OVERLAY_ID) {
|
getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_OVERLAY_ID) {
|
||||||
|
if (_mouseToOverlays) {
|
||||||
getOverlays().mouseMoveEvent(&mappedEvent);
|
getOverlays().mouseMoveEvent(&mappedEvent);
|
||||||
|
} else {
|
||||||
getEntities()->mouseMoveEvent(&mappedEvent);
|
getEntities()->mouseMoveEvent(&mappedEvent);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_mouseToOverlays) {
|
||||||
_controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts
|
_controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts
|
||||||
|
}
|
||||||
|
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
if (_controllerScriptingInterface->isMouseCaptured()) {
|
if (_controllerScriptingInterface->isMouseCaptured()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_keyboardMouseDevice->isActive()) {
|
if (!_mouseToOverlays && _keyboardMouseDevice->isActive()) {
|
||||||
_keyboardMouseDevice->mouseMoveEvent(event);
|
_keyboardMouseDevice->mouseMoveEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3116,6 +3129,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
||||||
void Application::mousePressEvent(QMouseEvent* event) {
|
void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
// Inhibit the menu if the user is using alt-mouse dragging
|
// Inhibit the menu if the user is using alt-mouse dragging
|
||||||
_altPressed = false;
|
_altPressed = false;
|
||||||
|
_mouseToOverlays = false;
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
// If we get a mouse press event it means it wasn't consumed by the offscreen UI,
|
// If we get a mouse press event it means it wasn't consumed by the offscreen UI,
|
||||||
|
@ -3132,21 +3146,23 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
event->buttons(), event->modifiers());
|
event->buttons(), event->modifiers());
|
||||||
|
|
||||||
if (!_aboutToQuit) {
|
if (!_aboutToQuit) {
|
||||||
getOverlays().mousePressEvent(&mappedEvent);
|
if (getOverlays().mousePressEvent(&mappedEvent)) {
|
||||||
|
_mouseToOverlays = true;
|
||||||
if (!_controllerScriptingInterface->areEntityClicksCaptured()) {
|
} else if (!_controllerScriptingInterface->areEntityClicksCaptured()) {
|
||||||
getEntities()->mousePressEvent(&mappedEvent);
|
getEntities()->mousePressEvent(&mappedEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_mouseToOverlays) {
|
||||||
_controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts
|
_controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts
|
||||||
|
}
|
||||||
|
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
if (_controllerScriptingInterface->isMouseCaptured()) {
|
if (_controllerScriptingInterface->isMouseCaptured()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasFocus()) {
|
if (!_mouseToOverlays && hasFocus()) {
|
||||||
if (_keyboardMouseDevice->isActive()) {
|
if (_keyboardMouseDevice->isActive()) {
|
||||||
_keyboardMouseDevice->mousePressEvent(event);
|
_keyboardMouseDevice->mousePressEvent(event);
|
||||||
}
|
}
|
||||||
|
@ -3180,18 +3196,23 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
event->buttons(), event->modifiers());
|
event->buttons(), event->modifiers());
|
||||||
|
|
||||||
if (!_aboutToQuit) {
|
if (!_aboutToQuit) {
|
||||||
|
if (_mouseToOverlays) {
|
||||||
getOverlays().mouseReleaseEvent(&mappedEvent);
|
getOverlays().mouseReleaseEvent(&mappedEvent);
|
||||||
|
} else {
|
||||||
getEntities()->mouseReleaseEvent(&mappedEvent);
|
getEntities()->mouseReleaseEvent(&mappedEvent);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_mouseToOverlays) {
|
||||||
_controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
|
_controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
|
||||||
|
}
|
||||||
|
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
if (_controllerScriptingInterface->isMouseCaptured()) {
|
if (_controllerScriptingInterface->isMouseCaptured()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasFocus()) {
|
if (!_mouseToOverlays && hasFocus()) {
|
||||||
if (_keyboardMouseDevice->isActive()) {
|
if (_keyboardMouseDevice->isActive()) {
|
||||||
_keyboardMouseDevice->mouseReleaseEvent(event);
|
_keyboardMouseDevice->mouseReleaseEvent(event);
|
||||||
}
|
}
|
||||||
|
@ -6926,5 +6947,10 @@ OverlayID Application::getTabletScreenID() const {
|
||||||
|
|
||||||
OverlayID Application::getTabletHomeButtonID() const {
|
OverlayID Application::getTabletHomeButtonID() const {
|
||||||
auto HMD = DependencyManager::get<HMDScriptingInterface>();
|
auto HMD = DependencyManager::get<HMDScriptingInterface>();
|
||||||
return HMD->getCurrentHomeButtonUUID();
|
return HMD->getCurrentHomeButtonID();
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid Application::getTabletFrameID() const {
|
||||||
|
auto HMD = DependencyManager::get<HMDScriptingInterface>();
|
||||||
|
return HMD->getCurrentTabletFrameID();
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,6 +218,8 @@ public:
|
||||||
void setDesktopTabletBecomesToolbarSetting(bool value);
|
void setDesktopTabletBecomesToolbarSetting(bool value);
|
||||||
bool getHmdTabletBecomesToolbarSetting() { return _hmdTabletBecomesToolbarSetting.get(); }
|
bool getHmdTabletBecomesToolbarSetting() { return _hmdTabletBecomesToolbarSetting.get(); }
|
||||||
void setHmdTabletBecomesToolbarSetting(bool value);
|
void setHmdTabletBecomesToolbarSetting(bool value);
|
||||||
|
bool getTabletVisibleToOthersSetting() { return _tabletVisibleToOthersSetting.get(); }
|
||||||
|
void setTabletVisibleToOthersSetting(bool value);
|
||||||
|
|
||||||
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
||||||
void setSettingConstrainToolbarPosition(bool setting);
|
void setSettingConstrainToolbarPosition(bool setting);
|
||||||
|
@ -300,6 +302,7 @@ public:
|
||||||
|
|
||||||
OverlayID getTabletScreenID() const;
|
OverlayID getTabletScreenID() const;
|
||||||
OverlayID getTabletHomeButtonID() const;
|
OverlayID getTabletHomeButtonID() const;
|
||||||
|
QUuid getTabletFrameID() const; // may be an entity or an overlay
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void svoImportRequested(const QString& url);
|
void svoImportRequested(const QString& url);
|
||||||
|
@ -561,6 +564,7 @@ private:
|
||||||
Setting::Handle<float> _desktopTabletScale;
|
Setting::Handle<float> _desktopTabletScale;
|
||||||
Setting::Handle<bool> _desktopTabletBecomesToolbarSetting;
|
Setting::Handle<bool> _desktopTabletBecomesToolbarSetting;
|
||||||
Setting::Handle<bool> _hmdTabletBecomesToolbarSetting;
|
Setting::Handle<bool> _hmdTabletBecomesToolbarSetting;
|
||||||
|
Setting::Handle<bool> _tabletVisibleToOthersSetting;
|
||||||
Setting::Handle<bool> _constrainToolbarPosition;
|
Setting::Handle<bool> _constrainToolbarPosition;
|
||||||
|
|
||||||
float _scaleMirror;
|
float _scaleMirror;
|
||||||
|
@ -672,6 +676,8 @@ private:
|
||||||
void addAssetToWorldInfoDone(QString modelName);
|
void addAssetToWorldInfoDone(QString modelName);
|
||||||
void addAssetToWorldError(QString modelName, QString errorText);
|
void addAssetToWorldError(QString modelName, QString errorText);
|
||||||
|
|
||||||
|
bool _mouseToOverlays { false };
|
||||||
|
|
||||||
QQuickItem* _addAssetToWorldMessageBox{ nullptr };
|
QQuickItem* _addAssetToWorldMessageBox{ nullptr };
|
||||||
QStringList _addAssetToWorldInfoKeys; // Model name
|
QStringList _addAssetToWorldInfoKeys; // Model name
|
||||||
QStringList _addAssetToWorldInfoMessages; // Info message
|
QStringList _addAssetToWorldInfoMessages; // Info message
|
||||||
|
|
|
@ -192,6 +192,8 @@ QVariantMap Camera::getViewFrustum() {
|
||||||
result["orientation"].setValue(frustum.getOrientation());
|
result["orientation"].setValue(frustum.getOrientation());
|
||||||
result["projection"].setValue(frustum.getProjection());
|
result["projection"].setValue(frustum.getProjection());
|
||||||
result["centerRadius"].setValue(frustum.getCenterRadius());
|
result["centerRadius"].setValue(frustum.getCenterRadius());
|
||||||
|
result["fieldOfView"].setValue(frustum.getFieldOfView());
|
||||||
|
result["aspectRatio"].setValue(frustum.getAspectRatio());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -933,6 +933,10 @@ glm::vec3 Avatar::getDefaultJointTranslation(int index) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||||
|
if (index < 0) {
|
||||||
|
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
||||||
|
}
|
||||||
|
|
||||||
switch(index) {
|
switch(index) {
|
||||||
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||||
|
@ -969,6 +973,10 @@ glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||||
|
if (index < 0) {
|
||||||
|
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
||||||
|
}
|
||||||
|
|
||||||
switch(index) {
|
switch(index) {
|
||||||
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||||
|
|
|
@ -85,7 +85,7 @@ AvatarManager::AvatarManager(QObject* parent) :
|
||||||
// immediately remove that avatar instead of waiting for the absence of packets from avatar mixer
|
// immediately remove that avatar instead of waiting for the absence of packets from avatar mixer
|
||||||
connect(nodeList.data(), &NodeList::ignoredNode, this, [=](const QUuid& nodeID, bool enabled) {
|
connect(nodeList.data(), &NodeList::ignoredNode, this, [=](const QUuid& nodeID, bool enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
removeAvatar(nodeID);
|
removeAvatar(nodeID, KillAvatarReason::AvatarIgnored);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -823,7 +823,7 @@ void MyAvatar::saveData() {
|
||||||
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||||
_avatarEntitiesLock.withReadLock([&] {
|
_avatarEntitiesLock.withReadLock([&] {
|
||||||
for (auto entityID : _avatarEntityData.keys()) {
|
for (auto entityID : _avatarEntityData.keys()) {
|
||||||
if (hmdInterface->getCurrentTabletUIID() == entityID) {
|
if (hmdInterface->getCurrentTabletFrameID() == entityID) {
|
||||||
// don't persist the tablet between domains / sessions
|
// don't persist the tablet between domains / sessions
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2410,6 +2410,10 @@ glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& c
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||||
|
if (index < 0) {
|
||||||
|
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
||||||
|
}
|
||||||
|
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case CONTROLLER_LEFTHAND_INDEX: {
|
case CONTROLLER_LEFTHAND_INDEX: {
|
||||||
return getLeftHandControllerPoseInAvatarFrame().getRotation();
|
return getLeftHandControllerPoseInAvatarFrame().getRotation();
|
||||||
|
@ -2443,6 +2447,10 @@ glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||||
|
if (index < 0) {
|
||||||
|
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
||||||
|
}
|
||||||
|
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case CONTROLLER_LEFTHAND_INDEX: {
|
case CONTROLLER_LEFTHAND_INDEX: {
|
||||||
return getLeftHandControllerPoseInAvatarFrame().getTranslation();
|
return getLeftHandControllerPoseInAvatarFrame().getTranslation();
|
||||||
|
|
|
@ -29,8 +29,8 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen
|
||||||
Q_PROPERTY(glm::quat orientation READ getOrientation)
|
Q_PROPERTY(glm::quat orientation READ getOrientation)
|
||||||
Q_PROPERTY(bool mounted READ isMounted)
|
Q_PROPERTY(bool mounted READ isMounted)
|
||||||
Q_PROPERTY(bool showTablet READ getShouldShowTablet)
|
Q_PROPERTY(bool showTablet READ getShouldShowTablet)
|
||||||
Q_PROPERTY(QUuid tabletID READ getCurrentTabletUIID WRITE setCurrentTabletUIID)
|
Q_PROPERTY(QUuid tabletID READ getCurrentTabletFrameID WRITE setCurrentTabletFrameID)
|
||||||
Q_PROPERTY(QUuid homeButtonID READ getCurrentHomeButtonUUID WRITE setCurrentHomeButtonUUID)
|
Q_PROPERTY(QUuid homeButtonID READ getCurrentHomeButtonID WRITE setCurrentHomeButtonID)
|
||||||
Q_PROPERTY(QUuid tabletScreenID READ getCurrentTabletScreenID WRITE setCurrentTabletScreenID)
|
Q_PROPERTY(QUuid tabletScreenID READ getCurrentTabletScreenID WRITE setCurrentTabletScreenID)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -90,11 +90,11 @@ public:
|
||||||
void setShouldShowTablet(bool value) { _showTablet = value; }
|
void setShouldShowTablet(bool value) { _showTablet = value; }
|
||||||
bool getShouldShowTablet() const { return _showTablet; }
|
bool getShouldShowTablet() const { return _showTablet; }
|
||||||
|
|
||||||
void setCurrentTabletUIID(QUuid tabletID) { _tabletUIID = tabletID; }
|
void setCurrentTabletFrameID(QUuid tabletID) { _tabletUIID = tabletID; }
|
||||||
QUuid getCurrentTabletUIID() const { return _tabletUIID; }
|
QUuid getCurrentTabletFrameID() const { return _tabletUIID; }
|
||||||
|
|
||||||
void setCurrentHomeButtonUUID(QUuid homeButtonID) { _homeButtonID = homeButtonID; }
|
void setCurrentHomeButtonID(QUuid homeButtonID) { _homeButtonID = homeButtonID; }
|
||||||
QUuid getCurrentHomeButtonUUID() const { return _homeButtonID; }
|
QUuid getCurrentHomeButtonID() const { return _homeButtonID; }
|
||||||
|
|
||||||
void setCurrentTabletScreenID(QUuid tabletID) { _tabletScreenID = tabletID; }
|
void setCurrentTabletScreenID(QUuid tabletID) { _tabletScreenID = tabletID; }
|
||||||
QUuid getCurrentTabletScreenID() const { return _tabletScreenID; }
|
QUuid getCurrentTabletScreenID() const { return _tabletScreenID; }
|
||||||
|
|
|
@ -102,7 +102,11 @@ void setupPreferences() {
|
||||||
auto setter = [](bool value) { qApp->setHmdTabletBecomesToolbarSetting(value); };
|
auto setter = [](bool value) { qApp->setHmdTabletBecomesToolbarSetting(value); };
|
||||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "HMD Tablet Becomes Toolbar", getter, setter));
|
preferences->addPreference(new CheckPreference(UI_CATEGORY, "HMD Tablet Becomes Toolbar", getter, setter));
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
auto getter = []()->bool { return qApp->getTabletVisibleToOthersSetting(); };
|
||||||
|
auto setter = [](bool value) { qApp->setTabletVisibleToOthersSetting(value); };
|
||||||
|
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Tablet Is Visible To Others", getter, setter));
|
||||||
|
}
|
||||||
// Snapshots
|
// Snapshots
|
||||||
static const QString SNAPSHOTS { "Snapshots" };
|
static const QString SNAPSHOTS { "Snapshots" };
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,7 +39,8 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
|
||||||
_isDashedLine(base3DOverlay->_isDashedLine),
|
_isDashedLine(base3DOverlay->_isDashedLine),
|
||||||
_ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection),
|
_ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection),
|
||||||
_drawInFront(base3DOverlay->_drawInFront),
|
_drawInFront(base3DOverlay->_drawInFront),
|
||||||
_isAA(base3DOverlay->_isAA)
|
_isAA(base3DOverlay->_isAA),
|
||||||
|
_isGrabbable(base3DOverlay->_isGrabbable)
|
||||||
{
|
{
|
||||||
setTransform(base3DOverlay->getTransform());
|
setTransform(base3DOverlay->getTransform());
|
||||||
}
|
}
|
||||||
|
@ -59,16 +60,20 @@ QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& propert
|
||||||
} else if (result["position"].isValid()) {
|
} else if (result["position"].isValid()) {
|
||||||
glm::vec3 localPosition = SpatiallyNestable::worldToLocal(vec3FromVariant(result["position"]),
|
glm::vec3 localPosition = SpatiallyNestable::worldToLocal(vec3FromVariant(result["position"]),
|
||||||
parentID, parentJointIndex, success);
|
parentID, parentJointIndex, success);
|
||||||
|
if (success) {
|
||||||
result["position"] = vec3toVariant(localPosition);
|
result["position"] = vec3toVariant(localPosition);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (result["localOrientation"].isValid()) {
|
if (result["localOrientation"].isValid()) {
|
||||||
result["orientation"] = result["localOrientation"];
|
result["orientation"] = result["localOrientation"];
|
||||||
} else if (result["orientation"].isValid()) {
|
} else if (result["orientation"].isValid()) {
|
||||||
glm::quat localOrientation = SpatiallyNestable::worldToLocal(quatFromVariant(result["orientation"]),
|
glm::quat localOrientation = SpatiallyNestable::worldToLocal(quatFromVariant(result["orientation"]),
|
||||||
parentID, parentJointIndex, success);
|
parentID, parentJointIndex, success);
|
||||||
|
if (success) {
|
||||||
result["orientation"] = quatToVariant(localOrientation);
|
result["orientation"] = quatToVariant(localOrientation);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -125,6 +130,11 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) {
|
||||||
needRenderItemUpdate = true;
|
needRenderItemUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto isGrabbable = properties["grabbable"];
|
||||||
|
if (isGrabbable.isValid()) {
|
||||||
|
setIsGrabbable(isGrabbable.toBool());
|
||||||
|
}
|
||||||
|
|
||||||
if (properties["position"].isValid()) {
|
if (properties["position"].isValid()) {
|
||||||
setLocalPosition(vec3FromVariant(properties["position"]));
|
setLocalPosition(vec3FromVariant(properties["position"]));
|
||||||
needRenderItemUpdate = true;
|
needRenderItemUpdate = true;
|
||||||
|
@ -227,6 +237,9 @@ QVariant Base3DOverlay::getProperty(const QString& property) {
|
||||||
if (property == "drawInFront") {
|
if (property == "drawInFront") {
|
||||||
return _drawInFront;
|
return _drawInFront;
|
||||||
}
|
}
|
||||||
|
if (property == "grabbable") {
|
||||||
|
return _isGrabbable;
|
||||||
|
}
|
||||||
if (property == "parentID") {
|
if (property == "parentID") {
|
||||||
return getParentID();
|
return getParentID();
|
||||||
}
|
}
|
||||||
|
@ -246,6 +259,8 @@ bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3
|
||||||
}
|
}
|
||||||
|
|
||||||
void Base3DOverlay::locationChanged(bool tellPhysics) {
|
void Base3DOverlay::locationChanged(bool tellPhysics) {
|
||||||
|
SpatiallyNestable::locationChanged(tellPhysics);
|
||||||
|
|
||||||
auto itemID = getRenderItemID();
|
auto itemID = getRenderItemID();
|
||||||
if (render::Item::isValidID(itemID)) {
|
if (render::Item::isValidID(itemID)) {
|
||||||
render::ScenePointer scene = qApp->getMain3DScene();
|
render::ScenePointer scene = qApp->getMain3DScene();
|
||||||
|
@ -253,8 +268,6 @@ void Base3DOverlay::locationChanged(bool tellPhysics) {
|
||||||
pendingChanges.updateItem(itemID);
|
pendingChanges.updateItem(itemID);
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
}
|
}
|
||||||
// Overlays can't currently have children.
|
|
||||||
// SpatiallyNestable::locationChanged(tellPhysics); // tell all the children, also
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Base3DOverlay::parentDeleted() {
|
void Base3DOverlay::parentDeleted() {
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
bool getIsSolidLine() const { return !_isDashedLine; }
|
bool getIsSolidLine() const { return !_isDashedLine; }
|
||||||
bool getIgnoreRayIntersection() const { return _ignoreRayIntersection; }
|
bool getIgnoreRayIntersection() const { return _ignoreRayIntersection; }
|
||||||
bool getDrawInFront() const { return _drawInFront; }
|
bool getDrawInFront() const { return _drawInFront; }
|
||||||
|
bool getIsGrabbable() const { return _isGrabbable; }
|
||||||
|
|
||||||
virtual bool isAA() const { return _isAA; }
|
virtual bool isAA() const { return _isAA; }
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ public:
|
||||||
void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; }
|
void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; }
|
||||||
void setDrawInFront(bool value) { _drawInFront = value; }
|
void setDrawInFront(bool value) { _drawInFront = value; }
|
||||||
void setIsAA(bool value) { _isAA = value; }
|
void setIsAA(bool value) { _isAA = value; }
|
||||||
|
void setIsGrabbable(bool value) { _isGrabbable = value; }
|
||||||
|
|
||||||
virtual AABox getBounds() const override = 0;
|
virtual AABox getBounds() const override = 0;
|
||||||
|
|
||||||
|
@ -71,6 +73,7 @@ protected:
|
||||||
bool _ignoreRayIntersection;
|
bool _ignoreRayIntersection;
|
||||||
bool _drawInFront;
|
bool _drawInFront;
|
||||||
bool _isAA;
|
bool _isAA;
|
||||||
|
bool _isGrabbable { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Base3DOverlay_h
|
#endif // hifi_Base3DOverlay_h
|
||||||
|
|
|
@ -341,27 +341,26 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
||||||
return UNKNOWN_OVERLAY_ID;
|
return UNKNOWN_OVERLAY_ID;
|
||||||
}
|
}
|
||||||
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysHUD);
|
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysHUD);
|
||||||
i.toBack();
|
|
||||||
|
|
||||||
const float LARGE_NEGATIVE_FLOAT = -9999999;
|
const float LARGE_NEGATIVE_FLOAT = -9999999;
|
||||||
glm::vec3 origin(pointCopy.x, pointCopy.y, LARGE_NEGATIVE_FLOAT);
|
glm::vec3 origin(pointCopy.x, pointCopy.y, LARGE_NEGATIVE_FLOAT);
|
||||||
glm::vec3 direction(0, 0, 1);
|
glm::vec3 direction(0, 0, 1);
|
||||||
BoxFace thisFace;
|
// BoxFace thisFace;
|
||||||
glm::vec3 thisSurfaceNormal;
|
glm::vec3 thisSurfaceNormal;
|
||||||
float distance;
|
// float distance;
|
||||||
unsigned int bestStackOrder = 0;
|
unsigned int bestStackOrder = 0;
|
||||||
OverlayID bestOverlayID = UNKNOWN_OVERLAY_ID;
|
OverlayID bestOverlayID = UNKNOWN_OVERLAY_ID;
|
||||||
|
|
||||||
while (i.hasPrevious()) {
|
while (i.hasNext()) {
|
||||||
i.previous();
|
i.next();
|
||||||
OverlayID thisID = i.key();
|
OverlayID thisID = i.key();
|
||||||
if (i.value()->is3D()) {
|
if (i.value()->is3D()) {
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Base3DOverlay>(i.value());
|
// auto thisOverlay = std::dynamic_pointer_cast<Base3DOverlay>(i.value());
|
||||||
if (thisOverlay && !thisOverlay->getIgnoreRayIntersection()) {
|
// if (thisOverlay && !thisOverlay->getIgnoreRayIntersection()) {
|
||||||
if (thisOverlay->findRayIntersection(origin, direction, distance, thisFace, thisSurfaceNormal)) {
|
// if (thisOverlay->findRayIntersection(origin, direction, distance, thisFace, thisSurfaceNormal)) {
|
||||||
return thisID;
|
// return thisID;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
} else {
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value());
|
auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value());
|
||||||
if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() &&
|
if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() &&
|
||||||
|
@ -406,16 +405,25 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray,
|
||||||
const QScriptValue& overlayIDsToInclude,
|
const QScriptValue& overlayIDsToInclude,
|
||||||
const QScriptValue& overlayIDsToDiscard,
|
const QScriptValue& overlayIDsToDiscard,
|
||||||
bool visibleOnly, bool collidableOnly) {
|
bool visibleOnly, bool collidableOnly) {
|
||||||
float bestDistance = std::numeric_limits<float>::max();
|
|
||||||
bool bestIsFront = false;
|
|
||||||
const QVector<OverlayID> overlaysToInclude = qVectorOverlayIDFromScriptValue(overlayIDsToInclude);
|
const QVector<OverlayID> overlaysToInclude = qVectorOverlayIDFromScriptValue(overlayIDsToInclude);
|
||||||
const QVector<OverlayID> overlaysToDiscard = qVectorOverlayIDFromScriptValue(overlayIDsToDiscard);
|
const QVector<OverlayID> overlaysToDiscard = qVectorOverlayIDFromScriptValue(overlayIDsToDiscard);
|
||||||
|
|
||||||
|
return findRayIntersectionInternal(ray, precisionPicking,
|
||||||
|
overlaysToInclude, overlaysToDiscard, visibleOnly, collidableOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickRay& ray, bool precisionPicking,
|
||||||
|
const QVector<OverlayID>& overlaysToInclude,
|
||||||
|
const QVector<OverlayID>& overlaysToDiscard,
|
||||||
|
bool visibleOnly, bool collidableOnly) {
|
||||||
|
float bestDistance = std::numeric_limits<float>::max();
|
||||||
|
bool bestIsFront = false;
|
||||||
|
|
||||||
RayToOverlayIntersectionResult result;
|
RayToOverlayIntersectionResult result;
|
||||||
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
|
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
|
||||||
i.toBack();
|
while (i.hasNext()) {
|
||||||
while (i.hasPrevious()) {
|
i.next();
|
||||||
i.previous();
|
|
||||||
OverlayID thisID = i.key();
|
OverlayID thisID = i.key();
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Base3DOverlay>(i.value());
|
auto thisOverlay = std::dynamic_pointer_cast<Base3DOverlay>(i.value());
|
||||||
|
|
||||||
|
@ -719,11 +727,41 @@ PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay r
|
||||||
return pointerEvent;
|
return pointerEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::mousePressEvent(QMouseEvent* event) {
|
|
||||||
|
RayToOverlayIntersectionResult Overlays::findRayIntersectionForMouseEvent(PickRay ray) {
|
||||||
|
QVector<OverlayID> overlaysToInclude;
|
||||||
|
QVector<OverlayID> overlaysToDiscard;
|
||||||
|
RayToOverlayIntersectionResult rayPickResult;
|
||||||
|
|
||||||
|
// first priority is tablet screen
|
||||||
|
overlaysToInclude << qApp->getTabletScreenID();
|
||||||
|
rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDiscard);
|
||||||
|
if (rayPickResult.intersects) {
|
||||||
|
return rayPickResult;
|
||||||
|
}
|
||||||
|
// then tablet home button
|
||||||
|
overlaysToInclude.clear();
|
||||||
|
overlaysToInclude << qApp->getTabletHomeButtonID();
|
||||||
|
rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDiscard);
|
||||||
|
if (rayPickResult.intersects) {
|
||||||
|
return rayPickResult;
|
||||||
|
}
|
||||||
|
// then tablet frame
|
||||||
|
overlaysToInclude.clear();
|
||||||
|
overlaysToInclude << OverlayID(qApp->getTabletFrameID());
|
||||||
|
rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDiscard);
|
||||||
|
if (rayPickResult.intersects) {
|
||||||
|
return rayPickResult;
|
||||||
|
}
|
||||||
|
// then whatever
|
||||||
|
return findRayIntersection(ray);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Overlays::mousePressEvent(QMouseEvent* event) {
|
||||||
PerformanceTimer perfTimer("Overlays::mousePressEvent");
|
PerformanceTimer perfTimer("Overlays::mousePressEvent");
|
||||||
|
|
||||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
RayToOverlayIntersectionResult rayPickResult = findRayIntersection(ray);
|
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||||
|
|
||||||
|
@ -732,19 +770,18 @@ void Overlays::mousePressEvent(QMouseEvent* event) {
|
||||||
if (thisOverlay) {
|
if (thisOverlay) {
|
||||||
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Press);
|
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Press);
|
||||||
emit mousePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
emit mousePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
||||||
} else {
|
return true;
|
||||||
emit mousePressOffOverlay();
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
emit mousePressOffOverlay();
|
|
||||||
}
|
}
|
||||||
|
emit mousePressOffOverlay();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
||||||
|
|
||||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
RayToOverlayIntersectionResult rayPickResult = findRayIntersection(ray);
|
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
|
|
||||||
// Only Web overlays can have focus.
|
// Only Web overlays can have focus.
|
||||||
|
@ -756,13 +793,14 @@ void Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentClickingOnOverlayID = UNKNOWN_OVERLAY_ID;
|
_currentClickingOnOverlayID = UNKNOWN_OVERLAY_ID;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::mouseMoveEvent(QMouseEvent* event) {
|
bool Overlays::mouseMoveEvent(QMouseEvent* event) {
|
||||||
PerformanceTimer perfTimer("Overlays::mouseMoveEvent");
|
PerformanceTimer perfTimer("Overlays::mouseMoveEvent");
|
||||||
|
|
||||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
RayToOverlayIntersectionResult rayPickResult = findRayIntersection(ray);
|
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
|
|
||||||
// Only Web overlays can have focus.
|
// Only Web overlays can have focus.
|
||||||
|
@ -802,4 +840,34 @@ void Overlays::mouseMoveEvent(QMouseEvent* event) {
|
||||||
_currentHoverOverOverlayID = UNKNOWN_OVERLAY_ID;
|
_currentHoverOverOverlayID = UNKNOWN_OVERLAY_ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) const {
|
||||||
|
QVector<QUuid> result;
|
||||||
|
|
||||||
|
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
|
||||||
|
int checked = 0;
|
||||||
|
while (i.hasNext()) {
|
||||||
|
checked++;
|
||||||
|
i.next();
|
||||||
|
OverlayID thisID = i.key();
|
||||||
|
auto overlay = std::dynamic_pointer_cast<Volume3DOverlay>(i.value());
|
||||||
|
if (overlay && overlay->getVisible() && !overlay->getIgnoreRayIntersection() && overlay->isLoaded()) {
|
||||||
|
// get AABox in frame of overlay
|
||||||
|
glm::vec3 dimensions = overlay->getDimensions();
|
||||||
|
glm::vec3 low = dimensions * -0.5f;
|
||||||
|
AABox overlayFrameBox(low, dimensions);
|
||||||
|
|
||||||
|
Transform overlayToWorldMatrix = overlay->getTransform();
|
||||||
|
glm::mat4 worldToOverlayMatrix = glm::inverse(overlayToWorldMatrix.getMatrix());
|
||||||
|
glm::vec3 overlayFrameSearchPosition = glm::vec3(worldToOverlayMatrix * glm::vec4(center, 1.0f));
|
||||||
|
glm::vec3 penetration;
|
||||||
|
if (overlayFrameBox.findSpherePenetration(overlayFrameSearchPosition, radius, penetration)) {
|
||||||
|
result.append(thisID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,9 +100,9 @@ public:
|
||||||
OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
|
OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
|
||||||
OverlayID addOverlay(Overlay::Pointer overlay);
|
OverlayID addOverlay(Overlay::Pointer overlay);
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent* event);
|
bool mousePressEvent(QMouseEvent* event);
|
||||||
void mouseReleaseEvent(QMouseEvent* event);
|
bool mouseReleaseEvent(QMouseEvent* event);
|
||||||
void mouseMoveEvent(QMouseEvent* event);
|
bool mouseMoveEvent(QMouseEvent* event);
|
||||||
|
|
||||||
void cleanupAllOverlays();
|
void cleanupAllOverlays();
|
||||||
|
|
||||||
|
@ -206,6 +206,16 @@ public slots:
|
||||||
bool visibleOnly = false,
|
bool visibleOnly = false,
|
||||||
bool collidableOnly = false);
|
bool collidableOnly = false);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Return a list of 3d overlays with bounding boxes that touch the given sphere
|
||||||
|
*
|
||||||
|
* @function Overlays.findOverlays
|
||||||
|
* @param {Vec3} center the point to search from.
|
||||||
|
* @param {float} radius search radius
|
||||||
|
* @return {List of Overlays.OverlayID} list of overlays withing the radius
|
||||||
|
*/
|
||||||
|
QVector<QUuid> findOverlays(const glm::vec3& center, float radius) const;
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Check whether an overlay's assets have been loaded. For example, if the
|
* Check whether an overlay's assets have been loaded. For example, if the
|
||||||
* overlay is an "image" overlay, this will indicate whether the its image
|
* overlay is an "image" overlay, this will indicate whether the its image
|
||||||
|
@ -317,6 +327,12 @@ private:
|
||||||
|
|
||||||
OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
|
OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
|
||||||
OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
|
OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
|
||||||
|
|
||||||
|
RayToOverlayIntersectionResult findRayIntersectionInternal(const PickRay& ray, bool precisionPicking,
|
||||||
|
const QVector<OverlayID>& overlaysToInclude,
|
||||||
|
const QVector<OverlayID>& overlaysToDiscard,
|
||||||
|
bool visibleOnly = false, bool collidableOnly = false);
|
||||||
|
RayToOverlayIntersectionResult findRayIntersectionForMouseEvent(PickRay ray);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Overlays_h
|
#endif // hifi_Overlays_h
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace render {
|
||||||
return overlay->getBounds();
|
return overlay->getBounds();
|
||||||
}
|
}
|
||||||
template <> int payloadGetLayer(const Overlay::Pointer& overlay) {
|
template <> int payloadGetLayer(const Overlay::Pointer& overlay) {
|
||||||
// MAgic number while we are defining the layering mechanism:
|
// Magic number while we are defining the layering mechanism:
|
||||||
const int LAYER_NO_AA = 3;
|
const int LAYER_NO_AA = 3;
|
||||||
const int LAYER_2D = 2;
|
const int LAYER_2D = 2;
|
||||||
const int LAYER_3D_FRONT = 1;
|
const int LAYER_3D_FRONT = 1;
|
||||||
|
|
|
@ -182,7 +182,7 @@ void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason remo
|
||||||
|
|
||||||
void AvatarHashMap::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
|
void AvatarHashMap::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
|
||||||
qCDebug(avatars) << "Removed avatar with UUID" << uuidStringWithoutCurlyBraces(removedAvatar->getSessionUUID())
|
qCDebug(avatars) << "Removed avatar with UUID" << uuidStringWithoutCurlyBraces(removedAvatar->getSessionUUID())
|
||||||
<< "from AvatarHashMap";
|
<< "from AvatarHashMap" << removalReason;
|
||||||
emit avatarRemovedEvent(removedAvatar->getSessionUUID());
|
emit avatarRemovedEvent(removedAvatar->getSessionUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1419,8 +1419,7 @@ QVector<QUuid> EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& pare
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
parent->forEachChild([&](SpatiallyNestablePointer child) {
|
parent->forEachChild([&](SpatiallyNestablePointer child) {
|
||||||
if (child->getParentJointIndex() == jointIndex &&
|
if (child->getParentJointIndex() == jointIndex) {
|
||||||
child->getNestableType() != NestableType::Overlay) {
|
|
||||||
result.push_back(child->getID());
|
result.push_back(child->getID());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -44,6 +44,8 @@ public:
|
||||||
// Mutable, but must retain structure of vector
|
// Mutable, but must retain structure of vector
|
||||||
using NetworkMaterials = std::vector<std::shared_ptr<NetworkMaterial>>;
|
using NetworkMaterials = std::vector<std::shared_ptr<NetworkMaterial>>;
|
||||||
|
|
||||||
|
bool isGeometryLoaded() const { return (bool)_fbxGeometry; }
|
||||||
|
|
||||||
const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; }
|
const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; }
|
||||||
const GeometryMeshes& getMeshes() const { return *_meshes; }
|
const GeometryMeshes& getMeshes() const { return *_meshes; }
|
||||||
const std::shared_ptr<const NetworkMaterial> getShapeMaterial(int shapeID) const;
|
const std::shared_ptr<const NetworkMaterial> getShapeMaterial(int shapeID) const;
|
||||||
|
|
|
@ -16,8 +16,8 @@ void UserActivityLoggerScriptingInterface::enabledEdit() {
|
||||||
logAction("enabled_edit");
|
logAction("enabled_edit");
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserActivityLoggerScriptingInterface::openedTablet() {
|
void UserActivityLoggerScriptingInterface::openedTablet(bool visibleToOthers) {
|
||||||
logAction("opened_tablet");
|
logAction("opened_tablet", { { "visible_to_others", visibleToOthers } });
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserActivityLoggerScriptingInterface::closedTablet() {
|
void UserActivityLoggerScriptingInterface::closedTablet() {
|
||||||
|
|
|
@ -21,7 +21,7 @@ class UserActivityLoggerScriptingInterface : public QObject, public Dependency {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE void enabledEdit();
|
Q_INVOKABLE void enabledEdit();
|
||||||
Q_INVOKABLE void openedTablet();
|
Q_INVOKABLE void openedTablet(bool visibleToOthers);
|
||||||
Q_INVOKABLE void closedTablet();
|
Q_INVOKABLE void closedTablet();
|
||||||
Q_INVOKABLE void openedMarketplace();
|
Q_INVOKABLE void openedMarketplace();
|
||||||
Q_INVOKABLE void toggledAway(bool isAway);
|
Q_INVOKABLE void toggledAway(bool isAway);
|
||||||
|
|
|
@ -114,7 +114,7 @@ public:
|
||||||
void setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
|
void setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
|
||||||
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
||||||
|
|
||||||
bool isLoaded() const { return (bool)_renderGeometry; }
|
bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isGeometryLoaded(); }
|
||||||
|
|
||||||
void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; }
|
void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; }
|
||||||
bool isWireframe() const { return _isWireframe; }
|
bool isWireframe() const { return _isWireframe; }
|
||||||
|
|
|
@ -150,7 +150,6 @@ signals:
|
||||||
private:
|
private:
|
||||||
bool getRequestsDomainListData();
|
bool getRequestsDomainListData();
|
||||||
void setRequestsDomainListData(bool requests);
|
void setRequestsDomainListData(bool requests);
|
||||||
bool _requestsDomainListData;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -331,6 +331,12 @@ Grabber.prototype.pressEvent = function(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
|
||||||
|
var overlayResult = Overlays.findRayIntersection(pickRay, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]);
|
||||||
|
if (overlayResult.intersects) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var pickResults = Entities.findRayIntersection(pickRay, true); // accurate picking
|
var pickResults = Entities.findRayIntersection(pickRay, true); // accurate picking
|
||||||
if (!pickResults.intersects) {
|
if (!pickResults.intersects) {
|
||||||
// didn't click on anything
|
// didn't click on anything
|
||||||
|
|
|
@ -399,7 +399,7 @@ function entityHasActions(entityID) {
|
||||||
|
|
||||||
function findRayIntersection(pickRay, precise, include, exclude) {
|
function findRayIntersection(pickRay, precise, include, exclude) {
|
||||||
var entities = Entities.findRayIntersection(pickRay, precise, include, exclude, true);
|
var entities = Entities.findRayIntersection(pickRay, precise, include, exclude, true);
|
||||||
var overlays = Overlays.findRayIntersection(pickRay);
|
var overlays = Overlays.findRayIntersection(pickRay, precise, [], [HMD.tabletID]);
|
||||||
if (!overlays.intersects || (entities.intersects && (entities.distance <= overlays.distance))) {
|
if (!overlays.intersects || (entities.intersects && (entities.distance <= overlays.distance))) {
|
||||||
return entities;
|
return entities;
|
||||||
}
|
}
|
||||||
|
@ -644,6 +644,7 @@ EquipHotspotBuddy.prototype.updateHotspot = function(hotspot, timestamp) {
|
||||||
|
|
||||||
// override default sphere with a user specified model, if it exists.
|
// override default sphere with a user specified model, if it exists.
|
||||||
overlayInfoSet.overlays.push(Overlays.addOverlay("model", {
|
overlayInfoSet.overlays.push(Overlays.addOverlay("model", {
|
||||||
|
name: "hotspot overlay",
|
||||||
url: hotspot.modelURL ? hotspot.modelURL : DEFAULT_SPHERE_MODEL_URL,
|
url: hotspot.modelURL ? hotspot.modelURL : DEFAULT_SPHERE_MODEL_URL,
|
||||||
position: hotspot.worldPosition,
|
position: hotspot.worldPosition,
|
||||||
rotation: {
|
rotation: {
|
||||||
|
@ -777,7 +778,7 @@ function MyController(hand) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.actionID = null; // action this script created...
|
this.actionID = null; // action this script created...
|
||||||
this.grabbedEntity = null; // on this entity.
|
this.grabbedThingID = null; // on this entity.
|
||||||
this.grabbedOverlay = null;
|
this.grabbedOverlay = null;
|
||||||
this.state = STATE_OFF;
|
this.state = STATE_OFF;
|
||||||
this.pointer = null; // entity-id of line object
|
this.pointer = null; // entity-id of line object
|
||||||
|
@ -854,12 +855,15 @@ function MyController(hand) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.callEntityMethodOnGrabbed = function(entityMethodName) {
|
this.callEntityMethodOnGrabbed = function(entityMethodName) {
|
||||||
|
if (this.grabbedIsOverlay) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
||||||
Entities.callEntityMethod(this.grabbedEntity, entityMethodName, args);
|
Entities.callEntityMethod(this.grabbedThingID, entityMethodName, args);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setState = function(newState, reason) {
|
this.setState = function(newState, reason) {
|
||||||
if ((isInEditMode() && this.grabbedEntity !== HMD.tabletID) &&
|
if ((isInEditMode() && this.grabbedThingID !== HMD.tabletID) &&
|
||||||
(newState !== STATE_OFF &&
|
(newState !== STATE_OFF &&
|
||||||
newState !== STATE_SEARCHING &&
|
newState !== STATE_SEARCHING &&
|
||||||
newState !== STATE_OVERLAY_STYLUS_TOUCHING &&
|
newState !== STATE_OVERLAY_STYLUS_TOUCHING &&
|
||||||
|
@ -906,6 +910,7 @@ function MyController(hand) {
|
||||||
|
|
||||||
if (!this.grabPointSphere) {
|
if (!this.grabPointSphere) {
|
||||||
this.grabPointSphere = Overlays.addOverlay("sphere", {
|
this.grabPointSphere = Overlays.addOverlay("sphere", {
|
||||||
|
name: "grabPointSphere",
|
||||||
localPosition: getGrabPointSphereOffset(this.handToController()),
|
localPosition: getGrabPointSphereOffset(this.handToController()),
|
||||||
localRotation: { x: 0, y: 0, z: 0, w: 1 },
|
localRotation: { x: 0, y: 0, z: 0, w: 1 },
|
||||||
dimensions: GRAB_POINT_SPHERE_RADIUS * 2,
|
dimensions: GRAB_POINT_SPHERE_RADIUS * 2,
|
||||||
|
@ -936,6 +941,7 @@ function MyController(hand) {
|
||||||
var brightColor = colorPow(color, 0.06);
|
var brightColor = colorPow(color, 0.06);
|
||||||
if (this.searchSphere === null) {
|
if (this.searchSphere === null) {
|
||||||
var sphereProperties = {
|
var sphereProperties = {
|
||||||
|
name: "searchSphere",
|
||||||
position: location,
|
position: location,
|
||||||
rotation: rotation,
|
rotation: rotation,
|
||||||
outerRadius: size * 1.2,
|
outerRadius: size * 1.2,
|
||||||
|
@ -958,7 +964,8 @@ function MyController(hand) {
|
||||||
innerAlpha: 1.0,
|
innerAlpha: 1.0,
|
||||||
outerAlpha: 0.0,
|
outerAlpha: 0.0,
|
||||||
outerRadius: size * 1.2,
|
outerRadius: size * 1.2,
|
||||||
visible: true
|
visible: true,
|
||||||
|
ignoreRayIntersection: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -969,6 +976,7 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var stylusProperties = {
|
var stylusProperties = {
|
||||||
|
name: "stylus",
|
||||||
url: Script.resourcesPath() + "meshes/tablet-stylus-fat.fbx",
|
url: Script.resourcesPath() + "meshes/tablet-stylus-fat.fbx",
|
||||||
localPosition: Vec3.sum({ x: 0.0,
|
localPosition: Vec3.sum({ x: 0.0,
|
||||||
y: WEB_TOUCH_Y_OFFSET,
|
y: WEB_TOUCH_Y_OFFSET,
|
||||||
|
@ -1003,6 +1011,7 @@ function MyController(hand) {
|
||||||
this.overlayLineOn = function(closePoint, farPoint, color) {
|
this.overlayLineOn = function(closePoint, farPoint, color) {
|
||||||
if (this.overlayLine === null) {
|
if (this.overlayLine === null) {
|
||||||
var lineProperties = {
|
var lineProperties = {
|
||||||
|
name: "line",
|
||||||
glow: 1.0,
|
glow: 1.0,
|
||||||
start: closePoint,
|
start: closePoint,
|
||||||
end: farPoint,
|
end: farPoint,
|
||||||
|
@ -1178,6 +1187,13 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var candidateOverlays = Overlays.findOverlays(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE);
|
||||||
|
for (var j = 0; j < candidateOverlays.length; j++) {
|
||||||
|
if (this.isTablet(candidateOverlays[j])) {
|
||||||
|
nearWeb = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (nearWeb) {
|
if (nearWeb) {
|
||||||
this.showStylus();
|
this.showStylus();
|
||||||
var rayPickInfo = this.calcRayPickInfo(this.hand);
|
var rayPickInfo = this.calcRayPickInfo(this.hand);
|
||||||
|
@ -1430,7 +1446,7 @@ function MyController(hand) {
|
||||||
|
|
||||||
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().grabbedThingID == hotspot.entityID);
|
||||||
var hasParent = true;
|
var hasParent = true;
|
||||||
if (props.parentID === NULL_UUID) {
|
if (props.parentID === NULL_UUID) {
|
||||||
hasParent = false;
|
hasParent = false;
|
||||||
|
@ -1588,7 +1604,7 @@ function MyController(hand) {
|
||||||
|
|
||||||
var farSearching = this.triggerSmoothedSqueezed() && (Date.now() - this.searchStartTime > FAR_SEARCH_DELAY);
|
var farSearching = this.triggerSmoothedSqueezed() && (Date.now() - this.searchStartTime > FAR_SEARCH_DELAY);
|
||||||
|
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.grabbedOverlay = null;
|
this.grabbedOverlay = null;
|
||||||
this.isInitialGrab = false;
|
this.isInitialGrab = false;
|
||||||
this.preparingHoldRelease = false;
|
this.preparingHoldRelease = false;
|
||||||
|
@ -1596,7 +1612,7 @@ function MyController(hand) {
|
||||||
this.checkForUnexpectedChildren();
|
this.checkForUnexpectedChildren();
|
||||||
|
|
||||||
if ((this.triggerSmoothedReleased() && this.secondaryReleased())) {
|
if ((this.triggerSmoothedReleased() && this.secondaryReleased())) {
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.setState(STATE_OFF, "trigger released");
|
this.setState(STATE_OFF, "trigger released");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1617,8 +1633,9 @@ function MyController(hand) {
|
||||||
if (potentialEquipHotspot) {
|
if (potentialEquipHotspot) {
|
||||||
if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && holdEnabled) {
|
if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && holdEnabled) {
|
||||||
this.grabbedHotspot = potentialEquipHotspot;
|
this.grabbedHotspot = potentialEquipHotspot;
|
||||||
this.grabbedEntity = potentialEquipHotspot.entityID;
|
this.grabbedThingID = potentialEquipHotspot.entityID;
|
||||||
this.setState(STATE_HOLD, "equipping '" + entityPropertiesCache.getProps(this.grabbedEntity).name + "'");
|
this.grabbedIsOverlay = false;
|
||||||
|
this.setState(STATE_HOLD, "equipping '" + entityPropertiesCache.getProps(this.grabbedThingID).name + "'");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1629,6 +1646,11 @@ function MyController(hand) {
|
||||||
return _this.entityIsNearGrabbable(entity, handPosition, NEAR_GRAB_MAX_DISTANCE);
|
return _this.entityIsNearGrabbable(entity, handPosition, NEAR_GRAB_MAX_DISTANCE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var candidateOverlays = Overlays.findOverlays(handPosition, NEAR_GRAB_RADIUS);
|
||||||
|
var grabbableOverlays = candidateOverlays.filter(function(overlayID) {
|
||||||
|
return Overlays.getProperty(overlayID, "grabbable");
|
||||||
|
});
|
||||||
|
|
||||||
if (rayPickInfo.entityID) {
|
if (rayPickInfo.entityID) {
|
||||||
this.intersectionDistance = rayPickInfo.distance;
|
this.intersectionDistance = rayPickInfo.distance;
|
||||||
if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) {
|
if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) {
|
||||||
|
@ -1640,6 +1662,23 @@ function MyController(hand) {
|
||||||
this.intersectionDistance = 0;
|
this.intersectionDistance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (grabbableOverlays.length > 0) {
|
||||||
|
grabbableOverlays.sort(function(a, b) {
|
||||||
|
var aPosition = Overlays.getProperty(a, "position");
|
||||||
|
var aDistance = Vec3.distance(aPosition, handPosition);
|
||||||
|
var bPosition = Overlays.getProperty(b, "position");
|
||||||
|
var bDistance = Vec3.distance(bPosition, handPosition);
|
||||||
|
return aDistance - bDistance;
|
||||||
|
});
|
||||||
|
this.grabbedThingID = grabbableOverlays[0];
|
||||||
|
this.grabbedIsOverlay = true;
|
||||||
|
if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) {
|
||||||
|
this.setState(STATE_NEAR_GRABBING, "near grab overlay '" +
|
||||||
|
Overlays.getProperty(this.grabbedThingID, "name") + "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var entity;
|
var entity;
|
||||||
if (grabbableEntities.length > 0) {
|
if (grabbableEntities.length > 0) {
|
||||||
// sort by distance
|
// sort by distance
|
||||||
|
@ -1649,23 +1688,20 @@ function MyController(hand) {
|
||||||
return aDistance - bDistance;
|
return aDistance - bDistance;
|
||||||
});
|
});
|
||||||
entity = grabbableEntities[0];
|
entity = grabbableEntities[0];
|
||||||
if (!isInEditMode() || entity == HMD.tabletID) {
|
if (!isInEditMode() || entity == HMD.tabletID) { // tablet is grabbable, even when editing
|
||||||
name = entityPropertiesCache.getProps(entity).name;
|
name = entityPropertiesCache.getProps(entity).name;
|
||||||
this.grabbedEntity = entity;
|
this.grabbedThingID = entity;
|
||||||
|
this.grabbedIsOverlay = false;
|
||||||
if (this.entityWantsTrigger(entity)) {
|
if (this.entityWantsTrigger(entity)) {
|
||||||
if (this.triggerSmoothedGrab()) {
|
if (this.triggerSmoothedGrab()) {
|
||||||
this.setState(STATE_NEAR_TRIGGER, "near trigger '" + name + "'");
|
this.setState(STATE_NEAR_TRIGGER, "near trigger '" + name + "'");
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
// potentialNearTriggerEntity = entity;
|
|
||||||
}
|
}
|
||||||
} 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 + "'");
|
this.setState(STATE_NEAR_GRABBING, "near grab entity '" + name + "'");
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
// potentialNearGrabEntity = entity;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1701,7 +1737,8 @@ function MyController(hand) {
|
||||||
name = entityPropertiesCache.getProps(entity).name;
|
name = entityPropertiesCache.getProps(entity).name;
|
||||||
if (this.entityWantsTrigger(entity)) {
|
if (this.entityWantsTrigger(entity)) {
|
||||||
if (this.triggerSmoothedGrab()) {
|
if (this.triggerSmoothedGrab()) {
|
||||||
this.grabbedEntity = entity;
|
this.grabbedThingID = entity;
|
||||||
|
this.grabbedIsOverlay = false;
|
||||||
this.setState(STATE_FAR_TRIGGER, "far trigger '" + name + "'");
|
this.setState(STATE_FAR_TRIGGER, "far trigger '" + name + "'");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1709,7 +1746,8 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
} else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) {
|
} else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) {
|
||||||
if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) {
|
if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) {
|
||||||
this.grabbedEntity = entity;
|
this.grabbedThingID = entity;
|
||||||
|
this.grabbedIsOverlay = false;
|
||||||
this.grabbedDistance = rayPickInfo.distance;
|
this.grabbedDistance = rayPickInfo.distance;
|
||||||
this.setState(STATE_DISTANCE_HOLDING, "distance hold '" + name + "'");
|
this.setState(STATE_DISTANCE_HOLDING, "distance hold '" + name + "'");
|
||||||
return;
|
return;
|
||||||
|
@ -1789,7 +1827,8 @@ function MyController(hand) {
|
||||||
Entities.sendHoverOverEntity(entity, pointerEvent);
|
Entities.sendHoverOverEntity(entity, pointerEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.grabbedEntity = entity;
|
this.grabbedThingID = entity;
|
||||||
|
this.grabbedIsOverlay = false;
|
||||||
this.setState(STATE_ENTITY_STYLUS_TOUCHING, "begin touching entity '" + name + "'");
|
this.setState(STATE_ENTITY_STYLUS_TOUCHING, "begin touching entity '" + name + "'");
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -1917,7 +1956,8 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.triggerSmoothedGrab() && (!isEditing() || this.isTablet(entity))) {
|
if (this.triggerSmoothedGrab() && (!isEditing() || this.isTablet(entity))) {
|
||||||
this.grabbedEntity = entity;
|
this.grabbedThingID = entity;
|
||||||
|
this.grabbedIsOverlay = false;
|
||||||
this.setState(STATE_ENTITY_LASER_TOUCHING, "begin touching entity '" + name + "'");
|
this.setState(STATE_ENTITY_LASER_TOUCHING, "begin touching entity '" + name + "'");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2028,7 +2068,7 @@ function MyController(hand) {
|
||||||
var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix());
|
var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix());
|
||||||
var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition);
|
var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition);
|
||||||
|
|
||||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES);
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
|
|
||||||
// add the action and initialize some variables
|
// add the action and initialize some variables
|
||||||
|
@ -2058,7 +2098,7 @@ function MyController(hand) {
|
||||||
var timeScale = this.distanceGrabTimescale(this.mass, distanceToObject);
|
var timeScale = this.distanceGrabTimescale(this.mass, distanceToObject);
|
||||||
|
|
||||||
this.actionID = NULL_UUID;
|
this.actionID = NULL_UUID;
|
||||||
this.actionID = Entities.addAction("spring", this.grabbedEntity, {
|
this.actionID = Entities.addAction("spring", this.grabbedThingID, {
|
||||||
targetPosition: this.currentObjectPosition,
|
targetPosition: this.currentObjectPosition,
|
||||||
linearTimeScale: timeScale,
|
linearTimeScale: timeScale,
|
||||||
targetRotation: this.currentObjectRotation,
|
targetRotation: this.currentObjectRotation,
|
||||||
|
@ -2083,12 +2123,12 @@ function MyController(hand) {
|
||||||
this.ensureDynamic = function() {
|
this.ensureDynamic = function() {
|
||||||
// if we distance hold something and keep it very still before releasing it, it ends up
|
// if we distance hold something and keep it very still before releasing it, it ends up
|
||||||
// non-dynamic in bullet. If it's too still, give it a little bounce so it will fall.
|
// non-dynamic in bullet. If it's too still, give it a little bounce so it will fall.
|
||||||
var props = Entities.getEntityProperties(this.grabbedEntity, ["velocity", "dynamic", "parentID"]);
|
var props = Entities.getEntityProperties(this.grabbedThingID, ["velocity", "dynamic", "parentID"]);
|
||||||
if (props.dynamic && props.parentID == NULL_UUID) {
|
if (props.dynamic && props.parentID == NULL_UUID) {
|
||||||
var velocity = props.velocity;
|
var velocity = props.velocity;
|
||||||
if (Vec3.length(velocity) < 0.05) { // see EntityMotionState.cpp DYNAMIC_LINEAR_VELOCITY_THRESHOLD
|
if (Vec3.length(velocity) < 0.05) { // see EntityMotionState.cpp DYNAMIC_LINEAR_VELOCITY_THRESHOLD
|
||||||
velocity = { x: 0.0, y: 0.2, z:0.0 };
|
velocity = { x: 0.0, y: 0.2, z:0.0 };
|
||||||
Entities.editEntity(this.grabbedEntity, { velocity: velocity });
|
Entities.editEntity(this.grabbedThingID, { velocity: velocity });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2110,7 +2150,7 @@ function MyController(hand) {
|
||||||
var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix());
|
var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix());
|
||||||
var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition);
|
var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition);
|
||||||
|
|
||||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES);
|
||||||
|
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds
|
var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds
|
||||||
|
@ -2165,7 +2205,7 @@ function MyController(hand) {
|
||||||
newTargetPosition = Vec3.sum(newTargetPosition, this.offsetPosition);
|
newTargetPosition = Vec3.sum(newTargetPosition, this.offsetPosition);
|
||||||
|
|
||||||
var objectToAvatar = Vec3.subtract(this.currentObjectPosition, MyAvatar.position);
|
var objectToAvatar = Vec3.subtract(this.currentObjectPosition, MyAvatar.position);
|
||||||
var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData);
|
var handControllerData = getEntityCustomData('handControllerKey', this.grabbedThingID, 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) {
|
||||||
|
@ -2194,7 +2234,7 @@ function MyController(hand) {
|
||||||
this.overlayLineOn(rayPickInfo.searchRay.origin, Vec3.subtract(grabbedProperties.position, this.offsetPosition), COLORS_GRAB_DISTANCE_HOLD);
|
this.overlayLineOn(rayPickInfo.searchRay.origin, Vec3.subtract(grabbedProperties.position, this.offsetPosition), COLORS_GRAB_DISTANCE_HOLD);
|
||||||
|
|
||||||
var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition));
|
var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition));
|
||||||
var success = Entities.updateAction(this.grabbedEntity, this.actionID, {
|
var success = Entities.updateAction(this.grabbedThingID, this.actionID, {
|
||||||
targetPosition: newTargetPosition,
|
targetPosition: newTargetPosition,
|
||||||
linearTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject),
|
linearTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject),
|
||||||
targetRotation: this.currentObjectRotation,
|
targetRotation: this.currentObjectRotation,
|
||||||
|
@ -2211,7 +2251,7 @@ function MyController(hand) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setupHoldAction = function() {
|
this.setupHoldAction = function() {
|
||||||
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
|
this.actionID = Entities.addAction("hold", this.grabbedThingID, {
|
||||||
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
||||||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||||
relativePosition: this.offsetPosition,
|
relativePosition: this.offsetPosition,
|
||||||
|
@ -2301,18 +2341,31 @@ function MyController(hand) {
|
||||||
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
|
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
|
||||||
|
|
||||||
if (this.entityActivated) {
|
if (this.entityActivated) {
|
||||||
var saveGrabbedID = this.grabbedEntity;
|
var saveGrabbedID = this.grabbedThingID;
|
||||||
this.release();
|
this.release();
|
||||||
this.grabbedEntity = saveGrabbedID;
|
this.grabbedThingID = saveGrabbedID;
|
||||||
}
|
}
|
||||||
|
|
||||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
var grabbedProperties;
|
||||||
|
if (this.grabbedIsOverlay) {
|
||||||
|
grabbedProperties = {
|
||||||
|
position: Overlays.getProperty(this.grabbedThingID, "position"),
|
||||||
|
rotation: Overlays.getProperty(this.grabbedThingID, "rotation"),
|
||||||
|
parentID: Overlays.getProperty(this.grabbedThingID, "parentID"),
|
||||||
|
parentJointIndex: Overlays.getProperty(this.grabbedThingID, "parentJointIndex"),
|
||||||
|
dynamic: false,
|
||||||
|
shapeType: "none"
|
||||||
|
};
|
||||||
|
this.ignoreIK = true;
|
||||||
|
} else {
|
||||||
|
grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES);
|
||||||
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);
|
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedThingID, DEFAULT_GRABBABLE_DATA);
|
||||||
this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true;
|
this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var handRotation;
|
var handRotation;
|
||||||
var handPosition;
|
var handPosition;
|
||||||
|
@ -2350,7 +2403,8 @@ function MyController(hand) {
|
||||||
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
|
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
var isPhysical = propsArePhysical(grabbedProperties) || entityHasActions(this.grabbedEntity);
|
var isPhysical = propsArePhysical(grabbedProperties) ||
|
||||||
|
(!this.grabbedIsOverlay && entityHasActions(this.grabbedThingID));
|
||||||
if (isPhysical && this.state == STATE_NEAR_GRABBING && grabbedProperties.parentID === NULL_UUID) {
|
if (isPhysical && this.state == STATE_NEAR_GRABBING && grabbedProperties.parentID === NULL_UUID) {
|
||||||
// grab entity via action
|
// grab entity via action
|
||||||
if (!this.setupHoldAction()) {
|
if (!this.setupHoldAction()) {
|
||||||
|
@ -2358,7 +2412,7 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||||
action: 'grab',
|
action: 'grab',
|
||||||
grabbedEntity: this.grabbedEntity,
|
grabbedEntity: this.grabbedThingID,
|
||||||
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
|
@ -2383,29 +2437,36 @@ function MyController(hand) {
|
||||||
reparentProps.localPosition = this.offsetPosition;
|
reparentProps.localPosition = this.offsetPosition;
|
||||||
reparentProps.localRotation = this.offsetRotation;
|
reparentProps.localRotation = this.offsetRotation;
|
||||||
}
|
}
|
||||||
Entities.editEntity(this.grabbedEntity, reparentProps);
|
|
||||||
|
if (this.grabbedIsOverlay) {
|
||||||
|
Overlays.editOverlay(this.grabbedThingID, reparentProps);
|
||||||
|
} else {
|
||||||
|
Entities.editEntity(this.grabbedThingID, reparentProps);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.thisHandIsParent(grabbedProperties)) {
|
if (this.thisHandIsParent(grabbedProperties)) {
|
||||||
// this should never happen, but if it does, don't set previous parent to be this hand.
|
// this should never happen, but if it does, don't set previous parent to be this hand.
|
||||||
// this.previousParentID[this.grabbedEntity] = NULL;
|
// this.previousParentID[this.grabbedThingID] = NULL;
|
||||||
// this.previousParentJointIndex[this.grabbedEntity] = -1;
|
// this.previousParentJointIndex[this.grabbedThingID] = -1;
|
||||||
} else {
|
} else {
|
||||||
this.previousParentID[this.grabbedEntity] = grabbedProperties.parentID;
|
this.previousParentID[this.grabbedThingID] = grabbedProperties.parentID;
|
||||||
this.previousParentJointIndex[this.grabbedEntity] = grabbedProperties.parentJointIndex;
|
this.previousParentJointIndex[this.grabbedThingID] = grabbedProperties.parentJointIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||||
action: 'equip',
|
action: 'equip',
|
||||||
grabbedEntity: this.grabbedEntity,
|
grabbedEntity: this.grabbedThingID,
|
||||||
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Entities.editEntity(this.grabbedEntity, {
|
if (!this.grabbedIsOverlay) {
|
||||||
|
Entities.editEntity(this.grabbedThingID, {
|
||||||
velocity: { x: 0, y: 0, z: 0 },
|
velocity: { x: 0, y: 0, z: 0 },
|
||||||
angularVelocity: { x: 0, y: 0, z: 0 },
|
angularVelocity: { x: 0, y: 0, z: 0 },
|
||||||
// dynamic: false
|
// dynamic: false
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (this.state == STATE_NEAR_GRABBING) {
|
if (this.state == STATE_NEAR_GRABBING) {
|
||||||
this.callEntityMethodOnGrabbed("startNearGrab");
|
this.callEntityMethodOnGrabbed("startNearGrab");
|
||||||
|
@ -2471,26 +2532,39 @@ function MyController(hand) {
|
||||||
|
|
||||||
if (dropDetected && !this.waitForTriggerRelease && this.triggerSmoothedGrab()) {
|
if (dropDetected && !this.waitForTriggerRelease && this.triggerSmoothedGrab()) {
|
||||||
// store the offset attach points into preferences.
|
// store the offset attach points into preferences.
|
||||||
if (USE_ATTACH_POINT_SETTINGS && this.grabbedHotspot && this.grabbedEntity) {
|
if (USE_ATTACH_POINT_SETTINGS && this.grabbedHotspot && this.grabbedThingID) {
|
||||||
var prefprops = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "localRotation"]);
|
var prefprops = Entities.getEntityProperties(this.grabbedThingID, ["localPosition", "localRotation"]);
|
||||||
if (prefprops && prefprops.localPosition && prefprops.localRotation) {
|
if (prefprops && prefprops.localPosition && prefprops.localRotation) {
|
||||||
storeAttachPointForHotspotInSettings(this.grabbedHotspot, this.hand,
|
storeAttachPointForHotspotInSettings(this.grabbedHotspot, this.hand,
|
||||||
prefprops.localPosition, prefprops.localRotation);
|
prefprops.localPosition, prefprops.localRotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var grabbedEntity = this.grabbedEntity;
|
var grabbedEntity = this.grabbedThingID;
|
||||||
this.release();
|
this.release();
|
||||||
this.grabbedEntity = grabbedEntity;
|
this.grabbedThingID = grabbedEntity;
|
||||||
this.setState(STATE_NEAR_GRABBING, "drop gesture detected");
|
this.setState(STATE_NEAR_GRABBING, "drop gesture detected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.prevDropDetected = dropDetected;
|
this.prevDropDetected = dropDetected;
|
||||||
}
|
}
|
||||||
|
|
||||||
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "parentJointIndex",
|
var props;
|
||||||
|
if (this.grabbedIsOverlay) {
|
||||||
|
props = {
|
||||||
|
localPosition: Overlays.getProperty(this.grabbedThingID, "localPosition"),
|
||||||
|
parentID: Overlays.getProperty(this.grabbedThingID, "parentID"),
|
||||||
|
parentJointIndex: Overlays.getProperty(this.grabbedThingID, "parentJointIndex"),
|
||||||
|
position: Overlays.getProperty(this.grabbedThingID, "position"),
|
||||||
|
rotation: Overlays.getProperty(this.grabbedThingID, "rotation"),
|
||||||
|
dimensions: Overlays.getProperty(this.grabbedThingID, "dimensions"),
|
||||||
|
registrationPoint: { x: 0.5, y: 0.5, z: 0.5 }
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
props = Entities.getEntityProperties(this.grabbedThingID, ["localPosition", "parentID", "parentJointIndex",
|
||||||
"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");
|
||||||
|
@ -2502,7 +2576,7 @@ function MyController(hand) {
|
||||||
// someone took it from us or otherwise edited the parentID. end the grab. We don't do this
|
// someone took it from us or otherwise edited the parentID. end the grab. We don't do this
|
||||||
// for equipped things so that they can be adjusted while equipped.
|
// for equipped things so that they can be adjusted while equipped.
|
||||||
this.callEntityMethodOnGrabbed("releaseGrab");
|
this.callEntityMethodOnGrabbed("releaseGrab");
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.setState(STATE_OFF, "someone took it");
|
this.setState(STATE_OFF, "someone took it");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2584,7 +2658,7 @@ function MyController(hand) {
|
||||||
|
|
||||||
if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSECS_PER_SEC) {
|
if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSECS_PER_SEC) {
|
||||||
// if less than a 5 seconds left, refresh the actions ttl
|
// if less than a 5 seconds left, refresh the actions ttl
|
||||||
var success = Entities.updateAction(this.grabbedEntity, this.actionID, {
|
var success = Entities.updateAction(this.grabbedThingID, this.actionID, {
|
||||||
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
||||||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||||
relativePosition: this.offsetPosition,
|
relativePosition: this.offsetPosition,
|
||||||
|
@ -2598,14 +2672,14 @@ function MyController(hand) {
|
||||||
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
|
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
|
||||||
} else {
|
} else {
|
||||||
print("continueNearGrabbing -- updateAction failed");
|
print("continueNearGrabbing -- updateAction failed");
|
||||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
Entities.deleteAction(this.grabbedThingID, this.actionID);
|
||||||
this.setupHoldAction();
|
this.setupHoldAction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.maybeScale = function(props) {
|
this.maybeScale = function(props) {
|
||||||
if (!objectScalingEnabled || this.isTablet(this.grabbedEntity)) {
|
if (!objectScalingEnabled || this.isTablet(this.grabbedThingID) || this.grabbedIsOverlay) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2627,7 +2701,7 @@ function MyController(hand) {
|
||||||
this.getOtherHandController().getHandPosition()));
|
this.getOtherHandController().getHandPosition()));
|
||||||
var currentRescale = scalingCurrentDistance / this.scalingStartDistance;
|
var currentRescale = scalingCurrentDistance / this.scalingStartDistance;
|
||||||
var newDimensions = Vec3.multiply(currentRescale, this.scalingStartDimensions);
|
var newDimensions = Vec3.multiply(currentRescale, this.scalingStartDimensions);
|
||||||
Entities.editEntity(this.grabbedEntity, { dimensions: newDimensions });
|
Entities.editEntity(this.grabbedThingID, { dimensions: newDimensions });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2678,7 +2752,7 @@ function MyController(hand) {
|
||||||
this.nearTrigger = function(deltaTime, timestamp) {
|
this.nearTrigger = function(deltaTime, timestamp) {
|
||||||
if (this.triggerSmoothedReleased()) {
|
if (this.triggerSmoothedReleased()) {
|
||||||
this.callEntityMethodOnGrabbed("stopNearTrigger");
|
this.callEntityMethodOnGrabbed("stopNearTrigger");
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.setState(STATE_OFF, "trigger released");
|
this.setState(STATE_OFF, "trigger released");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2688,7 +2762,7 @@ function MyController(hand) {
|
||||||
this.farTrigger = function(deltaTime, timestamp) {
|
this.farTrigger = function(deltaTime, timestamp) {
|
||||||
if (this.triggerSmoothedReleased()) {
|
if (this.triggerSmoothedReleased()) {
|
||||||
this.callEntityMethodOnGrabbed("stopFarTrigger");
|
this.callEntityMethodOnGrabbed("stopFarTrigger");
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.setState(STATE_OFF, "trigger released");
|
this.setState(STATE_OFF, "trigger released");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2703,9 +2777,9 @@ function MyController(hand) {
|
||||||
var intersection = findRayIntersection(pickRay, true, [], [], true);
|
var intersection = findRayIntersection(pickRay, true, [], [], true);
|
||||||
if (intersection.accurate || intersection.overlayID) {
|
if (intersection.accurate || intersection.overlayID) {
|
||||||
this.lastPickTime = now;
|
this.lastPickTime = now;
|
||||||
if (intersection.entityID != this.grabbedEntity) {
|
if (intersection.entityID != this.grabbedThingID) {
|
||||||
this.callEntityMethodOnGrabbed("stopFarTrigger");
|
this.callEntityMethodOnGrabbed("stopFarTrigger");
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.setState(STATE_OFF, "laser moved off of entity");
|
this.setState(STATE_OFF, "laser moved off of entity");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2727,13 +2801,13 @@ function MyController(hand) {
|
||||||
|
|
||||||
this.entityTouchingEnter = function() {
|
this.entityTouchingEnter = function() {
|
||||||
// test for intersection between controller laser and web entity plane.
|
// test for intersection between controller laser and web entity plane.
|
||||||
var intersectInfo = handLaserIntersectEntity(this.grabbedEntity,
|
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID,
|
||||||
getControllerWorldLocation(this.handToController(), true));
|
getControllerWorldLocation(this.handToController(), true));
|
||||||
if (intersectInfo) {
|
if (intersectInfo) {
|
||||||
var pointerEvent = {
|
var pointerEvent = {
|
||||||
type: "Press",
|
type: "Press",
|
||||||
id: this.hand + 1, // 0 is reserved for hardware mouse
|
id: this.hand + 1, // 0 is reserved for hardware mouse
|
||||||
pos2D: projectOntoEntityXYPlane(this.grabbedEntity, intersectInfo.point),
|
pos2D: projectOntoEntityXYPlane(this.grabbedThingID, intersectInfo.point),
|
||||||
pos3D: intersectInfo.point,
|
pos3D: intersectInfo.point,
|
||||||
normal: intersectInfo.normal,
|
normal: intersectInfo.normal,
|
||||||
direction: intersectInfo.searchRay.direction,
|
direction: intersectInfo.searchRay.direction,
|
||||||
|
@ -2741,8 +2815,8 @@ function MyController(hand) {
|
||||||
isPrimaryHeld: true
|
isPrimaryHeld: true
|
||||||
};
|
};
|
||||||
|
|
||||||
Entities.sendMousePressOnEntity(this.grabbedEntity, pointerEvent);
|
Entities.sendMousePressOnEntity(this.grabbedThingID, pointerEvent);
|
||||||
Entities.sendClickDownOnEntity(this.grabbedEntity, pointerEvent);
|
Entities.sendClickDownOnEntity(this.grabbedThingID, pointerEvent);
|
||||||
|
|
||||||
this.touchingEnterTimer = 0;
|
this.touchingEnterTimer = 0;
|
||||||
this.touchingEnterPointerEvent = pointerEvent;
|
this.touchingEnterPointerEvent = pointerEvent;
|
||||||
|
@ -2764,7 +2838,7 @@ function MyController(hand) {
|
||||||
|
|
||||||
this.entityTouchingExit = function() {
|
this.entityTouchingExit = function() {
|
||||||
// test for intersection between controller laser and web entity plane.
|
// test for intersection between controller laser and web entity plane.
|
||||||
var intersectInfo = handLaserIntersectEntity(this.grabbedEntity,
|
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID,
|
||||||
getControllerWorldLocation(this.handToController(), true));
|
getControllerWorldLocation(this.handToController(), true));
|
||||||
if (intersectInfo) {
|
if (intersectInfo) {
|
||||||
var pointerEvent;
|
var pointerEvent;
|
||||||
|
@ -2772,7 +2846,7 @@ function MyController(hand) {
|
||||||
pointerEvent = {
|
pointerEvent = {
|
||||||
type: "Release",
|
type: "Release",
|
||||||
id: this.hand + 1, // 0 is reserved for hardware mouse
|
id: this.hand + 1, // 0 is reserved for hardware mouse
|
||||||
pos2D: projectOntoEntityXYPlane(this.grabbedEntity, intersectInfo.point),
|
pos2D: projectOntoEntityXYPlane(this.grabbedThingID, intersectInfo.point),
|
||||||
pos3D: intersectInfo.point,
|
pos3D: intersectInfo.point,
|
||||||
normal: intersectInfo.normal,
|
normal: intersectInfo.normal,
|
||||||
direction: intersectInfo.searchRay.direction,
|
direction: intersectInfo.searchRay.direction,
|
||||||
|
@ -2785,11 +2859,11 @@ function MyController(hand) {
|
||||||
pointerEvent.isPrimaryHeld = false;
|
pointerEvent.isPrimaryHeld = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entities.sendMouseReleaseOnEntity(this.grabbedEntity, pointerEvent);
|
Entities.sendMouseReleaseOnEntity(this.grabbedThingID, pointerEvent);
|
||||||
Entities.sendClickReleaseOnEntity(this.grabbedEntity, pointerEvent);
|
Entities.sendClickReleaseOnEntity(this.grabbedThingID, pointerEvent);
|
||||||
Entities.sendHoverLeaveEntity(this.grabbedEntity, pointerEvent);
|
Entities.sendHoverLeaveEntity(this.grabbedThingID, pointerEvent);
|
||||||
}
|
}
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.grabbedOverlay = null;
|
this.grabbedOverlay = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2797,7 +2871,7 @@ function MyController(hand) {
|
||||||
|
|
||||||
this.touchingEnterTimer += dt;
|
this.touchingEnterTimer += dt;
|
||||||
|
|
||||||
entityPropertiesCache.addEntity(this.grabbedEntity);
|
entityPropertiesCache.addEntity(this.grabbedThingID);
|
||||||
|
|
||||||
if (this.state == STATE_ENTITY_LASER_TOUCHING && !this.triggerSmoothedGrab()) {
|
if (this.state == STATE_ENTITY_LASER_TOUCHING && !this.triggerSmoothedGrab()) {
|
||||||
this.setState(STATE_OFF, "released trigger");
|
this.setState(STATE_OFF, "released trigger");
|
||||||
|
@ -2805,7 +2879,7 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// test for intersection between controller laser and web entity plane.
|
// test for intersection between controller laser and web entity plane.
|
||||||
var intersectInfo = handLaserIntersectEntity(this.grabbedEntity,
|
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID,
|
||||||
getControllerWorldLocation(this.handToController(), true));
|
getControllerWorldLocation(this.handToController(), true));
|
||||||
if (intersectInfo) {
|
if (intersectInfo) {
|
||||||
|
|
||||||
|
@ -2815,15 +2889,15 @@ function MyController(hand) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Entities.keyboardFocusEntity != this.grabbedEntity) {
|
if (Entities.keyboardFocusEntity != this.grabbedThingID) {
|
||||||
Overlays.keyboardFocusOverlay = 0;
|
Overlays.keyboardFocusOverlay = 0;
|
||||||
Entities.keyboardFocusEntity = this.grabbedEntity;
|
Entities.keyboardFocusEntity = this.grabbedThingID;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pointerEvent = {
|
var pointerEvent = {
|
||||||
type: "Move",
|
type: "Move",
|
||||||
id: this.hand + 1, // 0 is reserved for hardware mouse
|
id: this.hand + 1, // 0 is reserved for hardware mouse
|
||||||
pos2D: projectOntoEntityXYPlane(this.grabbedEntity, intersectInfo.point),
|
pos2D: projectOntoEntityXYPlane(this.grabbedThingID, intersectInfo.point),
|
||||||
pos3D: intersectInfo.point,
|
pos3D: intersectInfo.point,
|
||||||
normal: intersectInfo.normal,
|
normal: intersectInfo.normal,
|
||||||
direction: intersectInfo.searchRay.direction,
|
direction: intersectInfo.searchRay.direction,
|
||||||
|
@ -2834,8 +2908,8 @@ function MyController(hand) {
|
||||||
var POINTER_PRESS_TO_MOVE_DELAY = 0.25; // seconds
|
var POINTER_PRESS_TO_MOVE_DELAY = 0.25; // seconds
|
||||||
if (this.deadspotExpired || this.touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY ||
|
if (this.deadspotExpired || this.touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY ||
|
||||||
Vec3.distance(intersectInfo.point, this.touchingEnterPointerEvent.pos3D) > this.deadspotRadius) {
|
Vec3.distance(intersectInfo.point, this.touchingEnterPointerEvent.pos3D) > this.deadspotRadius) {
|
||||||
Entities.sendMouseMoveOnEntity(this.grabbedEntity, pointerEvent);
|
Entities.sendMouseMoveOnEntity(this.grabbedThingID, pointerEvent);
|
||||||
Entities.sendHoldingClickOnEntity(this.grabbedEntity, pointerEvent);
|
Entities.sendHoldingClickOnEntity(this.grabbedThingID, pointerEvent);
|
||||||
this.deadspotExpired = true;
|
this.deadspotExpired = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2845,7 +2919,7 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
Reticle.setVisible(false);
|
Reticle.setVisible(false);
|
||||||
} else {
|
} else {
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.setState(STATE_OFF, "grabbed entity was destroyed");
|
this.setState(STATE_OFF, "grabbed entity was destroyed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2930,7 +3004,7 @@ function MyController(hand) {
|
||||||
Overlays.sendMouseReleaseOnOverlay(this.grabbedOverlay, pointerEvent);
|
Overlays.sendMouseReleaseOnOverlay(this.grabbedOverlay, pointerEvent);
|
||||||
Overlays.sendHoverLeaveOverlay(this.grabbedOverlay, pointerEvent);
|
Overlays.sendHoverLeaveOverlay(this.grabbedOverlay, pointerEvent);
|
||||||
}
|
}
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.grabbedOverlay = null;
|
this.grabbedOverlay = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2953,7 +3027,7 @@ function MyController(hand) {
|
||||||
|
|
||||||
if (this.state == STATE_OVERLAY_STYLUS_TOUCHING &&
|
if (this.state == STATE_OVERLAY_STYLUS_TOUCHING &&
|
||||||
intersectInfo.distance > WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET + WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE) {
|
intersectInfo.distance > WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET + WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE) {
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.setState(STATE_OFF, "pulled away from overlay");
|
this.setState(STATE_OFF, "pulled away from overlay");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3010,7 +3084,7 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
Reticle.setVisible(false);
|
Reticle.setVisible(false);
|
||||||
} else {
|
} else {
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.setState(STATE_OFF, "grabbed overlay was destroyed");
|
this.setState(STATE_OFF, "grabbed overlay was destroyed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3019,7 +3093,7 @@ function MyController(hand) {
|
||||||
this.release = function() {
|
this.release = function() {
|
||||||
this.turnOffVisualizations();
|
this.turnOffVisualizations();
|
||||||
|
|
||||||
if (this.grabbedEntity !== null) {
|
if (this.grabbedThingID !== null) {
|
||||||
if (this.state === STATE_HOLD) {
|
if (this.state === STATE_HOLD) {
|
||||||
this.callEntityMethodOnGrabbed("releaseEquip");
|
this.callEntityMethodOnGrabbed("releaseEquip");
|
||||||
}
|
}
|
||||||
|
@ -3027,35 +3101,49 @@ 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.actionID !== null) {
|
if (this.actionID !== null) {
|
||||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
Entities.deleteAction(this.grabbedThingID, this.actionID);
|
||||||
} else {
|
} else {
|
||||||
// no action, so it's a parenting grab
|
// no action, so it's a parenting grab
|
||||||
if (this.previousParentID[this.grabbedEntity] === NULL_UUID) {
|
if (this.previousParentID[this.grabbedThingID] === NULL_UUID) {
|
||||||
Entities.editEntity(this.grabbedEntity, {
|
if (this.grabbedIsOverlay) {
|
||||||
parentID: this.previousParentID[this.grabbedEntity],
|
Overlays.editOverlay(this.grabbedThingID, {
|
||||||
parentJointIndex: this.previousParentJointIndex[this.grabbedEntity]
|
parentID: NULL_UUID,
|
||||||
|
parentJointIndex: -1
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Entities.editEntity(this.grabbedThingID, {
|
||||||
|
parentID: this.previousParentID[this.grabbedThingID],
|
||||||
|
parentJointIndex: this.previousParentJointIndex[this.grabbedThingID]
|
||||||
});
|
});
|
||||||
this.ensureDynamic();
|
this.ensureDynamic();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.grabbedIsOverlay) {
|
||||||
|
Overlays.editOverlay(this.grabbedThingID, {
|
||||||
|
parentID: this.previousParentID[this.grabbedThingID],
|
||||||
|
parentJointIndex: this.previousParentJointIndex[this.grabbedThingID],
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// we're putting this back as a child of some other parent, so zero its velocity
|
// we're putting this back as a child of some other parent, so zero its velocity
|
||||||
Entities.editEntity(this.grabbedEntity, {
|
Entities.editEntity(this.grabbedThingID, {
|
||||||
parentID: this.previousParentID[this.grabbedEntity],
|
parentID: this.previousParentID[this.grabbedThingID],
|
||||||
parentJointIndex: this.previousParentJointIndex[this.grabbedEntity],
|
parentJointIndex: this.previousParentJointIndex[this.grabbedThingID],
|
||||||
velocity: {x: 0, y: 0, z: 0},
|
velocity: {x: 0, y: 0, z: 0},
|
||||||
angularVelocity: {x: 0, y: 0, z: 0}
|
angularVelocity: {x: 0, y: 0, z: 0}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||||
action: 'release',
|
action: 'release',
|
||||||
grabbedEntity: this.grabbedEntity,
|
grabbedEntity: this.grabbedThingID,
|
||||||
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.actionID = null;
|
this.actionID = null;
|
||||||
this.grabbedEntity = null;
|
this.grabbedThingID = null;
|
||||||
this.grabbedOverlay = null;
|
this.grabbedOverlay = null;
|
||||||
this.grabbedHotspot = null;
|
this.grabbedHotspot = null;
|
||||||
|
|
||||||
|
@ -3143,9 +3231,13 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
_this.previouslyUnhooked[childID] = now;
|
_this.previouslyUnhooked[childID] = now;
|
||||||
|
|
||||||
|
// we don't know if it's an entity or an overlay
|
||||||
Entities.editEntity(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex });
|
Entities.editEntity(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex });
|
||||||
|
Overlays.editOverlay(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex });
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Entities.editEntity(childID, { parentID: NULL_UUID });
|
Entities.editEntity(childID, { parentID: NULL_UUID });
|
||||||
|
Overlays.editOverlay(childID, { parentID: NULL_UUID });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -3264,8 +3356,8 @@ var handleHandMessages = function(channel, message, sender) {
|
||||||
selectedController.release();
|
selectedController.release();
|
||||||
var wearableEntity = data.entityID;
|
var wearableEntity = data.entityID;
|
||||||
entityPropertiesCache.addEntity(wearableEntity);
|
entityPropertiesCache.addEntity(wearableEntity);
|
||||||
selectedController.grabbedEntity = wearableEntity;
|
selectedController.grabbedThingID = wearableEntity;
|
||||||
var hotspots = selectedController.collectEquipHotspots(selectedController.grabbedEntity);
|
var hotspots = selectedController.collectEquipHotspots(selectedController.grabbedThingID);
|
||||||
if (hotspots.length > 0) {
|
if (hotspots.length > 0) {
|
||||||
if (hotspotIndex >= hotspots.length) {
|
if (hotspotIndex >= hotspots.length) {
|
||||||
hotspotIndex = 0;
|
hotspotIndex = 0;
|
||||||
|
|
|
@ -538,6 +538,11 @@ function findClickedEntity(event) {
|
||||||
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
|
||||||
|
var overlayResult = Overlays.findRayIntersection(pickRay, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]);
|
||||||
|
if (overlayResult.intersects) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking
|
var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking
|
||||||
var lightResult = lightOverlayManager.findRayIntersection(pickRay);
|
var lightResult = lightOverlayManager.findRayIntersection(pickRay);
|
||||||
lightResult.accurate = true;
|
lightResult.accurate = true;
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
// 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 getControllerWorldLocation, setEntityCustomData, Tablet, WebTablet:true, HMD, Settings, Script,
|
/* global getControllerWorldLocation, Tablet, WebTablet:true, HMD, Settings, Script,
|
||||||
Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform, clamp */
|
Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform, clamp, Controller, Mat4 */
|
||||||
|
|
||||||
Script.include(Script.resolvePath("../libraries/utils.js"));
|
Script.include(Script.resolvePath("../libraries/utils.js"));
|
||||||
Script.include(Script.resolvePath("../libraries/controllers.js"));
|
Script.include(Script.resolvePath("../libraries/controllers.js"));
|
||||||
|
@ -34,7 +34,7 @@ var TABLET_NATURAL_DIMENSIONS = {x: 33.797, y: 50.129, z: 2.269};
|
||||||
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-close.png";
|
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-close.png";
|
||||||
// var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-close.png";
|
// var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-close.png";
|
||||||
var TABLET_MODEL_PATH = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx";
|
var TABLET_MODEL_PATH = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx";
|
||||||
// var TABLET_MODEL_PATH = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx";
|
var LOCAL_TABLET_MODEL_PATH = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx";
|
||||||
|
|
||||||
// returns object with two fields:
|
// returns object with two fields:
|
||||||
// * position - position in front of the user
|
// * position - position in front of the user
|
||||||
|
@ -112,10 +112,19 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
|
||||||
this.dpi = DEFAULT_DPI * (DEFAULT_WIDTH / this.width);
|
this.dpi = DEFAULT_DPI * (DEFAULT_WIDTH / this.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var modelURL;
|
||||||
|
if (Settings.getValue("tabletVisibleToOthers")) {
|
||||||
|
modelURL = TABLET_MODEL_PATH;
|
||||||
|
} else {
|
||||||
|
modelURL = LOCAL_TABLET_MODEL_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
var tabletProperties = {
|
var tabletProperties = {
|
||||||
name: "WebTablet Tablet",
|
name: "WebTablet Tablet",
|
||||||
type: "Model",
|
type: "Model",
|
||||||
modelURL: TABLET_MODEL_PATH,
|
modelURL: modelURL,
|
||||||
|
url: modelURL, // for overlay
|
||||||
|
grabbable: true, // for overlay
|
||||||
userData: JSON.stringify({
|
userData: JSON.stringify({
|
||||||
"grabbableKey": {"grabbable": true}
|
"grabbableKey": {"grabbable": true}
|
||||||
}),
|
}),
|
||||||
|
@ -127,7 +136,14 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
|
||||||
this.calculateTabletAttachmentProperties(hand, true, tabletProperties);
|
this.calculateTabletAttachmentProperties(hand, true, tabletProperties);
|
||||||
|
|
||||||
this.cleanUpOldTablets();
|
this.cleanUpOldTablets();
|
||||||
|
|
||||||
|
if (Settings.getValue("tabletVisibleToOthers")) {
|
||||||
this.tabletEntityID = Entities.addEntity(tabletProperties, clientOnly);
|
this.tabletEntityID = Entities.addEntity(tabletProperties, clientOnly);
|
||||||
|
this.tabletIsOverlay = false;
|
||||||
|
} else {
|
||||||
|
this.tabletEntityID = Overlays.addOverlay("model", tabletProperties);
|
||||||
|
this.tabletIsOverlay = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.webOverlayID) {
|
if (this.webOverlayID) {
|
||||||
Overlays.deleteOverlay(this.webOverlayID);
|
Overlays.deleteOverlay(this.webOverlayID);
|
||||||
|
@ -152,7 +168,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
|
||||||
});
|
});
|
||||||
|
|
||||||
var HOME_BUTTON_Y_OFFSET = (this.height / 2) - 0.035;
|
var HOME_BUTTON_Y_OFFSET = (this.height / 2) - 0.035;
|
||||||
this.homeButtonEntity = Overlays.addOverlay("sphere", {
|
this.homeButtonID = Overlays.addOverlay("sphere", {
|
||||||
name: "homeButton",
|
name: "homeButton",
|
||||||
localPosition: {x: 0.0, y: -HOME_BUTTON_Y_OFFSET, z: -0.01},
|
localPosition: {x: 0.0, y: -HOME_BUTTON_Y_OFFSET, z: -0.01},
|
||||||
localRotation: Quat.angleAxis(0, Y_AXIS),
|
localRotation: Quat.angleAxis(0, Y_AXIS),
|
||||||
|
@ -165,7 +181,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.receive = function (channel, senderID, senderUUID, localOnly) {
|
this.receive = function (channel, senderID, senderUUID, localOnly) {
|
||||||
if (_this.homeButtonEntity == senderID) {
|
if (_this.homeButtonID == senderID) {
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
var onHomeScreen = tablet.onHomeScreen();
|
var onHomeScreen = tablet.onHomeScreen();
|
||||||
if (onHomeScreen) {
|
if (onHomeScreen) {
|
||||||
|
@ -190,7 +206,16 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getLocation = function() {
|
this.getLocation = function() {
|
||||||
|
if (this.tabletIsOverlay) {
|
||||||
|
var location = Overlays.getProperty(this.tabletEntityID, "localPosition");
|
||||||
|
var orientation = Overlays.getProperty(this.tabletEntityID, "localOrientation");
|
||||||
|
return {
|
||||||
|
localPosition: location,
|
||||||
|
localRotation: orientation
|
||||||
|
};
|
||||||
|
} else {
|
||||||
return Entities.getEntityProperties(_this.tabletEntityID, ["localPosition", "localRotation"]);
|
return Entities.getEntityProperties(_this.tabletEntityID, ["localPosition", "localRotation"]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
this.clicked = false;
|
this.clicked = false;
|
||||||
|
|
||||||
|
@ -248,8 +273,12 @@ WebTablet.prototype.getOverlayObject = function () {
|
||||||
|
|
||||||
WebTablet.prototype.destroy = function () {
|
WebTablet.prototype.destroy = function () {
|
||||||
Overlays.deleteOverlay(this.webOverlayID);
|
Overlays.deleteOverlay(this.webOverlayID);
|
||||||
|
if (this.tabletIsOverlay) {
|
||||||
|
Overlays.deleteOverlay(this.tabletEntityID);
|
||||||
|
} else {
|
||||||
Entities.deleteEntity(this.tabletEntityID);
|
Entities.deleteEntity(this.tabletEntityID);
|
||||||
Overlays.deleteOverlay(this.homeButtonEntity);
|
}
|
||||||
|
Overlays.deleteOverlay(this.homeButtonID);
|
||||||
HMD.displayModeChanged.disconnect(this.myOnHmdChanged);
|
HMD.displayModeChanged.disconnect(this.myOnHmdChanged);
|
||||||
|
|
||||||
Controller.mousePressEvent.disconnect(this.myMousePressEvent);
|
Controller.mousePressEvent.disconnect(this.myMousePressEvent);
|
||||||
|
@ -432,10 +461,16 @@ WebTablet.prototype.getPosition = function () {
|
||||||
|
|
||||||
WebTablet.prototype.mousePressEvent = function (event) {
|
WebTablet.prototype.mousePressEvent = function (event) {
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
var entityPickResults = Entities.findRayIntersection(pickRay, true, [this.tabletEntityID]); // non-accurate picking
|
var entityPickResults;
|
||||||
if (entityPickResults.intersects && entityPickResults.entityID === this.tabletEntityID) {
|
if (this.tabletIsOverlay) {
|
||||||
var overlayPickResults = Overlays.findRayIntersection(pickRay);
|
entityPickResults = Overlays.findRayIntersection(pickRay, true, [this.tabletEntityID]);
|
||||||
if (overlayPickResults.intersects && overlayPickResults.overlayID === HMD.homeButtonID) {
|
} else {
|
||||||
|
entityPickResults = Entities.findRayIntersection(pickRay, true, [this.tabletEntityID]);
|
||||||
|
}
|
||||||
|
if (entityPickResults.intersects && (entityPickResults.entityID === this.tabletEntityID ||
|
||||||
|
entityPickResults.overlayID === this.tabletEntityID)) {
|
||||||
|
var overlayPickResults = Overlays.findRayIntersection(pickRay, true, [this.webOverlayID, this.homeButtonID], []);
|
||||||
|
if (overlayPickResults.intersects && overlayPickResults.overlayID === this.homeButtonID) {
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
var onHomeScreen = tablet.onHomeScreen();
|
var onHomeScreen = tablet.onHomeScreen();
|
||||||
var isMessageOpen = tablet.isMessageDialogOpen();
|
var isMessageOpen = tablet.isMessageDialogOpen();
|
||||||
|
@ -449,13 +484,17 @@ WebTablet.prototype.mousePressEvent = function (event) {
|
||||||
this.setHomeButtonTexture();
|
this.setHomeButtonTexture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!HMD.active && (!overlayPickResults.intersects || !overlayPickResults.overlayID === this.webOverlayID)) {
|
} else if (!HMD.active && (!overlayPickResults.intersects || overlayPickResults.overlayID !== this.webOverlayID)) {
|
||||||
this.dragging = true;
|
this.dragging = true;
|
||||||
var invCameraXform = new Xform(Camera.orientation, Camera.position).inv();
|
var invCameraXform = new Xform(Camera.orientation, Camera.position).inv();
|
||||||
this.initialLocalIntersectionPoint = invCameraXform.xformPoint(entityPickResults.intersection);
|
this.initialLocalIntersectionPoint = invCameraXform.xformPoint(entityPickResults.intersection);
|
||||||
|
if (this.tabletIsOverlay) {
|
||||||
|
this.initialLocalPosition = Overlays.getProperty(this.tabletEntityID, "localPosition");
|
||||||
|
} else {
|
||||||
this.initialLocalPosition = Entities.getEntityProperties(this.tabletEntityID, ["localPosition"]).localPosition;
|
this.initialLocalPosition = Entities.getEntityProperties(this.tabletEntityID, ["localPosition"]).localPosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
WebTablet.prototype.cameraModeChanged = function (newMode) {
|
WebTablet.prototype.cameraModeChanged = function (newMode) {
|
||||||
|
@ -499,11 +538,17 @@ WebTablet.prototype.mouseMoveEvent = function (event) {
|
||||||
var localIntersectionPoint = Vec3.sum(localPickRay.origin, Vec3.multiply(localPickRay.direction, result.distance));
|
var localIntersectionPoint = Vec3.sum(localPickRay.origin, Vec3.multiply(localPickRay.direction, result.distance));
|
||||||
var localOffset = Vec3.subtract(localIntersectionPoint, this.initialLocalIntersectionPoint);
|
var localOffset = Vec3.subtract(localIntersectionPoint, this.initialLocalIntersectionPoint);
|
||||||
var localPosition = Vec3.sum(this.initialLocalPosition, localOffset);
|
var localPosition = Vec3.sum(this.initialLocalPosition, localOffset);
|
||||||
|
if (this.tabletIsOverlay) {
|
||||||
|
Overlays.editOverlay(this.tabletEntityID, {
|
||||||
|
localPosition: localPosition
|
||||||
|
});
|
||||||
|
} else {
|
||||||
Entities.editEntity(this.tabletEntityID, {
|
Entities.editEntity(this.tabletEntityID, {
|
||||||
localPosition: localPosition
|
localPosition: localPosition
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
WebTablet.prototype.mouseReleaseEvent = function (event) {
|
WebTablet.prototype.mouseReleaseEvent = function (event) {
|
||||||
|
|
|
@ -3866,7 +3866,7 @@ SelectionDisplay = (function() {
|
||||||
var somethingClicked = false;
|
var somethingClicked = false;
|
||||||
var pickRay = generalComputePickRay(event.x, event.y);
|
var pickRay = generalComputePickRay(event.x, event.y);
|
||||||
|
|
||||||
var result = Overlays.findRayIntersection(pickRay, true, [HMD.tabletScreenID, HMD.homeButtonID]);
|
var result = Overlays.findRayIntersection(pickRay, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]);
|
||||||
if (result.intersects) {
|
if (result.intersects) {
|
||||||
// mouse clicks on the tablet should override the edit affordances
|
// mouse clicks on the tablet should override the edit affordances
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -37,6 +37,15 @@ var conserveResources = true;
|
||||||
|
|
||||||
Script.include("/~/system/libraries/controllers.js");
|
Script.include("/~/system/libraries/controllers.js");
|
||||||
|
|
||||||
|
function projectVectorOntoPlane(normalizedVector, planeNormal) {
|
||||||
|
return Vec3.cross(planeNormal, Vec3.cross(normalizedVector, planeNormal));
|
||||||
|
}
|
||||||
|
function angleBetweenVectorsInPlane(from, to, normal) {
|
||||||
|
var projectedFrom = projectVectorOntoPlane(from, normal);
|
||||||
|
var projectedTo = projectVectorOntoPlane(to, normal);
|
||||||
|
return Vec3.orientedAngle(projectedFrom, projectedTo, normal);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Overlays.
|
// Overlays.
|
||||||
//
|
//
|
||||||
|
@ -229,7 +238,11 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
||||||
break;
|
break;
|
||||||
case 'refresh':
|
case 'refresh':
|
||||||
removeOverlays();
|
removeOverlays();
|
||||||
populateUserList(message.params);
|
// If filter is specified from .qml instead of through settings, update the settings.
|
||||||
|
if (message.params.filter !== undefined) {
|
||||||
|
Settings.setValue('pal/filtered', !!message.params.filter);
|
||||||
|
}
|
||||||
|
populateUserList(message.params.selected);
|
||||||
UserActivityLogger.palAction("refresh", "");
|
UserActivityLogger.palAction("refresh", "");
|
||||||
break;
|
break;
|
||||||
case 'updateGain':
|
case 'updateGain':
|
||||||
|
@ -271,13 +284,42 @@ function addAvatarNode(id) {
|
||||||
color: color(selected, false, 0.0),
|
color: color(selected, false, 0.0),
|
||||||
ignoreRayIntersection: false}, selected, !conserveResources);
|
ignoreRayIntersection: false}, selected, !conserveResources);
|
||||||
}
|
}
|
||||||
|
// Each open/refresh will capture a stable set of avatarsOfInterest, within the specified filter.
|
||||||
|
var avatarsOfInterest = {};
|
||||||
function populateUserList(selectData) {
|
function populateUserList(selectData) {
|
||||||
|
var filter = Settings.getValue('pal/filtered') && {distance: Settings.getValue('pal/nearDistance')};
|
||||||
var data = [], avatars = AvatarList.getAvatarIdentifiers();
|
var data = [], avatars = AvatarList.getAvatarIdentifiers();
|
||||||
conserveResources = avatars.length > 20;
|
avatarsOfInterest = {};
|
||||||
|
var myPosition = filter && Camera.position,
|
||||||
|
frustum = filter && Camera.frustum,
|
||||||
|
verticalHalfAngle = filter && (frustum.fieldOfView / 2),
|
||||||
|
horizontalHalfAngle = filter && (verticalHalfAngle * frustum.aspectRatio),
|
||||||
|
orientation = filter && Camera.orientation,
|
||||||
|
front = filter && Quat.getFront(orientation),
|
||||||
|
verticalAngleNormal = filter && Quat.getRight(orientation),
|
||||||
|
horizontalAngleNormal = filter && Quat.getUp(orientation);
|
||||||
avatars.forEach(function (id) { // sorting the identifiers is just an aid for debugging
|
avatars.forEach(function (id) { // sorting the identifiers is just an aid for debugging
|
||||||
var avatar = AvatarList.getAvatar(id);
|
var avatar = AvatarList.getAvatar(id);
|
||||||
|
var name = avatar.sessionDisplayName;
|
||||||
|
if (!name) {
|
||||||
|
// Either we got a data packet but no identity yet, or something is really messed up. In any case,
|
||||||
|
// we won't be able to do anything with this user, so don't include them.
|
||||||
|
// In normal circumstances, a refresh will bring in the new user, but if we're very heavily loaded,
|
||||||
|
// we could be losing and gaining people randomly.
|
||||||
|
print('No avatar identity data for', id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (id && myPosition && (Vec3.distance(avatar.position, myPosition) > filter.distance)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var normal = id && filter && Vec3.normalize(Vec3.subtract(avatar.position, myPosition));
|
||||||
|
var horizontal = normal && angleBetweenVectorsInPlane(normal, front, horizontalAngleNormal);
|
||||||
|
var vertical = normal && angleBetweenVectorsInPlane(normal, front, verticalAngleNormal);
|
||||||
|
if (id && filter && ((Math.abs(horizontal) > horizontalHalfAngle) || (Math.abs(vertical) > verticalHalfAngle))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var avatarPalDatum = {
|
var avatarPalDatum = {
|
||||||
displayName: avatar.sessionDisplayName,
|
displayName: name,
|
||||||
userName: '',
|
userName: '',
|
||||||
sessionId: id || '',
|
sessionId: id || '',
|
||||||
audioLevel: 0.0,
|
audioLevel: 0.0,
|
||||||
|
@ -289,10 +331,12 @@ function populateUserList(selectData) {
|
||||||
addAvatarNode(id); // No overlay for ourselves
|
addAvatarNode(id); // No overlay for ourselves
|
||||||
// Everyone needs to see admin status. Username and fingerprint returns default constructor output if the requesting user isn't an admin.
|
// Everyone needs to see admin status. Username and fingerprint returns default constructor output if the requesting user isn't an admin.
|
||||||
Users.requestUsernameFromID(id);
|
Users.requestUsernameFromID(id);
|
||||||
|
avatarsOfInterest[id] = true;
|
||||||
}
|
}
|
||||||
data.push(avatarPalDatum);
|
data.push(avatarPalDatum);
|
||||||
print('PAL data:', JSON.stringify(avatarPalDatum));
|
print('PAL data:', JSON.stringify(avatarPalDatum));
|
||||||
});
|
});
|
||||||
|
conserveResources = Object.keys(avatarsOfInterest).length > 20;
|
||||||
sendToQml({ method: 'users', params: data });
|
sendToQml({ method: 'users', params: data });
|
||||||
if (selectData) {
|
if (selectData) {
|
||||||
selectData[2] = true;
|
selectData[2] = true;
|
||||||
|
@ -317,8 +361,8 @@ var pingPong = true;
|
||||||
function updateOverlays() {
|
function updateOverlays() {
|
||||||
var eye = Camera.position;
|
var eye = Camera.position;
|
||||||
AvatarList.getAvatarIdentifiers().forEach(function (id) {
|
AvatarList.getAvatarIdentifiers().forEach(function (id) {
|
||||||
if (!id) {
|
if (!id || !avatarsOfInterest[id]) {
|
||||||
return; // don't update ourself
|
return; // don't update ourself, or avatars we're not interested in
|
||||||
}
|
}
|
||||||
var avatar = AvatarList.getAvatar(id);
|
var avatar = AvatarList.getAvatar(id);
|
||||||
if (!avatar) {
|
if (!avatar) {
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
UIWebTablet = new WebTablet("qml/hifi/tablet/TabletRoot.qml", DEFAULT_WIDTH * (HMD_TABLET_SCALE / 100), null, activeHand, true);
|
UIWebTablet = new WebTablet("qml/hifi/tablet/TabletRoot.qml", DEFAULT_WIDTH * (HMD_TABLET_SCALE / 100), null, activeHand, true);
|
||||||
UIWebTablet.register();
|
UIWebTablet.register();
|
||||||
HMD.tabletID = UIWebTablet.tabletEntityID;
|
HMD.tabletID = UIWebTablet.tabletEntityID;
|
||||||
HMD.homeButtonID = UIWebTablet.homeButtonEntity;
|
HMD.homeButtonID = UIWebTablet.homeButtonID;
|
||||||
HMD.tabletScreenID = UIWebTablet.webOverlayID;
|
HMD.tabletScreenID = UIWebTablet.webOverlayID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
hideTabletUI();
|
hideTabletUI();
|
||||||
HMD.closeTablet();
|
HMD.closeTablet();
|
||||||
} else if (HMD.showTablet && !tabletShown && !toolbarMode) {
|
} else if (HMD.showTablet && !tabletShown && !toolbarMode) {
|
||||||
UserActivityLogger.openedTablet();
|
UserActivityLogger.openedTablet(Settings.getValue("tabletVisibleToOthers"));
|
||||||
showTabletUI();
|
showTabletUI();
|
||||||
} else if (!HMD.showTablet && tabletShown) {
|
} else if (!HMD.showTablet && tabletShown) {
|
||||||
UserActivityLogger.closedTablet();
|
UserActivityLogger.closedTablet();
|
||||||
|
@ -128,5 +128,6 @@
|
||||||
Entities.deleteEntity(HMD.tabletID);
|
Entities.deleteEntity(HMD.tabletID);
|
||||||
HMD.tabletID = null;
|
HMD.tabletID = null;
|
||||||
HMD.homeButtonID = null;
|
HMD.homeButtonID = null;
|
||||||
|
HMD.tabletScreenID = null;
|
||||||
});
|
});
|
||||||
}()); // END LOCAL_SCOPE
|
}()); // END LOCAL_SCOPE
|
||||||
|
|
Loading…
Reference in a new issue