merge in tablet-as-overlay code

This commit is contained in:
Seth Alves 2017-02-23 18:40:20 -08:00
commit ce717d04e9
15 changed files with 402 additions and 139 deletions

View file

@ -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),
@ -2348,6 +2350,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);
@ -6903,5 +6910,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();
} }

View file

@ -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;

View file

@ -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();

View file

@ -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();

View file

@ -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; }

View file

@ -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" };
{ {

View file

@ -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,15 +60,19 @@ 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);
result["position"] = vec3toVariant(localPosition); if (success) {
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);
result["orientation"] = quatToVariant(localOrientation); if (success) {
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();
} }

View file

@ -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

View file

@ -406,11 +406,21 @@ 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(); i.toBack();
@ -719,11 +729,41 @@ PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay r
return pointerEvent; return pointerEvent;
} }
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);
}
void Overlays::mousePressEvent(QMouseEvent* event) { void 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;
@ -744,7 +784,7 @@ void 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.
@ -762,7 +802,7 @@ void 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.
@ -803,3 +843,31 @@ void Overlays::mouseMoveEvent(QMouseEvent* event) {
} }
} }
} }
QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) const {
QVector<QUuid> result;
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
i.toBack();
while (i.hasPrevious()) {
i.previous();
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;
}

View file

@ -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

View file

@ -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() {

View file

@ -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);

View file

@ -13,7 +13,7 @@
// 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 getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, /* global getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings,
Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset, Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset,
setGrabCommunications, Menu, HMD, isInEditMode */ setGrabCommunications, Menu, HMD, isInEditMode */
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
@ -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,8 +855,11 @@ 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) {
@ -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);
@ -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(a, "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,17 +2341,30 @@ 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 (FORCE_IGNORE_IK) { 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; this.ignoreIK = true;
} else { } else {
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES);
this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true; if (FORCE_IGNORE_IK) {
this.ignoreIK = true;
} else {
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedThingID, DEFAULT_GRABBABLE_DATA);
this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true;
}
} }
var handRotation; var handRotation;
@ -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) {
velocity: { x: 0, y: 0, z: 0 }, Entities.editEntity(this.grabbedThingID, {
angularVelocity: { x: 0, y: 0, z: 0 }, velocity: { x: 0, y: 0, z: 0 },
// dynamic: false angularVelocity: { x: 0, y: 0, z: 0 },
}); // 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
this.ensureDynamic(); });
} else {
Entities.editEntity(this.grabbedThingID, {
parentID: this.previousParentID[this.grabbedThingID],
parentJointIndex: this.previousParentJointIndex[this.grabbedThingID]
});
this.ensureDynamic();
}
} else { } else {
// we're putting this back as a child of some other parent, so zero its velocity if (this.grabbedIsOverlay) {
Entities.editEntity(this.grabbedEntity, { Overlays.editOverlay(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}, });
angularVelocity: {x: 0, y: 0, z: 0} } else {
}); // we're putting this back as a child of some other parent, so zero its velocity
Entities.editEntity(this.grabbedThingID, {
parentID: this.previousParentID[this.grabbedThingID],
parentJointIndex: this.previousParentJointIndex[this.grabbedThingID],
velocity: {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;

View file

@ -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"));
@ -116,6 +116,8 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
name: "WebTablet Tablet", name: "WebTablet Tablet",
type: "Model", type: "Model",
modelURL: TABLET_MODEL_PATH, modelURL: TABLET_MODEL_PATH,
url: TABLET_MODEL_PATH, // for overlay
grabbable: true, // for overlay
userData: JSON.stringify({ userData: JSON.stringify({
"grabbableKey": {"grabbable": true} "grabbableKey": {"grabbable": true}
}), }),
@ -127,7 +129,14 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
this.calculateTabletAttachmentProperties(hand, true, tabletProperties); this.calculateTabletAttachmentProperties(hand, true, tabletProperties);
this.cleanUpOldTablets(); this.cleanUpOldTablets();
this.tabletEntityID = Entities.addEntity(tabletProperties, clientOnly);
if (Settings.getValue("tabletVisibleToOthers")) {
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 +161,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 +174,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) {
@ -184,7 +193,16 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
}; };
this.getLocation = function() { this.getLocation = function() {
return Entities.getEntityProperties(_this.tabletEntityID, ["localPosition", "localRotation"]); 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"]);
}
}; };
this.clicked = false; this.clicked = false;
@ -242,8 +260,12 @@ WebTablet.prototype.getOverlayObject = function () {
WebTablet.prototype.destroy = function () { WebTablet.prototype.destroy = function () {
Overlays.deleteOverlay(this.webOverlayID); Overlays.deleteOverlay(this.webOverlayID);
Entities.deleteEntity(this.tabletEntityID); if (this.tabletIsOverlay) {
Overlays.deleteOverlay(this.homeButtonEntity); Overlays.deleteOverlay(this.tabletEntityID);
} else {
Entities.deleteEntity(this.tabletEntityID);
}
Overlays.deleteOverlay(this.homeButtonID);
HMD.displayModeChanged.disconnect(this.myOnHmdChanged); HMD.displayModeChanged.disconnect(this.myOnHmdChanged);
Controller.mousePressEvent.disconnect(this.myMousePressEvent); Controller.mousePressEvent.disconnect(this.myMousePressEvent);
@ -426,10 +448,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();
if (onHomeScreen) { if (onHomeScreen) {
@ -438,11 +466,15 @@ WebTablet.prototype.mousePressEvent = function (event) {
tablet.gotoHomeScreen(); tablet.gotoHomeScreen();
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);
this.initialLocalPosition = Entities.getEntityProperties(this.tabletEntityID, ["localPosition"]).localPosition; if (this.tabletIsOverlay) {
this.initialLocalPosition = Overlays.getProperty(this.tabletEntityID, "localPosition");
} else {
this.initialLocalPosition = Entities.getEntityProperties(this.tabletEntityID, ["localPosition"]).localPosition;
}
} }
} }
}; };
@ -488,9 +520,15 @@ 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);
Entities.editEntity(this.tabletEntityID, { if (this.tabletIsOverlay) {
localPosition: localPosition Overlays.editOverlay(this.tabletEntityID, {
}); localPosition: localPosition
});
} else {
Entities.editEntity(this.tabletEntityID, {
localPosition: localPosition
});
}
} }
} }
}; };

View file

@ -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