mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 19:50:38 +02:00
resolve merge conflict
This commit is contained in:
commit
5fb2c3ccd1
30 changed files with 669 additions and 287 deletions
222
examples/libraries/promise.js
Normal file
222
examples/libraries/promise.js
Normal file
|
@ -0,0 +1,222 @@
|
|||
// Copyright (c) 2014 Taylor Hakes
|
||||
// Copyright (c) 2014 Forbes Lindesay
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
|
||||
|
||||
function promiseMaker() {
|
||||
|
||||
// Use polyfill for setImmediate for performance gains
|
||||
var asap = (typeof setImmediate === 'function' && setImmediate) ||
|
||||
function(fn) {
|
||||
Script.setTimeout(fn, 1);
|
||||
};
|
||||
|
||||
// Polyfill for Function.prototype.bind
|
||||
function bind(fn, thisArg) {
|
||||
return function() {
|
||||
fn.apply(thisArg, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
var isArray = Array.isArray || function(value) {
|
||||
return Object.prototype.toString.call(value) === "[object Array]"
|
||||
};
|
||||
|
||||
function Promise(fn) {
|
||||
if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
|
||||
if (typeof fn !== 'function') throw new TypeError('not a function');
|
||||
this._state = null;
|
||||
this._value = null;
|
||||
this._deferreds = []
|
||||
|
||||
doResolve(fn, bind(resolve, this), bind(reject, this))
|
||||
}
|
||||
|
||||
function handle(deferred) {
|
||||
var me = this;
|
||||
if (this._state === null) {
|
||||
this._deferreds.push(deferred);
|
||||
return
|
||||
}
|
||||
asap(function() {
|
||||
var cb = me._state ? deferred.onFulfilled : deferred.onRejected
|
||||
if (cb === null) {
|
||||
(me._state ? deferred.resolve : deferred.reject)(me._value);
|
||||
return;
|
||||
}
|
||||
var ret;
|
||||
try {
|
||||
ret = cb(me._value);
|
||||
} catch (e) {
|
||||
deferred.reject(e);
|
||||
return;
|
||||
}
|
||||
deferred.resolve(ret);
|
||||
})
|
||||
}
|
||||
|
||||
function resolve(newValue) {
|
||||
try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
|
||||
if (newValue === this) throw new TypeError('A promise cannot be resolved with itself.');
|
||||
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
|
||||
var then = newValue.then;
|
||||
if (typeof then === 'function') {
|
||||
doResolve(bind(then, newValue), bind(resolve, this), bind(reject, this));
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._state = true;
|
||||
this._value = newValue;
|
||||
finale.call(this);
|
||||
} catch (e) {
|
||||
reject.call(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
function reject(newValue) {
|
||||
this._state = false;
|
||||
this._value = newValue;
|
||||
finale.call(this);
|
||||
}
|
||||
|
||||
function finale() {
|
||||
for (var i = 0, len = this._deferreds.length; i < len; i++) {
|
||||
handle.call(this, this._deferreds[i]);
|
||||
}
|
||||
this._deferreds = null;
|
||||
}
|
||||
|
||||
function Handler(onFulfilled, onRejected, resolve, reject) {
|
||||
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
|
||||
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a potentially misbehaving resolver function and make sure
|
||||
* onFulfilled and onRejected are only called once.
|
||||
*
|
||||
* Makes no guarantees about asynchrony.
|
||||
*/
|
||||
function doResolve(fn, onFulfilled, onRejected) {
|
||||
var done = false;
|
||||
try {
|
||||
fn(function(value) {
|
||||
if (done) return;
|
||||
done = true;
|
||||
onFulfilled(value);
|
||||
}, function(reason) {
|
||||
if (done) return;
|
||||
done = true;
|
||||
onRejected(reason);
|
||||
})
|
||||
} catch (ex) {
|
||||
if (done) return;
|
||||
done = true;
|
||||
onRejected(ex);
|
||||
}
|
||||
}
|
||||
|
||||
Promise.prototype['catch'] = function(onRejected) {
|
||||
return this.then(null, onRejected);
|
||||
};
|
||||
|
||||
Promise.prototype.then = function(onFulfilled, onRejected) {
|
||||
var me = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
handle.call(me, new Handler(onFulfilled, onRejected, resolve, reject));
|
||||
})
|
||||
};
|
||||
|
||||
Promise.all = function() {
|
||||
var args = Array.prototype.slice.call(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments);
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (args.length === 0) return resolve([]);
|
||||
var remaining = args.length;
|
||||
|
||||
function res(i, val) {
|
||||
try {
|
||||
if (val && (typeof val === 'object' || typeof val === 'function')) {
|
||||
var then = val.then;
|
||||
if (typeof then === 'function') {
|
||||
then.call(val, function(val) {
|
||||
res(i, val)
|
||||
}, reject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
args[i] = val;
|
||||
if (--remaining === 0) {
|
||||
resolve(args);
|
||||
}
|
||||
} catch (ex) {
|
||||
reject(ex);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
res(i, args[i]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Promise.resolve = function(value) {
|
||||
if (value && typeof value === 'object' && value.constructor === Promise) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return new Promise(function(resolve) {
|
||||
resolve(value);
|
||||
});
|
||||
};
|
||||
|
||||
Promise.reject = function(value) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
reject(value);
|
||||
});
|
||||
};
|
||||
|
||||
Promise.race = function(values) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
for (var i = 0, len = values.length; i < len; i++) {
|
||||
values[i].then(resolve, reject);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the immediate function to execute callbacks
|
||||
* @param fn {function} Function to execute
|
||||
* @private
|
||||
*/
|
||||
Promise._setImmediateFn = function _setImmediateFn(fn) {
|
||||
asap = fn;
|
||||
};
|
||||
|
||||
|
||||
return Promise
|
||||
|
||||
}
|
||||
|
||||
loadPromise = function() {
|
||||
return promiseMaker();
|
||||
}
|
18
examples/libraries/promiseExample.js
Normal file
18
examples/libraries/promiseExample.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
Script.include('promise.js');
|
||||
var Promise = loadPromise();
|
||||
var prom = new Promise(function(resolve, reject) {
|
||||
print('making a promise')
|
||||
// do a thing, possibly async, then…
|
||||
var thing = true;
|
||||
if (thing) {
|
||||
resolve("Stuff worked!");
|
||||
} else {
|
||||
print('ERROR')
|
||||
reject(new Error("It broke"));
|
||||
}
|
||||
});
|
||||
|
||||
// Do something when async done
|
||||
prom.then(function(result) {
|
||||
print('result ' + result);
|
||||
});
|
|
@ -13,13 +13,18 @@
|
|||
Script.include("../../utilities.js");
|
||||
Script.include("../../libraries/utils.js");
|
||||
|
||||
var WAND_MODEL = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/wand.fbx';
|
||||
var WAND_COLLISION_SHAPE = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/collisionHull.obj';
|
||||
var WAND_MODEL = 'http://hifi-public.s3.amazonaws.com/models/bubblewand/wand.fbx';
|
||||
var WAND_COLLISION_SHAPE = 'http://hifi-public.s3.amazonaws.com/models/bubblewand/actual_no_top_collision_hull.obj';
|
||||
|
||||
var WAND_SCRIPT_URL = Script.resolvePath("wand.js");
|
||||
|
||||
//create the wand in front of the avatar
|
||||
|
||||
var center = Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0, y: 0.5, z: 0}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation())));
|
||||
var center = Vec3.sum(Vec3.sum(MyAvatar.position, {
|
||||
x: 0,
|
||||
y: 0.5,
|
||||
z: 0
|
||||
}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
var wand = Entities.addEntity({
|
||||
name: 'Bubble Wand',
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
Script.include("../../utilities.js");
|
||||
Script.include("../../libraries/utils.js");
|
||||
|
||||
var BUBBLE_MODEL = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/bubble/bubble.fbx";
|
||||
var BUBBLE_MODEL = "http://hifi-public.s3.amazonaws.com/models/bubblewand/bubble.fbx";
|
||||
|
||||
var BUBBLE_INITIAL_DIMENSIONS = {
|
||||
x: 0.01,
|
||||
|
|
|
@ -14,8 +14,16 @@
|
|||
]
|
||||
},
|
||||
{ "from": "Standard.RX", "to": "Actions.Yaw" },
|
||||
{ "from": "Standard.RY", "when": "!Application.InHMD", "to": "Actions.Pitch" },
|
||||
{ "from": "Standard.RY", "when": "Application.InHMD", "filters": "invert", "to": "Actions.TranslateY" },
|
||||
{ "from": "Standard.RY",
|
||||
"when": "Application.Grounded",
|
||||
"to": "Actions.Up",
|
||||
"filters":
|
||||
[
|
||||
{ "type": "deadZone", "min": 0.95 },
|
||||
"invert"
|
||||
]
|
||||
},
|
||||
{ "from": "Standard.RY", "to": "Actions.Up", "filters": "invert"},
|
||||
|
||||
{ "from": [ "Standard.DU", "Standard.DL", "Standard.DR", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
|
||||
{ "from": "Standard.Back", "to": "Standard.LeftSecondaryThumb" },
|
||||
|
|
|
@ -646,11 +646,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
_applicationStateDevice->addInputVariant(QString("ComfortMode"), controller::StateController::ReadLambda([]() -> float {
|
||||
return (float)Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode);
|
||||
}));
|
||||
_applicationStateDevice->addInputVariant(QString("Grounded"), controller::StateController::ReadLambda([]() -> float {
|
||||
return (float)qApp->getMyAvatar()->getCharacterController()->onGround();
|
||||
}));
|
||||
|
||||
userInputMapper->registerDevice(_applicationStateDevice);
|
||||
|
||||
// Setup the keyboardMouseDevice and the user input mapper with the default bindings
|
||||
userInputMapper->registerDevice(_keyboardMouseDevice);
|
||||
userInputMapper->registerDevice(_keyboardMouseDevice->getInputDevice());
|
||||
|
||||
|
||||
userInputMapper->loadDefaultMapping(userInputMapper->getStandardDeviceID());
|
||||
|
@ -726,8 +729,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
// Now that menu is initalized we can sync myAvatar with it's state.
|
||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||
|
||||
// FIXME spacemouse code still needs cleanup
|
||||
#if 0
|
||||
// the 3Dconnexion device wants to be initiliazed after a window is displayed.
|
||||
SpacemouseManager::getInstance().init();
|
||||
#endif
|
||||
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket");
|
||||
|
@ -1847,9 +1853,12 @@ void Application::focusOutEvent(QFocusEvent* event) {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME spacemouse code still needs cleanup
|
||||
#if 0
|
||||
//SpacemouseDevice::getInstance().focusOutEvent();
|
||||
//SpacemouseManager::getInstance().getDevice()->focusOutEvent();
|
||||
SpacemouseManager::getInstance().ManagerFocusOutEvent();
|
||||
#endif
|
||||
|
||||
// synthesize events for keys currently pressed, since we may not get their release events
|
||||
foreach (int key, _keysPressed) {
|
||||
|
|
|
@ -465,8 +465,6 @@ Menu::Menu() {
|
|||
avatar, SLOT(setEnableMeshVisible(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false);
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::Connexion, 0, false, &SpacemouseManager::getInstance(), SLOT(toggleSpacemouse(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ComfortMode, 0, true);
|
||||
|
||||
MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands");
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
QByteArray serialize() const;
|
||||
virtual void deserialize(QByteArray serializedArguments);
|
||||
|
||||
virtual bool shouldSuppressLocationEdits() { return true; }
|
||||
virtual bool shouldSuppressLocationEdits() { return _active && !_ownerEntity.expired(); }
|
||||
|
||||
private:
|
||||
static const uint16_t holdVersion;
|
||||
|
|
|
@ -156,11 +156,11 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
|
|||
// cache tip absolute transform
|
||||
int tipIndex = target.getIndex();
|
||||
int pivotIndex = _skeleton->getParentIndex(tipIndex);
|
||||
if (pivotIndex == -1) {
|
||||
if (pivotIndex == -1 || pivotIndex == _hipsIndex) {
|
||||
continue;
|
||||
}
|
||||
int pivotsParentIndex = _skeleton->getParentIndex(pivotIndex);
|
||||
if (pivotsParentIndex == -1) {
|
||||
if (pivotsParentIndex == -1 || pivotIndex == _hipsIndex) {
|
||||
// TODO?: handle case where tip's parent is root?
|
||||
continue;
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
|
|||
glm::quat tipParentRotation = absolutePoses[pivotIndex].rot;
|
||||
|
||||
// descend toward root, pivoting each joint to get tip closer to target
|
||||
while (pivotsParentIndex != -1) {
|
||||
while (pivotsParentIndex != _hipsIndex && pivotsParentIndex != -1) {
|
||||
// compute the two lines that should be aligned
|
||||
glm::vec3 jointPosition = absolutePoses[pivotIndex].trans;
|
||||
glm::vec3 leverArm = tipPosition - jointPosition;
|
||||
|
@ -285,7 +285,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
|
|||
// only update the absolutePoses that need it: those between lowestMovedIndex and _maxTargetIndex
|
||||
for (int i = lowestMovedIndex; i <= _maxTargetIndex; ++i) {
|
||||
int parentIndex = _skeleton->getParentIndex(i);
|
||||
if (parentIndex != -1) {
|
||||
if (parentIndex != -1 && parentIndex != _hipsIndex) {
|
||||
absolutePoses[i] = absolutePoses[parentIndex] * _relativePoses[i];
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
|
|||
for (auto& target: targets) {
|
||||
int tipIndex = target.getIndex();
|
||||
int parentIndex = _skeleton->getParentIndex(tipIndex);
|
||||
if (parentIndex != -1) {
|
||||
if (parentIndex != -1 && parentIndex != _hipsIndex) {
|
||||
const glm::quat& targetRotation = target.getRotation();
|
||||
// compute tip's new parent-relative rotation
|
||||
// Q = Qp * q --> q' = Qp^ * Q
|
||||
|
|
11
libraries/display-plugins/src/display-plugins/Logging.cpp
Normal file
11
libraries/display-plugins/src/display-plugins/Logging.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/11
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(displayPlugins, "hifi.plugins.display")
|
16
libraries/display-plugins/src/display-plugins/Logging.h
Normal file
16
libraries/display-plugins/src/display-plugins/Logging.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/11
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_DisplayPlugins_Logging_h
|
||||
#define hifi_DisplayPlugins_Logging_h
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(displayPlugins)
|
||||
|
||||
#endif
|
|
@ -37,8 +37,6 @@ const QString & OpenVrDisplayPlugin::getName() const {
|
|||
return NAME;
|
||||
}
|
||||
|
||||
vr::IVRSystem* _hmd{ nullptr };
|
||||
int hmdRefCount = 0;
|
||||
static vr::IVRCompositor* _compositor{ nullptr };
|
||||
vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
|
||||
mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
|
||||
|
@ -78,24 +76,17 @@ mat4 toGlm(const vr::HmdMatrix34_t& m) {
|
|||
}
|
||||
|
||||
bool OpenVrDisplayPlugin::isSupported() const {
|
||||
bool success = vr::VR_IsHmdPresent();
|
||||
if (success) {
|
||||
vr::HmdError eError = vr::HmdError_None;
|
||||
auto hmd = vr::VR_Init(&eError);
|
||||
success = (hmd != nullptr);
|
||||
vr::VR_Shutdown();
|
||||
}
|
||||
auto hmd = acquireOpenVrSystem();
|
||||
bool success = nullptr != hmd;
|
||||
releaseOpenVrSystem();
|
||||
return success;
|
||||
}
|
||||
|
||||
void OpenVrDisplayPlugin::activate() {
|
||||
_container->setIsOptionChecked(StandingHMDSensorMode, true);
|
||||
|
||||
hmdRefCount++;
|
||||
vr::HmdError eError = vr::HmdError_None;
|
||||
if (!_hmd) {
|
||||
_hmd = vr::VR_Init(&eError);
|
||||
Q_ASSERT(eError == vr::HmdError_None);
|
||||
_hmd = acquireOpenVrSystem();
|
||||
}
|
||||
Q_ASSERT(_hmd);
|
||||
|
||||
|
@ -114,6 +105,7 @@ void OpenVrDisplayPlugin::activate() {
|
|||
});
|
||||
|
||||
|
||||
vr::HmdError eError = vr::HmdError_None;
|
||||
_compositor = (vr::IVRCompositor*)vr::VR_GetGenericInterface(vr::IVRCompositor_Version, &eError);
|
||||
Q_ASSERT(eError == vr::HmdError_None);
|
||||
Q_ASSERT(_compositor);
|
||||
|
@ -133,11 +125,8 @@ void OpenVrDisplayPlugin::activate() {
|
|||
|
||||
void OpenVrDisplayPlugin::deactivate() {
|
||||
_container->setIsOptionChecked(StandingHMDSensorMode, false);
|
||||
|
||||
hmdRefCount--;
|
||||
|
||||
if (hmdRefCount == 0 && _hmd) {
|
||||
vr::VR_Shutdown();
|
||||
if (_hmd) {
|
||||
releaseOpenVrSystem();
|
||||
_hmd = nullptr;
|
||||
}
|
||||
_compositor = nullptr;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <QtGlobal>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <openvr.h>
|
||||
|
||||
#include "../WindowOpenGLDisplayPlugin.h"
|
||||
|
||||
|
@ -39,6 +40,7 @@ protected:
|
|||
virtual void finishFrame() override;
|
||||
|
||||
private:
|
||||
vr::IVRSystem* _hmd { nullptr };
|
||||
static const QString NAME;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/11/01
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "OpenVrHelpers.h"
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#include "../Logging.h"
|
||||
|
||||
using Mutex = std::mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
|
||||
static int refCount { 0 };
|
||||
static Mutex mutex;
|
||||
static vr::IVRSystem* activeHmd { nullptr };
|
||||
static bool hmdPresent = vr::VR_IsHmdPresent();
|
||||
|
||||
static const uint32_t RELEASE_OPENVR_HMD_DELAY_MS = 5000;
|
||||
|
||||
vr::IVRSystem* acquireOpenVrSystem() {
|
||||
if (hmdPresent) {
|
||||
Lock lock(mutex);
|
||||
if (!activeHmd) {
|
||||
qCDebug(displayPlugins) << "openvr: No vr::IVRSystem instance active, building";
|
||||
vr::HmdError eError = vr::HmdError_None;
|
||||
activeHmd = vr::VR_Init(&eError);
|
||||
qCDebug(displayPlugins) << "openvr display: HMD is " << activeHmd << " error is " << eError;
|
||||
}
|
||||
if (activeHmd) {
|
||||
qCDebug(displayPlugins) << "openvr: incrementing refcount";
|
||||
++refCount;
|
||||
}
|
||||
}
|
||||
return activeHmd;
|
||||
}
|
||||
|
||||
void releaseOpenVrSystem() {
|
||||
if (activeHmd) {
|
||||
Lock lock(mutex);
|
||||
qDebug() << "openvr: decrementing refcount";
|
||||
--refCount;
|
||||
if (0 == refCount) {
|
||||
qDebug() << "openvr: zero refcount, deallocate VR system";
|
||||
// Avoid spamming the VR system with activate/deactivate calls at system startup by
|
||||
// putting in a delay before we destory the shutdown the VR subsystem
|
||||
|
||||
// FIXME releasing the VR system at all seems to trigger an exception deep inside the Oculus DLL.
|
||||
// disabling for now.
|
||||
//QTimer* releaseTimer = new QTimer();
|
||||
//releaseTimer->singleShot(RELEASE_OPENVR_HMD_DELAY_MS, [releaseTimer] {
|
||||
// Lock lock(mutex);
|
||||
// qDebug() << "Delayed openvr destroy activated";
|
||||
// if (0 == refCount && nullptr != activeHmd) {
|
||||
// qDebug() << "Delayed openvr destroy: releasing resources";
|
||||
// activeHmd = nullptr;
|
||||
// vr::VR_Shutdown();
|
||||
// } else {
|
||||
// qDebug() << "Delayed openvr destroy: HMD still in use";
|
||||
// }
|
||||
// releaseTimer->deleteLater();
|
||||
//});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -7,10 +7,16 @@
|
|||
//
|
||||
#pragma once
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <openvr.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
vr::IVRSystem* acquireOpenVrSystem();
|
||||
void releaseOpenVrSystem();
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -611,6 +611,16 @@ EntityItemPointer EntityTree::findEntityByEntityItemID(const EntityItemID& entit
|
|||
return foundEntity;
|
||||
}
|
||||
|
||||
void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<QString>& changedProperties) {
|
||||
if (properties.simulationOwnerChanged()) {
|
||||
int simIndex = changedProperties.indexOf("simulationOwner");
|
||||
if (simIndex >= 0) {
|
||||
SimulationOwner simOwner = properties.getSimulationOwner();
|
||||
changedProperties[simIndex] = QString("simulationOwner:") + QString::number((int)simOwner.getPriority());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength,
|
||||
const SharedNodePointer& senderNode) {
|
||||
|
||||
|
@ -661,7 +671,9 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi
|
|||
qCDebug(entities) << " properties:" << properties;
|
||||
}
|
||||
if (wantTerseEditLogging()) {
|
||||
qCDebug(entities) << "edit" << entityItemID.toString() << properties.listChangedProperties();
|
||||
QList<QString> changedProperties = properties.listChangedProperties();
|
||||
fixupTerseEditLogging(properties, changedProperties);
|
||||
qCDebug(entities) << "edit" << entityItemID.toString() << changedProperties;
|
||||
}
|
||||
endLogging = usecTimestampNow();
|
||||
|
||||
|
@ -689,7 +701,9 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi
|
|||
qCDebug(entities) << " properties:" << properties;
|
||||
}
|
||||
if (wantTerseEditLogging()) {
|
||||
qCDebug(entities) << "add" << entityItemID.toString() << properties.listChangedProperties();
|
||||
QList<QString> changedProperties = properties.listChangedProperties();
|
||||
fixupTerseEditLogging(properties, changedProperties);
|
||||
qCDebug(entities) << "add" << entityItemID.toString() << changedProperties;
|
||||
}
|
||||
endLogging = usecTimestampNow();
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
virtual bool canProcessVersion(PacketVersion thisVersion) const
|
||||
{ return thisVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS; }
|
||||
virtual bool handlesEditPacketType(PacketType packetType) const;
|
||||
void fixupTerseEditLogging(EntityItemProperties& properties, QList<QString>& changedProperties);
|
||||
virtual int processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength,
|
||||
const SharedNodePointer& senderNode);
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
|
||||
const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse";
|
||||
|
||||
void KeyboardMouseDevice::update(float deltaTime, bool jointsCaptured) {
|
||||
_axisStateMap.clear();
|
||||
void KeyboardMouseDevice::pluginUpdate(float deltaTime, bool jointsCaptured) {
|
||||
_inputDevice->update(deltaTime, jointsCaptured);
|
||||
|
||||
// For touch event, we need to check that the last event is not too long ago
|
||||
// Maybe it's a Qt issue, but the touch event sequence (begin, update, end) is not always called properly
|
||||
|
@ -35,26 +35,30 @@ void KeyboardMouseDevice::update(float deltaTime, bool jointsCaptured) {
|
|||
}
|
||||
}
|
||||
|
||||
void KeyboardMouseDevice::focusOutEvent() {
|
||||
void KeyboardMouseDevice::InputDevice::update(float deltaTime, bool jointsCaptured) {
|
||||
_axisStateMap.clear();
|
||||
}
|
||||
|
||||
void KeyboardMouseDevice::InputDevice::focusOutEvent() {
|
||||
_buttonPressedMap.clear();
|
||||
};
|
||||
}
|
||||
|
||||
void KeyboardMouseDevice::keyPressEvent(QKeyEvent* event) {
|
||||
auto input = makeInput((Qt::Key) event->key());
|
||||
auto result = _buttonPressedMap.insert(input.getChannel());
|
||||
auto input = _inputDevice->makeInput((Qt::Key) event->key());
|
||||
auto result = _inputDevice->_buttonPressedMap.insert(input.getChannel());
|
||||
if (!result.second) {
|
||||
// key pressed again ? without catching the release event ?
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardMouseDevice::keyReleaseEvent(QKeyEvent* event) {
|
||||
auto input = makeInput((Qt::Key) event->key());
|
||||
_buttonPressedMap.erase(input.getChannel());
|
||||
auto input = _inputDevice->makeInput((Qt::Key) event->key());
|
||||
_inputDevice->_buttonPressedMap.erase(input.getChannel());
|
||||
}
|
||||
|
||||
void KeyboardMouseDevice::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||
auto input = makeInput((Qt::MouseButton) event->button());
|
||||
auto result = _buttonPressedMap.insert(input.getChannel());
|
||||
auto input = _inputDevice->makeInput((Qt::MouseButton) event->button());
|
||||
auto result = _inputDevice->_buttonPressedMap.insert(input.getChannel());
|
||||
if (!result.second) {
|
||||
// key pressed again ? without catching the release event ?
|
||||
}
|
||||
|
@ -65,32 +69,32 @@ void KeyboardMouseDevice::mousePressEvent(QMouseEvent* event, unsigned int devic
|
|||
}
|
||||
|
||||
void KeyboardMouseDevice::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||
auto input = makeInput((Qt::MouseButton) event->button());
|
||||
_buttonPressedMap.erase(input.getChannel());
|
||||
auto input = _inputDevice->makeInput((Qt::MouseButton) event->button());
|
||||
_inputDevice->_buttonPressedMap.erase(input.getChannel());
|
||||
|
||||
// if we pressed and released at the same location, then create a "_CLICKED" input for this button
|
||||
// we might want to add some small tolerance to this so if you do a small drag it still counts as
|
||||
// a clicked.
|
||||
if (_mousePressAt == event->pos()) {
|
||||
_buttonPressedMap.insert(makeInput((Qt::MouseButton) event->button(), true).getChannel());
|
||||
_inputDevice->_buttonPressedMap.insert(_inputDevice->makeInput((Qt::MouseButton) event->button(), true).getChannel());
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardMouseDevice::eraseMouseClicked() {
|
||||
_buttonPressedMap.erase(makeInput(Qt::LeftButton, true).getChannel());
|
||||
_buttonPressedMap.erase(makeInput(Qt::MiddleButton, true).getChannel());
|
||||
_buttonPressedMap.erase(makeInput(Qt::RightButton, true).getChannel());
|
||||
_inputDevice->_buttonPressedMap.erase(_inputDevice->makeInput(Qt::LeftButton, true).getChannel());
|
||||
_inputDevice->_buttonPressedMap.erase(_inputDevice->makeInput(Qt::MiddleButton, true).getChannel());
|
||||
_inputDevice->_buttonPressedMap.erase(_inputDevice->makeInput(Qt::RightButton, true).getChannel());
|
||||
}
|
||||
|
||||
void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||
QPoint currentPos = event->pos();
|
||||
QPoint currentMove = currentPos - _lastCursor;
|
||||
|
||||
_axisStateMap[makeInput(MOUSE_AXIS_X_POS).getChannel()] = (currentMove.x() > 0 ? currentMove.x() : 0.0f);
|
||||
_axisStateMap[makeInput(MOUSE_AXIS_X_NEG).getChannel()] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f);
|
||||
_inputDevice->_axisStateMap[MOUSE_AXIS_X_POS] = (currentMove.x() > 0 ? currentMove.x() : 0.0f);
|
||||
_inputDevice->_axisStateMap[MOUSE_AXIS_X_NEG] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f);
|
||||
// Y mouse is inverted positive is pointing up the screen
|
||||
_axisStateMap[makeInput(MOUSE_AXIS_Y_POS).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f);
|
||||
_axisStateMap[makeInput(MOUSE_AXIS_Y_NEG).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f);
|
||||
_inputDevice->_axisStateMap[MOUSE_AXIS_Y_POS] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f);
|
||||
_inputDevice->_axisStateMap[MOUSE_AXIS_Y_NEG] = (currentMove.y() > 0 ? currentMove.y() : 0.0f);
|
||||
|
||||
_lastCursor = currentPos;
|
||||
|
||||
|
@ -100,10 +104,10 @@ void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event, unsigned int device
|
|||
void KeyboardMouseDevice::wheelEvent(QWheelEvent* event) {
|
||||
auto currentMove = event->angleDelta() / 120.0f;
|
||||
|
||||
_axisStateMap[makeInput(MOUSE_AXIS_WHEEL_X_POS).getChannel()] = (currentMove.x() > 0 ? currentMove.x() : 0.0f);
|
||||
_axisStateMap[makeInput(MOUSE_AXIS_WHEEL_X_NEG).getChannel()] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f);
|
||||
_axisStateMap[makeInput(MOUSE_AXIS_WHEEL_Y_POS).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f);
|
||||
_axisStateMap[makeInput(MOUSE_AXIS_WHEEL_Y_NEG).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f);
|
||||
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_X_POS).getChannel()] = (currentMove.x() > 0 ? currentMove.x() : 0.0f);
|
||||
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_X_NEG).getChannel()] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f);
|
||||
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_Y_POS).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f);
|
||||
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_Y_NEG).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f);
|
||||
}
|
||||
|
||||
glm::vec2 evalAverageTouchPoints(const QList<QTouchEvent::TouchPoint>& points) {
|
||||
|
@ -138,17 +142,17 @@ void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) {
|
|||
} else {
|
||||
auto currentMove = currentPos - _lastTouch;
|
||||
|
||||
_axisStateMap[makeInput(TOUCH_AXIS_X_POS).getChannel()] = (currentMove.x > 0 ? currentMove.x : 0.0f);
|
||||
_axisStateMap[makeInput(TOUCH_AXIS_X_NEG).getChannel()] = (currentMove.x < 0 ? -currentMove.x : 0.0f);
|
||||
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_POS).getChannel()] = (currentMove.x > 0 ? currentMove.x : 0.0f);
|
||||
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_NEG).getChannel()] = (currentMove.x < 0 ? -currentMove.x : 0.0f);
|
||||
// Y mouse is inverted positive is pointing up the screen
|
||||
_axisStateMap[makeInput(TOUCH_AXIS_Y_POS).getChannel()] = (currentMove.y < 0 ? -currentMove.y : 0.0f);
|
||||
_axisStateMap[makeInput(TOUCH_AXIS_Y_NEG).getChannel()] = (currentMove.y > 0 ? currentMove.y : 0.0f);
|
||||
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_POS).getChannel()] = (currentMove.y < 0 ? -currentMove.y : 0.0f);
|
||||
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_NEG).getChannel()] = (currentMove.y > 0 ? currentMove.y : 0.0f);
|
||||
}
|
||||
|
||||
_lastTouch = currentPos;
|
||||
}
|
||||
|
||||
controller::Input KeyboardMouseDevice::makeInput(Qt::Key code) const {
|
||||
controller::Input KeyboardMouseDevice::InputDevice::makeInput(Qt::Key code) const {
|
||||
auto shortCode = (uint16_t)(code & KEYBOARD_MASK);
|
||||
if (shortCode != code) {
|
||||
shortCode |= 0x0800; // add this bit instead of the way Qt::Key add a bit on the 3rd byte for some keys
|
||||
|
@ -156,7 +160,7 @@ controller::Input KeyboardMouseDevice::makeInput(Qt::Key code) const {
|
|||
return controller::Input(_deviceID, shortCode, controller::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
controller::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code, bool clicked) const {
|
||||
controller::Input KeyboardMouseDevice::InputDevice::makeInput(Qt::MouseButton code, bool clicked) const {
|
||||
switch (code) {
|
||||
case Qt::LeftButton:
|
||||
return controller::Input(_deviceID, clicked ? MOUSE_BUTTON_LEFT_CLICKED :
|
||||
|
@ -172,19 +176,19 @@ controller::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code, bool clic
|
|||
};
|
||||
}
|
||||
|
||||
controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) const {
|
||||
controller::Input KeyboardMouseDevice::InputDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) const {
|
||||
return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) const {
|
||||
controller::Input KeyboardMouseDevice::InputDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) const {
|
||||
return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) const {
|
||||
controller::Input KeyboardMouseDevice::InputDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) const {
|
||||
return controller::Input(_deviceID, button, controller::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
controller::Input::NamedVector KeyboardMouseDevice::getAvailableInputs() const {
|
||||
controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInputs() const {
|
||||
using namespace controller;
|
||||
static QVector<Input::NamedPair> availableInputs;
|
||||
static std::once_flag once;
|
||||
|
@ -229,7 +233,7 @@ controller::Input::NamedVector KeyboardMouseDevice::getAvailableInputs() const {
|
|||
return availableInputs;
|
||||
}
|
||||
|
||||
QString KeyboardMouseDevice::getDefaultMappingConfig() const {
|
||||
QString KeyboardMouseDevice::InputDevice::getDefaultMappingConfig() const {
|
||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/keyboardMouse.json";
|
||||
return MAPPING_JSON;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ class QKeyEvent;
|
|||
class QMouseEvent;
|
||||
class QWheelEvent;
|
||||
|
||||
class KeyboardMouseDevice : public InputPlugin, public controller::InputDevice {
|
||||
class KeyboardMouseDevice : public InputPlugin {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum KeyboardChannel {
|
||||
|
@ -64,22 +64,14 @@ public:
|
|||
TOUCH_BUTTON_PRESS = TOUCH_AXIS_Y_NEG + 1,
|
||||
};
|
||||
|
||||
KeyboardMouseDevice() : InputDevice("Keyboard") {}
|
||||
|
||||
// Plugin functions
|
||||
virtual bool isSupported() const override { return true; }
|
||||
virtual bool isJointController() const override { return false; }
|
||||
const QString& getName() const override { return NAME; }
|
||||
|
||||
virtual void pluginFocusOutEvent() override { focusOutEvent(); }
|
||||
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
|
||||
virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
|
||||
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override;
|
||||
|
||||
// Device functions
|
||||
virtual controller::Input::NamedVector getAvailableInputs() const override;
|
||||
virtual QString getDefaultMappingConfig() const override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
void keyReleaseEvent(QKeyEvent* event);
|
||||
|
||||
|
@ -94,21 +86,40 @@ public:
|
|||
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
|
||||
// Let's make it easy for Qt because we assume we love Qt forever
|
||||
controller::Input makeInput(Qt::Key code) const;
|
||||
controller::Input makeInput(Qt::MouseButton code, bool clicked = false) const;
|
||||
controller::Input makeInput(MouseAxisChannel axis) const;
|
||||
controller::Input makeInput(TouchAxisChannel axis) const;
|
||||
controller::Input makeInput(TouchButtonChannel button) const;
|
||||
|
||||
static const QString NAME;
|
||||
|
||||
protected:
|
||||
|
||||
class InputDevice : public controller::InputDevice {
|
||||
public:
|
||||
InputDevice() : controller::InputDevice("Keyboard") {}
|
||||
private:
|
||||
// Device functions
|
||||
virtual controller::Input::NamedVector getAvailableInputs() const override;
|
||||
virtual QString getDefaultMappingConfig() const override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
// Let's make it easy for Qt because we assume we love Qt forever
|
||||
controller::Input makeInput(Qt::Key code) const;
|
||||
controller::Input makeInput(Qt::MouseButton code, bool clicked = false) const;
|
||||
controller::Input makeInput(MouseAxisChannel axis) const;
|
||||
controller::Input makeInput(TouchAxisChannel axis) const;
|
||||
controller::Input makeInput(TouchButtonChannel button) const;
|
||||
|
||||
friend class KeyboardMouseDevice;
|
||||
};
|
||||
|
||||
public:
|
||||
const std::shared_ptr<InputDevice>& getInputDevice() const { return _inputDevice; }
|
||||
|
||||
protected:
|
||||
QPoint _lastCursor;
|
||||
QPoint _mousePressAt;
|
||||
glm::vec2 _lastTouch;
|
||||
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>() };
|
||||
|
||||
bool _isTouching = false;
|
||||
|
||||
std::chrono::high_resolution_clock _clock;
|
||||
std::chrono::high_resolution_clock::time_point _lastTouchTime;
|
||||
};
|
||||
|
|
|
@ -30,6 +30,11 @@
|
|||
|
||||
#ifdef HAVE_SIXENSE
|
||||
#include "sixense.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
static QLibrary* _sixenseLibrary { nullptr };
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// TODO: This should not be here
|
||||
|
@ -39,13 +44,10 @@ Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins")
|
|||
|
||||
#ifdef HAVE_SIXENSE
|
||||
|
||||
const int CALIBRATION_STATE_IDLE = 0;
|
||||
const int CALIBRATION_STATE_IN_PROGRESS = 1;
|
||||
const int CALIBRATION_STATE_COMPLETE = 2;
|
||||
|
||||
const glm::vec3 DEFAULT_AVATAR_POSITION(-0.25f, -0.35f, -0.3f); // in hydra frame
|
||||
|
||||
const float CONTROLLER_THRESHOLD = 0.35f;
|
||||
const glm::vec3 SixenseManager::DEFAULT_AVATAR_POSITION { -0.25f, -0.35f, -0.3f }; // in hydra frame
|
||||
const float SixenseManager::CONTROLLER_THRESHOLD { 0.35f };
|
||||
const float SixenseManager::DEFAULT_REACH_LENGTH { 1.5f };
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -66,14 +68,6 @@ const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
|
|||
const QString TOGGLE_SMOOTH = "Smooth Sixense Movement";
|
||||
const float DEFAULT_REACH_LENGTH = 1.5f;
|
||||
|
||||
static std::shared_ptr<SixenseManager> instance;
|
||||
SixenseManager::SixenseManager() :
|
||||
InputDevice("Hydra"),
|
||||
_reachLength(DEFAULT_REACH_LENGTH)
|
||||
{
|
||||
instance = std::shared_ptr<SixenseManager>(this);
|
||||
}
|
||||
|
||||
bool SixenseManager::isSupported() const {
|
||||
#ifdef HAVE_SIXENSE
|
||||
|
||||
|
@ -91,8 +85,6 @@ bool SixenseManager::isSupported() const {
|
|||
void SixenseManager::activate() {
|
||||
InputPlugin::activate();
|
||||
#ifdef HAVE_SIXENSE
|
||||
_calibrationState = CALIBRATION_STATE_IDLE;
|
||||
_avatarPosition = DEFAULT_AVATAR_POSITION;
|
||||
|
||||
_container->addMenu(MENU_PATH);
|
||||
_container->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
|
||||
|
@ -100,7 +92,7 @@ void SixenseManager::activate() {
|
|||
true, true);
|
||||
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->registerDevice(instance);
|
||||
userInputMapper->registerDevice(_inputDevice);
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
|
@ -139,12 +131,12 @@ void SixenseManager::deactivate() {
|
|||
_container->removeMenuItem(MENU_NAME, TOGGLE_SMOOTH);
|
||||
_container->removeMenu(MENU_PATH);
|
||||
|
||||
_poseStateMap.clear();
|
||||
_collectedSamples.clear();
|
||||
_inputDevice->_poseStateMap.clear();
|
||||
_inputDevice->_collectedSamples.clear();
|
||||
|
||||
if (_deviceID != controller::Input::INVALID_DEVICE) {
|
||||
if (_inputDevice->_deviceID != controller::Input::INVALID_DEVICE) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->removeDevice(_deviceID);
|
||||
userInputMapper->removeDevice(_inputDevice->_deviceID);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
@ -170,7 +162,15 @@ void SixenseManager::setSixenseFilter(bool filter) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void SixenseManager::update(float deltaTime, bool jointsCaptured) {
|
||||
void SixenseManager::pluginUpdate(float deltaTime, bool jointsCaptured) {
|
||||
_inputDevice->update(deltaTime, jointsCaptured);
|
||||
if (_inputDevice->_calibrationState == CALIBRATION_STATE_COMPLETE) {
|
||||
_container->requestReset();
|
||||
_inputDevice->_calibrationState = CALIBRATION_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) {
|
||||
// FIXME - Some of the code in update() will crash if you haven't actually activated the
|
||||
// plugin. But we want register with the UserInputMapper if we don't call this.
|
||||
// We need to clean this up.
|
||||
|
@ -297,7 +297,7 @@ const float MINIMUM_ARM_REACH = 0.3f; // meters
|
|||
const float MAXIMUM_NOISE_LEVEL = 0.05f; // meters
|
||||
const quint64 LOCK_DURATION = USECS_PER_SECOND / 4; // time for lock to be acquired
|
||||
|
||||
void SixenseManager::updateCalibration(void* controllersX) {
|
||||
void SixenseManager::InputDevice::updateCalibration(void* controllersX) {
|
||||
auto controllers = reinterpret_cast<sixenseControllerData*>(controllersX);
|
||||
const sixenseControllerData* dataLeft = controllers;
|
||||
const sixenseControllerData* dataRight = controllers + 1;
|
||||
|
@ -309,26 +309,25 @@ void SixenseManager::updateCalibration(void* controllersX) {
|
|||
}
|
||||
switch (_calibrationState) {
|
||||
case CALIBRATION_STATE_COMPLETE:
|
||||
{
|
||||
// compute calibration results
|
||||
_avatarPosition = - 0.5f * (_reachLeft + _reachRight); // neck is midway between right and left hands
|
||||
glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft);
|
||||
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, Vectors::UNIT_Y));
|
||||
xAxis = glm::normalize(glm::cross(Vectors::UNIT_Y, zAxis));
|
||||
_reachLength = glm::dot(xAxis, _reachRight - _reachLeft);
|
||||
_avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis)));
|
||||
const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f;
|
||||
_avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR;
|
||||
_container->requestReset();
|
||||
qCDebug(inputplugins, "succeess: sixense calibration");
|
||||
}
|
||||
break;
|
||||
{
|
||||
// compute calibration results
|
||||
_avatarPosition = - 0.5f * (_reachLeft + _reachRight); // neck is midway between right and left hands
|
||||
glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft);
|
||||
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, Vectors::UNIT_Y));
|
||||
xAxis = glm::normalize(glm::cross(Vectors::UNIT_Y, zAxis));
|
||||
_reachLength = glm::dot(xAxis, _reachRight - _reachLeft);
|
||||
_avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis)));
|
||||
const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f;
|
||||
_avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR;
|
||||
qCDebug(inputplugins, "succeess: sixense calibration");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
_calibrationState = CALIBRATION_STATE_IDLE;
|
||||
qCDebug(inputplugins, "failed: sixense calibration");
|
||||
break;
|
||||
}
|
||||
|
||||
_calibrationState = CALIBRATION_STATE_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -382,15 +381,15 @@ void SixenseManager::updateCalibration(void* controllersX) {
|
|||
|
||||
#endif // HAVE_SIXENSE
|
||||
|
||||
void SixenseManager::focusOutEvent() {
|
||||
void SixenseManager::InputDevice::focusOutEvent() {
|
||||
_axisStateMap.clear();
|
||||
_buttonPressedMap.clear();
|
||||
};
|
||||
|
||||
void SixenseManager::handleAxisEvent(float stickX, float stickY, float trigger, bool left) {
|
||||
void SixenseManager::InputDevice::handleAxisEvent(float stickX, float stickY, float trigger, bool left) {
|
||||
}
|
||||
|
||||
void SixenseManager::handleButtonEvent(unsigned int buttons, bool left) {
|
||||
void SixenseManager::InputDevice::handleButtonEvent(unsigned int buttons, bool left) {
|
||||
using namespace controller;
|
||||
if (buttons & BUTTON_0) {
|
||||
_buttonPressedMap.insert(left ? BACK : START);
|
||||
|
@ -415,7 +414,7 @@ void SixenseManager::handleButtonEvent(unsigned int buttons, bool left) {
|
|||
}
|
||||
}
|
||||
|
||||
void SixenseManager::handlePoseEvent(float deltaTime, glm::vec3 position, glm::quat rotation, bool left) {
|
||||
void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, glm::vec3 position, glm::quat rotation, bool left) {
|
||||
#ifdef HAVE_SIXENSE
|
||||
auto hand = left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND;
|
||||
|
||||
|
@ -521,7 +520,7 @@ static const auto R4 = controller::Y;
|
|||
|
||||
using namespace controller;
|
||||
|
||||
controller::Input::NamedVector SixenseManager::getAvailableInputs() const {
|
||||
controller::Input::NamedVector SixenseManager::InputDevice::getAvailableInputs() const {
|
||||
using namespace controller;
|
||||
static const Input::NamedVector availableInputs {
|
||||
makePair(L0, "L0"),
|
||||
|
@ -551,7 +550,7 @@ controller::Input::NamedVector SixenseManager::getAvailableInputs() const {
|
|||
};
|
||||
|
||||
|
||||
QString SixenseManager::getDefaultMappingConfig() const {
|
||||
QString SixenseManager::InputDevice::getDefaultMappingConfig() const {
|
||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/hydra.json";
|
||||
return MAPPING_JSON;
|
||||
}
|
||||
|
@ -562,9 +561,9 @@ void SixenseManager::saveSettings() const {
|
|||
QString idString = getID();
|
||||
settings.beginGroup(idString);
|
||||
{
|
||||
settings.setVec3Value(QString("avatarPosition"), _avatarPosition);
|
||||
settings.setQuatValue(QString("avatarRotation"), _avatarRotation);
|
||||
settings.setValue(QString("reachLength"), QVariant(_reachLength));
|
||||
settings.setVec3Value(QString("avatarPosition"), _inputDevice->_avatarPosition);
|
||||
settings.setQuatValue(QString("avatarRotation"), _inputDevice->_avatarRotation);
|
||||
settings.setValue(QString("reachLength"), QVariant(_inputDevice->_reachLength));
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
@ -574,9 +573,9 @@ void SixenseManager::loadSettings() {
|
|||
QString idString = getID();
|
||||
settings.beginGroup(idString);
|
||||
{
|
||||
settings.getVec3ValueIfValid(QString("avatarPosition"), _avatarPosition);
|
||||
settings.getQuatValueIfValid(QString("avatarRotation"), _avatarRotation);
|
||||
settings.getFloatValueIfValid(QString("reachLength"), _reachLength);
|
||||
settings.getVec3ValueIfValid(QString("avatarPosition"), _inputDevice->_avatarPosition);
|
||||
settings.getQuatValueIfValid(QString("avatarRotation"), _inputDevice->_avatarRotation);
|
||||
settings.getFloatValueIfValid(QString("reachLength"), _inputDevice->_reachLength);
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
|
|
@ -44,11 +44,10 @@ const unsigned int BUTTON_TRIGGER = 1U << 8;
|
|||
const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
|
||||
|
||||
// Handles interaction with the Sixense SDK (e.g., Razer Hydra).
|
||||
class SixenseManager : public InputPlugin, public controller::InputDevice {
|
||||
class SixenseManager : public InputPlugin {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SixenseManager();
|
||||
|
||||
|
||||
// Plugin functions
|
||||
virtual bool isSupported() const override;
|
||||
virtual bool isJointController() const override { return true; }
|
||||
|
@ -58,15 +57,8 @@ public:
|
|||
virtual void activate() override;
|
||||
virtual void deactivate() override;
|
||||
|
||||
virtual void pluginFocusOutEvent() override { focusOutEvent(); }
|
||||
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
|
||||
|
||||
// Device functions
|
||||
virtual controller::Input::NamedVector getAvailableInputs() const override;
|
||||
virtual QString getDefaultMappingConfig() const override;
|
||||
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
|
||||
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override;
|
||||
|
||||
virtual void saveSettings() const override;
|
||||
virtual void loadSettings() override;
|
||||
|
@ -75,38 +67,57 @@ public slots:
|
|||
void setSixenseFilter(bool filter);
|
||||
|
||||
private:
|
||||
void handleButtonEvent(unsigned int buttons, bool left);
|
||||
void handleAxisEvent(float x, float y, float trigger, bool left);
|
||||
void handlePoseEvent(float deltaTime, glm::vec3 position, glm::quat rotation, bool left);
|
||||
|
||||
void updateCalibration(void* controllers);
|
||||
|
||||
int _calibrationState;
|
||||
|
||||
// these are calibration results
|
||||
glm::vec3 _avatarPosition; // in hydra-frame
|
||||
glm::quat _avatarRotation; // in hydra-frame
|
||||
float _reachLength;
|
||||
|
||||
// these are measured values used to compute the calibration results
|
||||
quint64 _lockExpiry;
|
||||
glm::vec3 _averageLeft;
|
||||
glm::vec3 _averageRight;
|
||||
glm::vec3 _reachLeft;
|
||||
glm::vec3 _reachRight;
|
||||
float _lastDistance;
|
||||
bool _useSixenseFilter = true;
|
||||
|
||||
|
||||
static const int MAX_NUM_AVERAGING_SAMPLES = 50; // At ~100 updates per seconds this means averaging over ~.5s
|
||||
static const int CALIBRATION_STATE_IDLE = 0;
|
||||
static const int CALIBRATION_STATE_IN_PROGRESS = 1;
|
||||
static const int CALIBRATION_STATE_COMPLETE = 2;
|
||||
static const glm::vec3 DEFAULT_AVATAR_POSITION;
|
||||
static const float CONTROLLER_THRESHOLD;
|
||||
static const float DEFAULT_REACH_LENGTH;
|
||||
|
||||
|
||||
using Samples = std::pair< MovingAverage< glm::vec3, MAX_NUM_AVERAGING_SAMPLES>, MovingAverage< glm::vec4, MAX_NUM_AVERAGING_SAMPLES> >;
|
||||
using MovingAverageMap = std::map< int, Samples >;
|
||||
MovingAverageMap _collectedSamples;
|
||||
|
||||
#ifdef __APPLE__
|
||||
QLibrary* _sixenseLibrary { nullptr };
|
||||
#endif
|
||||
|
||||
class InputDevice : public controller::InputDevice {
|
||||
public:
|
||||
InputDevice() : controller::InputDevice("Hydra") {}
|
||||
private:
|
||||
// Device functions
|
||||
virtual controller::Input::NamedVector getAvailableInputs() const override;
|
||||
virtual QString getDefaultMappingConfig() const override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
void handleButtonEvent(unsigned int buttons, bool left);
|
||||
void handleAxisEvent(float x, float y, float trigger, bool left);
|
||||
void handlePoseEvent(float deltaTime, glm::vec3 position, glm::quat rotation, bool left);
|
||||
void updateCalibration(void* controllers);
|
||||
|
||||
friend class SixenseManager;
|
||||
|
||||
MovingAverageMap _collectedSamples;
|
||||
|
||||
int _calibrationState { CALIBRATION_STATE_IDLE };
|
||||
// these are calibration results
|
||||
glm::vec3 _avatarPosition { DEFAULT_AVATAR_POSITION }; // in hydra-frame
|
||||
glm::quat _avatarRotation; // in hydra-frame
|
||||
|
||||
float _reachLength { DEFAULT_REACH_LENGTH };
|
||||
float _lastDistance;
|
||||
// these are measured values used to compute the calibration results
|
||||
quint64 _lockExpiry;
|
||||
glm::vec3 _averageLeft;
|
||||
glm::vec3 _averageRight;
|
||||
glm::vec3 _reachLeft;
|
||||
glm::vec3 _reachRight;
|
||||
};
|
||||
|
||||
|
||||
|
||||
bool _useSixenseFilter = true;
|
||||
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>() };
|
||||
|
||||
static const QString NAME;
|
||||
static const QString HYDRA_ID_STRING;
|
||||
};
|
||||
|
|
|
@ -21,11 +21,10 @@
|
|||
|
||||
const float MAX_AXIS = 75.0f; // max forward = 2x speed
|
||||
|
||||
static std::shared_ptr<SpacemouseDevice> instance;
|
||||
SpacemouseDevice::SpacemouseDevice() :
|
||||
InputDevice("Spacemouse")
|
||||
static std::shared_ptr<SpacemouseDevice> instance = std::make_shared<SpacemouseDevice>();
|
||||
|
||||
SpacemouseDevice::SpacemouseDevice() : InputDevice("Spacemouse")
|
||||
{
|
||||
instance = std::shared_ptr<SpacemouseDevice>(this);
|
||||
}
|
||||
|
||||
void SpacemouseDevice::focusOutEvent() {
|
||||
|
@ -118,14 +117,6 @@ void SpacemouseDevice::update(float deltaTime, bool jointsCaptured) {
|
|||
// for osx the api will call DeviceAddedHandler or DeviceRemoveHandler when a 3Dconnexion device is attached or detached
|
||||
}
|
||||
|
||||
SpacemouseManager& SpacemouseManager::getInstance() {
|
||||
static SpacemouseManager sharedInstance;
|
||||
if (instance == nullptr) {
|
||||
new SpacemouseDevice();
|
||||
}
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
void SpacemouseManager::ManagerFocusOutEvent() {
|
||||
instance->focusOutEvent();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
class SpacemouseManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static SpacemouseManager& getInstance();
|
||||
void ManagerFocusOutEvent();
|
||||
void init();
|
||||
void destroy() {};
|
||||
|
@ -92,7 +91,6 @@ class SpacemouseManager : public QObject, public QAbstractNativeEventFilter {
|
|||
public:
|
||||
SpacemouseManager() {};
|
||||
|
||||
static SpacemouseManager& getInstance();
|
||||
void init();
|
||||
void destroy();
|
||||
bool Is3dmouseAttached();
|
||||
|
@ -169,7 +167,6 @@ private:
|
|||
class SpacemouseManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static SpacemouseManager& getInstance();
|
||||
void init();
|
||||
void destroy();
|
||||
bool Is3dmouseAttached();
|
||||
|
|
|
@ -27,12 +27,13 @@
|
|||
#include <controllers/StandardControls.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
extern vr::IVRSystem* _hmd;
|
||||
extern int hmdRefCount;
|
||||
extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
|
||||
extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
|
||||
#endif
|
||||
|
||||
vr::IVRSystem* acquireOpenVrSystem();
|
||||
void releaseOpenVrSystem();
|
||||
|
||||
|
||||
const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
|
||||
const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
|
||||
|
@ -44,28 +45,11 @@ const QString MENU_NAME = "Vive Controllers";
|
|||
const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
|
||||
const QString RENDER_CONTROLLERS = "Render Hand Controllers";
|
||||
|
||||
static std::shared_ptr<ViveControllerManager> instance;
|
||||
|
||||
ViveControllerManager::ViveControllerManager() :
|
||||
InputDevice("Vive"),
|
||||
_trackedControllers(0),
|
||||
_modelLoaded(false),
|
||||
_leftHandRenderID(0),
|
||||
_rightHandRenderID(0),
|
||||
_renderControllers(false)
|
||||
{
|
||||
instance = std::shared_ptr<ViveControllerManager>(this);
|
||||
}
|
||||
|
||||
bool ViveControllerManager::isSupported() const {
|
||||
#ifdef Q_OS_WIN
|
||||
bool success = vr::VR_IsHmdPresent();
|
||||
if (success) {
|
||||
vr::HmdError eError = vr::HmdError_None;
|
||||
auto hmd = vr::VR_Init(&eError);
|
||||
success = (hmd != nullptr);
|
||||
vr::VR_Shutdown();
|
||||
}
|
||||
auto hmd = acquireOpenVrSystem();
|
||||
bool success = hmd != nullptr;
|
||||
releaseOpenVrSystem();
|
||||
return success;
|
||||
#else
|
||||
return false;
|
||||
|
@ -80,11 +64,8 @@ void ViveControllerManager::activate() {
|
|||
[this] (bool clicked) { this->setRenderControllers(clicked); },
|
||||
true, true);
|
||||
|
||||
hmdRefCount++;
|
||||
if (!_hmd) {
|
||||
vr::HmdError eError = vr::HmdError_None;
|
||||
_hmd = vr::VR_Init(&eError);
|
||||
Q_ASSERT(eError == vr::HmdError_None);
|
||||
_hmd = acquireOpenVrSystem();
|
||||
}
|
||||
Q_ASSERT(_hmd);
|
||||
|
||||
|
@ -138,7 +119,7 @@ void ViveControllerManager::activate() {
|
|||
|
||||
// unregister with UserInputMapper
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->registerDevice(instance);
|
||||
userInputMapper->registerDevice(_inputDevice);
|
||||
_registeredWithInputMapper = true;
|
||||
}
|
||||
|
||||
|
@ -149,18 +130,17 @@ void ViveControllerManager::deactivate() {
|
|||
_container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
|
||||
_container->removeMenu(MENU_PATH);
|
||||
|
||||
hmdRefCount--;
|
||||
|
||||
if (hmdRefCount == 0 && _hmd) {
|
||||
vr::VR_Shutdown();
|
||||
if (_hmd) {
|
||||
releaseOpenVrSystem();
|
||||
_hmd = nullptr;
|
||||
}
|
||||
_poseStateMap.clear();
|
||||
|
||||
_inputDevice->_poseStateMap.clear();
|
||||
#endif
|
||||
|
||||
// unregister with UserInputMapper
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->removeDevice(_deviceID);
|
||||
userInputMapper->removeDevice(_inputDevice->_deviceID);
|
||||
_registeredWithInputMapper = false;
|
||||
}
|
||||
|
||||
|
@ -177,8 +157,8 @@ void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePoint
|
|||
//pendingChanges.updateItem(_leftHandRenderID, );
|
||||
|
||||
|
||||
controller::Pose leftHand = _poseStateMap[controller::StandardPoseChannel::LEFT_HAND];
|
||||
controller::Pose rightHand = _poseStateMap[controller::StandardPoseChannel::RIGHT_HAND];
|
||||
controller::Pose leftHand = _inputDevice->_poseStateMap[controller::StandardPoseChannel::LEFT_HAND];
|
||||
controller::Pose rightHand = _inputDevice->_poseStateMap[controller::StandardPoseChannel::RIGHT_HAND];
|
||||
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
@ -223,15 +203,28 @@ void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch&
|
|||
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
|
||||
}
|
||||
|
||||
void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
|
||||
|
||||
void ViveControllerManager::pluginUpdate(float deltaTime, bool jointsCaptured) {
|
||||
_inputDevice->update(deltaTime, jointsCaptured);
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
|
||||
if (_inputDevice->_trackedControllers == 0 && _registeredWithInputMapper) {
|
||||
userInputMapper->removeDevice(_inputDevice->_deviceID);
|
||||
_registeredWithInputMapper = false;
|
||||
_inputDevice->_poseStateMap.clear();
|
||||
}
|
||||
|
||||
if (!_registeredWithInputMapper && _inputDevice->_trackedControllers > 0) {
|
||||
userInputMapper->registerDevice(_inputDevice);
|
||||
_registeredWithInputMapper = true;
|
||||
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "steamVR");
|
||||
}
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::update(float deltaTime, bool jointsCaptured) {
|
||||
#ifdef Q_OS_WIN
|
||||
_poseStateMap.clear();
|
||||
|
||||
// TODO: This shouldn't be necessary
|
||||
if (!_hmd) {
|
||||
return;
|
||||
}
|
||||
|
||||
_buttonPressedMap.clear();
|
||||
|
||||
PerformanceTimer perfTimer("ViveControllerManager::update");
|
||||
|
@ -279,33 +272,17 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
|
|||
}
|
||||
}
|
||||
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
|
||||
if (numTrackedControllers == 0) {
|
||||
if (_registeredWithInputMapper) {
|
||||
userInputMapper->removeDevice(_deviceID);
|
||||
_registeredWithInputMapper = false;
|
||||
_poseStateMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (_trackedControllers == 0 && numTrackedControllers > 0) {
|
||||
userInputMapper->registerDevice(instance);
|
||||
_registeredWithInputMapper = true;
|
||||
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "steamVR");
|
||||
}
|
||||
|
||||
_trackedControllers = numTrackedControllers;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ViveControllerManager::focusOutEvent() {
|
||||
void ViveControllerManager::InputDevice::focusOutEvent() {
|
||||
_axisStateMap.clear();
|
||||
_buttonPressedMap.clear();
|
||||
};
|
||||
|
||||
// These functions do translation from the Steam IDs to the standard controller IDs
|
||||
void ViveControllerManager::handleAxisEvent(uint32_t axis, float x, float y, bool left) {
|
||||
void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool left) {
|
||||
#ifdef Q_OS_WIN
|
||||
//FIX ME? It enters here every frame: probably we want to enter only if an event occurs
|
||||
axis += vr::k_EButton_Axis0;
|
||||
|
@ -320,7 +297,7 @@ void ViveControllerManager::handleAxisEvent(uint32_t axis, float x, float y, boo
|
|||
}
|
||||
|
||||
// These functions do translation from the Steam IDs to the standard controller IDs
|
||||
void ViveControllerManager::handleButtonEvent(uint32_t button, bool pressed, bool left) {
|
||||
void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool left) {
|
||||
#ifdef Q_OS_WIN
|
||||
if (!pressed) {
|
||||
return;
|
||||
|
@ -342,7 +319,7 @@ void ViveControllerManager::handleButtonEvent(uint32_t button, bool pressed, boo
|
|||
#endif
|
||||
}
|
||||
|
||||
void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) {
|
||||
void ViveControllerManager::InputDevice::handlePoseEvent(const mat4& mat, bool left) {
|
||||
glm::vec3 position = extractTranslation(mat);
|
||||
glm::quat rotation = glm::quat_cast(mat);
|
||||
|
||||
|
@ -409,7 +386,7 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) {
|
|||
_poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = controller::Pose(position, rotation);
|
||||
}
|
||||
|
||||
controller::Input::NamedVector ViveControllerManager::getAvailableInputs() const {
|
||||
controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const {
|
||||
using namespace controller;
|
||||
QVector<Input::NamedPair> availableInputs{
|
||||
// Trackpad analogs
|
||||
|
@ -450,7 +427,7 @@ controller::Input::NamedVector ViveControllerManager::getAvailableInputs() const
|
|||
return availableInputs;
|
||||
}
|
||||
|
||||
QString ViveControllerManager::getDefaultMappingConfig() const {
|
||||
QString ViveControllerManager::InputDevice::getDefaultMappingConfig() const {
|
||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json";
|
||||
return MAPPING_JSON;
|
||||
}
|
||||
|
|
|
@ -24,10 +24,13 @@
|
|||
#include <RenderArgs.h>
|
||||
#include <render/Scene.h>
|
||||
|
||||
class ViveControllerManager : public InputPlugin, public controller::InputDevice {
|
||||
namespace vr {
|
||||
class IVRSystem;
|
||||
}
|
||||
|
||||
class ViveControllerManager : public InputPlugin {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ViveControllerManager();
|
||||
|
||||
// Plugin functions
|
||||
virtual bool isSupported() const override;
|
||||
|
@ -37,40 +40,51 @@ public:
|
|||
virtual void activate() override;
|
||||
virtual void deactivate() override;
|
||||
|
||||
virtual void pluginFocusOutEvent() override { focusOutEvent(); }
|
||||
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); }
|
||||
|
||||
// Device functions
|
||||
virtual controller::Input::NamedVector getAvailableInputs() const override;
|
||||
virtual QString getDefaultMappingConfig() const override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
|
||||
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override;
|
||||
|
||||
void updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges);
|
||||
|
||||
void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; }
|
||||
|
||||
private:
|
||||
class InputDevice : public controller::InputDevice {
|
||||
public:
|
||||
InputDevice(vr::IVRSystem*& hmd) : controller::InputDevice("Vive"), _hmd(hmd) {}
|
||||
private:
|
||||
// Device functions
|
||||
virtual controller::Input::NamedVector getAvailableInputs() const override;
|
||||
virtual QString getDefaultMappingConfig() const override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
void handleButtonEvent(uint32_t button, bool pressed, bool left);
|
||||
void handleAxisEvent(uint32_t axis, float x, float y, bool left);
|
||||
void handlePoseEvent(const mat4& mat, bool left);
|
||||
|
||||
int _trackedControllers { 0 };
|
||||
vr::IVRSystem*& _hmd;
|
||||
friend class ViveControllerManager;
|
||||
};
|
||||
|
||||
void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
|
||||
|
||||
void handleButtonEvent(uint32_t button, bool pressed, bool left);
|
||||
void handleAxisEvent(uint32_t axis, float x, float y, bool left);
|
||||
void handlePoseEvent(const mat4& mat, bool left);
|
||||
|
||||
int _trackedControllers;
|
||||
|
||||
bool _modelLoaded;
|
||||
bool _registeredWithInputMapper { false };
|
||||
bool _modelLoaded { false };
|
||||
model::Geometry _modelGeometry;
|
||||
gpu::TexturePointer _texture;
|
||||
|
||||
int _leftHandRenderID;
|
||||
int _rightHandRenderID;
|
||||
int _leftHandRenderID { 0 };
|
||||
int _rightHandRenderID { 0 };
|
||||
|
||||
bool _renderControllers;
|
||||
bool _renderControllers { false };
|
||||
vr::IVRSystem* _hmd { nullptr };
|
||||
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_hmd) };
|
||||
|
||||
static const QString NAME;
|
||||
|
||||
bool _registeredWithInputMapper { false };
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -79,8 +79,13 @@ EntityMotionState::~EntityMotionState() {
|
|||
assert(!_entity);
|
||||
}
|
||||
|
||||
void EntityMotionState::updateServerPhysicsVariables() {
|
||||
void EntityMotionState::updateServerPhysicsVariables(const QUuid& sessionID) {
|
||||
assert(entityTreeIsLocked());
|
||||
if (_entity->getSimulatorID() == sessionID) {
|
||||
// don't slam these values if we are the simulation owner
|
||||
return;
|
||||
}
|
||||
|
||||
_serverPosition = _entity->getPosition();
|
||||
_serverRotation = _entity->getRotation();
|
||||
_serverVelocity = _entity->getVelocity();
|
||||
|
@ -92,7 +97,7 @@ void EntityMotionState::updateServerPhysicsVariables() {
|
|||
// virtual
|
||||
bool EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) {
|
||||
assert(entityTreeIsLocked());
|
||||
updateServerPhysicsVariables();
|
||||
updateServerPhysicsVariables(engine->getSessionID());
|
||||
ObjectMotionState::handleEasyChanges(flags, engine);
|
||||
|
||||
if (flags & Simulation::DIRTY_SIMULATOR_ID) {
|
||||
|
@ -129,7 +134,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine)
|
|||
|
||||
// virtual
|
||||
bool EntityMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) {
|
||||
updateServerPhysicsVariables();
|
||||
updateServerPhysicsVariables(engine->getSessionID());
|
||||
return ObjectMotionState::handleHardAndEasyChanges(flags, engine);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
EntityMotionState(btCollisionShape* shape, EntityItemPointer item);
|
||||
virtual ~EntityMotionState();
|
||||
|
||||
void updateServerPhysicsVariables();
|
||||
void updateServerPhysicsVariables(const QUuid& sessionID);
|
||||
virtual bool handleEasyChanges(uint32_t flags, PhysicsEngine* engine);
|
||||
virtual bool handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine);
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ int main(int argc, char** argv) {
|
|||
inputPlugin->activate();
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
if (name == KeyboardMouseDevice::NAME) {
|
||||
userInputMapper->registerDevice(std::dynamic_pointer_cast<KeyboardMouseDevice>(inputPlugin));
|
||||
userInputMapper->registerDevice(std::dynamic_pointer_cast<KeyboardMouseDevice>(inputPlugin)->getInputDevice());
|
||||
}
|
||||
inputPlugin->pluginUpdate(0, false);
|
||||
}
|
||||
|
|
|
@ -927,9 +927,8 @@
|
|||
}
|
||||
|
||||
function createWand(position) {
|
||||
var WAND_MODEL = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/wand.fbx';
|
||||
var WAND_COLLISION_SHAPE = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/actual_no_top_collision_hull.obj';
|
||||
|
||||
var WAND_MODEL = 'http://hifi-public.s3.amazonaws.com/models/bubblewand/wand.fbx';
|
||||
var WAND_COLLISION_SHAPE = 'http://hifi-public.s3.amazonaws.com/models/bubblewand/actual_no_top_collision_hull.obj';
|
||||
var entity = Entities.addEntity({
|
||||
name: 'Bubble Wand',
|
||||
type: "Model",
|
||||
|
|
|
@ -909,8 +909,8 @@ MasterReset = function() {
|
|||
}
|
||||
|
||||
function createWand(position) {
|
||||
var WAND_MODEL = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/wand.fbx';
|
||||
var WAND_COLLISION_SHAPE = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/actual_no_top_collision_hull.obj';
|
||||
var WAND_MODEL = 'http://hifi-public.s3.amazonaws.com/models/bubblewand/wand.fbx';
|
||||
var WAND_COLLISION_SHAPE = 'http://hifi-public.s3.amazonaws.com/models/bubblewand/actual_no_top_collision_hull.obj';
|
||||
|
||||
var entity = Entities.addEntity({
|
||||
name: 'Bubble Wand',
|
||||
|
|
Loading…
Reference in a new issue