mirror of
https://github.com/overte-org/overte.git
synced 2025-07-23 06:26:14 +02:00
Merge pull request #12087 from ctrlaltdavid/21661
Laser auto-on with tablet and Web overlays
This commit is contained in:
commit
b28684f15e
22 changed files with 265 additions and 108 deletions
|
@ -738,6 +738,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_PREFER_STYLUS_OVER_LASER = false;
|
||||||
const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false;
|
const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false;
|
||||||
const QString DEFAULT_CURSOR_NAME = "DEFAULT";
|
const QString DEFAULT_CURSOR_NAME = "DEFAULT";
|
||||||
|
|
||||||
|
@ -757,6 +758,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),
|
||||||
|
_preferStylusOverLaserSetting("preferStylusOverLaser", DEFAULT_PREFER_STYLUS_OVER_LASER),
|
||||||
_preferAvatarFingerOverStylusSetting("preferAvatarFingerOverStylus", DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS),
|
_preferAvatarFingerOverStylusSetting("preferAvatarFingerOverStylus", DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS),
|
||||||
_constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true),
|
_constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true),
|
||||||
_preferredCursor("preferredCursor", DEFAULT_CURSOR_NAME),
|
_preferredCursor("preferredCursor", DEFAULT_CURSOR_NAME),
|
||||||
|
@ -2580,6 +2582,10 @@ void Application::setHmdTabletBecomesToolbarSetting(bool value) {
|
||||||
updateSystemTabletMode();
|
updateSystemTabletMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::setPreferStylusOverLaser(bool value) {
|
||||||
|
_preferStylusOverLaserSetting.set(value);
|
||||||
|
}
|
||||||
|
|
||||||
void Application::setPreferAvatarFingerOverStylus(bool value) {
|
void Application::setPreferAvatarFingerOverStylus(bool value) {
|
||||||
_preferAvatarFingerOverStylusSetting.set(value);
|
_preferAvatarFingerOverStylusSetting.set(value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,11 @@ 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 getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
bool getPreferStylusOverLaser() { return _preferStylusOverLaserSetting.get(); }
|
||||||
|
void setPreferStylusOverLaser(bool value);
|
||||||
|
// FIXME: Remove setting completely or make available through JavaScript API?
|
||||||
|
//bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
||||||
|
bool getPreferAvatarFingerOverStylus() { return false; }
|
||||||
void setPreferAvatarFingerOverStylus(bool value);
|
void setPreferAvatarFingerOverStylus(bool value);
|
||||||
|
|
||||||
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
||||||
|
@ -551,6 +555,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> _preferStylusOverLaserSetting;
|
||||||
Setting::Handle<bool> _preferAvatarFingerOverStylusSetting;
|
Setting::Handle<bool> _preferAvatarFingerOverStylusSetting;
|
||||||
Setting::Handle<bool> _constrainToolbarPosition;
|
Setting::Handle<bool> _constrainToolbarPosition;
|
||||||
Setting::Handle<QString> _preferredCursor;
|
Setting::Handle<QString> _preferredCursor;
|
||||||
|
|
|
@ -218,14 +218,40 @@ Pointer::PickedObject LaserPointer::getHoveredObject(const PickResultPointer& pi
|
||||||
return PickedObject(rayPickResult->objectID, rayPickResult->type);
|
return PickedObject(rayPickResult->objectID, rayPickResult->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pointer::Buttons LaserPointer::getPressedButtons() {
|
Pointer::Buttons LaserPointer::getPressedButtons(const PickResultPointer& pickResult) {
|
||||||
std::unordered_set<std::string> toReturn;
|
std::unordered_set<std::string> toReturn;
|
||||||
for (const PointerTrigger& trigger : _triggers) {
|
auto rayPickResult = std::static_pointer_cast<const RayPickResult>(pickResult);
|
||||||
// TODO: right now, LaserPointers don't support axes, only on/off buttons
|
|
||||||
if (trigger.getEndpoint()->peek() >= 1.0f) {
|
if (rayPickResult) {
|
||||||
toReturn.insert(trigger.getButton());
|
for (const PointerTrigger& trigger : _triggers) {
|
||||||
|
std::string button = trigger.getButton();
|
||||||
|
TriggerState& state = _states[button];
|
||||||
|
// TODO: right now, LaserPointers don't support axes, only on/off buttons
|
||||||
|
if (trigger.getEndpoint()->peek() >= 1.0f) {
|
||||||
|
toReturn.insert(button);
|
||||||
|
|
||||||
|
if (_previousButtons.find(button) == _previousButtons.end()) {
|
||||||
|
// start triggering for buttons that were just pressed
|
||||||
|
state.triggeredObject = PickedObject(rayPickResult->objectID, rayPickResult->type);
|
||||||
|
state.intersection = rayPickResult->intersection;
|
||||||
|
state.triggerPos2D = findPos2D(state.triggeredObject, rayPickResult->intersection);
|
||||||
|
state.triggerStartTime = usecTimestampNow();
|
||||||
|
state.surfaceNormal = rayPickResult->surfaceNormal;
|
||||||
|
state.deadspotExpired = false;
|
||||||
|
state.wasTriggering = true;
|
||||||
|
state.triggering = true;
|
||||||
|
_latestState = state;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// stop triggering for buttons that aren't pressed
|
||||||
|
state.wasTriggering = state.triggering;
|
||||||
|
state.triggering = false;
|
||||||
|
_latestState = state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_previousButtons = toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +329,7 @@ RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) {
|
||||||
return RenderState(startID, pathID, endID);
|
return RenderState(startID, pathID, endID);
|
||||||
}
|
}
|
||||||
|
|
||||||
PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, bool hover) const {
|
PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, const std::string& button, bool hover) {
|
||||||
QUuid pickedID;
|
QUuid pickedID;
|
||||||
glm::vec3 intersection, surfaceNormal, direction, origin;
|
glm::vec3 intersection, surfaceNormal, direction, origin;
|
||||||
auto rayPickResult = std::static_pointer_cast<RayPickResult>(pickResult);
|
auto rayPickResult = std::static_pointer_cast<RayPickResult>(pickResult);
|
||||||
|
@ -316,20 +342,48 @@ PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const P
|
||||||
pickedID = rayPickResult->objectID;
|
pickedID = rayPickResult->objectID;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 pos2D;
|
|
||||||
if (pickedID != target.objectID) {
|
if (pickedID != target.objectID) {
|
||||||
if (target.type == ENTITY) {
|
intersection = findIntersection(target, origin, direction);
|
||||||
intersection = RayPick::intersectRayWithEntityXYPlane(target.objectID, origin, direction);
|
|
||||||
} else if (target.type == OVERLAY) {
|
|
||||||
intersection = RayPick::intersectRayWithOverlayXYPlane(target.objectID, origin, direction);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (target.type == ENTITY) {
|
glm::vec2 pos2D = findPos2D(target, intersection);
|
||||||
pos2D = RayPick::projectOntoEntityXYPlane(target.objectID, intersection);
|
|
||||||
} else if (target.type == OVERLAY) {
|
// If we just started triggering and we haven't moved too much, don't update intersection and pos2D
|
||||||
pos2D = RayPick::projectOntoOverlayXYPlane(target.objectID, intersection);
|
TriggerState& state = hover ? _latestState : _states[button];
|
||||||
} else if (target.type == HUD) {
|
float sensorToWorldScale = DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale();
|
||||||
pos2D = DependencyManager::get<PickManager>()->calculatePos2DFromHUD(intersection);
|
float deadspotSquared = TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED * sensorToWorldScale * sensorToWorldScale;
|
||||||
|
bool withinDeadspot = usecTimestampNow() - state.triggerStartTime < POINTER_MOVE_DELAY && glm::distance2(pos2D, state.triggerPos2D) < deadspotSquared;
|
||||||
|
if ((state.triggering || state.wasTriggering) && !state.deadspotExpired && withinDeadspot) {
|
||||||
|
pos2D = state.triggerPos2D;
|
||||||
|
intersection = state.intersection;
|
||||||
|
surfaceNormal = state.surfaceNormal;
|
||||||
}
|
}
|
||||||
|
if (!withinDeadspot) {
|
||||||
|
state.deadspotExpired = true;
|
||||||
|
}
|
||||||
|
|
||||||
return PointerEvent(pos2D, intersection, surfaceNormal, direction);
|
return PointerEvent(pos2D, intersection, surfaceNormal, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 LaserPointer::findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction) {
|
||||||
|
switch (pickedObject.type) {
|
||||||
|
case ENTITY:
|
||||||
|
return RayPick::intersectRayWithEntityXYPlane(pickedObject.objectID, origin, direction);
|
||||||
|
case OVERLAY:
|
||||||
|
return RayPick::intersectRayWithOverlayXYPlane(pickedObject.objectID, origin, direction);
|
||||||
|
default:
|
||||||
|
return glm::vec3(NAN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 LaserPointer::findPos2D(const PickedObject& pickedObject, const glm::vec3& origin) {
|
||||||
|
switch (pickedObject.type) {
|
||||||
|
case ENTITY:
|
||||||
|
return RayPick::projectOntoEntityXYPlane(pickedObject.objectID, origin);
|
||||||
|
case OVERLAY:
|
||||||
|
return RayPick::projectOntoOverlayXYPlane(pickedObject.objectID, origin);
|
||||||
|
case HUD:
|
||||||
|
return DependencyManager::get<PickManager>()->calculatePos2DFromHUD(origin);
|
||||||
|
default:
|
||||||
|
return glm::vec2(NAN);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -80,10 +80,10 @@ public:
|
||||||
static RenderState buildRenderState(const QVariantMap& propMap);
|
static RenderState buildRenderState(const QVariantMap& propMap);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, bool hover = true) const override;
|
PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, const std::string& button = "", bool hover = true) override;
|
||||||
|
|
||||||
PickedObject getHoveredObject(const PickResultPointer& pickResult) override;
|
PickedObject getHoveredObject(const PickResultPointer& pickResult) override;
|
||||||
Pointer::Buttons getPressedButtons() override;
|
Pointer::Buttons getPressedButtons(const PickResultPointer& pickResult) override;
|
||||||
|
|
||||||
bool shouldHover(const PickResultPointer& pickResult) override { return _currentRenderState != ""; }
|
bool shouldHover(const PickResultPointer& pickResult) override { return _currentRenderState != ""; }
|
||||||
bool shouldTrigger(const PickResultPointer& pickResult) override { return _currentRenderState != ""; }
|
bool shouldTrigger(const PickResultPointer& pickResult) override { return _currentRenderState != ""; }
|
||||||
|
@ -105,6 +105,23 @@ private:
|
||||||
void updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState);
|
void updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState);
|
||||||
void disableRenderState(const RenderState& renderState);
|
void disableRenderState(const RenderState& renderState);
|
||||||
|
|
||||||
|
struct TriggerState {
|
||||||
|
PickedObject triggeredObject;
|
||||||
|
glm::vec3 intersection { NAN };
|
||||||
|
glm::vec3 surfaceNormal { NAN };
|
||||||
|
glm::vec2 triggerPos2D { NAN };
|
||||||
|
quint64 triggerStartTime { 0 };
|
||||||
|
bool deadspotExpired { true };
|
||||||
|
bool triggering { false };
|
||||||
|
bool wasTriggering { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
Pointer::Buttons _previousButtons;
|
||||||
|
std::unordered_map<std::string, TriggerState> _states;
|
||||||
|
TriggerState _latestState;
|
||||||
|
static glm::vec3 findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction);
|
||||||
|
static glm::vec2 findPos2D(const PickedObject& pickedObject, const glm::vec3& origin);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_LaserPointer_h
|
#endif // hifi_LaserPointer_h
|
||||||
|
|
|
@ -92,4 +92,4 @@ glm::vec2 RayPick::projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::
|
||||||
glm::vec2 RayPick::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized) {
|
glm::vec2 RayPick::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized) {
|
||||||
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
|
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
|
||||||
return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint(), unNormalized);
|
return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint(), unNormalized);
|
||||||
}
|
}
|
|
@ -28,10 +28,6 @@ static const float TABLET_MAX_TOUCH_DISTANCE = 0.005f;
|
||||||
static const float HOVER_HYSTERESIS = 0.01f;
|
static const float HOVER_HYSTERESIS = 0.01f;
|
||||||
static const float TOUCH_HYSTERESIS = 0.001f;
|
static const float TOUCH_HYSTERESIS = 0.001f;
|
||||||
|
|
||||||
static const float STYLUS_MOVE_DELAY = 0.33f * USECS_PER_SECOND;
|
|
||||||
static const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f;
|
|
||||||
static const float TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED = TOUCH_PRESS_TO_MOVE_DEADSPOT * TOUCH_PRESS_TO_MOVE_DEADSPOT;
|
|
||||||
|
|
||||||
StylusPointer::StylusPointer(const QVariant& props, const OverlayID& stylusOverlay, bool hover, bool enabled) :
|
StylusPointer::StylusPointer(const QVariant& props, const OverlayID& stylusOverlay, bool hover, bool enabled) :
|
||||||
Pointer(DependencyManager::get<PickScriptingInterface>()->createStylusPick(props), enabled, hover),
|
Pointer(DependencyManager::get<PickScriptingInterface>()->createStylusPick(props), enabled, hover),
|
||||||
_stylusOverlay(stylusOverlay)
|
_stylusOverlay(stylusOverlay)
|
||||||
|
@ -112,37 +108,37 @@ bool StylusPointer::shouldHover(const PickResultPointer& pickResult) {
|
||||||
|
|
||||||
bool StylusPointer::shouldTrigger(const PickResultPointer& pickResult) {
|
bool StylusPointer::shouldTrigger(const PickResultPointer& pickResult) {
|
||||||
auto stylusPickResult = std::static_pointer_cast<const StylusPickResult>(pickResult);
|
auto stylusPickResult = std::static_pointer_cast<const StylusPickResult>(pickResult);
|
||||||
|
bool wasTriggering = false;
|
||||||
if (_renderState == EVENTS_ON && stylusPickResult) {
|
if (_renderState == EVENTS_ON && stylusPickResult) {
|
||||||
auto sensorScaleFactor = DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale();
|
auto sensorScaleFactor = DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale();
|
||||||
float distance = stylusPickResult->distance;
|
float distance = stylusPickResult->distance;
|
||||||
|
|
||||||
// If we're triggering on an object, recalculate the distance instead of using the pickResult
|
// If we're triggering on an object, recalculate the distance instead of using the pickResult
|
||||||
glm::vec3 origin = vec3FromVariant(stylusPickResult->pickVariant["position"]);
|
glm::vec3 origin = vec3FromVariant(stylusPickResult->pickVariant["position"]);
|
||||||
glm::vec3 direction = -_state.surfaceNormal;
|
glm::vec3 direction = _state.triggering ? -_state.surfaceNormal : -stylusPickResult->surfaceNormal;
|
||||||
if (!_state.triggeredObject.objectID.isNull() && stylusPickResult->objectID != _state.triggeredObject.objectID) {
|
if ((_state.triggering || _state.wasTriggering) && stylusPickResult->objectID != _state.triggeredObject.objectID) {
|
||||||
distance = glm::dot(findIntersection(_state.triggeredObject, origin, direction) - origin, direction);
|
distance = glm::dot(findIntersection(_state.triggeredObject, origin, direction) - origin, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
float hysteresis = _state.triggering ? TOUCH_HYSTERESIS * sensorScaleFactor : 0.0f;
|
float hysteresis = _state.triggering ? TOUCH_HYSTERESIS * sensorScaleFactor : 0.0f;
|
||||||
if (isWithinBounds(distance, TABLET_MIN_TOUCH_DISTANCE * sensorScaleFactor,
|
if (isWithinBounds(distance, TABLET_MIN_TOUCH_DISTANCE * sensorScaleFactor,
|
||||||
TABLET_MAX_TOUCH_DISTANCE * sensorScaleFactor, hysteresis)) {
|
TABLET_MAX_TOUCH_DISTANCE * sensorScaleFactor, hysteresis)) {
|
||||||
if (_state.triggeredObject.objectID.isNull()) {
|
_state.wasTriggering = _state.triggering;
|
||||||
|
if (!_state.triggering) {
|
||||||
_state.triggeredObject = PickedObject(stylusPickResult->objectID, stylusPickResult->type);
|
_state.triggeredObject = PickedObject(stylusPickResult->objectID, stylusPickResult->type);
|
||||||
_state.intersection = findIntersection(_state.triggeredObject, origin, direction);
|
_state.intersection = stylusPickResult->intersection;
|
||||||
_state.triggerPos2D = findPos2D(_state.triggeredObject, origin);
|
_state.triggerPos2D = findPos2D(_state.triggeredObject, origin);
|
||||||
_state.triggerStartTime = usecTimestampNow();
|
_state.triggerStartTime = usecTimestampNow();
|
||||||
_state.surfaceNormal = stylusPickResult->surfaceNormal;
|
_state.surfaceNormal = stylusPickResult->surfaceNormal;
|
||||||
|
_state.deadspotExpired = false;
|
||||||
_state.triggering = true;
|
_state.triggering = true;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
wasTriggering = _state.triggering;
|
||||||
}
|
}
|
||||||
|
|
||||||
_state.triggeredObject = PickedObject();
|
_state.wasTriggering = wasTriggering;
|
||||||
_state.intersection = glm::vec3(NAN);
|
|
||||||
_state.triggerPos2D = glm::vec2(NAN);
|
|
||||||
_state.triggerStartTime = 0;
|
|
||||||
_state.surfaceNormal = glm::vec3(NAN);
|
|
||||||
_state.triggering = false;
|
_state.triggering = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -155,13 +151,13 @@ Pointer::PickedObject StylusPointer::getHoveredObject(const PickResultPointer& p
|
||||||
return PickedObject(stylusPickResult->objectID, stylusPickResult->type);
|
return PickedObject(stylusPickResult->objectID, stylusPickResult->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pointer::Buttons StylusPointer::getPressedButtons() {
|
Pointer::Buttons StylusPointer::getPressedButtons(const PickResultPointer& pickResult) {
|
||||||
// TODO: custom buttons for styluses
|
// TODO: custom buttons for styluses
|
||||||
Pointer::Buttons toReturn({ "Primary", "Focus" });
|
Pointer::Buttons toReturn({ "Primary", "Focus" });
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
PointerEvent StylusPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, bool hover) const {
|
PointerEvent StylusPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, const std::string& button, bool hover) {
|
||||||
QUuid pickedID;
|
QUuid pickedID;
|
||||||
glm::vec2 pos2D;
|
glm::vec2 pos2D;
|
||||||
glm::vec3 intersection, surfaceNormal, direction, origin;
|
glm::vec3 intersection, surfaceNormal, direction, origin;
|
||||||
|
@ -177,18 +173,22 @@ PointerEvent StylusPointer::buildPointerEvent(const PickedObject& target, const
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we just started triggering and we haven't moved too much, don't update intersection and pos2D
|
// If we just started triggering and we haven't moved too much, don't update intersection and pos2D
|
||||||
if (!_state.triggeredObject.objectID.isNull() && usecTimestampNow() - _state.triggerStartTime < STYLUS_MOVE_DELAY &&
|
float sensorToWorldScale = DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale();
|
||||||
glm::distance2(pos2D, _state.triggerPos2D) < TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED) {
|
float deadspotSquared = TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED * sensorToWorldScale * sensorToWorldScale;
|
||||||
|
bool withinDeadspot = usecTimestampNow() - _state.triggerStartTime < POINTER_MOVE_DELAY && glm::distance2(pos2D, _state.triggerPos2D) < deadspotSquared;
|
||||||
|
if ((_state.triggering || _state.wasTriggering) && !_state.deadspotExpired && withinDeadspot) {
|
||||||
pos2D = _state.triggerPos2D;
|
pos2D = _state.triggerPos2D;
|
||||||
intersection = _state.intersection;
|
intersection = _state.intersection;
|
||||||
} else if (pickedID != target.objectID) {
|
} else if (pickedID != target.objectID) {
|
||||||
intersection = findIntersection(target, origin, direction);
|
intersection = findIntersection(target, origin, direction);
|
||||||
}
|
}
|
||||||
|
if (!withinDeadspot) {
|
||||||
|
_state.deadspotExpired = true;
|
||||||
|
}
|
||||||
|
|
||||||
return PointerEvent(pos2D, intersection, surfaceNormal, direction);
|
return PointerEvent(pos2D, intersection, surfaceNormal, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool StylusPointer::isWithinBounds(float distance, float min, float max, float hysteresis) {
|
bool StylusPointer::isWithinBounds(float distance, float min, float max, float hysteresis) {
|
||||||
return (distance == glm::clamp(distance, min - hysteresis, max + hysteresis));
|
return (distance == glm::clamp(distance, min - hysteresis, max + hysteresis));
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,11 +37,11 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PickedObject getHoveredObject(const PickResultPointer& pickResult) override;
|
PickedObject getHoveredObject(const PickResultPointer& pickResult) override;
|
||||||
Buttons getPressedButtons() override;
|
Buttons getPressedButtons(const PickResultPointer& pickResult) override;
|
||||||
bool shouldHover(const PickResultPointer& pickResult) override;
|
bool shouldHover(const PickResultPointer& pickResult) override;
|
||||||
bool shouldTrigger(const PickResultPointer& pickResult) override;
|
bool shouldTrigger(const PickResultPointer& pickResult) override;
|
||||||
|
|
||||||
PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, bool hover = true) const override;
|
PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, const std::string& button = "", bool hover = true) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void show(const StylusTip& tip);
|
void show(const StylusTip& tip);
|
||||||
|
@ -53,7 +53,9 @@ private:
|
||||||
glm::vec2 triggerPos2D { NAN };
|
glm::vec2 triggerPos2D { NAN };
|
||||||
glm::vec3 surfaceNormal { NAN };
|
glm::vec3 surfaceNormal { NAN };
|
||||||
quint64 triggerStartTime { 0 };
|
quint64 triggerStartTime { 0 };
|
||||||
|
bool deadspotExpired { true };
|
||||||
bool triggering { false };
|
bool triggering { false };
|
||||||
|
bool wasTriggering { false };
|
||||||
|
|
||||||
bool hovering { false };
|
bool hovering { false };
|
||||||
};
|
};
|
||||||
|
|
|
@ -90,11 +90,19 @@ void setupPreferences() {
|
||||||
preference->setMax(500);
|
preference->setMax(500);
|
||||||
preferences->addPreference(preference);
|
preferences->addPreference(preference);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
auto getter = []()->bool { return qApp->getPreferStylusOverLaser(); };
|
||||||
|
auto setter = [](bool value) { qApp->setPreferStylusOverLaser(value); };
|
||||||
|
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Stylus Over Laser", getter, setter));
|
||||||
|
}
|
||||||
|
// FIXME: Remove setting completely or make available through JavaScript API?
|
||||||
|
/*
|
||||||
{
|
{
|
||||||
auto getter = []()->bool { return qApp->getPreferAvatarFingerOverStylus(); };
|
auto getter = []()->bool { return qApp->getPreferAvatarFingerOverStylus(); };
|
||||||
auto setter = [](bool value) { qApp->setPreferAvatarFingerOverStylus(value); };
|
auto setter = [](bool value) { qApp->setPreferAvatarFingerOverStylus(value); };
|
||||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Avatar Finger Over Stylus", getter, setter));
|
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Avatar Finger Over Stylus", getter, setter));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
static const QString RETICLE_ICON_NAME = { Cursor::Manager::getIconName(Cursor::Icon::RETICLE) };
|
static const QString RETICLE_ICON_NAME = { Cursor::Manager::getIconName(Cursor::Icon::RETICLE) };
|
||||||
auto getter = []()->bool { return qApp->getPreferredCursor() == RETICLE_ICON_NAME; };
|
auto getter = []()->bool { return qApp->getPreferredCursor() == RETICLE_ICON_NAME; };
|
||||||
|
|
|
@ -11,6 +11,12 @@
|
||||||
#include "PickManager.h"
|
#include "PickManager.h"
|
||||||
#include "PointerManager.h"
|
#include "PointerManager.h"
|
||||||
|
|
||||||
|
#include "NumericalConstants.h"
|
||||||
|
|
||||||
|
const float Pointer::POINTER_MOVE_DELAY = 0.33f * USECS_PER_SECOND;
|
||||||
|
const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f;
|
||||||
|
const float Pointer::TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED = TOUCH_PRESS_TO_MOVE_DEADSPOT * TOUCH_PRESS_TO_MOVE_DEADSPOT;
|
||||||
|
|
||||||
Pointer::~Pointer() {
|
Pointer::~Pointer() {
|
||||||
DependencyManager::get<PickManager>()->removePick(_pickUID);
|
DependencyManager::get<PickManager>()->removePick(_pickUID);
|
||||||
}
|
}
|
||||||
|
@ -77,7 +83,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
|
||||||
Buttons newButtons;
|
Buttons newButtons;
|
||||||
Buttons sameButtons;
|
Buttons sameButtons;
|
||||||
if (_enabled && shouldTrigger(pickResult)) {
|
if (_enabled && shouldTrigger(pickResult)) {
|
||||||
buttons = getPressedButtons();
|
buttons = getPressedButtons(pickResult);
|
||||||
for (const std::string& button : buttons) {
|
for (const std::string& button : buttons) {
|
||||||
if (_prevButtons.find(button) == _prevButtons.end()) {
|
if (_prevButtons.find(button) == _prevButtons.end()) {
|
||||||
newButtons.insert(button);
|
newButtons.insert(button);
|
||||||
|
@ -175,17 +181,6 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send hoverEnd events if we disable the pointer or disable hovering
|
|
||||||
if (_hover && ((!_enabled && _prevEnabled) || (!doHover && _prevDoHover))) {
|
|
||||||
if (_prevHoveredObject.type == ENTITY) {
|
|
||||||
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
|
|
||||||
} else if (_prevHoveredObject.type == OVERLAY) {
|
|
||||||
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
|
|
||||||
} else if (_prevHoveredObject.type == HUD) {
|
|
||||||
emit pointerManager->hoverEndHUD(hoveredEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger begin
|
// Trigger begin
|
||||||
const std::string SHOULD_FOCUS_BUTTON = "Focus";
|
const std::string SHOULD_FOCUS_BUTTON = "Focus";
|
||||||
for (const std::string& button : newButtons) {
|
for (const std::string& button : newButtons) {
|
||||||
|
@ -204,7 +199,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
|
||||||
|
|
||||||
// Trigger continue
|
// Trigger continue
|
||||||
for (const std::string& button : sameButtons) {
|
for (const std::string& button : sameButtons) {
|
||||||
PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult, false);
|
PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult, button, false);
|
||||||
triggeredEvent.setID(pointerID);
|
triggeredEvent.setID(pointerID);
|
||||||
triggeredEvent.setType(PointerEvent::Move);
|
triggeredEvent.setType(PointerEvent::Move);
|
||||||
triggeredEvent.setButton(chooseButton(button));
|
triggeredEvent.setButton(chooseButton(button));
|
||||||
|
@ -219,7 +214,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
|
||||||
|
|
||||||
// Trigger end
|
// Trigger end
|
||||||
for (const std::string& button : _prevButtons) {
|
for (const std::string& button : _prevButtons) {
|
||||||
PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult, false);
|
PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult, button, false);
|
||||||
triggeredEvent.setID(pointerID);
|
triggeredEvent.setID(pointerID);
|
||||||
triggeredEvent.setType(PointerEvent::Release);
|
triggeredEvent.setType(PointerEvent::Release);
|
||||||
triggeredEvent.setButton(chooseButton(button));
|
triggeredEvent.setButton(chooseButton(button));
|
||||||
|
@ -233,6 +228,17 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin
|
||||||
_triggeredObjects.erase(button);
|
_triggeredObjects.erase(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we disable the pointer or disable hovering, send hoverEnd events after triggerEnd
|
||||||
|
if (_hover && ((!_enabled && _prevEnabled) || (!doHover && _prevDoHover))) {
|
||||||
|
if (_prevHoveredObject.type == ENTITY) {
|
||||||
|
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
|
||||||
|
} else if (_prevHoveredObject.type == OVERLAY) {
|
||||||
|
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
|
||||||
|
} else if (_prevHoveredObject.type == HUD) {
|
||||||
|
emit pointerManager->hoverEndHUD(hoveredEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_prevHoveredObject = hoveredObject;
|
_prevHoveredObject = hoveredObject;
|
||||||
_prevButtons = buttons;
|
_prevButtons = buttons;
|
||||||
_prevEnabled = _enabled;
|
_prevEnabled = _enabled;
|
||||||
|
|
|
@ -82,14 +82,17 @@ protected:
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
bool _hover;
|
bool _hover;
|
||||||
|
|
||||||
virtual PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, bool hover = true) const = 0;
|
virtual PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, const std::string& button = "", bool hover = true) = 0;
|
||||||
|
|
||||||
virtual PickedObject getHoveredObject(const PickResultPointer& pickResult) = 0;
|
virtual PickedObject getHoveredObject(const PickResultPointer& pickResult) = 0;
|
||||||
virtual Buttons getPressedButtons() = 0;
|
virtual Buttons getPressedButtons(const PickResultPointer& pickResult) = 0;
|
||||||
|
|
||||||
virtual bool shouldHover(const PickResultPointer& pickResult) { return true; }
|
virtual bool shouldHover(const PickResultPointer& pickResult) { return true; }
|
||||||
virtual bool shouldTrigger(const PickResultPointer& pickResult) { return true; }
|
virtual bool shouldTrigger(const PickResultPointer& pickResult) { return true; }
|
||||||
|
|
||||||
|
static const float POINTER_MOVE_DELAY;
|
||||||
|
static const float TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PickedObject _prevHoveredObject;
|
PickedObject _prevHoveredObject;
|
||||||
Buttons _prevButtons;
|
Buttons _prevButtons;
|
||||||
|
|
|
@ -145,11 +145,11 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
return deltaTime;
|
return deltaTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setIgnoreTablet = function() {
|
this.setIgnorePointerItems = function() {
|
||||||
if (HMD.tabletID !== this.tabletID) {
|
if (HMD.tabletID !== this.tabletID) {
|
||||||
this.tabletID = HMD.tabletID;
|
this.tabletID = HMD.tabletID;
|
||||||
Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist.concat([HMD.tabletID]));
|
Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist);
|
||||||
Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist.concat([HMD.tabletID]));
|
Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
}
|
}
|
||||||
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
var deltaTime = _this.updateTimings();
|
var deltaTime = _this.updateTimings();
|
||||||
_this.setIgnoreTablet();
|
_this.setIgnorePointerItems();
|
||||||
|
|
||||||
if (controllerDispatcherPluginsNeedSort) {
|
if (controllerDispatcherPluginsNeedSort) {
|
||||||
_this.orderedPluginNames = [];
|
_this.orderedPluginNames = [];
|
||||||
|
@ -182,16 +182,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
controllerDispatcherPlugins[b].parameters.priority;
|
controllerDispatcherPlugins[b].parameters.priority;
|
||||||
});
|
});
|
||||||
|
|
||||||
var output = "controllerDispatcher -- new plugin order: ";
|
|
||||||
for (var k = 0; k < _this.orderedPluginNames.length; k++) {
|
|
||||||
var dbgPluginName = _this.orderedPluginNames[k];
|
|
||||||
var priority = controllerDispatcherPlugins[dbgPluginName].parameters.priority;
|
|
||||||
output += dbgPluginName + ":" + priority;
|
|
||||||
if (k + 1 < _this.orderedPluginNames.length) {
|
|
||||||
output += ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
controllerDispatcherPluginsNeedSort = false;
|
controllerDispatcherPluginsNeedSort = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,8 +378,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setBlacklist = function() {
|
this.setBlacklist = function() {
|
||||||
RayPick.setIgnoreItems(_this.leftControllerRayPick, this.blacklist.concat(HMD.tabletID));
|
RayPick.setIgnoreItems(_this.leftControllerRayPick, this.blacklist);
|
||||||
RayPick.setIgnoreItems(_this.rightControllerRayPick, this.blacklist.concat(HMD.tabletID));
|
RayPick.setIgnoreItems(_this.rightControllerRayPick, this.blacklist);
|
||||||
};
|
};
|
||||||
|
|
||||||
var MAPPING_NAME = "com.highfidelity.controllerDispatcher";
|
var MAPPING_NAME = "com.highfidelity.controllerDispatcher";
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
|
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
|
||||||
DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
|
DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
|
||||||
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI
|
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI
|
||||||
Picks, makeLaserLockInfo Xform
|
Picks, makeLaserLockInfo Xform, makeLaserParams
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
|
@ -119,7 +119,7 @@ Script.include("/~/system/libraries/Xform.js");
|
||||||
this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"],
|
this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"],
|
||||||
[],
|
[],
|
||||||
100,
|
100,
|
||||||
this.hand);
|
makeLaserParams(this.hand, false));
|
||||||
|
|
||||||
|
|
||||||
this.handToController = function() {
|
this.handToController = function() {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
/* global Script, Controller, LaserPointers, RayPick, RIGHT_HAND, LEFT_HAND, MyAvatar, getGrabPointSphereOffset,
|
/* global Script, Controller, LaserPointers, RayPick, RIGHT_HAND, LEFT_HAND, MyAvatar, getGrabPointSphereOffset,
|
||||||
makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters,
|
makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters,
|
||||||
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
|
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
|
||||||
DEFAULT_SEARCH_SPHERE_DISTANCE, getGrabbableData
|
DEFAULT_SEARCH_SPHERE_DISTANCE, getGrabbableData, makeLaserParams
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
|
@ -34,7 +34,7 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"],
|
this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"],
|
||||||
[],
|
[],
|
||||||
100,
|
100,
|
||||||
this.hand);
|
makeLaserParams(this.hand, false));
|
||||||
|
|
||||||
this.getTargetProps = function (controllerData) {
|
this.getTargetProps = function (controllerData) {
|
||||||
// nearbyEntityProperties is already sorted by length from controller
|
// nearbyEntityProperties is already sorted by length from controller
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
|
makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
|
||||||
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
|
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
|
||||||
DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
|
DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
|
||||||
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI
|
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI,
|
||||||
|
makeLaserParams
|
||||||
|
|
||||||
*/
|
*/
|
||||||
(function() {
|
(function() {
|
||||||
|
@ -36,7 +37,7 @@
|
||||||
this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"],
|
this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"],
|
||||||
[],
|
[],
|
||||||
100,
|
100,
|
||||||
(this.hand + HUD_LASER_OFFSET));
|
makeLaserParams((this.hand + HUD_LASER_OFFSET), false));
|
||||||
|
|
||||||
this.getOtherHandController = function() {
|
this.getOtherHandController = function() {
|
||||||
return (this.hand === RIGHT_HAND) ? Controller.Standard.LeftHand : Controller.Standard.RightHand;
|
return (this.hand === RIGHT_HAND) ? Controller.Standard.LeftHand : Controller.Standard.RightHand;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, makeRunningValues,
|
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, makeRunningValues,
|
||||||
Messages, makeDispatcherModuleParameters, HMD, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
Messages, makeDispatcherModuleParameters, HMD, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||||
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE,
|
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE,
|
||||||
getEnabledModuleByName, PICK_MAX_DISTANCE, isInEditMode, LaserPointers, RayPick, Picks
|
getEnabledModuleByName, PICK_MAX_DISTANCE, isInEditMode, LaserPointers, RayPick, Picks, makeLaserParams
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
|
@ -28,7 +28,7 @@ Script.include("/~/system/libraries/utils.js");
|
||||||
this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip", "rightHandTrigger"] : ["leftHand", "leftHandEquip", "leftHandTrigger"],
|
this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip", "rightHandTrigger"] : ["leftHand", "leftHandEquip", "leftHandTrigger"],
|
||||||
[],
|
[],
|
||||||
100,
|
100,
|
||||||
this.hand);
|
makeLaserParams(this.hand, false));
|
||||||
|
|
||||||
this.nearTablet = function(overlays) {
|
this.nearTablet = function(overlays) {
|
||||||
for (var i = 0; i < overlays.length; i++) {
|
for (var i = 0; i < overlays.length; i++) {
|
||||||
|
@ -44,10 +44,7 @@ Script.include("/~/system/libraries/utils.js");
|
||||||
};
|
};
|
||||||
|
|
||||||
this.pointingAtTablet = function(objectID) {
|
this.pointingAtTablet = function(objectID) {
|
||||||
if (objectID === HMD.tabletScreenID || objectID === HMD.homeButtonID) {
|
return objectID === HMD.tabletScreenID || objectID === HMD.homeButtonID;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.sendPickData = function(controllerData) {
|
this.sendPickData = function(controllerData) {
|
||||||
|
@ -99,8 +96,8 @@ Script.include("/~/system/libraries/utils.js");
|
||||||
var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput");
|
var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput");
|
||||||
if (overlayLaser) {
|
if (overlayLaser) {
|
||||||
var overlayLaserReady = overlayLaser.isReady(controllerData);
|
var overlayLaserReady = overlayLaser.isReady(controllerData);
|
||||||
|
var target = controllerData.rayPicks[this.hand].objectID;
|
||||||
if (overlayLaserReady.active && this.pointingAtTablet(overlayLaser.target)) {
|
if (overlayLaserReady.active && this.pointingAtTablet(target)) {
|
||||||
return this.exitModule();
|
return this.exitModule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,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 Script, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
|
/* global Script, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
|
||||||
makeDispatcherModuleParameters, makeRunningValues, getEnabledModuleByName
|
makeDispatcherModuleParameters, makeRunningValues, getEnabledModuleByName, makeLaserParams
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
|
@ -19,15 +19,21 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
function InVREditMode(hand) {
|
function InVREditMode(hand) {
|
||||||
this.hand = hand;
|
this.hand = hand;
|
||||||
this.disableModules = false;
|
this.disableModules = false;
|
||||||
|
var NO_HAND_LASER = -1; // Invalid hand parameter so that default laser is not displayed.
|
||||||
this.parameters = makeDispatcherModuleParameters(
|
this.parameters = makeDispatcherModuleParameters(
|
||||||
200, // Not too high otherwise the tablet laser doesn't work.
|
200, // Not too high otherwise the tablet laser doesn't work.
|
||||||
this.hand === RIGHT_HAND
|
this.hand === RIGHT_HAND
|
||||||
? ["rightHand", "rightHandEquip", "rightHandTrigger"]
|
? ["rightHand", "rightHandEquip", "rightHandTrigger"]
|
||||||
: ["leftHand", "leftHandEquip", "leftHandTrigger"],
|
: ["leftHand", "leftHandEquip", "leftHandTrigger"],
|
||||||
[],
|
[],
|
||||||
100
|
100,
|
||||||
|
makeLaserParams(NO_HAND_LASER, false)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.pointingAtTablet = function (objectID) {
|
||||||
|
return objectID === HMD.tabletScreenID || objectID === HMD.homeButtonID;
|
||||||
|
};
|
||||||
|
|
||||||
this.isReady = function (controllerData) {
|
this.isReady = function (controllerData) {
|
||||||
if (this.disableModules) {
|
if (this.disableModules) {
|
||||||
return makeRunningValues(true, [], []);
|
return makeRunningValues(true, [], []);
|
||||||
|
@ -42,7 +48,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tablet stylus.
|
// Tablet stylus.
|
||||||
// Includes the tablet laser.
|
|
||||||
var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND
|
var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND
|
||||||
? "RightTabletStylusInput"
|
? "RightTabletStylusInput"
|
||||||
: "LeftTabletStylusInput");
|
: "LeftTabletStylusInput");
|
||||||
|
@ -53,6 +58,18 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tablet surface.
|
||||||
|
var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND
|
||||||
|
? "RightWebSurfaceLaserInput"
|
||||||
|
: "LeftWebSurfaceLaserInput");
|
||||||
|
if (overlayLaser) {
|
||||||
|
var overlayLaserReady = overlayLaser.isReady(controllerData);
|
||||||
|
var target = controllerData.rayPicks[this.hand].objectID;
|
||||||
|
if (overlayLaserReady.active && this.pointingAtTablet(target)) {
|
||||||
|
return makeRunningValues(false, [], []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tablet grabbing.
|
// Tablet grabbing.
|
||||||
var nearOverlay = getEnabledModuleByName(this.hand === RIGHT_HAND
|
var nearOverlay = getEnabledModuleByName(this.hand === RIGHT_HAND
|
||||||
? "RightNearParentingGrabOverlay"
|
? "RightNearParentingGrabOverlay"
|
||||||
|
|
|
@ -142,7 +142,10 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
};
|
};
|
||||||
|
|
||||||
this.isReady = function (controllerData) {
|
this.isReady = function (controllerData) {
|
||||||
if (this.processStylus(controllerData)) {
|
var PREFER_STYLUS_OVER_LASER = "preferStylusOverLaser";
|
||||||
|
var isUsingStylus = Settings.getValue(PREFER_STYLUS_OVER_LASER, false);
|
||||||
|
|
||||||
|
if (isUsingStylus && this.processStylus(controllerData)) {
|
||||||
Pointers.enablePointer(this.pointer);
|
Pointers.enablePointer(this.pointer);
|
||||||
return makeRunningValues(true, [], []);
|
return makeRunningValues(true, [], []);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
makeRunningValues, Messages, Quat, Vec3, makeDispatcherModuleParameters, Overlays, ZERO_VEC, HMD,
|
makeRunningValues, Messages, Quat, Vec3, makeDispatcherModuleParameters, Overlays, ZERO_VEC, HMD,
|
||||||
INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||||
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE,
|
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE,
|
||||||
TRIGGER_OFF_VALUE, getEnabledModuleByName, PICK_MAX_DISTANCE, LaserPointers, RayPick, ContextOverlay, Picks
|
TRIGGER_OFF_VALUE, getEnabledModuleByName, PICK_MAX_DISTANCE, LaserPointers, RayPick, ContextOverlay, Picks, makeLaserParams
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
|
@ -18,6 +18,7 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
(function() {
|
(function() {
|
||||||
function WebSurfaceLaserInput(hand) {
|
function WebSurfaceLaserInput(hand) {
|
||||||
this.hand = hand;
|
this.hand = hand;
|
||||||
|
this.otherHand = this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND;
|
||||||
this.running = false;
|
this.running = false;
|
||||||
|
|
||||||
this.parameters = makeDispatcherModuleParameters(
|
this.parameters = makeDispatcherModuleParameters(
|
||||||
|
@ -25,7 +26,7 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"],
|
this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"],
|
||||||
[],
|
[],
|
||||||
100,
|
100,
|
||||||
this.hand);
|
makeLaserParams(hand, true));
|
||||||
|
|
||||||
this.grabModuleWantsNearbyOverlay = function(controllerData) {
|
this.grabModuleWantsNearbyOverlay = function(controllerData) {
|
||||||
if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) {
|
if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) {
|
||||||
|
@ -65,7 +66,8 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
};
|
};
|
||||||
|
|
||||||
this.deleteContextOverlay = function() {
|
this.deleteContextOverlay = function() {
|
||||||
var farGrabModule = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightFarActionGrabEntity" : "LeftFarActionGrabEntity");
|
var farGrabModule = getEnabledModuleByName(this.hand === RIGHT_HAND
|
||||||
|
? "RightFarActionGrabEntity" : "LeftFarActionGrabEntity");
|
||||||
if (farGrabModule) {
|
if (farGrabModule) {
|
||||||
var entityWithContextOverlay = farGrabModule.entityWithContextOverlay;
|
var entityWithContextOverlay = farGrabModule.entityWithContextOverlay;
|
||||||
|
|
||||||
|
@ -76,25 +78,50 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.isReady = function (controllerData) {
|
this.updateAllwaysOn = function() {
|
||||||
|
var PREFER_STYLUS_OVER_LASER = "preferStylusOverLaser";
|
||||||
|
this.parameters.handLaser.allwaysOn = !Settings.getValue(PREFER_STYLUS_OVER_LASER, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getDominantHand = function() {
|
||||||
|
return MyAvatar.getDominantHand() === "right" ? 1 : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.dominantHandOverride = false;
|
||||||
|
|
||||||
|
this.isReady = function(controllerData) {
|
||||||
var otherModuleRunning = this.getOtherModule().running;
|
var otherModuleRunning = this.getOtherModule().running;
|
||||||
if ((this.isPointingAtOverlay(controllerData) || this.isPointingAtWebEntity(controllerData)) &&
|
otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand.
|
||||||
!otherModuleRunning) {
|
var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE
|
||||||
if (controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE) {
|
&& controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE;
|
||||||
|
if ((!otherModuleRunning || isTriggerPressed)
|
||||||
|
&& (this.isPointingAtOverlay(controllerData) || this.isPointingAtWebEntity(controllerData))) {
|
||||||
|
this.updateAllwaysOn();
|
||||||
|
if (isTriggerPressed) {
|
||||||
|
this.dominantHandOverride = true; // Override dominant hand.
|
||||||
|
this.getOtherModule().dominantHandOverride = false;
|
||||||
|
}
|
||||||
|
if (this.parameters.handLaser.allwaysOn || isTriggerPressed) {
|
||||||
return makeRunningValues(true, [], []);
|
return makeRunningValues(true, [], []);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return makeRunningValues(false, [], []);
|
return makeRunningValues(false, [], []);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.run = function (controllerData, deltaTime) {
|
this.run = function(controllerData, deltaTime) {
|
||||||
|
var otherModuleRunning = this.getOtherModule().running;
|
||||||
|
otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand.
|
||||||
|
otherModuleRunning = otherModuleRunning || this.getOtherModule().dominantHandOverride; // Override dominant hand.
|
||||||
var grabModuleNeedsToRun = this.grabModuleWantsNearbyOverlay(controllerData);
|
var grabModuleNeedsToRun = this.grabModuleWantsNearbyOverlay(controllerData);
|
||||||
if (controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE && !grabModuleNeedsToRun) {
|
if (!otherModuleRunning && !grabModuleNeedsToRun && (controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE
|
||||||
|
|| this.parameters.handLaser.allwaysOn
|
||||||
|
&& (this.isPointingAtOverlay(controllerData) || this.isPointingAtWebEntity(controllerData)))) {
|
||||||
this.running = true;
|
this.running = true;
|
||||||
return makeRunningValues(true, [], []);
|
return makeRunningValues(true, [], []);
|
||||||
}
|
}
|
||||||
this.deleteContextOverlay();
|
this.deleteContextOverlay();
|
||||||
this.running = false;
|
this.running = false;
|
||||||
|
this.dominantHandOverride = false;
|
||||||
return makeRunningValues(false, [], []);
|
return makeRunningValues(false, [], []);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,8 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
Overlays.deleteOverlay(this.webOverlayID);
|
Overlays.deleteOverlay(this.webOverlayID);
|
||||||
}
|
}
|
||||||
|
|
||||||
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2.0) / sensorScaleFactor;
|
var RAYPICK_OFFSET = 0.0001; // Sufficient for raypick to reliably intersect tablet screen before tablet model.
|
||||||
|
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2.0) / sensorScaleFactor + RAYPICK_OFFSET;
|
||||||
var WEB_ENTITY_Y_OFFSET = 0.004;
|
var WEB_ENTITY_Y_OFFSET = 0.004;
|
||||||
var screenWidth = 0.82 * tabletWidth;
|
var screenWidth = 0.82 * tabletWidth;
|
||||||
var screenHeight = 0.81 * tabletHeight;
|
var screenHeight = 0.81 * tabletHeight;
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
BUMPER_ON_VALUE:true,
|
BUMPER_ON_VALUE:true,
|
||||||
getEntityParents:true,
|
getEntityParents:true,
|
||||||
findHandChildEntities:true,
|
findHandChildEntities:true,
|
||||||
|
makeLaserParams:true,
|
||||||
TEAR_AWAY_DISTANCE:true,
|
TEAR_AWAY_DISTANCE:true,
|
||||||
TEAR_AWAY_COUNT:true,
|
TEAR_AWAY_COUNT:true,
|
||||||
TEAR_AWAY_CHECK_TIME:true,
|
TEAR_AWAY_CHECK_TIME:true,
|
||||||
|
@ -134,6 +135,17 @@ makeLaserLockInfo = function(targetID, isOverlay, hand, offset) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
makeLaserParams = function(hand, allwaysOn) {
|
||||||
|
if (allwaysOn === undefined) {
|
||||||
|
allwaysOn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
hand: hand,
|
||||||
|
allwaysOn: allwaysOn
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
makeRunningValues = function (active, targets, requiredDataForRun, laserLockInfo) {
|
makeRunningValues = function (active, targets, requiredDataForRun, laserLockInfo) {
|
||||||
return {
|
return {
|
||||||
active: active,
|
active: active,
|
||||||
|
|
|
@ -95,6 +95,7 @@ Pointer = function(hudLayer, pickType, pointerData) {
|
||||||
this.pointerID = null;
|
this.pointerID = null;
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
this.locked = false;
|
this.locked = false;
|
||||||
|
this.allwaysOn = false;
|
||||||
this.hand = pointerData.hand;
|
this.hand = pointerData.hand;
|
||||||
delete pointerData.hand;
|
delete pointerData.hand;
|
||||||
|
|
||||||
|
@ -150,7 +151,7 @@ Pointer = function(hudLayer, pickType, pointerData) {
|
||||||
mode = "hold";
|
mode = "hold";
|
||||||
} else if (triggerClicks[this.hand]) {
|
} else if (triggerClicks[this.hand]) {
|
||||||
mode = "full";
|
mode = "full";
|
||||||
} else if (triggerValues[this.hand] > TRIGGER_ON_VALUE) {
|
} else if (triggerValues[this.hand] > TRIGGER_ON_VALUE || this.allwaysOn) {
|
||||||
mode = "half";
|
mode = "half";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,19 +173,23 @@ PointerManager = function() {
|
||||||
return pointer.pointerID;
|
return pointer.pointerID;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.makePointerVisible = function(index) {
|
this.makePointerVisible = function(laserParams) {
|
||||||
|
var index = laserParams.hand;
|
||||||
if (index < this.pointers.length && index >= 0) {
|
if (index < this.pointers.length && index >= 0) {
|
||||||
this.pointers[index].makeVisible();
|
this.pointers[index].makeVisible();
|
||||||
|
this.pointers[index].allwaysOn = laserParams.allwaysOn;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.makePointerInvisible = function(index) {
|
this.makePointerInvisible = function(laserParams) {
|
||||||
|
var index = laserParams.hand;
|
||||||
if (index < this.pointers.length && index >= 0) {
|
if (index < this.pointers.length && index >= 0) {
|
||||||
this.pointers[index].makeInvisible();
|
this.pointers[index].makeInvisible();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.lockPointerEnd = function(index, lockData) {
|
this.lockPointerEnd = function(laserParams, lockData) {
|
||||||
|
var index = laserParams.hand;
|
||||||
if (index < this.pointers.length && index >= 0) {
|
if (index < this.pointers.length && index >= 0) {
|
||||||
this.pointers[index].lockEnd(lockData);
|
this.pointers[index].lockEnd(lockData);
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,7 +400,8 @@ resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride)
|
||||||
});
|
});
|
||||||
|
|
||||||
// update webOverlay
|
// update webOverlay
|
||||||
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2.0) * sensorScaleOffsetOverride;
|
var RAYPICK_OFFSET = 0.0001; // Sufficient for raypick to reliably intersect tablet screen before tablet model.
|
||||||
|
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2.0) * sensorScaleOffsetOverride + RAYPICK_OFFSET;
|
||||||
var WEB_ENTITY_Y_OFFSET = 0.004 * sensorScaleFactor * sensorScaleOffsetOverride;
|
var WEB_ENTITY_Y_OFFSET = 0.004 * sensorScaleFactor * sensorScaleOffsetOverride;
|
||||||
var screenWidth = 0.82 * tabletWidth;
|
var screenWidth = 0.82 * tabletWidth;
|
||||||
var screenHeight = 0.81 * tabletHeight;
|
var screenHeight = 0.81 * tabletHeight;
|
||||||
|
@ -417,11 +418,13 @@ resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride)
|
||||||
var homeButtonDim = 4.0 * tabletScaleFactor / 3.0;
|
var homeButtonDim = 4.0 * tabletScaleFactor / 3.0;
|
||||||
Overlays.editOverlay(HMD.homeButtonID, {
|
Overlays.editOverlay(HMD.homeButtonID, {
|
||||||
localPosition: { x: 0, y: -HOME_BUTTON_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
localPosition: { x: 0, y: -HOME_BUTTON_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
||||||
|
localRotation: Quat.angleAxis(180, Vec3.UNIT_Y),
|
||||||
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
||||||
});
|
});
|
||||||
|
|
||||||
Overlays.editOverlay(HMD.homeButtonHighlightID, {
|
Overlays.editOverlay(HMD.homeButtonHighlightID, {
|
||||||
localPosition: { x: 0, y: -HOME_BUTTON_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
localPosition: { x: 0, y: -HOME_BUTTON_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
||||||
|
localRotation: Quat.angleAxis(180, Vec3.UNIT_Y),
|
||||||
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue