diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index b6223497e6..b177d2a9a0 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -277,14 +277,17 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio // set of stats to have, but we'd probably want a different data structure if we keep it very long. // Since this version uses a single shared QMap for all senders, there could be some lock contention // on this QWriteLocker -void EntityServer::trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { +void EntityServer::trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& sessionID) { QWriteLocker locker(&_viewerSendingStatsLock); - _viewerSendingStats[viewerNode][dataID] = { usecTimestampNow(), dataLastEdited }; + _viewerSendingStats[sessionID][dataID] = { usecTimestampNow(), dataLastEdited }; } -void EntityServer::trackViewerGone(const QUuid& viewerNode) { +void EntityServer::trackViewerGone(const QUuid& sessionID) { QWriteLocker locker(&_viewerSendingStatsLock); - _viewerSendingStats.remove(viewerNode); + _viewerSendingStats.remove(sessionID); + if (_entitySimulation) { + _entitySimulation->clearOwnership(sessionID); + } } QString EntityServer::serverSubclassStats() { diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index cd603f44d8..74057bfa5d 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -27,6 +27,8 @@ struct ViewerSendingStats { quint64 lastEdited; }; +class SimpleEntitySimulation; + class EntityServer : public OctreeServer, public NewlyCreatedEntityHook { Q_OBJECT public: @@ -52,8 +54,8 @@ public: virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override; virtual QString serverSubclassStats() override; - virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) override; - virtual void trackViewerGone(const QUuid& viewerNode) override; + virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& sessionID) override; + virtual void trackViewerGone(const QUuid& sessionID) override; public slots: void pruneDeletedEntities(); @@ -65,7 +67,7 @@ private slots: void handleEntityPacket(QSharedPointer message, SharedNodePointer senderNode); private: - EntitySimulation* _entitySimulation; + SimpleEntitySimulation* _entitySimulation; QTimer* _pruneDeletedEntitiesTimer = nullptr; QReadWriteLock _viewerSendingStatsLock; diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 04e93334cb..2bddc5d677 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1,3 +1,4 @@ +"use strict"; // handControllerGrab.js // // Created by Eric Levin on 9/2/15 @@ -801,6 +802,8 @@ function MyController(hand) { this.isInitialGrab = false; this.doubleParentGrab = false; + this.checkForStrayChildren(); + if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { this.setState(STATE_RELEASE); return; @@ -1444,6 +1447,13 @@ function MyController(hand) { this.heartBeat(this.grabbedEntity); var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position"]); + if (!props.position) { + // server may have reset, taking our equipped entity with it. move back to "off" stte + this.setState(STATE_RELEASE); + this.callEntityMethodOnGrabbed("releaseGrab"); + return; + } + if (props.parentID == MyAvatar.sessionUUID && Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) { // for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip. @@ -1751,6 +1761,17 @@ function MyController(hand) { return data; }; + this.checkForStrayChildren = function() { + // sometimes things can get parented to a hand and this script is unaware. Search for such entities and + // unhook them. + var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); + var children = Entities.getChildrenIDsOfJoint(MyAvatar.sessionUUID, handJointIndex); + children.forEach(function(childID) { + print("disconnecting stray child of hand: (" + _this.hand + ") " + childID); + Entities.editEntity(childID, {parentID: NULL_UUID}); + }); + } + this.deactivateEntity = function(entityID, noVelocity) { var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); if (data && data["refCount"]) { diff --git a/examples/depthReticle.js b/examples/depthReticle.js index a60e61d07c..4b649f49b6 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -12,17 +12,23 @@ var APPARENT_2D_OVERLAY_DEPTH = 1.0; var APPARENT_MAXIMUM_DEPTH = 100.0; // this is a depth at which things all seem sufficiently distant -var lastDepthCheckTime = 0; +var lastDepthCheckTime = Date.now(); +var desiredDepth = APPARENT_2D_OVERLAY_DEPTH; +var TIME_BETWEEN_DEPTH_CHECKS = 100; +var MINIMUM_DEPTH_ADJUST = 0.01; +var NON_LINEAR_DIVISOR = 2; Script.update.connect(function(deltaTime) { - var TIME_BETWEEN_DEPTH_CHECKS = 100; - var timeSinceLastDepthCheck = Date.now() - lastDepthCheckTime; + var now = Date.now(); + var timeSinceLastDepthCheck = now - lastDepthCheckTime; if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) { + var newDesiredDepth = desiredDepth; + lastDepthCheckTime = now; var reticlePosition = Reticle.position; // first check the 2D Overlays if (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(reticlePosition)) { - Reticle.setDepth(APPARENT_2D_OVERLAY_DEPTH); + newDesiredDepth = APPARENT_2D_OVERLAY_DEPTH; } else { var pickRay = Camera.computePickRay(reticlePosition.x, reticlePosition.y); @@ -37,11 +43,30 @@ Script.update.connect(function(deltaTime) { // If either the overlays or entities intersect, then set the reticle depth to // the distance of intersection if (result.intersects) { - Reticle.setDepth(result.distance); + newDesiredDepth = result.distance; } else { // if nothing intersects... set the depth to some sufficiently large depth - Reticle.setDepth(APPARENT_MAXIMUM_DEPTH); + newDesiredDepth = APPARENT_MAXIMUM_DEPTH; } } + + // If the desired depth has changed, reset our fade start time + if (desiredDepth != newDesiredDepth) { + desiredDepth = newDesiredDepth; + } + } + + // move the reticle toward the desired depth + if (desiredDepth != Reticle.depth) { + + // cut distance between desiredDepth and current depth in half until we're close enough + var distanceToAdjustThisCycle = (desiredDepth - Reticle.depth) / NON_LINEAR_DIVISOR; + if (Math.abs(distanceToAdjustThisCycle) < MINIMUM_DEPTH_ADJUST) { + newDepth = desiredDepth; + } else { + newDepth = Reticle.depth + distanceToAdjustThisCycle; + } + + Reticle.setDepth(newDepth); } }); diff --git a/examples/edit.js b/examples/edit.js index 50a66ea31f..59e1f74d20 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -711,13 +711,32 @@ var intersection; var SCALE_FACTOR = 200.0; -function rayPlaneIntersection(pickRay, point, normal) { +function rayPlaneIntersection(pickRay, point, normal) { // + // + // This version of the test returns the intersection of a line with a plane + // + var collides = Vec3.dot(pickRay.direction, normal); + var d = -Vec3.dot(point, normal); - var t = -(Vec3.dot(pickRay.origin, normal) + d) / Vec3.dot(pickRay.direction, normal); + var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides; return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t)); } +function rayPlaneIntersection2(pickRay, point, normal) { + // + // This version of the test returns false if the ray is directed away from the plane + // + var collides = Vec3.dot(pickRay.direction, normal); + var d = -Vec3.dot(point, normal); + var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides; + if (t < 0.0) { + return false; + } else { + return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t)); + } +} + function findClickedEntity(event) { var pickZones = event.isControl; @@ -758,7 +777,8 @@ function findClickedEntity(event) { var foundEntity = result.entityID; return { pickRay: pickRay, - entityID: foundEntity + entityID: foundEntity, + intersection: result.intersection }; } @@ -926,6 +946,7 @@ function mouseReleaseEvent(event) { } function mouseClickEvent(event) { + var wantDebug = false; if (isActive && event.isLeftButton) { var result = findClickedEntity(event); if (result === null) { @@ -940,11 +961,15 @@ function mouseClickEvent(event) { var properties = Entities.getEntityProperties(foundEntity); if (isLocked(properties)) { - print("Model locked " + properties.id); + if (wantDebug) { + print("Model locked " + properties.id); + } } else { var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal); + if (wantDebug) { + print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal); + } // P P - Model // /| A - Palm // / | d B - unit vector toward tip @@ -981,8 +1006,9 @@ function mouseClickEvent(event) { } else { selectionManager.addEntity(foundEntity, true); } - - print("Model selected: " + foundEntity); + if (wantDebug) { + print("Model selected: " + foundEntity); + } selectionDisplay.select(selectedEntityID, event); if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) { diff --git a/examples/gridTest.js b/examples/gridTest.js index 0d6040470f..5bbd3246ae 100644 --- a/examples/gridTest.js +++ b/examples/gridTest.js @@ -17,8 +17,8 @@ var SIZE = 10.0; var SEPARATION = 20.0; var ROWS_X = 30; var ROWS_Z = 30; -var TYPE = "Sphere"; // Right now this can be "Box" or "Model" or "Sphere" -var MODEL_URL = "https://hifi-public.s3.amazonaws.com/models/props/LowPolyIsland/CypressTreeGroup.fbx"; +var TYPE = "Model"; // Right now this can be "Box" or "Model" or "Sphere" +var MODEL_URL = "http://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Instances/vesicle.fbx"; var MODEL_DIMENSION = { x: 33, y: 16, z: 49 }; var RATE_PER_SECOND = 1000; // The entity server will drop data if we create things too fast. var SCRIPT_INTERVAL = 100; @@ -38,6 +38,7 @@ Script.setInterval(function () { var numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0); for (var i = 0; i < numToCreate; i++) { var position = { x: SIZE + (x * SEPARATION), y: SIZE, z: SIZE + (z * SEPARATION) }; + print('position:'+JSON.stringify(position)) if (TYPE == "Model") { Entities.addEntity({ type: TYPE, diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index c1675ef044..95e695aa9c 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -16,6 +16,11 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; SPACE_LOCAL = "local"; SPACE_WORLD = "world"; +function objectTranslationPlanePoint(position, dimensions) { + var newPosition = { x: position.x, y: position.y, z: position.z }; + newPosition.y -= dimensions.y / 2.0; + return newPosition; +} SelectionManager = (function() { var that = {}; @@ -2252,15 +2257,20 @@ SelectionDisplay = (function() { var constrainMajorOnly = false; var startPosition = null; var duplicatedEntityIDs = null; + var translateXZTool = { mode: 'TRANSLATE_XZ', + pickPlanePosition: { x: 0, y: 0, z: 0 }, + greatestDimension: 0.0, + startingDistance: 0.0, + startingElevation: 0.0, onBegin: function(event) { SelectionManager.saveProperties(); startPosition = SelectionManager.worldPosition; var dimensions = SelectionManager.worldDimensions; var pickRay = Camera.computePickRay(event.x, event.y); - initialXZPick = rayPlaneIntersection(pickRay, startPosition, { + initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, { x: 0, y: 1, z: 0 @@ -2297,16 +2307,56 @@ SelectionDisplay = (function() { visible: false }); }, + elevation: function(origin, intersection) { + return (origin.y - intersection.y) / Vec3.distance(origin, intersection); + }, onMove: function(event) { + var wantDebug = false; pickRay = Camera.computePickRay(event.x, event.y); - var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { + var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, { x: 0, y: 1, z: 0 }); + + // If the pick ray doesn't hit the pick plane in this direction, do nothing. + // this will happen when someone drags across the horizon from the side they started on. + if (!pick) { + if (wantDebug) { + print("Pick ray does not intersect XZ plane."); + } + return; + } + var vector = Vec3.subtract(pick, initialXZPick); + // If the mouse is too close to the horizon of the pick plane, stop moving + var MIN_ELEVATION = 0.02; // largest dimension of object divided by distance to it + var elevation = translateXZTool.elevation(pickRay.origin, pick); + if (wantDebug) { + print("Start Elevation: " + translateXZTool.startingElevation + ", elevation: " + elevation); + } + if ((translateXZTool.startingElevation > 0.0 && elevation < MIN_ELEVATION) || + (translateXZTool.startingElevation < 0.0 && elevation > -MIN_ELEVATION)) { + if (wantDebug) { + print("too close to horizon!"); + } + return; + } + + // If the angular size of the object is too small, stop moving + var MIN_ANGULAR_SIZE = 0.01; // Radians + if (translateXZTool.greatestDimension > 0) { + var angularSize = Math.atan(translateXZTool.greatestDimension / Vec3.distance(pickRay.origin, pick)); + if (wantDebug) { + print("Angular size = " + angularSize); + } + if (angularSize < MIN_ANGULAR_SIZE) { + return; + } + } + // If shifted, constrain to one axis if (event.isShifted) { if (Math.abs(vector.x) > Math.abs(vector.z)) { @@ -2368,7 +2418,7 @@ SelectionDisplay = (function() { grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), cornerPosition); - var wantDebug = false; + for (var i = 0; i < SelectionManager.selections.length; i++) { var properties = SelectionManager.savedProperties[SelectionManager.selections[i]]; @@ -2645,11 +2695,6 @@ SelectionDisplay = (function() { pickRayPosition, planeNormal); - // Overlays.editOverlay(normalLine, { - // start: initialPosition, - // end: Vec3.sum(Vec3.multiply(100000, planeNormal), initialPosition), - // }); - SelectionManager.saveProperties(); }; @@ -3751,7 +3796,7 @@ SelectionDisplay = (function() { }; that.mousePressEvent = function(event) { - + var wantDebug = false; if (!event.isLeftButton) { // if another mouse button than left is pressed ignore it return false; @@ -3777,7 +3822,7 @@ SelectionDisplay = (function() { if (result.intersects) { - var wantDebug = false; + if (wantDebug) { print("something intersects... "); print(" result.overlayID:" + result.overlayID + "[" + overlayNames[result.overlayID] + "]"); @@ -3874,7 +3919,10 @@ SelectionDisplay = (function() { if (!somethingClicked) { - print("rotate handle case..."); + if (wantDebug) { + print("rotate handle case..."); + } + // After testing our stretch handles, then check out rotate handles Overlays.editOverlay(yawHandle, { @@ -3942,15 +3990,17 @@ SelectionDisplay = (function() { break; default: - print("mousePressEvent()...... " + overlayNames[result.overlayID]); + if (wantDebug) { + print("mousePressEvent()...... " + overlayNames[result.overlayID]); + } mode = "UNKNOWN"; break; } } - - print(" somethingClicked:" + somethingClicked); - print(" mode:" + mode); - + if (wantDebug) { + print(" somethingClicked:" + somethingClicked); + print(" mode:" + mode); + } if (somethingClicked) { @@ -4093,12 +4143,25 @@ SelectionDisplay = (function() { switch (result.overlayID) { case selectionBox: activeTool = translateXZTool; + translateXZTool.pickPlanePosition = result.intersection; + translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y), + SelectionManager.worldDimensions.z); + if (wantDebug) { + print("longest dimension: " + translateXZTool.greatestDimension); + translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position); + print("starting distance: " + translateXZTool.startingDistance); + translateXZTool.startingElevation = translateXZTool.elevation(pickRay.origin, translateXZTool.pickPlanePosition); + print(" starting elevation: " + translateXZTool.startingElevation); + } + mode = translateXZTool.mode; activeTool.onBegin(event); somethingClicked = true; break; default: - print("mousePressEvent()...... " + overlayNames[result.overlayID]); + if (wantDebug) { + print("mousePressEvent()...... " + overlayNames[result.overlayID]); + } mode = "UNKNOWN"; break; } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 83351d5188..0bd134bef5 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -400,7 +400,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { frustum = qApp->getDisplayViewFrustum(); } - if (frustum->sphereIntersectsFrustum(getPosition(), boundingRadius)) { + if (!frustum->sphereIntersectsFrustum(getPosition(), boundingRadius)) { endRender(); return; } diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 5b493c4215..b62cae1d58 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -153,25 +153,6 @@ std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::qu palmPosition = holdingAvatar->getLeftPalmPosition(); palmRotation = holdingAvatar->getLeftPalmRotation(); } - - // In this case we are simulating the grab of another avatar. - // Because the hand controller velocity for their palms is not transmitted over the - // network, we have to synthesize our own. - - if (_previousSet) { - // smooth linear velocity over two frames - glm::vec3 positionalDelta = palmPosition - _previousPositionalTarget; - linearVelocity = (positionalDelta + _previousPositionalDelta) / (deltaTimeStep + _previousDeltaTimeStep); - glm::quat deltaRotation = palmRotation * glm::inverse(_previousRotationalTarget); - float rotationAngle = glm::angle(deltaRotation); - if (rotationAngle > EPSILON) { - angularVelocity = glm::normalize(glm::axis(deltaRotation)); - angularVelocity *= (rotationAngle / deltaTimeStep); - } - - _previousPositionalDelta = positionalDelta; - _previousDeltaTimeStep = deltaTimeStep; - } } rotation = palmRotation * _relativeRotation; @@ -278,6 +259,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { }); forceBodyNonStatic(); + activateBody(true); } bool AvatarActionHold::updateArguments(QVariantMap arguments) { diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 99f0b4fdc4..59d794d7cb 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -301,7 +301,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int // look at borrowed from overlays float elevation = -asinf(relativePosition.y / glm::length(relativePosition)); float azimuth = atan2f(relativePosition.x, relativePosition.z); - glm::quat faceCamera = glm::quat(glm::vec3(elevation, azimuth, 0)) * quat(vec3(0, 0, -1)); // this extra *quat(vec3(0,0,-1)) was required to get the quad to flip this seems like we could optimize + glm::quat faceCamera = glm::quat(glm::vec3(elevation, azimuth, 0)) * quat(vec3(0, -PI, 0)); // this extra *quat(vec3(0,-PI,0)) was required to get the quad to flip this seems like we could optimize Transform transform; transform.setTranslation(relativePosition); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index d7a47136b5..26f73eb65a 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -12,6 +12,7 @@ #include "EntityItemID.h" #include +#include #include "EntitiesLogging.h" #include "EntityActionFactoryInterface.h" @@ -1063,6 +1064,34 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) { return result; } +QVector EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) { + QVector result; + if (!_entityTree) { + return result; + } + _entityTree->withReadLock([&] { + QSharedPointer parentFinder = DependencyManager::get(); + if (!parentFinder) { + return; + } + bool success; + SpatiallyNestableWeakPointer parentWP = parentFinder->find(parentID, success); + if (!success) { + return; + } + SpatiallyNestablePointer parent = parentWP.lock(); + if (!parent) { + return; + } + parent->forEachChild([&](SpatiallyNestablePointer child) { + if (child->getParentJointIndex() == jointIndex) { + result.push_back(child->getID()); + } + }); + }); + return result; +} + float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) { return std::abs(mass * (newVelocity - oldVelocity)); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index fef000cc3d..79d8f0a0b0 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -168,7 +168,7 @@ public slots: Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name); Q_INVOKABLE QStringList getJointNames(const QUuid& entityID); - + Q_INVOKABLE QVector getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex); signals: void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index bdf27f4440..6bf25f767d 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -18,51 +18,69 @@ #include "EntityItem.h" #include "EntitiesLogging.h" -const quint64 MIN_SIMULATION_OWNERSHIP_UPDATE_PERIOD = 2 * USECS_PER_SECOND; - -void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { - if (_entitiesWithSimulator.size() == 0) { - return; - } - - if (now < _nextSimulationExpiry) { - // nothing has expired yet - return; - } - - // If an Entity has a simulation owner but there has been no update for a while: clear the owner. - // If an Entity goes ownerless for too long: zero velocity and remove from _entitiesWithSimulator. - _nextSimulationExpiry = now + MIN_SIMULATION_OWNERSHIP_UPDATE_PERIOD; +const quint64 MAX_OWNERLESS_PERIOD = 2 * USECS_PER_SECOND; +void SimpleEntitySimulation::clearOwnership(const QUuid& ownerID) { QMutexLocker lock(&_mutex); - SetOfEntities::iterator itemItr = _entitiesWithSimulator.begin(); - while (itemItr != _entitiesWithSimulator.end()) { + SetOfEntities::iterator itemItr = _entitiesWithSimulationOwner.begin(); + while (itemItr != _entitiesWithSimulationOwner.end()) { EntityItemPointer entity = *itemItr; - quint64 expiry = entity->getLastChangedOnServer() + MIN_SIMULATION_OWNERSHIP_UPDATE_PERIOD; - if (expiry < now) { - if (entity->getSimulatorID().isNull()) { - // no simulators are volunteering - // zero the velocity on this entity so that it doesn't drift far away - entity->setVelocity(Vectors::ZERO); - entity->setAngularVelocity(Vectors::ZERO); - entity->setAcceleration(Vectors::ZERO); - // remove from list - itemItr = _entitiesWithSimulator.erase(itemItr); - continue; - } else { - // the simulator has stopped updating this object - // clear ownership and restart timer, giving nearby simulators time to volunteer - qCDebug(entities) << "auto-removing simulation owner " << entity->getSimulatorID(); - entity->clearSimulationOwnership(); + if (entity->getSimulatorID() == ownerID) { + // the simulator has abandonded this object --> remove from owned list + qCDebug(entities) << "auto-removing simulation owner " << entity->getSimulatorID(); + itemItr = _entitiesWithSimulationOwner.erase(itemItr); + + if (entity->getDynamic() && entity->hasLocalVelocity()) { + // it is still moving dynamically --> add to orphaned list + _entitiesThatNeedSimulationOwner.insert(entity); + quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; + if (expiry < _nextOwnerlessExpiry) { + _nextOwnerlessExpiry = expiry; + } } + + // remove ownership and dirty all the tree elements that contain the it + entity->clearSimulationOwnership(); entity->markAsChangedOnServer(); - // dirty all the tree elements that contain the entity DirtyOctreeElementOperator op(entity->getElement()); getEntityTree()->recurseTreeWithOperator(&op); - } else if (expiry < _nextSimulationExpiry) { - _nextSimulationExpiry = expiry; + } else { + ++itemItr; + } + } +} + +void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { + if (now > _nextOwnerlessExpiry) { + // search for ownerless objects that have expired + QMutexLocker lock(&_mutex); + _nextOwnerlessExpiry = -1; + SetOfEntities::iterator itemItr = _entitiesThatNeedSimulationOwner.begin(); + while (itemItr != _entitiesThatNeedSimulationOwner.end()) { + EntityItemPointer entity = *itemItr; + quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; + if (expiry < now) { + // no simulators have volunteered ownership --> remove from list + itemItr = _entitiesThatNeedSimulationOwner.erase(itemItr); + + if (entity->getSimulatorID().isNull() && entity->getDynamic() && entity->hasLocalVelocity()) { + // zero the derivatives + entity->setVelocity(Vectors::ZERO); + entity->setAngularVelocity(Vectors::ZERO); + entity->setAcceleration(Vectors::ZERO); + + // dirty all the tree elements that contain it + entity->markAsChangedOnServer(); + DirtyOctreeElementOperator op(entity->getElement()); + getEntityTree()->recurseTreeWithOperator(&op); + } + } else { + ++itemItr; + if (expiry < _nextOwnerlessExpiry) { + _nextOwnerlessExpiry = expiry; + } + } } - ++itemItr; } } @@ -70,26 +88,47 @@ void SimpleEntitySimulation::addEntityInternal(EntityItemPointer entity) { EntitySimulation::addEntityInternal(entity); if (!entity->getSimulatorID().isNull()) { QMutexLocker lock(&_mutex); - _entitiesWithSimulator.insert(entity); + _entitiesWithSimulationOwner.insert(entity); + } else if (entity->getDynamic() && entity->hasLocalVelocity()) { + QMutexLocker lock(&_mutex); + _entitiesThatNeedSimulationOwner.insert(entity); + quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; + if (expiry < _nextOwnerlessExpiry) { + _nextOwnerlessExpiry = expiry; + } } } void SimpleEntitySimulation::removeEntityInternal(EntityItemPointer entity) { EntitySimulation::removeEntityInternal(entity); QMutexLocker lock(&_mutex); - _entitiesWithSimulator.remove(entity); + _entitiesWithSimulationOwner.remove(entity); + _entitiesThatNeedSimulationOwner.remove(entity); } void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) { EntitySimulation::changeEntityInternal(entity); - if (!entity->getSimulatorID().isNull()) { + if (entity->getSimulatorID().isNull()) { QMutexLocker lock(&_mutex); - _entitiesWithSimulator.insert(entity); + _entitiesWithSimulationOwner.remove(entity); + if (entity->getDynamic() && entity->hasLocalVelocity()) { + _entitiesThatNeedSimulationOwner.insert(entity); + quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; + if (expiry < _nextOwnerlessExpiry) { + _nextOwnerlessExpiry = expiry; + } + } + } else { + QMutexLocker lock(&_mutex); + _entitiesWithSimulationOwner.insert(entity); + _entitiesThatNeedSimulationOwner.remove(entity); } entity->clearDirtyFlags(); } void SimpleEntitySimulation::clearEntitiesInternal() { - _entitiesWithSimulator.clear(); + QMutexLocker lock(&_mutex); + _entitiesWithSimulationOwner.clear(); + _entitiesThatNeedSimulationOwner.clear(); } diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index 53a7574bf2..d9c04fdcf9 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -21,6 +21,8 @@ public: SimpleEntitySimulation() : EntitySimulation() { } virtual ~SimpleEntitySimulation() { clearEntitiesInternal(); } + void clearOwnership(const QUuid& ownerID); + protected: virtual void updateEntitiesInternal(const quint64& now) override; virtual void addEntityInternal(EntityItemPointer entity) override; @@ -28,8 +30,9 @@ protected: virtual void changeEntityInternal(EntityItemPointer entity) override; virtual void clearEntitiesInternal() override; - SetOfEntities _entitiesWithSimulator; - quint64 _nextSimulationExpiry { 0 }; + SetOfEntities _entitiesWithSimulationOwner; + SetOfEntities _entitiesThatNeedSimulationOwner; + quint64 _nextOwnerlessExpiry { 0 }; }; #endif // hifi_SimpleEntitySimulation_h diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 8c0dab98db..6a818a1972 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -272,7 +272,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP; if (_numInactiveUpdates > 0) { - const uint8_t MAX_NUM_INACTIVE_UPDATES = 3; + const uint8_t MAX_NUM_INACTIVE_UPDATES = 20; if (_numInactiveUpdates > MAX_NUM_INACTIVE_UPDATES) { // clear local ownership (stop sending updates) and let the server clear itself _entity->clearSimulationOwnership(); @@ -282,7 +282,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { // until it is removed from the outgoing updates // (which happens when we don't own the simulation and it isn't touching our simulation) const float INACTIVE_UPDATE_PERIOD = 0.5f; - return (dt > INACTIVE_UPDATE_PERIOD); + return (dt > INACTIVE_UPDATE_PERIOD * (float)_numInactiveUpdates); } if (!_body->isActive()) { @@ -404,8 +404,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q assert(_entity); assert(entityTreeIsLocked()); - bool active = _body->isActive(); - if (!active) { + if (!_body->isActive()) { // make sure all derivatives are zero glm::vec3 zero(0.0f); _entity->setVelocity(zero); @@ -495,16 +494,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q qCDebug(physics) << " lastSimulated:" << debugTime(lastSimulated, now); #endif //def WANT_DEBUG - if (sessionID == _entity->getSimulatorID()) { - // we think we own the simulation - if (!active) { - // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID - // but we remember that we do still own it... and rely on the server to tell us that we don't - properties.clearSimulationOwner(); - _outgoingPriority = ZERO_SIMULATION_PRIORITY; - } - // else the ownership is not changing so we don't bother to pack it - } else { + if (_numInactiveUpdates > 0) { + // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID + // but we remember that we do still own it... and rely on the server to tell us that we don't + properties.clearSimulationOwner(); + _outgoingPriority = ZERO_SIMULATION_PRIORITY; + } else if (sessionID != _entity->getSimulatorID()) { // we don't own the simulation for this entity yet, but we're sending a bid for it properties.setSimulationOwner(sessionID, glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY)); _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 557b25d9b2..c8dceaa905 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -15,6 +15,7 @@ #include "SpatiallyNestable.h" const float defaultAACubeSize = 1.0f; +const int maxParentingChain = 30; SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) : _nestableType(nestableType), @@ -56,14 +57,14 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) { }); } -Transform SpatiallyNestable::getParentTransform(bool& success) const { +Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const { Transform result; SpatiallyNestablePointer parent = getParentPointer(success); if (!success) { return result; } if (parent) { - Transform parentTransform = parent->getTransform(_parentJointIndex, success); + Transform parentTransform = parent->getTransform(_parentJointIndex, success, depth + 1); result = parentTransform.setScale(1.0f); // TODO: scaling } return result; @@ -393,11 +394,11 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation) { glm::vec3 SpatiallyNestable::getVelocity(bool& success) const { glm::vec3 result; - glm::vec3 parentVelocity = getParentVelocity(success); + Transform parentTransform = getParentTransform(success); if (!success) { return result; } - Transform parentTransform = getParentTransform(success); + glm::vec3 parentVelocity = getParentVelocity(success); if (!success) { return result; } @@ -448,11 +449,11 @@ glm::vec3 SpatiallyNestable::getParentVelocity(bool& success) const { glm::vec3 SpatiallyNestable::getAngularVelocity(bool& success) const { glm::vec3 result; - glm::vec3 parentAngularVelocity = getParentAngularVelocity(success); + Transform parentTransform = getParentTransform(success); if (!success) { return result; } - Transform parentTransform = getParentTransform(success); + glm::vec3 parentAngularVelocity = getParentAngularVelocity(success); if (!success) { return result; } @@ -499,22 +500,36 @@ glm::vec3 SpatiallyNestable::getParentAngularVelocity(bool& success) const { return result; } -const Transform SpatiallyNestable::getTransform(bool& success) const { - // return a world-space transform for this object's location - Transform parentTransform = getParentTransform(success); +const Transform SpatiallyNestable::getTransform(bool& success, int depth) const { Transform result; + // return a world-space transform for this object's location + Transform parentTransform = getParentTransform(success, depth); _transformLock.withReadLock([&] { Transform::mult(result, parentTransform, _transform); }); return result; } -const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success) const { +const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, int depth) const { // this returns the world-space transform for this object. It finds its parent's transform (which may // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. Transform jointInWorldFrame; - Transform worldTransform = getTransform(success); + if (depth > maxParentingChain) { + success = false; + // someone created a loop. break it... + qDebug() << "Parenting loop detected."; + SpatiallyNestablePointer _this = getThisPointer(); + _this->setParentID(QUuid()); + bool setPositionSuccess; + AACube aaCube = getQueryAACube(setPositionSuccess); + if (setPositionSuccess) { + _this->setPosition(aaCube.calcCenter()); + } + return jointInWorldFrame; + } + + Transform worldTransform = getTransform(success, depth); worldTransform.setScale(1.0f); // TODO -- scale; if (!success) { return jointInWorldFrame; @@ -682,7 +697,7 @@ QList SpatiallyNestable::getChildren() const { _childrenLock.withReadLock([&] { foreach(SpatiallyNestableWeakPointer childWP, _children.values()) { SpatiallyNestablePointer child = childWP.lock(); - if (child) { + if (child && child->_parentKnowsMe && child->getParentID() == getID()) { children << child; } } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 2a8976b38f..ee6cccc7a8 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -52,10 +52,10 @@ public: static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success); // world frame - virtual const Transform getTransform(bool& success) const; + virtual const Transform getTransform(bool& success, int depth = 0) const; virtual void setTransform(const Transform& transform, bool& success); - virtual Transform getParentTransform(bool& success) const; + virtual Transform getParentTransform(bool& success, int depth = 0) const; virtual glm::vec3 getPosition(bool& success) const; virtual glm::vec3 getPosition() const; @@ -92,7 +92,7 @@ public: virtual void setScale(const glm::vec3& scale); // get world-frame values for a specific joint - virtual const Transform getTransform(int jointIndex, bool& success) const; + virtual const Transform getTransform(int jointIndex, bool& success, int depth = 0) const; virtual glm::vec3 getPosition(int jointIndex, bool& success) const; virtual glm::vec3 getScale(int jointIndex) const; diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 071d5fd631..0de8f6891d 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -60,10 +60,10 @@ void ViveControllerManager::activate() { [this] (bool clicked) { this->setRenderControllers(clicked); }, true, true); - if (!_hmd) { - _hmd = acquireOpenVrSystem(); + if (!_system) { + _system = acquireOpenVrSystem(); } - Q_ASSERT(_hmd); + Q_ASSERT(_system); // OpenVR provides 3d mesh representations of the controllers // Disabled controller rendering code @@ -71,7 +71,7 @@ void ViveControllerManager::activate() { auto renderModels = vr::VRRenderModels(); vr::RenderModel_t model; - if (!_hmd->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) { + if (!_system->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) { qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING); } else { model::Mesh* mesh = new model::Mesh(); @@ -118,7 +118,7 @@ void ViveControllerManager::activate() { } */ - // unregister with UserInputMapper + // register with UserInputMapper auto userInputMapper = DependencyManager::get(); userInputMapper->registerDevice(_inputDevice); _registeredWithInputMapper = true; @@ -130,9 +130,9 @@ void ViveControllerManager::deactivate() { _container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS); _container->removeMenu(MENU_PATH); - if (_hmd) { + if (_system) { releaseOpenVrSystem(); - _hmd = nullptr; + _system = nullptr; } _inputDevice->_poseStateMap.clear(); @@ -226,56 +226,56 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { _poseStateMap.clear(); - _buttonPressedMap.clear(); PerformanceTimer perfTimer("ViveControllerManager::update"); + auto leftHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand); + auto rightHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand); + + if (!jointsCaptured) { + handleHandController(deltaTime, leftHandDeviceIndex, inputCalibrationData, true); + handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false); + } + int numTrackedControllers = 0; - - for (vr::TrackedDeviceIndex_t device = vr::k_unTrackedDeviceIndex_Hmd + 1; - device < vr::k_unMaxTrackedDeviceCount && numTrackedControllers < 2; ++device) { - - if (!_hmd->IsTrackedDeviceConnected(device)) { - continue; - } - - if (_hmd->GetTrackedDeviceClass(device) != vr::TrackedDeviceClass_Controller) { - continue; - } - - if (!_trackedDevicePose[device].bPoseIsValid) { - continue; - } - + if (leftHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) { numTrackedControllers++; - bool left = numTrackedControllers == 2; + } + if (rightHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) { + numTrackedControllers++; + } + _trackedControllers = numTrackedControllers; +} - if (!jointsCaptured) { - const mat4& mat = _trackedDevicePoseMat4[device]; - const vec3 linearVelocity = _trackedDeviceLinearVelocities[device]; - const vec3 angularVelocity = _trackedDeviceAngularVelocities[device]; - handlePoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity, numTrackedControllers - 1); - } +void ViveControllerManager::InputDevice::handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand) { + + if (_system->IsTrackedDeviceConnected(deviceIndex) && + _system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_Controller && + _trackedDevicePose[deviceIndex].bPoseIsValid) { + + // process pose + const mat4& mat = _trackedDevicePoseMat4[deviceIndex]; + const vec3 linearVelocity = _trackedDeviceLinearVelocities[deviceIndex]; + const vec3 angularVelocity = _trackedDeviceAngularVelocities[deviceIndex]; + handlePoseEvent(deltaTime, inputCalibrationData, mat, linearVelocity, angularVelocity, isLeftHand); - // handle inputs vr::VRControllerState_t controllerState = vr::VRControllerState_t(); - if (_hmd->GetControllerState(device, &controllerState)) { - //qDebug() << (numTrackedControllers == 1 ? "Left: " : "Right: "); - //qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y; - //qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y; + if (_system->GetControllerState(deviceIndex, &controllerState)) { + + // process each button for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) { auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); bool pressed = 0 != (controllerState.ulButtonPressed & mask); - handleButtonEvent(i, pressed, left); + handleButtonEvent(deltaTime, i, pressed, isLeftHand); } + + // process each axis for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { - handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); + handleAxisEvent(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand); } } } - - _trackedControllers = numTrackedControllers; } void ViveControllerManager::InputDevice::focusOutEvent() { @@ -284,42 +284,46 @@ void ViveControllerManager::InputDevice::focusOutEvent() { }; // These functions do translation from the Steam IDs to the standard controller IDs -void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool left) { +void ViveControllerManager::InputDevice::handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand) { //FIX ME? It enters here every frame: probably we want to enter only if an event occurs axis += vr::k_EButton_Axis0; using namespace controller; + if (axis == vr::k_EButton_SteamVR_Touchpad) { - _axisStateMap[left ? LX : RX] = x; - _axisStateMap[left ? LY : RY] = y; + glm::vec2 stick(x, y); + if (isLeftHand) { + stick = _filteredLeftStick.process(deltaTime, stick); + } else { + stick = _filteredRightStick.process(deltaTime, stick); + } + _axisStateMap[isLeftHand ? LX : RX] = stick.x; + _axisStateMap[isLeftHand ? LY : RY] = stick.y; } else if (axis == vr::k_EButton_SteamVR_Trigger) { - _axisStateMap[left ? LT : RT] = x; + _axisStateMap[isLeftHand ? LT : RT] = x; } } // These functions do translation from the Steam IDs to the standard controller IDs -void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool left) { +void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand) { if (!pressed) { return; } + using namespace controller; if (button == vr::k_EButton_ApplicationMenu) { - _buttonPressedMap.insert(left ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB); + _buttonPressedMap.insert(isLeftHand ? LEFT_PRIMARY_THUMB : RIGHT_PRIMARY_THUMB); } else if (button == vr::k_EButton_Grip) { - // Tony says these are harder to reach, so make them the meta buttons - _buttonPressedMap.insert(left ? controller::LB : controller::RB); + _buttonPressedMap.insert(isLeftHand ? LB : RB); } else if (button == vr::k_EButton_SteamVR_Trigger) { - _buttonPressedMap.insert(left ? controller::LT : controller::RT); + _buttonPressedMap.insert(isLeftHand ? LT : RT); } else if (button == vr::k_EButton_SteamVR_Touchpad) { - _buttonPressedMap.insert(left ? controller::LS : controller::RS); - } else if (button == vr::k_EButton_System) { - //FIX ME: not able to ovrewrite the behaviour of this button - _buttonPressedMap.insert(left ? controller::LEFT_SECONDARY_THUMB : controller::RIGHT_SECONDARY_THUMB); + _buttonPressedMap.insert(isLeftHand ? LS : RS); } } -void ViveControllerManager::InputDevice::handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, +void ViveControllerManager::InputDevice::handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, const vec3& linearVelocity, - const vec3& angularVelocity, bool left) { + const vec3& angularVelocity, bool isLeftHand) { // When the sensor-to-world rotation is identity the coordinate axes look like this: // // user @@ -384,8 +388,8 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; - auto translationOffset = (left ? leftTranslationOffset : rightTranslationOffset); - auto rotationOffset = (left ? leftRotationOffset : rightRotationOffset); + auto translationOffset = (isLeftHand ? leftTranslationOffset : rightTranslationOffset); + auto rotationOffset = (isLeftHand ? leftRotationOffset : rightRotationOffset); glm::vec3 position = extractTranslation(mat); glm::quat rotation = glm::normalize(glm::quat_cast(mat)); @@ -399,7 +403,7 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input // handle change in velocity due to translationOffset avatarPose.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat)); avatarPose.angularVelocity = angularVelocity; - _poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar); + _poseStateMap[isLeftHand ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar); } controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const { diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 51339cd465..480fbfeb90 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -50,7 +50,7 @@ public: private: class InputDevice : public controller::InputDevice { public: - InputDevice(vr::IVRSystem*& hmd) : controller::InputDevice("Vive"), _hmd(hmd) {} + InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system) {} private: // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; @@ -58,20 +58,46 @@ private: virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, 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 controller::InputCalibrationData& inputCalibrationData, const mat4& mat, - const vec3& linearVelocity, const vec3& angularVelocity, bool left); + void handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand); + void handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand); + void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand); + void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, + const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand); + + class FilteredStick { + public: + glm::vec2 process(float deltaTime, const glm::vec2& stick) { + // Use a timer to prevent the stick going to back to zero. + // This to work around the noisy touch pad that will flash back to zero breifly + const float ZERO_HYSTERESIS_PERIOD = 0.2f; // 200 ms + if (glm::length(stick) == 0.0f) { + if (_timer <= 0.0f) { + return glm::vec2(0.0f, 0.0f); + } else { + _timer -= deltaTime; + return _stick; + } + } else { + _timer = ZERO_HYSTERESIS_PERIOD; + _stick = stick; + return stick; + } + } + protected: + float _timer { 0.0f }; + glm::vec2 _stick { 0.0f, 0.0f }; + }; + + FilteredStick _filteredLeftStick; + FilteredStick _filteredRightStick; int _trackedControllers { 0 }; - vr::IVRSystem*& _hmd; + vr::IVRSystem*& _system; friend class ViveControllerManager; }; void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign); - - bool _registeredWithInputMapper { false }; bool _modelLoaded { false }; model::Geometry _modelGeometry; @@ -81,8 +107,8 @@ private: int _rightHandRenderID { 0 }; bool _renderControllers { false }; - vr::IVRSystem* _hmd { nullptr }; - std::shared_ptr _inputDevice { std::make_shared(_hmd) }; + vr::IVRSystem* _system { nullptr }; + std::shared_ptr _inputDevice { std::make_shared(_system) }; static const QString NAME; diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js deleted file mode 100644 index a975f74733..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2016 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 -// -(function() { - - var self = this; - - this.preload = function(entityId) { - //print('preload move randomly') - this.isConnected = false; - this.entityId = entityId; - this.updateInterval = 100; - this.posFrame = 0; - this.rotFrame = 0; - this.posInterval = 100; - this.rotInterval = 100; - this.minVelocity = 1; - this.maxVelocity = 5; - this.minAngularVelocity = 0.01; - this.maxAngularVelocity = 0.03; - - this.initialize(entityId); - this.initTimeout = null; - - - var userData = { - ownershipKey: { - owner: MyAvatar.sessionUUID - }, - grabbableKey: { - grabbable: false - } - }; - - Entities.editEntity(entityId, { - userData: JSON.stringify(userData) - }) - } - - this.initialize = function(entityId) { - //print('move randomly should initialize' + entityId) - var properties = Entities.getEntityProperties(entityId); - if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) { - self.initTimeout = Script.setTimeout(function() { - //print('no user data yet, try again in one second') - self.initialize(entityId); - }, 1000) - - } else { - //print('userdata before parse attempt' + properties.userData) - self.userData = null; - try { - self.userData = JSON.parse(properties.userData); - } catch (err) { - //print('error parsing json'); - //print('properties are:' + properties.userData); - return; - } - Script.update.connect(self.update); - this.isConnected = true; - } - } - - this.update = function(deltaTime) { - // print('jbp in update') - var data = Entities.getEntityProperties(self.entityId, 'userData').userData; - var userData; - try { - userData = JSON.parse(data) - } catch (e) { - //print('error parsing json' + data) - return; - }; - - // print('userdata is' + data) - //if the entity doesnt have an owner set yet - if (userData.hasOwnProperty('ownershipKey') !== true) { - //print('no movement owner yet') - return; - } - - //print('owner is:::' + userData.ownershipKey.owner) - //get all the avatars to see if the owner is around - var avatars = AvatarList.getAvatarIdentifiers(); - var ownerIsAround = false; - - //if the current owner is not me... - if (userData.ownershipKey.owner !== MyAvatar.sessionUUID) { - - //look to see if the current owner is around anymore - for (var i = 0; i < avatars.length; i++) { - if (avatars[i] === userData.ownershipKey.owner) { - ownerIsAround = true - //the owner is around - return; - }; - } - - //if the owner is not around, then take ownership - if (ownerIsAround === false) { - //print('taking ownership') - - var userData = { - ownershipKey: { - owner: MyAvatar.sessionUUID - }, - grabbableKey: { - grabbable: false - } - }; - Entities.editEntity(self.entityId, { - userData: JSON.stringify(data) - }) - } - } - //but if the current owner IS me, then move it - else { - //print('jbp im the owner so move it') - self.posFrame++; - self.rotFrame++; - - if (self.posFrame > self.posInterval) { - - self.posInterval = 100 * Math.random() + 300; - self.posFrame = 0; - - var magnitudeV = self.maxVelocity; - var directionV = { - x: Math.random() - 0.5, - y: Math.random() - 0.5, - z: Math.random() - 0.5 - }; - - //print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); - Entities.editEntity(self.entityId, { - velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)) - - }); - - } - - if (self.rotFrame > self.rotInterval) { - - self.rotInterval = 100 * Math.random() + 250; - self.rotFrame = 0; - - var magnitudeAV = self.maxAngularVelocity; - - var directionAV = { - x: Math.random() - 0.5, - y: Math.random() - 0.5, - z: Math.random() - 0.5 - }; - //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); - Entities.editEntity(self.entityId, { - angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) - - }); - - } - - } - - } - - this.unload = function() { - if (this.initTimeout !== null) { - Script.clearTimeout(this.initTimeout); - } - - if (this.isConnected === true) { - Script.update.disconnect(this.update); - } - - } - - - -}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js b/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js index 4136f1f81b..c1187bc6d5 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js @@ -7,7 +7,7 @@ (function() { - var version = 11; + var version = 12; var added = false; this.frame = 0; var utilsScript = Script.resolvePath('utils.js'); @@ -23,22 +23,21 @@ } this.initialize = function(entityId) { - print('JBP nav button should initialize' + entityId) var properties = Entities.getEntityProperties(entityId); if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) { self.initTimeout = Script.setTimeout(function() { - print('JBP no user data yet, try again in one second') + // print(' no user data yet, try again in one second') self.initialize(entityId); }, 1000) } else { - print('JBP userdata before parse attempt' + properties.userData) + // print('userdata before parse attempt' + properties.userData) self.userData = null; try { self.userData = JSON.parse(properties.userData); } catch (err) { - print('JBP error parsing json'); - print('JBP properties are:' + properties.userData); + // print(' error parsing json'); + // print(' properties are:' + properties.userData); return; } @@ -46,9 +45,9 @@ var mySavedSettings = Settings.getValue(entityId); if (mySavedSettings.buttons !== undefined) { - print('JBP preload buttons' + mySavedSettings.buttons) + // print(' preload buttons' + mySavedSettings.buttons) mySavedSettings.buttons.forEach(function(b) { - print('JBP deleting button' + b) + // print(' deleting button' + b) Overlays.deleteOverlay(b); }) Settings.setValue(entityId, '') @@ -56,16 +55,15 @@ self.buttonImageURL = baseURL + "GUI/GUI_" + self.userData.name + ".png?" + version; - print('JBP BUTTON IMAGE URL:' + self.buttonImageURL) + // print(' BUTTON IMAGE URL:' + self.buttonImageURL) if (self.button === undefined) { - // print('NAV NO BUTTON ADDING ONE!!') + // print(' NO BUTTON ADDING ONE!!') self.button = true; self.addButton(); } else { - // print('NAV SELF ALREADY HAS A BUTTON!!') + //print(' SELF ALREADY HAS A BUTTON!!') } - } } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js index 6651e435b4..8ee5e0092e 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js @@ -36,8 +36,6 @@ return; } - - self.addButton(); self.buttonShowing = false; self.showDistance = self.userData.showDistance; @@ -51,8 +49,6 @@ }; self.sound = SoundCache.getSound(this.soundURL); - - } this.addButton = function() { diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js index d8b32ab176..3f6067693c 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js @@ -10,7 +10,7 @@ var self = this; var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; - var version = 2; + var version = 3; this.preload = function(entityId) { this.soundPlaying = null; this.entityId = entityId; diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js index da41ec64ba..3fc5acae2a 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js @@ -52,13 +52,7 @@ print("Teleporting to (" + data.location.x + ", " + data.location.y + ", " + data.location.z + ")"); MyAvatar.position = data.location; - - // if (data.hasOwnProperty('entryPoint') && data.hasOwnProperty('target')) { - // this.lookAtTarget(data.entryPoint, data.target); - // } - // else{ - // } } } @@ -103,10 +97,4 @@ } } - this.hoverEnterEntity = function(entityID) { - Entities.editEntity(entityID, { - animationURL: animationURL, - animationSettings: '{ "fps": 24, "firstFrame": 1, "lastFrame": 25, "frameIndex": 1, "running": true, "hold": true }' - }); - } }) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/backgroundMusicAC.js b/unpublishedScripts/DomainContent/CellScience/backgroundMusicAC.js index 0ee5b3bf32..1b4c06caaa 100644 --- a/unpublishedScripts/DomainContent/CellScience/backgroundMusicAC.js +++ b/unpublishedScripts/DomainContent/CellScience/backgroundMusicAC.js @@ -7,7 +7,7 @@ var soundMap = [{ y: 15850, z: 15850 }, - volume: 0.1, + volume: 0.03, loop: true } }, { @@ -19,7 +19,7 @@ var soundMap = [{ y: 15950, z: 15950 }, - volume: 0.1, + volume: 0.03, loop: true } }, { @@ -31,7 +31,7 @@ var soundMap = [{ y: 15650, z: 15650 }, - volume: 0.1, + volume: 0.03, loop: true } }, { @@ -43,7 +43,7 @@ var soundMap = [{ y: 15750, z: 15750 }, - volume: 0.1, + volume: 0.03, loop: true } } diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index ca0eb21f21..876df8adb1 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1035; +var version = 1112; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -103,9 +103,9 @@ var scenes = [{ instances: [{ model: "Cell", dimensions: { - x: 550, - y: 620, - z: 550 + x: 500, + y: 570, + z: 500 }, offset: { x: 0, @@ -151,294 +151,253 @@ var scenes = [{ skybox: "cosmos_skybox_blurred" }, instances: [{ - model: "translation", - dimensions: { - x: 10, - y: 16, - z: 10 - }, - offset: { - x: 0, - y: 0, - z: 0 - }, - radius: 300, - number: 7, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - }, - target: locations.ribosome[1], - location: locations.ribosome[0], - baseURL: baseLocation - }), - script: "zoom.js?" + version, - visible: true - }, { - model: "vesicle", - dimensions: { - x: 60, - y: 60, - z: 60 - }, - randomSize: 10, - offset: { - x: 0, - y: 0, - z: 0 - }, - radius: 1000, - number: 22, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - script: "moveRandomly.js?" + version, - visible: true - }, { //golgi vesicles - model: "vesicle", - dimensions: { - x: 10, - y: 10, - z: 10 - }, - randomSize: 10, - offset: { - x: -319, - y: 66, - z: 976 - }, - radius: 140, - number: 10, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - script: "", - visible: true - }, { //golgi vesicles - model: "vesicle", - dimensions: { - x: 15, - y: 15, - z: 15 - }, - randomSize: 10, - offset: { - x: -319, - y: 66, - z: 976 - }, - radius: 115, - number: 7, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - script: "moveRandomly.js?" + version, - visible: true - }, { - model: "vesicle", - dimensions: { - x: 50, - y: 50, - z: 50 - }, - randomSize: 10, - offset: { - x: 0, - y: 0, - z: 0 - }, - radius: 600, - number: 15, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - script: "", - visible: true - }, { //outer vesicles - model: "vesicle", - dimensions: { - x: 60, - y: 60, - z: 60 - }, - randomSize: 10, - offset: { - x: 0, - y: 0, - z: 0 - }, - radius: 1600, - number: 22, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - script: "", - visible: true - }, { //outer vesicles - model: "vesicle", - dimensions: { - x: 40, - y: 40, - z: 40 - }, - randomSize: 10, - offset: { - x: 0, - y: 0, - z: 0 - }, - radius: 1400, - number: 22, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - script: "moveRandomly.js?" + version, - visible: true - }, { //outer vesicles - model: "vesicle", - dimensions: { - x: 80, - y: 80, - z: 80 - }, - randomSize: 10, - offset: { - x: 0, - y: 0, - z: 0 - }, - radius: 1800, - number: 22, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - script: "moveRandomly.js?" + version, - visible: true + model: "translation", + dimensions: { + x: 10, + y: 16, + z: 10 }, - // {//wigglies - // model:"wiggly", - // dimensions:{x:320,y:40,z:160}, - // randomSize: 10, - // offset:{x:0,y:0,z:0}, - // radius:1800, - // number:50, - // userData:"", - // script:"moveRandomly", - // visible:true - // }, - //// {//wigglies - // model:"wiggly", - // dimensions:{x:640,y:80,z:320}, - // randomSize: 10, - // offset:{x:0,y:0,z:0}, - // radius:2100, - // number:50, - // userData:"", - // script:"moveRandomly", - // visible:true - // }, - { - model: "hexokinase", - dimensions: { - x: 3, - y: 4, - z: 3 + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 300, + number: 7, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false }, - randomSize: 10, - offset: { - x: 236, - y: 8, - z: 771 + target: locations.ribosome[1], + location: locations.ribosome[0], + baseURL: baseLocation + }), + script: "zoom.js?" + version, + visible: true + }, { + model: "vesicle", + dimensions: { + x: 60, + y: 60, + z: 60 + }, + randomSize: 10, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 1000, + number: 22, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + visible: true + }, { //golgi vesicles + model: "vesicle", + dimensions: { + x: 10, + y: 10, + z: 10 + }, + randomSize: 10, + offset: { + x: -319, + y: 66, + z: 976 + }, + radius: 140, + number: 10, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + script: "", + visible: true + }, { //golgi vesicles + model: "vesicle", + dimensions: { + x: 15, + y: 15, + z: 15 + }, + randomSize: 10, + offset: { + x: -319, + y: 66, + z: 976 + }, + radius: 115, + number: 7, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + visible: true + }, { + model: "vesicle", + dimensions: { + x: 50, + y: 50, + z: 50 + }, + randomSize: 10, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 600, + number: 15, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + script: "", + visible: true + }, { //outer vesicles + model: "vesicle", + dimensions: { + x: 60, + y: 60, + z: 60 + }, + randomSize: 10, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 1600, + number: 22, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + script: "", + visible: true + }, { //outer vesicles + model: "vesicle", + dimensions: { + x: 40, + y: 40, + z: 40 + }, + randomSize: 10, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 1400, + number: 22, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + visible: true + }, { //outer vesicles + model: "vesicle", + dimensions: { + x: 80, + y: 80, + z: 80 + }, + randomSize: 10, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 1800, + number: 22, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + visible: true + }, { + model: "hexokinase", + dimensions: { + x: 3, + y: 4, + z: 3 + }, + randomSize: 10, + offset: { + x: 236, + y: 8, + z: 771 + }, + radius: 80, + number: 7, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false }, - radius: 80, - number: 7, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - }, - target: locations.hexokinase[1], - location: locations.hexokinase[0], - baseURL: baseLocation - }), - script: "zoom.js?" + version, - visible: true - }, { - model: "pfructo_kinase", - dimensions: { - x: 3, - y: 4, - z: 3 + target: locations.hexokinase[1], + location: locations.hexokinase[0], + baseURL: baseLocation + }), + script: "zoom.js?" + version, + visible: true + }, { + model: "pfructo_kinase", + dimensions: { + x: 3, + y: 4, + z: 3 + }, + randomSize: 10, + offset: { + x: 236, + y: 8, + z: 771 + }, + radius: 60, + number: 7, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false }, - randomSize: 10, - offset: { - x: 236, - y: 8, - z: 771 + target: locations.hexokinase[1], + location: locations.hexokinase[0], + }), + script: "zoom.js?" + version, + visible: true + }, { + model: "glucose_isomerase", + dimensions: { + x: 3, + y: 4, + z: 3 + }, + randomSize: 10, + offset: { + x: 236, + y: 8, + z: 771 + }, + radius: 70, + number: 7, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false }, - radius: 60, - number: 7, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - }, - target: locations.hexokinase[1], - location: locations.hexokinase[0], - }), - script: "zoom.js?" + version, - visible: true - }, { - model: "glucose_isomerase", - dimensions: { - x: 3, - y: 4, - z: 3 - }, - randomSize: 10, - offset: { - x: 236, - y: 8, - z: 771 - }, - radius: 70, - number: 7, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - }, - target: locations.hexokinase[1], - location: locations.hexokinase[0], - }), - script: "zoom.js?" + version, - visible: true - } - // { - // model:"NPC", - // dimensions:{x:20,y:20,z:20}, - // randomSize: 10, - // offset:{x:208.593693,y:6.113100222,z:153.3202277}, - // radius:520, - // number:25, - // userData: "", - // script:"", - // visible:true - // } - - - ], + target: locations.hexokinase[1], + location: locations.hexokinase[0], + }), + script: "zoom.js?" + version, + visible: true + }], boundary: { radius: locations.cellLayout[2], center: locations.cellLayout[0], @@ -600,7 +559,7 @@ function ImportScene(scene) { CreateZone(scene); CreateInstances(scene); - CreateBoundary(scene); + // CreateBoundary(scene); // print("done " + scene.name); @@ -609,12 +568,10 @@ function ImportScene(scene) { clearAllNav(); function clearAllNav() { - // print('NAV CLEARING ALL NAV'); var result = Entities.findEntities(MyAvatar.position, 25000); result.forEach(function(r) { var properties = Entities.getEntityProperties(r, "name"); if (properties.name.indexOf('navigation button') > -1) { - // print('NAV DELETING NAV BUTTON AT START:: '+r) Entities.deleteEntity(r); } }) @@ -645,9 +602,6 @@ function createLayoutLights() { } function CreateNavigationButton(scene, number) { - // print('NAV NAVIGATION CREATING NAV!!' +scene.name + " " + number) - - Entities.addEntity({ type: "Box", name: scene.name + " navigation button", @@ -818,7 +772,7 @@ function CreateInstances(scene) { x: 0, y: 0, z: 0 - }, idBounds, 150); + }, idBounds, 150, scene.instances[i]); } //print('SCRIPT AT CREATE ENTITY: ' + script) @@ -831,6 +785,7 @@ function CreateInstances(scene) { function CreateIdentification(name, position, rotation, dimensions, showDistance) { //print ("creating ID for " + name); + Entities.addEntity({ type: "Sphere", name: "ID for " + name, @@ -9045,4 +9000,9 @@ createLayoutLights(); Script.scriptEnding.connect(function() { Entities.addingEntity.disconnect(makeUngrabbable); -}); \ No newline at end of file +}); + +Script.setTimeout(function() { + print('JBP stopping cell science import'); + Script.stop(); +}, 30000) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/motorProteinControllerAC.js b/unpublishedScripts/DomainContent/CellScience/motorProteinControllerAC.js index 672ec1fd92..59577d49ba 100644 --- a/unpublishedScripts/DomainContent/CellScience/motorProteinControllerAC.js +++ b/unpublishedScripts/DomainContent/CellScience/motorProteinControllerAC.js @@ -18,8 +18,6 @@ if (USE_LOCAL_HOST === true) { var USE_LOCAL_HOST = false; -Agent.isAvatar = true; - EntityViewer.setPosition({ x: 3000, y: 13500, diff --git a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js new file mode 100644 index 0000000000..cf35e081e0 --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js @@ -0,0 +1,103 @@ +// Copyright 2016 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 +// + +var basePosition = { + x: 3000, + y: 13500, + z: 3000 +}; + +var initialized = false; + +EntityViewer.setPosition(basePosition); +EntityViewer.setKeyholeRadius(60000); +var octreeQueryInterval = Script.setInterval(function() { + EntityViewer.queryOctree(); +}, 200); + +var THROTTLE = true; +var THROTTLE_RATE = 5000; + +var sinceLastUpdate = 0; + +//print('cells script') + +function findCells() { + var results = Entities.findEntities(basePosition, 60000); + + if (results.length === 0) { + // print('no entities found') + return; + } + + results.forEach(function(v) { + var name = Entities.getEntityProperties(v, 'name').name; + // print('name is:: ' + name) + if (name === 'Cell') { + // print('found a cell!!' + v) + Script.setTimeout(function() { + moveCell(v); + }, Math.random() * THROTTLE_RATE); + } + }); +} + + +var minAngularVelocity = 0.01; +var maxAngularVelocity = 0.03; + +function moveCell(entityId) { + // print('moving a cell! ' + entityId) + + var magnitudeAV = maxAngularVelocity; + + var directionAV = { + x: Math.random() - 0.5, + y: Math.random() - 0.5, + z: Math.random() - 0.5 + }; + // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + Entities.editEntity(entityId, { + angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) + }); + +} + +function update(deltaTime) { + + // print('deltaTime',deltaTime) + if (!initialized) { + print("checking for servers..."); + if (Entities.serversExist() && Entities.canRez()) { + print("servers exist -- makeAll..."); + Entities.setPacketsPerSecond(6000); + print("PPS:" + Entities.getPacketsPerSecond()); + initialized = true; + } + return; + } + + if (THROTTLE === true) { + sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; + if (sinceLastUpdate > THROTTLE_RATE) { + // print('SHOULD FIND CELLS!!!') + sinceLastUpdate = 0; + findCells(); + } else { + // print('returning in update ' + sinceLastUpdate) + return; + } + } + +} + +function unload() { + Script.update.disconnect(update); +} + +Script.update.connect(update); +Script.scriptEnding.connect(unload); \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js new file mode 100644 index 0000000000..922f0d94cf --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js @@ -0,0 +1,108 @@ +// Copyright 2016 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 +// + +var basePosition = { + x: 3000, + y: 13500, + z: 3000 +}; + +var initialized = false; + +EntityViewer.setPosition(basePosition); +EntityViewer.setKeyholeRadius(60000); +var octreeQueryInterval = Script.setInterval(function() { + EntityViewer.queryOctree(); +}, 200); + +var THROTTLE = true; +var THROTTLE_RATE = 5000; + +var sinceLastUpdate = 0; + +//print('vesicle script') + +function findVesicles() { + var results = Entities.findEntities(basePosition, 60000); + + if (results.length === 0) { + // print('no entities found'); + return; + } + + results.forEach(function(v) { + var name = Entities.getEntityProperties(v, 'name').name; + if (name === 'vesicle') { + //print('found a vesicle!!' + v) + Script.setTimeout(function() { + moveVesicle(v); + }, Math.random() * THROTTLE_RATE); + } + }); +} + +var minVelocity = 1; +var maxVelocity = 5; +var minAngularVelocity = 0.01; +var maxAngularVelocity = 0.03; + +function moveVesicle(entityId) { + // print('moving a vesicle! ' + entityId) + var magnitudeV = maxVelocity; + var directionV = { + x: Math.random() - 0.5, + y: Math.random() - 0.5, + z: Math.random() - 0.5 + }; + + // print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); + + var magnitudeAV = maxAngularVelocity; + + var directionAV = { + x: Math.random() - 0.5, + y: Math.random() - 0.5, + z: Math.random() - 0.5 + }; + // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + Entities.editEntity(entityId, { + velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), + angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) + }); + +} + +function update(deltaTime) { + if (!initialized) { + print("checking for servers..."); + if (Entities.serversExist() && Entities.canRez()) { + print("servers exist -- makeAll..."); + Entities.setPacketsPerSecond(6000); + print("PPS:" + Entities.getPacketsPerSecond()); + initialized = true; + } + return; + } + + if (THROTTLE === true) { + sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; + if (sinceLastUpdate > THROTTLE_RATE) { + sinceLastUpdate = 0; + findVesicles(); + } else { + return; + } + } + +} + +function unload() { + Script.update.disconnect(update); +} + +Script.update.connect(update); +Script.scriptEnding.connect(unload); \ No newline at end of file