Merge branch 'master' of https://github.com/worklist/hifi into js-hmd-position-orientation

Conflicts:
	interface/src/Application.cpp
	interface/src/scripting/HMDScriptingInterface.h
	libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h
This commit is contained in:
Thijs Wenker 2015-10-06 20:06:29 +02:00
commit 953ff6caa7
32 changed files with 477 additions and 355 deletions

View file

@ -79,8 +79,8 @@ var STATE_NEAR_GRABBING_NON_COLLIDING = 6;
var STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING = 7;
var STATE_RELEASE = 8;
var GRAB_USER_DATA_KEY = "grabKey";
var GRABBABLE_DATA_KEY = "grabbableKey";
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js
function getTag() {
return "grab-" + MyAvatar.sessionUUID;
@ -312,7 +312,8 @@ function MyController(hand, triggerAction) {
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]);
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation",
"gravity", "ignoreForCollisions"]);
// add the action and initialize some variables
this.currentObjectPosition = grabbedProperties.position;
@ -336,7 +337,7 @@ function MyController(hand, triggerAction) {
if (this.actionID !== null) {
this.setState(STATE_CONTINUE_DISTANCE_HOLDING);
this.activateEntity(this.grabbedEntity);
this.activateEntity(this.grabbedEntity, grabbedProperties);
if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
} else {
@ -439,9 +440,9 @@ function MyController(hand, triggerAction) {
this.lineOff();
this.activateEntity(this.grabbedEntity);
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]);
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity,
["position", "rotation", "gravity", "ignoreForCollisions"]);
this.activateEntity(this.grabbedEntity, grabbedProperties);
var handRotation = this.getHandRotation();
var handPosition = this.getHandPosition();
@ -454,7 +455,7 @@ function MyController(hand, triggerAction) {
var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset);
this.actionID = NULL_ACTION_ID;
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
this.actionID = Entities.addAction("kinematic-hold", this.grabbedEntity, {
hand: this.hand === RIGHT_HAND ? "right" : "left",
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
relativePosition: offsetPosition,
@ -640,20 +641,35 @@ function MyController(hand, triggerAction) {
this.release();
};
this.activateEntity = function() {
var data = {
activated: true,
avatarId: MyAvatar.sessionUUID
};
setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data);
this.activateEntity = function(entityID, grabbedProperties) {
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
data["activated"] = true;
data["avatarId"] = MyAvatar.sessionUUID;
data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1;
// zero gravity and set ignoreForCollisions to true, but in a way that lets us put them back, after all grabs are done
if (data["refCount"] == 1) {
data["gravity"] = grabbedProperties.gravity;
data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
Entities.editEntity(entityID, {gravity: {x:0, y:0, z:0}, ignoreForCollisions: true});
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
this.deactivateEntity = function() {
var data = {
activated: false,
avatarId: null
};
setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data);
this.deactivateEntity = function(entityID) {
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
if (data && data["refCount"]) {
data["refCount"] = data["refCount"] - 1;
if (data["refCount"] < 1) {
Entities.editEntity(entityID, {
gravity: data["gravity"],
ignoreForCollisions: data["ignoreForCollisions"]
});
data = null;
}
} else {
data = null;
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
}

View file

@ -1,42 +0,0 @@
//
// Created by Bradley Austin Davis on 2015/10/04
// Copyright 2013-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
//
IPDScalingTest = function() {
// Switch every 5 seconds between normal IPD and 0 IPD (in seconds)
this.UPDATE_INTERVAL = 10.0;
this.lastUpdateInterval = 0;
this.scaled = false;
var that = this;
Script.scriptEnding.connect(function() {
that.onCleanup();
});
Script.update.connect(function(deltaTime) {
that.lastUpdateInterval += deltaTime;
if (that.lastUpdateInterval >= that.UPDATE_INTERVAL) {
that.onUpdate(that.lastUpdateInterval);
that.lastUpdateInterval = 0;
}
});
}
IPDScalingTest.prototype.onCleanup = function() {
HMD.setIPDScale(1.0);
}
IPDScalingTest.prototype.onUpdate = function(deltaTime) {
this.scaled = !this.scaled;
if (this.scaled) {
HMD.ipdScale = 0.0;
} else {
HMD.ipdScale = 1.0;
}
}
new IPDScalingTest();

View file

@ -26,7 +26,8 @@ var IDENTITY_QUAT = {
z: 0,
w: 0
};
var GRABBABLE_DATA_KEY = "grabbableKey";
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with handControllerGrab.js
var GRAB_USER_DATA_KEY = "grabKey"; // shared with handControllerGrab.js
var defaultGrabbableData = {
grabbable: true
@ -247,7 +248,6 @@ Grabber = function() {
this.currentPosition = ZERO_VEC3;
this.planeNormal = ZERO_VEC3;
this.originalGravity = ZERO_VEC3;
// maxDistance is a function of the size of the object.
this.maxDistance;
@ -346,14 +346,11 @@ Grabber.prototype.pressEvent = function(event) {
return;
}
Entities.editEntity(clickedEntity, {
gravity: ZERO_VEC3
});
this.activateEntity(clickedEntity, entityProperties);
this.isGrabbing = true;
this.entityID = clickedEntity;
this.currentPosition = entityProperties.position;
this.originalGravity = entityProperties.gravity;
this.targetPosition = {
x: this.startPosition.x,
y: this.startPosition.y,
@ -379,12 +376,7 @@ Grabber.prototype.pressEvent = function(event) {
Grabber.prototype.releaseEvent = function() {
if (this.isGrabbing) {
if (Vec3.length(this.originalGravity) != 0) {
Entities.editEntity(this.entityID, {
gravity: this.originalGravity
});
}
this.deactivateEntity(this.entityID);
this.isGrabbing = false
Entities.deleteAction(this.entityID, this.actionID);
this.actionID = null;
@ -503,6 +495,39 @@ Grabber.prototype.keyPressEvent = function(event) {
this.computeNewGrabPlane();
}
Grabber.prototype.activateEntity = function(entityID, grabbedProperties) {
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
data["activated"] = true;
data["avatarId"] = MyAvatar.sessionUUID;
data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1;
// zero gravity and set ignoreForCollisions to true, but in a way that lets us put them back, after all grabs are done
if (data["refCount"] == 1) {
data["gravity"] = grabbedProperties.gravity;
data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
Entities.editEntity(entityID, {gravity: {x:0, y:0, z:0}, ignoreForCollisions: true});
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
Grabber.prototype.deactivateEntity = function(entityID) {
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
if (data && data["refCount"]) {
data["refCount"] = data["refCount"] - 1;
if (data["refCount"] < 1) {
Entities.editEntity(entityID, {
gravity: data["gravity"],
ignoreForCollisions: data["ignoreForCollisions"]
});
data = null;
}
} else {
data = null;
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
var grabber = new Grabber();
function pressEvent(event) {

View file

@ -79,13 +79,21 @@ getEntityUserData = function(id) {
// Non-destructively modify the user data of an entity.
setEntityCustomData = function(customKey, id, data) {
var userData = getEntityUserData(id);
userData[customKey] = data;
if (data == null) {
delete userData[customKey];
} else {
userData[customKey] = data;
}
setEntityUserData(id, userData);
}
getEntityCustomData = function(customKey, id, defaultValue) {
var userData = getEntityUserData(id);
return userData[customKey] ? userData[customKey] : defaultValue;
if (undefined != userData[customKey]) {
return userData[customKey];
} else {
return defaultValue;
}
}
mergeObjects = function(proto, custom) {

View file

@ -13,8 +13,8 @@ Script.include("../../utilities.js");
var scriptURL = Script.resolvePath('pingPongGun.js');
var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx'
var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_collision_hull.obj';
var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx?123'
var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_collision_hull.obj?123';
var center = Vec3.sum(Vec3.sum(MyAvatar.position, {
x: 0,
@ -25,14 +25,15 @@ var center = Vec3.sum(Vec3.sum(MyAvatar.position, {
var pingPongGun = Entities.addEntity({
type: "Model",
modelURL: MODEL_URL,
shapeType: 'compound',
compoundShapeURL: COLLISION_HULL_URL,
shapeType:'box',
// shapeType: 'compound',
// compoundShapeURL: COLLISION_HULL_URL,
script: scriptURL,
position: center,
dimensions: {
x:0.67,
y: 0.14,
z: 0.09
x: 0.08,
y: 0.21,
z: 0.47
},
collisionsWillMove: true,
});
@ -40,4 +41,4 @@ var pingPongGun = Entities.addEntity({
function cleanUp() {
Entities.deleteEntity(pingPongGun);
}
Script.scriptEnding.connect(cleanUp);
Script.scriptEnding.connect(cleanUp);

View file

@ -21,14 +21,14 @@
//if the trigger value goes below this value, reload the gun.
var RELOAD_THRESHOLD = 0.95;
var GUN_TIP_FWD_OFFSET = 0.45;
var GUN_TIP_FWD_OFFSET =-0.35;
var GUN_TIP_UP_OFFSET = 0.040;
var GUN_FORCE = 15;
var GUN_FORCE = 9;
var BALL_RESTITUTION = 0.6;
var BALL_LINEAR_DAMPING = 0.4;
var BALL_GRAVITY = {
x: 0,
y: -9.8,
y: -4.8,
z: 0
};
@ -36,14 +36,14 @@
x: 0.04,
y: 0.04,
z: 0.04
}
};
var BALL_COLOR = {
red: 255,
green: 255,
blue: 255
}
};
PingPongGun.prototype = {
hand: null,
@ -68,7 +68,6 @@
},
continueNearGrab: function() {
if (this.whichHand === null) {
//only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten
this.setWhichHand();
@ -81,10 +80,14 @@
},
releaseGrab: function() {
var _t = this;
this.canShootTimeout = Script.setTimeout(function() {
_t.canShoot = false;
}, 250)
var _this = this;
if (this.whichHand === this.hand) {
this.whichHand = null;
this.canShootTimeout = Script.setTimeout(function() {
_this.canShoot = false;
}, 250);
}
},
checkTriggerPressure: function(gunHand) {
@ -97,18 +100,20 @@
if (this.triggerValue < RELOAD_THRESHOLD) {
// print('RELOAD');
this.canShoot = true;
} else if (this.triggerValue >= RELOAD_THRESHOLD && this.canShoot === true) {
} else if (this.triggerValue >= RELOAD_THRESHOLD && this.canShoot === true && this.hand === this.whichHand) {
var gunProperties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
this.shootBall(gunProperties);
this.canShoot = false;
}
return;
},
shootBall: function(gunProperties) {
var forwardVec = Quat.getFront(Quat.multiply(gunProperties.rotation, Quat.fromPitchYawRollDegrees(0, -90, 0)));
var forwardVec = Quat.getFront(Quat.multiply(gunProperties.rotation, Quat.fromPitchYawRollDegrees(0, 180, 0)));
forwardVec = Vec3.normalize(forwardVec);
forwardVec = Vec3.multiply(forwardVec, GUN_FORCE);
var properties = {
type: 'Sphere',
color: BALL_COLOR,
@ -130,7 +135,7 @@
playSoundAtCurrentPosition: function(position) {
var audioProperties = {
volume: 0.1,
volume: 0.2,
position: position
};
@ -139,12 +144,14 @@
getGunTipPosition: function(properties) {
//the tip of the gun is going to be in a different place than the center, so we move in space relative to the model to find that position
var frontVector = Quat.getRight(properties.rotation);
var frontVector = Quat.getFront(properties.rotation);
var frontOffset = Vec3.multiply(frontVector, GUN_TIP_FWD_OFFSET);
var upVector = Quat.getRight(properties.rotation);
var upVector = Quat.getUp(properties.rotation);
var upOffset = Vec3.multiply(upVector, GUN_TIP_UP_OFFSET);
var gunTipPosition = Vec3.sum(properties.position, frontOffset);
gunTipPosition = Vec3.sum(gunTipPosition, upOffset);
return gunTipPosition;
},

View file

@ -300,7 +300,6 @@ bool setupEssentials(int& argc, char** argv) {
auto desktopScriptingInterface = DependencyManager::set<DesktopScriptingInterface>();
auto entityScriptingInterface = DependencyManager::set<EntityScriptingInterface>();
auto windowScriptingInterface = DependencyManager::set<WindowScriptingInterface>();
auto hmdScriptingInterface = DependencyManager::set<HMDScriptingInterface>();
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
auto speechRecognizer = DependencyManager::set<SpeechRecognizer>();
#endif
@ -1204,11 +1203,9 @@ void Application::paintGL() {
// right eye. There are FIXMEs in the relevant plugins
_myCamera.setProjection(displayPlugin->getProjection(Mono, _myCamera.getProjection()));
renderArgs._context->enableStereo(true);
mat4 eyeOffsets[2];
mat4 eyeViews[2];
mat4 eyeProjections[2];
auto baseProjection = renderArgs._viewFrustum->getProjection();
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
float IPDScale = hmdInterface->getIPDScale();
// FIXME we probably don't need to set the projection matrix every frame,
// only when the display plugin changes (or in non-HMD modes when the user
// changes the FOV manually, which right now I don't think they can.
@ -1217,24 +1214,14 @@ void Application::paintGL() {
// applied to the avatar, so we need to get the difference between the head
// pose applied to the avatar and the per eye pose, and use THAT as
// the per-eye stereo matrix adjustment.
mat4 eyeToHead = displayPlugin->getEyeToHeadTransform(eye);
// Grab the translation
vec3 eyeOffset = extractTranslation(eyeToHead);
// Apply IPD scaling
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale);
eyeOffsets[eye] = eyeOffsetTransform;
// Tell the plugin what pose we're using to render. In this case we're just using the
// unmodified head pose because the only plugin that cares (the Oculus plugin) uses it
// for rotational timewarp. If we move to support positonal timewarp, we need to
// ensure this contains the full pose composed with the eye offsets.
mat4 eyePose = displayPlugin->getEyePose(eye);
mat4 headPose = displayPlugin->getHeadPose();
displayPlugin->setEyeRenderPose(eye, headPose);
mat4 eyeView = glm::inverse(eyePose) * headPose;
eyeViews[eye] = eyeView;
eyeProjections[eye] = displayPlugin->getProjection(eye, baseProjection);
});
renderArgs._context->setStereoProjections(eyeProjections);
renderArgs._context->setStereoViews(eyeOffsets);
renderArgs._context->setStereoViews(eyeViews);
}
displaySide(&renderArgs, _myCamera);
renderArgs._context->enableStereo(false);
@ -4143,7 +4130,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("Paths", DependencyManager::get<PathUtils>().data());
scriptEngine->registerGlobalObject("HMD", DependencyManager::get<HMDScriptingInterface>().data());
scriptEngine->registerGlobalObject("HMD", &HMDScriptingInterface::getInstance());
scriptEngine->registerFunction("HMD", "getHUDLookAtPosition2D", HMDScriptingInterface::getHUDLookAtPosition2D, 0);
scriptEngine->registerFunction("HMD", "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0);
@ -4993,25 +4980,19 @@ mat4 Application::getEyeProjection(int eye) const {
mat4 Application::getEyePose(int eye) const {
if (isHMDMode()) {
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
float IPDScale = hmdInterface->getIPDScale();
auto displayPlugin = getActiveDisplayPlugin();
mat4 headPose = displayPlugin->getHeadPose();
mat4 eyeToHead = displayPlugin->getEyeToHeadTransform((Eye)eye);
{
vec3 eyeOffset = extractTranslation(eyeToHead);
// Apply IPD scaling
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale);
eyeToHead[3] = vec4(eyeOffset, 1.0);
return getActiveDisplayPlugin()->getEyePose((Eye)eye);
}
return eyeToHead * headPose;
}
return mat4();
}
mat4 Application::getEyeOffset(int eye) const {
// FIXME invert?
return getActiveDisplayPlugin()->getEyeToHeadTransform((Eye)eye);
if (isHMDMode()) {
mat4 identity;
return getActiveDisplayPlugin()->getView((Eye)eye, identity);
}
return mat4();
}
mat4 Application::getHMDSensorPose() const {

View file

@ -12,6 +12,7 @@
#include <avatar/AvatarActionHold.h>
#include <avatar/AvatarActionKinematicHold.h>
#include <ObjectActionOffset.h>
#include <ObjectActionSpring.h>
@ -28,6 +29,8 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& i
return (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);
case ACTION_TYPE_HOLD:
return (EntityActionPointer) new AvatarActionHold(id, ownerEntity);
case ACTION_TYPE_KINEMATIC_HOLD:
return (EntityActionPointer) new AvatarActionKinematicHold(id, ownerEntity);
}
assert(false);

View file

@ -16,9 +16,6 @@ PluginContainerProxy::PluginContainerProxy() {
Plugin::setContainer(this);
}
PluginContainerProxy::~PluginContainerProxy() {
}
bool PluginContainerProxy::isForeground() {
return qApp->_isForeground && !qApp->getWindow()->isMinimized();
}
@ -154,7 +151,3 @@ void PluginContainerProxy::showDisplayPluginsTools() {
QGLWidget* PluginContainerProxy::getPrimarySurface() {
return qApp->_glWidget;
}
const DisplayPlugin* PluginContainerProxy::getActiveDisplayPlugin() const {
return qApp->getActiveDisplayPlugin();
}

View file

@ -11,7 +11,6 @@
class PluginContainerProxy : public QObject, PluginContainer {
Q_OBJECT
PluginContainerProxy();
virtual ~PluginContainerProxy();
virtual void addMenu(const QString& menuName) override;
virtual void removeMenu(const QString& menuName) override;
virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override;
@ -24,8 +23,6 @@ class PluginContainerProxy : public QObject, PluginContainer {
virtual void requestReset() override;
virtual QGLWidget* getPrimarySurface() override;
virtual bool isForeground() override;
virtual const DisplayPlugin* getActiveDisplayPlugin() const override;
QRect _savedGeometry{ 10, 120, 800, 600 };
friend class Application;

View file

@ -0,0 +1,188 @@
//
// AvatarActionKinematicHold.cpp
// interface/src/avatar/
//
// Created by Seth Alves 2015-6-9
// 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 "QVariantGLM.h"
#include "avatar/MyAvatar.h"
#include "avatar/AvatarManager.h"
#include "AvatarActionKinematicHold.h"
const uint16_t AvatarActionKinematicHold::holdVersion = 1;
AvatarActionKinematicHold::AvatarActionKinematicHold(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectActionSpring(id, ownerEntity),
_relativePosition(glm::vec3(0.0f)),
_relativeRotation(glm::quat()),
_hand("right"),
_mine(false),
_previousPositionalTarget(Vectors::ZERO),
_previousRotationalTarget(Quaternions::IDENTITY)
{
_type = ACTION_TYPE_KINEMATIC_HOLD;
#if WANT_DEBUG
qDebug() << "AvatarActionKinematicHold::AvatarActionKinematicHold";
#endif
}
AvatarActionKinematicHold::~AvatarActionKinematicHold() {
#if WANT_DEBUG
qDebug() << "AvatarActionKinematicHold::~AvatarActionKinematicHold";
#endif
}
void AvatarActionKinematicHold::updateActionWorker(float deltaTimeStep) {
if (!_mine) {
// if a local script isn't updating this, then we are just getting spring-action data over the wire.
// let the super-class handle it.
ObjectActionSpring::updateActionWorker(deltaTimeStep);
return;
}
assert(deltaTimeStep > 0.0f);
glm::quat rotation;
glm::vec3 position;
glm::vec3 offset;
bool gotLock = withTryReadLock([&]{
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::vec3 palmPosition;
glm::quat palmRotation;
if (_hand == "right") {
palmPosition = myAvatar->getRightPalmPosition();
palmRotation = myAvatar->getRightPalmRotation();
} else {
palmPosition = myAvatar->getLeftPalmPosition();
palmRotation = myAvatar->getLeftPalmRotation();
}
rotation = palmRotation * _relativeRotation;
offset = rotation * _relativePosition;
position = palmPosition + offset;
});
if (gotLock) {
gotLock = withTryWriteLock([&]{
if (_positionalTarget != position || _rotationalTarget != rotation) {
_positionalTarget = position;
_rotationalTarget = rotation;
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
void* physicsInfo = ownerEntity->getPhysicsInfo();
if (physicsInfo) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
btRigidBody* rigidBody = motionState ? motionState->getRigidBody() : nullptr;
if (!rigidBody) {
qDebug() << "ObjectActionSpring::updateActionWorker no rigidBody";
return;
}
if (_setVelocity) {
if (_previousSet) {
glm::vec3 positionalVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep;
rigidBody->setLinearVelocity(glmToBullet(positionalVelocity));
// back up along velocity a bit in order to smooth out a "vibrating" appearance
_positionalTarget -= positionalVelocity * deltaTimeStep / 2.0f;
}
}
btTransform worldTrans = rigidBody->getWorldTransform();
worldTrans.setOrigin(glmToBullet(_positionalTarget));
worldTrans.setRotation(glmToBullet(_rotationalTarget));
rigidBody->setWorldTransform(worldTrans);
_previousPositionalTarget = _positionalTarget;
_previousRotationalTarget = _rotationalTarget;
_previousSet = true;
}
}
}
});
}
if (gotLock) {
ObjectActionSpring::updateActionWorker(deltaTimeStep);
}
}
bool AvatarActionKinematicHold::updateArguments(QVariantMap arguments) {
if (!ObjectAction::updateArguments(arguments)) {
return false;
}
bool ok = true;
glm::vec3 relativePosition =
EntityActionInterface::extractVec3Argument("kinematic-hold", arguments, "relativePosition", ok, false);
if (!ok) {
relativePosition = _relativePosition;
}
ok = true;
glm::quat relativeRotation =
EntityActionInterface::extractQuatArgument("kinematic-hold", arguments, "relativeRotation", ok, false);
if (!ok) {
relativeRotation = _relativeRotation;
}
ok = true;
QString hand =
EntityActionInterface::extractStringArgument("kinematic-hold", arguments, "hand", ok, false);
if (!ok || !(hand == "left" || hand == "right")) {
hand = _hand;
}
ok = true;
int setVelocity =
EntityActionInterface::extractIntegerArgument("kinematic-hold", arguments, "setVelocity", ok, false);
if (!ok) {
setVelocity = false;
}
if (relativePosition != _relativePosition
|| relativeRotation != _relativeRotation
|| hand != _hand) {
withWriteLock([&] {
_relativePosition = relativePosition;
_relativeRotation = relativeRotation;
_hand = hand;
_setVelocity = setVelocity;
_mine = true;
_active = true;
activateBody();
});
}
return true;
}
QVariantMap AvatarActionKinematicHold::getArguments() {
QVariantMap arguments = ObjectAction::getArguments();
withReadLock([&]{
if (!_mine) {
arguments = ObjectActionSpring::getArguments();
return;
}
arguments["relativePosition"] = glmToQMap(_relativePosition);
arguments["relativeRotation"] = glmToQMap(_relativeRotation);
arguments["setVelocity"] = _setVelocity;
arguments["hand"] = _hand;
});
return arguments;
}
void AvatarActionKinematicHold::deserialize(QByteArray serializedArguments) {
if (!_mine) {
ObjectActionSpring::deserialize(serializedArguments);
}
}

View file

@ -0,0 +1,47 @@
//
// AvatarActionKinematicHold.h
// interface/src/avatar/
//
// Created by Seth Alves 2015-10-2
// 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_AvatarActionKinematicHold_h
#define hifi_AvatarActionKinematicHold_h
#include <QUuid>
#include <EntityItem.h>
#include <ObjectActionSpring.h>
class AvatarActionKinematicHold : public ObjectActionSpring {
public:
AvatarActionKinematicHold(const QUuid& id, EntityItemPointer ownerEntity);
virtual ~AvatarActionKinematicHold();
virtual bool updateArguments(QVariantMap arguments);
virtual QVariantMap getArguments();
virtual void updateActionWorker(float deltaTimeStep);
virtual void deserialize(QByteArray serializedArguments);
private:
static const uint16_t holdVersion;
glm::vec3 _relativePosition;
glm::quat _relativeRotation;
QString _hand;
bool _mine = false;
bool _previousSet = false;
glm::vec3 _previousPositionalTarget;
glm::quat _previousRotationalTarget;
bool _setVelocity = false;
};
#endif // hifi_AvatarActionKinematicHold_h

View file

@ -1341,13 +1341,11 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl
if (qApp->isHMDMode()) {
glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();
glm::mat4 headPose = Application::getInstance()->getActiveDisplayPlugin()->getHeadPose();
glm::mat4 leftEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left);
leftEyePose = leftEyePose * headPose;
glm::mat4 leftEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyePose(Eye::Left);
glm::vec3 leftEyePosition = glm::vec3(leftEyePose[3]);
glm::mat4 rightEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Right);
rightEyePose = rightEyePose * headPose;
glm::mat4 rightEyePose = Application::getInstance()->getActiveDisplayPlugin()->getEyePose(Eye::Right);
glm::vec3 rightEyePosition = glm::vec3(rightEyePose[3]);
glm::mat4 headPose = Application::getInstance()->getActiveDisplayPlugin()->getHeadPose();
glm::vec3 headPosition = glm::vec3(headPose[3]);
getHead()->renderLookAts(renderArgs,

View file

@ -10,46 +10,12 @@
//
#include "HMDScriptingInterface.h"
#include <QtScript/QScriptContext>
#include "display-plugins/DisplayPlugin.h"
#include <avatar/AvatarManager.h>
#include "Application.h"
HMDScriptingInterface::HMDScriptingInterface() {
}
QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {
glm::vec3 hudIntersection;
auto instance = DependencyManager::get<HMDScriptingInterface>();
if (instance->getHUDLookAtPosition3D(hudIntersection)) {
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::vec3 sphereCenter = myAvatar->getDefaultEyePosition();
glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter);
glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction);
glm::vec3 eulers = ::safeEulerAngles(rotation);
return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationCompositor()
.sphericalToOverlay(glm::vec2(eulers.y, -eulers.x)));
}
return QScriptValue::NullValue;
}
QScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine) {
glm::vec3 result;
auto instance = DependencyManager::get<HMDScriptingInterface>();
if (instance->getHUDLookAtPosition3D(result)) {
return qScriptValueFromValue<glm::vec3>(engine, result);
}
return QScriptValue::NullValue;
}
void HMDScriptingInterface::toggleMagnifier() {
qApp->getApplicationCompositor().toggleMagnifier();
}
bool HMDScriptingInterface::getMagnifier() const {
return Application::getInstance()->getApplicationCompositor().hasMagnifier();
HMDScriptingInterface& HMDScriptingInterface::getInstance() {
static HMDScriptingInterface sharedInstance;
return sharedInstance;
}
bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const {
@ -64,6 +30,34 @@ bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const {
return compositor.calculateRayUICollisionPoint(position, direction, result);
}
QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {
glm::vec3 hudIntersection;
if ((&HMDScriptingInterface::getInstance())->getHUDLookAtPosition3D(hudIntersection)) {
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::vec3 sphereCenter = myAvatar->getDefaultEyePosition();
glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter);
glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction);
glm::vec3 eulers = ::safeEulerAngles(rotation);
return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationCompositor()
.sphericalToOverlay(glm::vec2(eulers.y, -eulers.x)));
}
return QScriptValue::NullValue;
}
QScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine) {
glm::vec3 result;
if ((&HMDScriptingInterface::getInstance())->getHUDLookAtPosition3D(result)) {
return qScriptValueFromValue<glm::vec3>(engine, result);
}
return QScriptValue::NullValue;
}
float HMDScriptingInterface::getIPD() const {
return Application::getInstance()->getActiveDisplayPlugin()->getIPD();
}
glm::vec3 HMDScriptingInterface::getPosition() const {
if (Application::getInstance()->getActiveDisplayPlugin()->isHmd()) {
return glm::vec3(Application::getInstance()->getActiveDisplayPlugin()->getHeadPose()[3]);

View file

@ -12,30 +12,32 @@
#ifndef hifi_HMDScriptingInterface_h
#define hifi_HMDScriptingInterface_h
#include <QtScript/QScriptValue>
class QScriptContext;
class QScriptEngine;
#include <GLMHelpers.h>
#include <DependencyManager.h>
#include <display-plugins/AbstractHMDScriptingInterface.h>
#include "Application.h"
class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency {
class HMDScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(bool magnifier READ getMagnifier)
Q_PROPERTY(bool active READ isHMDMode)
Q_PROPERTY(float ipd READ getIPD)
Q_PROPERTY(glm::vec3 position READ getPosition)
Q_PROPERTY(glm::quat orientation READ getOrientation)
public:
HMDScriptingInterface();
static HMDScriptingInterface& getInstance();
static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine);
static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine);
public slots:
void toggleMagnifier();
void toggleMagnifier() { Application::getInstance()->getApplicationCompositor().toggleMagnifier(); };
private:
bool getMagnifier() const;
HMDScriptingInterface() {};
bool getMagnifier() const { return Application::getInstance()->getApplicationCompositor().hasMagnifier(); };
bool isHMDMode() const { return Application::getInstance()->isHMDMode(); }
float getIPD() const;
// Get the position of the HMD
glm::vec3 getPosition() const;
@ -43,6 +45,7 @@ private:
glm::quat getOrientation() const;
bool getHUDLookAtPosition3D(glm::vec3& result) const;
};
#endif // hifi_HMDScriptingInterface_h

View file

@ -1,52 +0,0 @@
//
// Created by Bradley Austin Davis on 2015/10/04
// Copyright 2013-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 "AbstractHMDScriptingInterface.h"
#include <SettingHandle.h>
#include "DisplayPlugin.h"
#include <plugins/PluginContainer.h>
#include <OVR_CAPI_Keys.h>
static Setting::Handle<float> IPD_SCALE_HANDLE("hmd.ipdScale", 1.0f);
AbstractHMDScriptingInterface::AbstractHMDScriptingInterface() {
_IPDScale = IPD_SCALE_HANDLE.get();
}
float AbstractHMDScriptingInterface::getIPD() const {
return PluginContainer::getInstance().getActiveDisplayPlugin()->getIPD();
}
float AbstractHMDScriptingInterface::getEyeHeight() const {
// FIXME update the display plugin interface to expose per-plugin settings
return OVR_DEFAULT_EYE_HEIGHT;
}
float AbstractHMDScriptingInterface::getPlayerHeight() const {
// FIXME update the display plugin interface to expose per-plugin settings
return OVR_DEFAULT_PLAYER_HEIGHT;
}
float AbstractHMDScriptingInterface::getIPDScale() const {
return _IPDScale;
}
void AbstractHMDScriptingInterface::setIPDScale(float IPDScale) {
IPDScale = glm::clamp(IPDScale, -1.0f, 3.0f);
if (IPDScale != _IPDScale) {
_IPDScale = IPDScale;
IPD_SCALE_HANDLE.set(IPDScale);
emit IPDScaleChanged();
}
}
bool AbstractHMDScriptingInterface::isHMDMode() const {
return PluginContainer::getInstance().getActiveDisplayPlugin()->isHmd();
}

View file

@ -1,39 +0,0 @@
//
// Created by Bradley Austin Davis on 2015/10/04
// Copyright 2013-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
//
#pragma once
#ifndef hifi_AbstractHMDScriptingInterface_h
#define hifi_AbstractHMDScriptingInterface_h
#include <GLMHelpers.h>
class AbstractHMDScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(bool active READ isHMDMode)
Q_PROPERTY(float ipd READ getIPD)
Q_PROPERTY(float eyeHeight READ getEyeHeight)
Q_PROPERTY(float playerHeight READ getPlayerHeight)
Q_PROPERTY(float ipdScale READ getIPDScale WRITE setIPDScale NOTIFY IPDScaleChanged)
public:
AbstractHMDScriptingInterface();
float getIPD() const;
float getEyeHeight() const;
float getPlayerHeight() const;
float getIPDScale() const;
void setIPDScale(float ipdScale);
bool isHMDMode() const;
signals:
void IPDScaleChanged();
private:
float _IPDScale{ 1.0 };
};
#endif // hifi_AbstractHMDScriptingInterface_h

View file

@ -46,8 +46,6 @@ void for_each_eye(F f, FF ff) {
class QWindow;
#define AVERAGE_HUMAN_IPD 0.064f
class DisplayPlugin : public Plugin {
Q_OBJECT
public:
@ -109,22 +107,21 @@ public:
return baseProjection;
}
virtual glm::mat4 getView(Eye eye, const glm::mat4& baseView) const {
return glm::inverse(getEyePose(eye)) * baseView;
}
// HMD specific methods
// TODO move these into another class?
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
static const glm::mat4 transform; return transform;
virtual glm::mat4 getEyePose(Eye eye) const {
static const glm::mat4 pose; return pose;
}
virtual glm::mat4 getHeadPose() const {
static const glm::mat4 pose; return pose;
}
// Needed for timewarp style features
virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) {
// NOOP
}
virtual float getIPD() const { return AVERAGE_HUMAN_IPD; }
virtual float getIPD() const { return 0.0f; }
virtual void abandonCalibration() {}
virtual void resetSensors() {}

View file

@ -19,6 +19,7 @@ void OculusBaseDisplayPlugin::preRender() {
#if (OVR_MAJOR_VERSION >= 6)
ovrFrameTiming ftiming = ovr_GetFrameTiming(_hmd, _frameIndex);
_trackingState = ovr_GetTrackingState(_hmd, ftiming.DisplayMidpointSeconds);
ovr_CalcEyePoses(_trackingState.HeadPose.ThePose, _eyeOffsets, _eyePoses);
#endif
}
@ -32,19 +33,14 @@ void OculusBaseDisplayPlugin::resetSensors() {
#endif
}
glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
return glm::translate(mat4(), toGlm(_eyeOffsets[eye]));
glm::mat4 OculusBaseDisplayPlugin::getEyePose(Eye eye) const {
return toGlm(_eyePoses[eye]);
}
glm::mat4 OculusBaseDisplayPlugin::getHeadPose() const {
return toGlm(_trackingState.HeadPose.ThePose);
}
void OculusBaseDisplayPlugin::setEyeRenderPose(Eye eye, const glm::mat4& pose) {
_eyePoses[eye] = ovrPoseFromGlm(pose);
}
bool OculusBaseDisplayPlugin::isSupported() const {
#if (OVR_MAJOR_VERSION >= 6)
if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
@ -155,9 +151,9 @@ void OculusBaseDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sce
}
float OculusBaseDisplayPlugin::getIPD() const {
float result = OVR_DEFAULT_IPD;
float result = 0.0f;
#if (OVR_MAJOR_VERSION >= 6)
result = ovr_GetFloat(_hmd, OVR_KEY_IPD, result);
result = ovr_GetFloat(_hmd, OVR_KEY_IPD, OVR_DEFAULT_IPD);
#endif
return result;
}
}

View file

@ -29,9 +29,8 @@ public:
virtual glm::uvec2 getRecommendedRenderSize() const override final;
virtual glm::uvec2 getRecommendedUiSize() const override final { return uvec2(1920, 1080); }
virtual void resetSensors() override final;
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override final;
virtual glm::mat4 getEyePose(Eye eye) const override final;
virtual glm::mat4 getHeadPose() const override final;
virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) override final;
virtual float getIPD() const override final;
protected:
@ -40,7 +39,6 @@ protected:
protected:
ovrPosef _eyePoses[2];
ovrVector3f _eyeOffsets[2];
mat4 _eyeProjections[3];
mat4 _compositeEyeProjections[2];
@ -52,12 +50,13 @@ protected:
ovrHmd _hmd;
float _ipd{ OVR_DEFAULT_IPD };
ovrEyeRenderDesc _eyeRenderDescs[2];
ovrVector3f _eyeOffsets[2];
ovrFovPort _eyeFovs[2];
ovrHmdDesc _hmdDesc;
ovrLayerEyeFov _sceneLayer;
ovrHmdDesc _hmdDesc;
ovrLayerEyeFov _sceneLayer;
#endif
#if (OVR_MAJOR_VERSION == 7)
ovrGraphicsLuid _luid;
ovrGraphicsLuid _luid;
#endif
};

View file

@ -79,11 +79,3 @@ inline ovrQuatf ovrFromGlm(const glm::quat & q) {
return{ q.x, q.y, q.z, q.w };
}
inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) {
glm::vec3 translation = extractTranslation(m) / m[3].w;
glm::quat orientation = glm::quat_cast(m);
ovrPosef result;
result.Orientation = ovrFromGlm(orientation);
result.Position = ovrFromGlm(translation);
return result;
}

View file

@ -59,11 +59,11 @@ void OculusLegacyDisplayPlugin::resetSensors() {
#endif
}
glm::mat4 OculusLegacyDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
glm::mat4 OculusLegacyDisplayPlugin::getEyePose(Eye eye) const {
#if (OVR_MAJOR_VERSION == 5)
return toGlm(_eyePoses[eye]);
#else
return WindowOpenGLDisplayPlugin::getEyeToHeadTransform(eye);
return WindowOpenGLDisplayPlugin::getEyePose(eye);
#endif
}

View file

@ -31,7 +31,7 @@ public:
virtual glm::uvec2 getRecommendedRenderSize() const override;
virtual glm::uvec2 getRecommendedUiSize() const override { return uvec2(1920, 1080); }
virtual void resetSensors() override;
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
virtual glm::mat4 getEyePose(Eye eye) const override;
virtual glm::mat4 getHeadPose() const override;
protected:

View file

@ -160,8 +160,8 @@ void OpenVrDisplayPlugin::resetSensors() {
_sensorResetMat = glm::inverse(cancelOutRollAndPitch(_trackedDevicePoseMat4[0]));
}
glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
return _eyesData[eye]._eyeOffset;
glm::mat4 OpenVrDisplayPlugin::getEyePose(Eye eye) const {
return getHeadPose() * _eyesData[eye]._eyeOffset;
}
glm::mat4 OpenVrDisplayPlugin::getHeadPose() const {

View file

@ -29,7 +29,7 @@ public:
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override;
virtual void resetSensors() override;
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
virtual glm::mat4 getEyePose(Eye eye) const override;
virtual glm::mat4 getHeadPose() const override;
protected:

View file

@ -61,6 +61,10 @@ glm::mat4 StereoDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProje
return eyeProjection;
}
glm::mat4 StereoDisplayPlugin::getEyePose(Eye eye) const {
return mat4();
}
std::vector<QAction*> _screenActions;
void StereoDisplayPlugin::activate() {
auto screens = qApp->screens();

View file

@ -21,14 +21,7 @@ public:
virtual float getRecommendedAspectRatio() const override;
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override;
// NOTE, because Stereo displays don't include head tracking, and therefore
// can't include roll or pitch, the eye separation is embedded into the projection
// matrix. However, this eliminates the possibility of easily mainpulating
// the IPD at the Application level, the way we now allow with HMDs.
// If that becomes an issue then we'll need to break up the functionality similar
// to the HMD plugins.
// virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
virtual glm::mat4 getEyePose(Eye eye) const override;
protected:
void updateScreen();

View file

@ -100,6 +100,9 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS
if (normalizedActionTypeString == "hold") {
return ACTION_TYPE_HOLD;
}
if (normalizedActionTypeString == "kinematichold") {
return ACTION_TYPE_KINEMATIC_HOLD;
}
qDebug() << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
return ACTION_TYPE_NONE;
@ -115,6 +118,8 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) {
return "spring";
case ACTION_TYPE_HOLD:
return "hold";
case ACTION_TYPE_KINEMATIC_HOLD:
return "kinematic-hold";
}
assert(false);
return "none";
@ -244,6 +249,28 @@ float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMa
return v;
}
int EntityActionInterface::extractIntegerArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
qDebug() << objectName << "requires argument:" << argumentName;
}
ok = false;
return 0.0f;
}
QVariant vV = arguments[argumentName];
bool vOk = true;
int v = vV.toInt(&vOk);
if (!vOk || v != v) {
ok = false;
return 0;
}
return v;
}
QString EntityActionInterface::extractStringArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {

View file

@ -23,7 +23,8 @@ enum EntityActionType {
ACTION_TYPE_NONE = 0,
ACTION_TYPE_OFFSET = 1000,
ACTION_TYPE_SPRING = 2000,
ACTION_TYPE_HOLD = 3000
ACTION_TYPE_HOLD = 3000,
ACTION_TYPE_KINEMATIC_HOLD = 4000
};
@ -69,6 +70,8 @@ protected:
QString argumentName, bool& ok, bool required = true);
static float extractFloatArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required = true);
static int extractIntegerArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required = true);
static QString extractStringArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required = true);

View file

@ -9,17 +9,7 @@
static PluginContainer* INSTANCE{ nullptr };
PluginContainer& PluginContainer::getInstance() {
Q_ASSERT(INSTANCE);
return *INSTANCE;
}
PluginContainer::PluginContainer() {
Q_ASSERT(!INSTANCE);
INSTANCE = this;
};
PluginContainer::~PluginContainer() {
Q_ASSERT(INSTANCE == this);
INSTANCE = nullptr;
};

View file

@ -13,13 +13,10 @@
class QAction;
class QGLWidget;
class QScreen;
class DisplayPlugin;
class PluginContainer {
public:
static PluginContainer& getInstance();
PluginContainer();
virtual ~PluginContainer();
virtual void addMenu(const QString& menuName) = 0;
virtual void removeMenu(const QString& menuName) = 0;
virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0;
@ -32,5 +29,4 @@ public:
virtual void requestReset() = 0;
virtual QGLWidget* getPrimarySurface() = 0;
virtual bool isForeground() = 0;
virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0;
};

View file

@ -457,8 +457,7 @@ function createPingPongBallGun() {
var pingPongGun = Entities.addEntity({
type: "Model",
modelURL: MODEL_URL,
shapeType: 'compound',
compoundShapeURL: COLLISION_HULL_URL,
shapeType: 'box',
script: scriptURL,
position: position,
rotation: rotation,
@ -468,9 +467,9 @@ function createPingPongBallGun() {
z: 0
},
dimensions: {
x: 0.67,
y: 0.14,
z: 0.09
x: 0.08,
y: 0.21,
z: 0.47
},
collisionsWillMove: true,
});
@ -478,8 +477,6 @@ function createPingPongBallGun() {
setEntityCustomData(resetKey, pingPongGun, {
resetMe: true
});
}
function createBasketballHoop() {