mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-16 22:47:08 +02:00
Merge pull request #9754 from hyperlogic/feature/fingers-on-tablet
Touch the tablet with your finger
This commit is contained in:
commit
c677326025
11 changed files with 322 additions and 75 deletions
|
@ -549,6 +549,7 @@ const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f;
|
|||
const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true;
|
||||
const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false;
|
||||
const bool DEFAULT_TABLET_VISIBLE_TO_OTHERS = false;
|
||||
const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false;
|
||||
|
||||
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) :
|
||||
QApplication(argc, argv),
|
||||
|
@ -572,6 +573,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
_desktopTabletBecomesToolbarSetting("desktopTabletBecomesToolbar", DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR),
|
||||
_hmdTabletBecomesToolbarSetting("hmdTabletBecomesToolbar", DEFAULT_HMD_TABLET_BECOMES_TOOLBAR),
|
||||
_tabletVisibleToOthersSetting("tabletVisibleToOthers", DEFAULT_TABLET_VISIBLE_TO_OTHERS),
|
||||
_preferAvatarFingerOverStylusSetting("preferAvatarFingerOverStylus", DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS),
|
||||
_constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true),
|
||||
_scaleMirror(1.0f),
|
||||
_rotateMirror(0.0f),
|
||||
|
@ -2362,6 +2364,10 @@ void Application::setTabletVisibleToOthersSetting(bool value) {
|
|||
updateSystemTabletMode();
|
||||
}
|
||||
|
||||
void Application::setPreferAvatarFingerOverStylus(bool value) {
|
||||
_preferAvatarFingerOverStylusSetting.set(value);
|
||||
}
|
||||
|
||||
void Application::setSettingConstrainToolbarPosition(bool setting) {
|
||||
_constrainToolbarPosition.set(setting);
|
||||
DependencyManager::get<OffscreenUi>()->setConstrainToolbarToCenterX(setting);
|
||||
|
|
|
@ -220,6 +220,8 @@ public:
|
|||
void setHmdTabletBecomesToolbarSetting(bool value);
|
||||
bool getTabletVisibleToOthersSetting() { return _tabletVisibleToOthersSetting.get(); }
|
||||
void setTabletVisibleToOthersSetting(bool value);
|
||||
bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
||||
void setPreferAvatarFingerOverStylus(bool value);
|
||||
|
||||
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
||||
void setSettingConstrainToolbarPosition(bool setting);
|
||||
|
@ -565,6 +567,7 @@ private:
|
|||
Setting::Handle<bool> _desktopTabletBecomesToolbarSetting;
|
||||
Setting::Handle<bool> _hmdTabletBecomesToolbarSetting;
|
||||
Setting::Handle<bool> _tabletVisibleToOthersSetting;
|
||||
Setting::Handle<bool> _preferAvatarFingerOverStylusSetting;
|
||||
Setting::Handle<bool> _constrainToolbarPosition;
|
||||
|
||||
float _scaleMirror;
|
||||
|
|
|
@ -107,6 +107,12 @@ void setupPreferences() {
|
|||
auto setter = [](bool value) { qApp->setTabletVisibleToOthersSetting(value); };
|
||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Tablet Is Visible To Others", getter, setter));
|
||||
}
|
||||
{
|
||||
auto getter = []()->bool { return qApp->getPreferAvatarFingerOverStylus(); };
|
||||
auto setter = [](bool value) { qApp->setPreferAvatarFingerOverStylus(value); };
|
||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Avatar Finger Over Stylus", getter, setter));
|
||||
}
|
||||
|
||||
// Snapshots
|
||||
static const QString SNAPSHOTS { "Snapshots" };
|
||||
{
|
||||
|
|
|
@ -198,18 +198,27 @@ void Web3DOverlay::render(RenderArgs* args) {
|
|||
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
|
||||
currentContext->makeCurrent(currentSurface);
|
||||
|
||||
auto selfOverlayID = getOverlayID();
|
||||
std::weak_ptr<Web3DOverlay> weakSelf = std::dynamic_pointer_cast<Web3DOverlay>(qApp->getOverlays().getOverlay(selfOverlayID));
|
||||
auto forwardPointerEvent = [=](OverlayID overlayID, const PointerEvent& event) {
|
||||
if (overlayID == getOverlayID()) {
|
||||
handlePointerEvent(event);
|
||||
auto self = weakSelf.lock();
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
if (overlayID == selfOverlayID) {
|
||||
self->handlePointerEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
_mousePressConnection = connect(&(qApp->getOverlays()), &Overlays::mousePressOnOverlay, forwardPointerEvent);
|
||||
_mouseReleaseConnection = connect(&(qApp->getOverlays()), &Overlays::mouseReleaseOnOverlay, forwardPointerEvent);
|
||||
_mouseMoveConnection = connect(&(qApp->getOverlays()), &Overlays::mouseMoveOnOverlay, forwardPointerEvent);
|
||||
_hoverLeaveConnection = connect(&(qApp->getOverlays()), &Overlays::hoverLeaveOverlay,
|
||||
[=](OverlayID overlayID, const PointerEvent& event) {
|
||||
if (this->_pressed && this->getOverlayID() == overlayID) {
|
||||
_mousePressConnection = connect(&(qApp->getOverlays()), &Overlays::mousePressOnOverlay, this, forwardPointerEvent, Qt::DirectConnection);
|
||||
_mouseReleaseConnection = connect(&(qApp->getOverlays()), &Overlays::mouseReleaseOnOverlay, this, forwardPointerEvent, Qt::DirectConnection);
|
||||
_mouseMoveConnection = connect(&(qApp->getOverlays()), &Overlays::mouseMoveOnOverlay, this, forwardPointerEvent, Qt::DirectConnection);
|
||||
_hoverLeaveConnection = connect(&(qApp->getOverlays()), &Overlays::hoverLeaveOverlay, this, [=](OverlayID overlayID, const PointerEvent& event) {
|
||||
auto self = weakSelf.lock();
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
if (self->_pressed && overlayID == selfOverlayID) {
|
||||
// If the user mouses off the overlay while the button is down, simulate a touch end.
|
||||
QTouchEvent::TouchPoint point;
|
||||
point.setId(event.getID());
|
||||
|
@ -222,12 +231,12 @@ void Web3DOverlay::render(RenderArgs* args) {
|
|||
touchPoints.push_back(point);
|
||||
QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr, Qt::NoModifier, Qt::TouchPointReleased,
|
||||
touchPoints);
|
||||
touchEvent->setWindow(_webSurface->getWindow());
|
||||
touchEvent->setWindow(self->_webSurface->getWindow());
|
||||
touchEvent->setDevice(&_touchDevice);
|
||||
touchEvent->setTarget(_webSurface->getRootItem());
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
|
||||
touchEvent->setTarget(self->_webSurface->getRootItem());
|
||||
QCoreApplication::postEvent(self->_webSurface->getWindow(), touchEvent);
|
||||
}
|
||||
});
|
||||
}, Qt::DirectConnection);
|
||||
|
||||
_emitScriptEventConnection = connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
|
||||
_webEventReceivedConnection = connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
|
||||
|
|
|
@ -19,6 +19,16 @@
|
|||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
/**jsdoc
|
||||
* A Quaternion
|
||||
*
|
||||
* @typedef Quat
|
||||
* @property {float} x imaginary component i.
|
||||
* @property {float} y imaginary component j.
|
||||
* @property {float} z imaginary component k.
|
||||
* @property {float} w real component.
|
||||
*/
|
||||
|
||||
/// Scriptable interface a Quaternion helper class object. Used exclusively in the JavaScript API
|
||||
class Quat : public QObject {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <AudioConstants.h>
|
||||
#include <AudioEffectOptions.h>
|
||||
#include <AvatarData.h>
|
||||
#include <DebugDraw.h>
|
||||
#include <EntityScriptingInterface.h>
|
||||
#include <MessagesClient.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
|
@ -630,6 +631,8 @@ void ScriptEngine::init() {
|
|||
registerGlobalObject("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
||||
registerGlobalObject("Assets", &_assetScriptingInterface);
|
||||
registerGlobalObject("Resources", DependencyManager::get<ResourceScriptingInterface>().data());
|
||||
|
||||
registerGlobalObject("DebugDraw", &DebugDraw::getInstance());
|
||||
}
|
||||
|
||||
void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
|
||||
|
|
|
@ -37,6 +37,15 @@
|
|||
* @property {float} z Z-coordinate of the vector.
|
||||
*/
|
||||
|
||||
/**jsdoc
|
||||
* A 4-dimensional vector.
|
||||
*
|
||||
* @typedef Vec4
|
||||
* @property {float} x X-coordinate of the vector.
|
||||
* @property {float} y Y-coordinate of the vector.
|
||||
* @property {float} z Z-coordinate of the vector.
|
||||
* @property {float} w W-coordinate of the vector.
|
||||
*/
|
||||
|
||||
/// Scriptable interface a Vec3ernion helper class object. Used exclusively in the JavaScript API
|
||||
class Vec3 : public QObject {
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "DebugDraw.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
using Lock = std::unique_lock<std::mutex>;
|
||||
|
||||
DebugDraw& DebugDraw::getInstance() {
|
||||
static DebugDraw* instance = globalInstance<DebugDraw>("com.highfidelity.DebugDraw");
|
||||
return *instance;
|
||||
|
@ -25,22 +27,50 @@ DebugDraw::~DebugDraw() {
|
|||
|
||||
// world space line, drawn only once
|
||||
void DebugDraw::drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color) {
|
||||
Lock lock(_mapMutex);
|
||||
_rays.push_back(Ray(start, end, color));
|
||||
}
|
||||
|
||||
void DebugDraw::addMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) {
|
||||
void DebugDraw::addMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) {
|
||||
Lock lock(_mapMutex);
|
||||
_markers[key] = MarkerInfo(rotation, position, color);
|
||||
}
|
||||
|
||||
void DebugDraw::removeMarker(const std::string& key) {
|
||||
void DebugDraw::removeMarker(const QString& key) {
|
||||
Lock lock(_mapMutex);
|
||||
_markers.erase(key);
|
||||
}
|
||||
|
||||
void DebugDraw::addMyAvatarMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) {
|
||||
void DebugDraw::addMyAvatarMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) {
|
||||
Lock lock(_mapMutex);
|
||||
_myAvatarMarkers[key] = MarkerInfo(rotation, position, color);
|
||||
}
|
||||
|
||||
void DebugDraw::removeMyAvatarMarker(const std::string& key) {
|
||||
void DebugDraw::removeMyAvatarMarker(const QString& key) {
|
||||
Lock lock(_mapMutex);
|
||||
_myAvatarMarkers.erase(key);
|
||||
}
|
||||
|
||||
//
|
||||
// accessors used by renderer
|
||||
//
|
||||
|
||||
DebugDraw::MarkerMap DebugDraw::getMarkerMap() const {
|
||||
Lock lock(_mapMutex);
|
||||
return _markers;
|
||||
}
|
||||
|
||||
DebugDraw::MarkerMap DebugDraw::getMyAvatarMarkerMap() const {
|
||||
Lock lock(_mapMutex);
|
||||
return _myAvatarMarkers;
|
||||
}
|
||||
|
||||
DebugDraw::Rays DebugDraw::getRays() const {
|
||||
Lock lock(_mapMutex);
|
||||
return _rays;
|
||||
}
|
||||
|
||||
void DebugDraw::clearRays() {
|
||||
Lock lock(_mapMutex);
|
||||
_rays.clear();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef hifi_DebugDraw_h
|
||||
#define hifi_DebugDraw_h
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
|
@ -17,26 +18,69 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
class DebugDraw {
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
/**jsdoc
|
||||
* Helper functions to render ephemeral debug markers and lines.
|
||||
* DebugDraw markers and lines are only visible locally, they are not visible by other users.
|
||||
* @namespace DebugDraw
|
||||
*/
|
||||
class DebugDraw : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static DebugDraw& getInstance();
|
||||
|
||||
DebugDraw();
|
||||
~DebugDraw();
|
||||
|
||||
// world space line, drawn only once
|
||||
void drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color);
|
||||
/**jsdoc
|
||||
* Draws a line in world space, but it will only be visible for a single frame.
|
||||
* @function DebugDraw.drawRay
|
||||
* @param {Vec3} start - start position of line in world space.
|
||||
* @param {Vec3} end - end position of line in world space.
|
||||
* @param {Vec4} color - color of line, each component should be in the zero to one range. x = red, y = blue, z = green, w = alpha.
|
||||
*/
|
||||
Q_INVOKABLE void drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color);
|
||||
|
||||
// world space maker, marker drawn every frame until it is removed.
|
||||
void addMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color);
|
||||
void removeMarker(const std::string& key);
|
||||
/**jsdoc
|
||||
* Adds a debug marker to the world. This marker will be drawn every frame until it is removed with DebugDraw.removeMarker.
|
||||
* This can be called repeatedly to change the position of the marker.
|
||||
* @function DebugDraw.addMarker
|
||||
* @param {string} key - name to uniquely identify this marker, later used for DebugDraw.removeMarker.
|
||||
* @param {Quat} rotation - start position of line in world space.
|
||||
* @param {Vec3} position - position of the marker in world space.
|
||||
* @param {Vec4} color - color of the marker.
|
||||
*/
|
||||
Q_INVOKABLE void addMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color);
|
||||
|
||||
// myAvatar relative marker, maker is drawn every frame until it is removed.
|
||||
void addMyAvatarMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color);
|
||||
void removeMyAvatarMarker(const std::string& key);
|
||||
/**jsdoc
|
||||
* Removes debug marker from the world. Once a marker is removed, it will no longer be visible.
|
||||
* @function DebugDraw.removeMarker
|
||||
* @param {string} key - name of marker to remove.
|
||||
*/
|
||||
Q_INVOKABLE void removeMarker(const QString& key);
|
||||
|
||||
/**jsdoc
|
||||
* Adds a debug marker to the world, this marker will be drawn every frame until it is removed with DebugDraw.removeMyAvatarMarker.
|
||||
* This can be called repeatedly to change the position of the marker.
|
||||
* @function DebugDraw.addMyAvatarMarker
|
||||
* @param {string} key - name to uniquely identify this marker, later used for DebugDraw.removeMyAvatarMarker.
|
||||
* @param {Quat} rotation - start position of line in avatar space.
|
||||
* @param {Vec3} position - position of the marker in avatar space.
|
||||
* @param {Vec4} color - color of the marker.
|
||||
*/
|
||||
Q_INVOKABLE void addMyAvatarMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color);
|
||||
|
||||
/**jsdoc
|
||||
* Removes debug marker from the world. Once a marker is removed, it will no longer be visible
|
||||
* @function DebugDraw.removeMyAvatarMarker
|
||||
* @param {string} key - name of marker to remove.
|
||||
*/
|
||||
Q_INVOKABLE void removeMyAvatarMarker(const QString& key);
|
||||
|
||||
using MarkerInfo = std::tuple<glm::quat, glm::vec3, glm::vec4>;
|
||||
using MarkerMap = std::unordered_map<std::string, MarkerInfo>;
|
||||
using MarkerMap = std::map<QString, MarkerInfo>;
|
||||
using Ray = std::tuple<glm::vec3, glm::vec3, glm::vec4>;
|
||||
using Rays = std::vector<Ray>;
|
||||
|
||||
|
@ -44,16 +88,17 @@ public:
|
|||
// accessors used by renderer
|
||||
//
|
||||
|
||||
const MarkerMap& getMarkerMap() const { return _markers; }
|
||||
const MarkerMap& getMyAvatarMarkerMap() const { return _myAvatarMarkers; }
|
||||
MarkerMap getMarkerMap() const;
|
||||
MarkerMap getMyAvatarMarkerMap() const;
|
||||
void updateMyAvatarPos(const glm::vec3& pos) { _myAvatarPos = pos; }
|
||||
const glm::vec3& getMyAvatarPos() const { return _myAvatarPos; }
|
||||
void updateMyAvatarRot(const glm::quat& rot) { _myAvatarRot = rot; }
|
||||
const glm::quat& getMyAvatarRot() const { return _myAvatarRot; }
|
||||
const Rays getRays() const { return _rays; }
|
||||
void clearRays() { _rays.clear(); }
|
||||
Rays getRays() const;
|
||||
void clearRays();
|
||||
|
||||
protected:
|
||||
mutable std::mutex _mapMutex;
|
||||
MarkerMap _markers;
|
||||
MarkerMap _myAvatarMarkers;
|
||||
glm::quat _myAvatarRot;
|
||||
|
|
|
@ -74,6 +74,10 @@ var WEB_TOUCH_Y_OFFSET = 0.05; // how far forward (or back with a negative numbe
|
|||
var WEB_TOUCH_TOO_CLOSE = 0.03; // if the stylus is pushed far though the web surface, don't consider it touching
|
||||
var WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE = 0.01;
|
||||
|
||||
var FINGER_TOUCH_Y_OFFSET = -0.02;
|
||||
var FINGER_TOUCH_MIN = -0.01 - FINGER_TOUCH_Y_OFFSET;
|
||||
var FINGER_TOUCH_MAX = 0.01 - FINGER_TOUCH_Y_OFFSET;
|
||||
|
||||
//
|
||||
// distant manipulation
|
||||
//
|
||||
|
@ -258,19 +262,51 @@ CONTROLLER_STATE_MACHINE[STATE_FAR_TRIGGER] = {
|
|||
updateMethod: "farTrigger"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_ENTITY_STYLUS_TOUCHING] = {
|
||||
name: "entityTouching",
|
||||
name: "entityStylusTouching",
|
||||
enterMethod: "entityTouchingEnter",
|
||||
exitMethod: "entityTouchingExit",
|
||||
updateMethod: "entityTouching"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_ENTITY_LASER_TOUCHING] = {
|
||||
name: "entityLaserTouching",
|
||||
enterMethod: "entityTouchingEnter",
|
||||
exitMethod: "entityTouchingExit",
|
||||
updateMethod: "entityTouching"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_ENTITY_LASER_TOUCHING] = CONTROLLER_STATE_MACHINE[STATE_ENTITY_STYLUS_TOUCHING];
|
||||
CONTROLLER_STATE_MACHINE[STATE_OVERLAY_STYLUS_TOUCHING] = {
|
||||
name: "overlayTouching",
|
||||
name: "overlayStylusTouching",
|
||||
enterMethod: "overlayTouchingEnter",
|
||||
exitMethod: "overlayTouchingExit",
|
||||
updateMethod: "overlayTouching"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_OVERLAY_LASER_TOUCHING] = CONTROLLER_STATE_MACHINE[STATE_OVERLAY_STYLUS_TOUCHING];
|
||||
CONTROLLER_STATE_MACHINE[STATE_OVERLAY_LASER_TOUCHING] = {
|
||||
name: "overlayLaserTouching",
|
||||
enterMethod: "overlayTouchingEnter",
|
||||
exitMethod: "overlayTouchingExit",
|
||||
updateMethod: "overlayTouching"
|
||||
};
|
||||
|
||||
function getFingerWorldLocation(hand) {
|
||||
var fingerJointName = (hand === RIGHT_HAND) ? "RightHandIndex4" : "LeftHandIndex4";
|
||||
|
||||
var fingerJointIndex = MyAvatar.getJointIndex(fingerJointName);
|
||||
var fingerPosition = MyAvatar.getAbsoluteJointTranslationInObjectFrame(fingerJointIndex);
|
||||
var fingerRotation = MyAvatar.getAbsoluteJointRotationInObjectFrame(fingerJointIndex);
|
||||
var worldFingerRotation = Quat.multiply(MyAvatar.orientation, fingerRotation);
|
||||
var worldFingerPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, fingerPosition));
|
||||
|
||||
// local y offset.
|
||||
var localYOffset = Vec3.multiplyQbyV(worldFingerRotation, {x: 0, y: FINGER_TOUCH_Y_OFFSET, z: 0});
|
||||
|
||||
var offsetWorldFingerPosition = Vec3.sum(worldFingerPosition, localYOffset);
|
||||
|
||||
return {
|
||||
position: offsetWorldFingerPosition,
|
||||
orientation: worldFingerRotation,
|
||||
rotation: worldFingerRotation,
|
||||
valid: true
|
||||
};
|
||||
}
|
||||
|
||||
// Object assign polyfill
|
||||
if (typeof Object.assign != 'function') {
|
||||
|
@ -374,6 +410,7 @@ function handLaserIntersectItem(position, rotation, start) {
|
|||
direction: rayDirection,
|
||||
length: PICK_MAX_DISTANCE
|
||||
};
|
||||
|
||||
return intersectionInfo;
|
||||
} else {
|
||||
// entity has been destroyed? or is no longer in cache
|
||||
|
@ -849,6 +886,8 @@ function MyController(hand) {
|
|||
this.tabletStabbedPos2D = null;
|
||||
this.tabletStabbedPos3D = null;
|
||||
|
||||
this.useFingerInsteadOfStylus = false;
|
||||
|
||||
var _this = this;
|
||||
|
||||
var suppressedIn2D = [STATE_OFF, STATE_SEARCHING];
|
||||
|
@ -862,10 +901,22 @@ function MyController(hand) {
|
|||
this.updateSmoothedTrigger();
|
||||
this.maybeScaleMyAvatar();
|
||||
|
||||
var DEFAULT_USE_FINGER_AS_STYLUS = false;
|
||||
var USE_FINGER_AS_STYLUS = Settings.getValue("preferAvatarFingerOverStylus");
|
||||
if (USE_FINGER_AS_STYLUS === "") {
|
||||
USE_FINGER_AS_STYLUS = DEFAULT_USE_FINGER_AS_STYLUS;
|
||||
}
|
||||
if (USE_FINGER_AS_STYLUS && MyAvatar.getJointIndex("LeftHandIndex4") !== -1) {
|
||||
this.useFingerInsteadOfStylus = true;
|
||||
} else {
|
||||
this.useFingerInsteadOfStylus = false;
|
||||
}
|
||||
|
||||
if (this.ignoreInput()) {
|
||||
|
||||
// Most hand input is disabled, because we are interacting with the 2d hud.
|
||||
// However, we still should check for collisions of the stylus with the web overlay.
|
||||
|
||||
var controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||
this.processStylus(controllerLocation.position);
|
||||
|
||||
|
@ -1241,30 +1292,54 @@ function MyController(hand) {
|
|||
};
|
||||
|
||||
this.processStylus = function(worldHandPosition) {
|
||||
// see if the hand is near a tablet or web-entity
|
||||
var candidateEntities = Entities.findEntities(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE);
|
||||
entityPropertiesCache.addEntities(candidateEntities);
|
||||
var nearWeb = false;
|
||||
for (var i = 0; i < candidateEntities.length; i++) {
|
||||
var props = entityPropertiesCache.getProps(candidateEntities[i]);
|
||||
if (props && (props.type == "Web" || this.isTablet(candidateEntities[i]))) {
|
||||
nearWeb = true;
|
||||
break;
|
||||
|
||||
var performRayTest = false;
|
||||
if (this.useFingerInsteadOfStylus) {
|
||||
this.hideStylus();
|
||||
performRayTest = true;
|
||||
} else {
|
||||
var i;
|
||||
|
||||
// see if the hand is near a tablet or web-entity
|
||||
var candidateEntities = Entities.findEntities(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE);
|
||||
entityPropertiesCache.addEntities(candidateEntities);
|
||||
for (i = 0; i < candidateEntities.length; i++) {
|
||||
var props = entityPropertiesCache.getProps(candidateEntities[i]);
|
||||
if (props && (props.type == "Web" || this.isTablet(candidateEntities[i]))) {
|
||||
performRayTest = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!performRayTest) {
|
||||
var candidateOverlays = Overlays.findOverlays(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE);
|
||||
for (i = 0; i < candidateOverlays.length; i++) {
|
||||
if (this.isTablet(candidateOverlays[i])) {
|
||||
performRayTest = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (performRayTest) {
|
||||
this.showStylus();
|
||||
} else {
|
||||
this.hideStylus();
|
||||
}
|
||||
}
|
||||
|
||||
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 (performRayTest) {
|
||||
var rayPickInfo = this.calcRayPickInfo(this.hand, this.useFingerInsteadOfStylus);
|
||||
var max, min;
|
||||
if (this.useFingerInsteadOfStylus) {
|
||||
max = FINGER_TOUCH_MAX;
|
||||
min = FINGER_TOUCH_MIN;
|
||||
} else {
|
||||
max = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET;
|
||||
min = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearWeb) {
|
||||
this.showStylus();
|
||||
var rayPickInfo = this.calcRayPickInfo(this.hand);
|
||||
if (rayPickInfo.distance < WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET &&
|
||||
rayPickInfo.distance > WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE) {
|
||||
if (rayPickInfo.distance < max && rayPickInfo.distance > min) {
|
||||
this.handleStylusOnHomeButton(rayPickInfo);
|
||||
if (this.handleStylusOnWebEntity(rayPickInfo)) {
|
||||
return;
|
||||
|
@ -1273,10 +1348,8 @@ function MyController(hand) {
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
this.homeButtonTouched = false;
|
||||
}
|
||||
} else {
|
||||
this.hideStylus();
|
||||
this.homeButtonTouched = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1391,10 +1464,17 @@ function MyController(hand) {
|
|||
|
||||
// Performs ray pick test from the hand controller into the world
|
||||
// @param {number} which hand to use, RIGHT_HAND or LEFT_HAND
|
||||
// @param {bool} if true use the world position/orientation of the index finger to cast the ray from.
|
||||
// @returns {object} returns object with two keys entityID and distance
|
||||
//
|
||||
this.calcRayPickInfo = function(hand) {
|
||||
var controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||
this.calcRayPickInfo = function(hand, useFingerInsteadOfController) {
|
||||
|
||||
var controllerLocation;
|
||||
if (useFingerInsteadOfController) {
|
||||
controllerLocation = getFingerWorldLocation(hand);
|
||||
} else {
|
||||
controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||
}
|
||||
var worldHandPosition = controllerLocation.position;
|
||||
var worldHandRotation = controllerLocation.orientation;
|
||||
|
||||
|
@ -3018,8 +3098,13 @@ function MyController(hand) {
|
|||
|
||||
this.entityTouchingEnter = function() {
|
||||
// test for intersection between controller laser and web entity plane.
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID,
|
||||
getControllerWorldLocation(this.handToController(), true));
|
||||
var controllerLocation;
|
||||
if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) {
|
||||
controllerLocation = getFingerWorldLocation(this.hand);
|
||||
} else {
|
||||
controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||
}
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, controllerLocation);
|
||||
if (intersectInfo) {
|
||||
var pointerEvent = {
|
||||
type: "Press",
|
||||
|
@ -3055,8 +3140,13 @@ function MyController(hand) {
|
|||
|
||||
this.entityTouchingExit = function() {
|
||||
// test for intersection between controller laser and web entity plane.
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID,
|
||||
getControllerWorldLocation(this.handToController(), true));
|
||||
var controllerLocation;
|
||||
if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) {
|
||||
controllerLocation = getFingerWorldLocation(this.hand);
|
||||
} else {
|
||||
controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||
}
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, controllerLocation);
|
||||
if (intersectInfo) {
|
||||
var pointerEvent;
|
||||
if (this.deadspotExpired) {
|
||||
|
@ -3096,12 +3186,24 @@ function MyController(hand) {
|
|||
}
|
||||
|
||||
// test for intersection between controller laser and web entity plane.
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID,
|
||||
getControllerWorldLocation(this.handToController(), true));
|
||||
var controllerLocation;
|
||||
if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) {
|
||||
controllerLocation = getFingerWorldLocation(this.hand);
|
||||
} else {
|
||||
controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||
}
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, controllerLocation);
|
||||
if (intersectInfo) {
|
||||
|
||||
var max;
|
||||
if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) {
|
||||
max = FINGER_TOUCH_MAX;
|
||||
} else {
|
||||
max = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET;
|
||||
}
|
||||
|
||||
if (this.state == STATE_ENTITY_STYLUS_TOUCHING &&
|
||||
intersectInfo.distance > WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET) {
|
||||
intersectInfo.distance > max) {
|
||||
this.setState(STATE_OFF, "pulled away from web entity");
|
||||
return;
|
||||
}
|
||||
|
@ -3144,8 +3246,13 @@ function MyController(hand) {
|
|||
|
||||
this.overlayTouchingEnter = function () {
|
||||
// Test for intersection between controller laser and Web overlay plane.
|
||||
var intersectInfo =
|
||||
handLaserIntersectOverlay(this.grabbedOverlay, getControllerWorldLocation(this.handToController(), true));
|
||||
var controllerLocation;
|
||||
if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) {
|
||||
controllerLocation = getFingerWorldLocation(this.hand);
|
||||
} else {
|
||||
controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||
}
|
||||
var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation);
|
||||
if (intersectInfo) {
|
||||
var pointerEvent = {
|
||||
type: "Press",
|
||||
|
@ -3180,8 +3287,13 @@ function MyController(hand) {
|
|||
|
||||
this.overlayTouchingExit = function () {
|
||||
// Test for intersection between controller laser and Web overlay plane.
|
||||
var intersectInfo =
|
||||
handLaserIntersectOverlay(this.grabbedOverlay, getControllerWorldLocation(this.handToController(), true));
|
||||
var controllerLocation;
|
||||
if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) {
|
||||
controllerLocation = getFingerWorldLocation(this.hand);
|
||||
} else {
|
||||
controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||
}
|
||||
var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation);
|
||||
if (intersectInfo) {
|
||||
var pointerEvent;
|
||||
|
||||
|
@ -3238,12 +3350,25 @@ function MyController(hand) {
|
|||
}
|
||||
|
||||
// Test for intersection between controller laser and Web overlay plane.
|
||||
var intersectInfo =
|
||||
handLaserIntersectOverlay(this.grabbedOverlay, getControllerWorldLocation(this.handToController(), true));
|
||||
var controllerLocation;
|
||||
if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) {
|
||||
controllerLocation = getFingerWorldLocation(this.hand);
|
||||
} else {
|
||||
controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||
}
|
||||
var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation);
|
||||
if (intersectInfo) {
|
||||
|
||||
if (this.state == STATE_OVERLAY_STYLUS_TOUCHING &&
|
||||
intersectInfo.distance > WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET + WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE) {
|
||||
var max, min;
|
||||
if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) {
|
||||
max = FINGER_TOUCH_MAX;
|
||||
min = FINGER_TOUCH_MIN;
|
||||
} else {
|
||||
max = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET + WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE;
|
||||
min = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE;
|
||||
}
|
||||
|
||||
if (this.state == STATE_OVERLAY_STYLUS_TOUCHING && intersectInfo.distance > max) {
|
||||
this.grabbedThingID = null;
|
||||
this.setState(STATE_OFF, "pulled away from overlay");
|
||||
return;
|
||||
|
@ -3254,7 +3379,7 @@ function MyController(hand) {
|
|||
|
||||
if (this.state == STATE_OVERLAY_STYLUS_TOUCHING &&
|
||||
!this.tabletStabbed &&
|
||||
intersectInfo.distance < WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE) {
|
||||
intersectInfo.distance < min) {
|
||||
// they've stabbed the tablet, don't send events until they pull back
|
||||
this.tabletStabbed = true;
|
||||
this.tabletStabbedPos2D = pos2D;
|
||||
|
|
|
@ -21,6 +21,7 @@ exports.handlers = {
|
|||
'../../libraries/networking/src',
|
||||
'../../libraries/animation/src',
|
||||
'../../libraries/entities/src',
|
||||
'../../libraries/shared/src'
|
||||
];
|
||||
var exts = ['.h', '.cpp'];
|
||||
|
||||
|
|
Loading…
Reference in a new issue