From 0bf822f17b54731cb6bffa66e7660842381b2ae7 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 11 Feb 2016 16:48:54 -0800 Subject: [PATCH 01/34] update and add another entity script --- .../CellScience/Scripts/moveRandomly.js | 138 ++------------- .../Scripts/zoomAndMoveRandomly.js | 159 ++++++++++++++++++ .../CellScience/backgroundMusicAC.js | 8 +- .../CellScience/importCellScience.js | 4 +- 4 files changed, 181 insertions(+), 128 deletions(-) create mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js index a975f74733..8c3a6c0852 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js @@ -8,124 +8,32 @@ var self = this; - this.preload = function(entityId) { - //print('preload move randomly') + this.preload=function(entityId){ 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) - }) + Script.setTimeout(self.move,self.getTotalWait()) } - 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 + this.getTotalWait = function() { var avatars = AvatarList.getAvatarIdentifiers(); - var ownerIsAround = false; + var avatarCount = avatars.length; + var random = Math.random() * 2000; + var totalWait = random * (avatarCount * 2); - //if the current owner is not me... - if (userData.ownershipKey.owner !== MyAvatar.sessionUUID) { + return totalWait + } - //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') + this.move = function() { + print('jbp im the owner so move it') + + - 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 = { @@ -137,16 +45,9 @@ //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 = { @@ -160,20 +61,13 @@ }); - } - - } + + Script.setTimeout(self.move,self.getTotalWait()) } - this.unload = function() { - if (this.initTimeout !== null) { - Script.clearTimeout(this.initTimeout); - } - if (this.isConnected === true) { - Script.update.disconnect(this.update); - } + this.unload = function() { } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js new file mode 100644 index 0000000000..f0f77b12e0 --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -0,0 +1,159 @@ +// 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 teleport; + var portalDestination; + var animationURL; + var self = this; + + this.entered = true; + + this.preload = function(entityID) { + this.entityId = entityID; + this.initialize(entityID); + this.initTimeout = null; + this.minVelocity = 1; + this.maxVelocity = 5; + this.minAngularVelocity = 0.01; + this.maxAngularVelocity = 0.03; + Script.setTimeout(self.move, self.getTotalWait()) + } + + this.initialize = function(entityID) { + // print(' should initialize') + 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(' has userData') + self.portalDestination = properties.userData; + animationURL = properties.modelURL; + self.soundOptions = { + stereo: true, + loop: false, + localOnly: false, + position: properties.position, + volume: 0.5 + }; + + self.teleportSound = SoundCache.getSound("https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/whoosh.wav"); + // print(" portal destination is " + self.portalDestination); + } + } + + this.enterEntity = function(entityID) { + //print('ENTERED A BOUNDARY ENTITY, SHOULD ZOOM', entityID) + var data = JSON.parse(Entities.getEntityProperties(this.entityId).userData); + //print('DATA IS::' + data) + if (data != null) { + 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{ + + // } + } + + } + + this.lookAtTarget = function(entryPoint, target) { + //print('SHOULD LOOK AT TARGET') + var direction = Vec3.normalize(Vec3.subtract(entryPoint, target)); + var pitch = Quat.angleAxis(Math.asin(-direction.y) * 180.0 / Math.PI, { + x: 1, + y: 0, + z: 0 + }); + var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * 180.0 / Math.PI, { + x: 0, + y: 1, + z: 0 + }); + + MyAvatar.goToLocation(entryPoint, true, yaw); + + MyAvatar.headYaw = 0; + + } + + this.leaveEntity = function(entityID) { + Entities.editEntity(entityID, { + animationURL: animationURL, + animationSettings: '{ "frameIndex": 1, "running": false }' + }); + this.entered = false; + if (this.initTimeout !== null) { + Script.clearTimeout(this.initTimeout); + } + //playSound(); + } + + this.unload = function() { + if (this.initTimeout !== null) { + Script.clearTimeout(this.initTimeout); + } + } + + this.hoverEnterEntity = function(entityID) { + Entities.editEntity(entityID, { + animationURL: animationURL, + animationSettings: '{ "fps": 24, "firstFrame": 1, "lastFrame": 25, "frameIndex": 1, "running": true, "hold": true }' + }); + } + + this.getTotalWait = function() { + var avatars = AvatarList.getAvatarIdentifiers(); + var avatarCount = avatars.length; + var random = Math.random() * 2000; + var totalWait = random * (avatarCount * 2); + + return totalWait + } + + + this.move = function() { + print('jbp im the owner so move it') + + 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)) + }); + + + + 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)) + + }); + + Script.setTimeout(self.move, self.getTotalWait()) + } + +}) \ 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..7d9a49294f 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 = 1039; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -120,7 +120,7 @@ var scenes = [{ location: locations.cellLayout[1], baseURL: baseLocation }), - script: "zoom.js?" + version, + script: "zoomAndMoveRandomly.js?" + version, visible: true }], boundary: { From f346ac7023c4ea9f4819bc13677867ac9b9add91 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 12 Feb 2016 13:58:02 -0800 Subject: [PATCH 02/34] logging --- examples/gridTest.js | 5 +++-- .../CellScience/Scripts/moveRandomly.js | 8 ++------ .../CellScience/Scripts/navigationButton.js | 6 +++--- .../CellScience/Scripts/showIdentification.js | 3 ++- .../DomainContent/CellScience/Scripts/zoom.js | 1 + .../Scripts/zoomAndMoveRandomly.js | 1 - .../CellScience/importCellScience.js | 20 +++++++++++-------- 7 files changed, 23 insertions(+), 21 deletions(-) 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/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js index 8c3a6c0852..2cced94672 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js @@ -9,6 +9,7 @@ var self = this; this.preload=function(entityId){ + print('JBP MOVE RANDOMLY PRELOAD') this.isConnected = false; this.entityId = entityId; this.minVelocity = 1; @@ -22,7 +23,7 @@ this.getTotalWait = function() { var avatars = AvatarList.getAvatarIdentifiers(); var avatarCount = avatars.length; - var random = Math.random() * 2000; + var random = Math.random() * 5000; var totalWait = random * (avatarCount * 2); return totalWait @@ -30,11 +31,6 @@ this.move = function() { - print('jbp im the owner so move it') - - - - var magnitudeV = self.maxVelocity; var directionV = { x: Math.random() - 0.5, diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js b/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js index 4136f1f81b..16fb31189a 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js @@ -17,6 +17,7 @@ var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; this.preload = function(entityId) { + print('JBP NAV PRELOAD') this.entityId = entityId; this.initialize(entityId); this.initTimeout = null; @@ -58,14 +59,13 @@ self.buttonImageURL = baseURL + "GUI/GUI_" + self.userData.name + ".png?" + version; print('JBP BUTTON IMAGE URL:' + self.buttonImageURL) if (self.button === undefined) { - // print('NAV NO BUTTON ADDING ONE!!') + print('JBP NO BUTTON ADDING ONE!!') self.button = true; self.addButton(); } else { - // print('NAV SELF ALREADY HAS A BUTTON!!') + print('JBP SELF ALREADY HAS A BUTTON!!') } - } } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js index d8b32ab176..b7aad5e652 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js @@ -10,8 +10,9 @@ var self = this; var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; - var version = 2; + var version = 3; this.preload = function(entityId) { + print('JBP SHOW IDENTIFICATION PRELOAD') this.soundPlaying = null; this.entityId = entityId; self.initTimeout = null; diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js index da41ec64ba..d075966524 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js @@ -14,6 +14,7 @@ this.entered = true; this.preload = function(entityID) { + print('JBP Zoom PRELOAD') this.entityId = entityID; this.initialize(entityID); this.initTimeout = null; diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index f0f77b12e0..e4ee59cb6b 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -124,7 +124,6 @@ this.move = function() { - print('jbp im the owner so move it') var magnitudeV = self.maxVelocity; var directionV = { diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 7d9a49294f..bf112f5bad 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 = 1039; +var version = 1041; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -645,8 +645,7 @@ function createLayoutLights() { } function CreateNavigationButton(scene, number) { - // print('NAV NAVIGATION CREATING NAV!!' +scene.name + " " + number) - + print('JBP NAVIGATION CREATING NAV!!' +scene.name + " " + number) Entities.addEntity({ type: "Box", @@ -657,11 +656,11 @@ function CreateNavigationButton(scene, number) { blue: 0 }, dimensions: { - x: 16000, - y: 16000, - z: 16000 + x: 14000, + y: 14000, + z: 14000 }, - visible: false, + visible: true, userData: JSON.stringify({ name: scene.name, entryPoint: scene.entryPoint, @@ -9045,4 +9044,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 From e828a7e6e2b2fd0dfae93bfa202108b01698ce87 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 12 Feb 2016 19:38:40 -0800 Subject: [PATCH 03/34] quiet prints --- .../CellScience/Scripts/moveRandomly.js | 1 - .../CellScience/Scripts/navigationButton.js | 22 +++++++++---------- .../CellScience/Scripts/showIdentification.js | 1 - .../DomainContent/CellScience/Scripts/zoom.js | 1 - .../CellScience/importCellScience.js | 14 +++++------- 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js index 2cced94672..cc822ddf8a 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js @@ -9,7 +9,6 @@ var self = this; this.preload=function(entityId){ - print('JBP MOVE RANDOMLY PRELOAD') this.isConnected = false; this.entityId = entityId; this.minVelocity = 1; diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js b/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js index 16fb31189a..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'); @@ -17,29 +17,27 @@ var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; this.preload = function(entityId) { - print('JBP NAV PRELOAD') this.entityId = entityId; this.initialize(entityId); this.initTimeout = null; } 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; } @@ -47,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, '') @@ -57,14 +55,14 @@ 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('JBP NO BUTTON ADDING ONE!!') + // print(' NO BUTTON ADDING ONE!!') self.button = true; self.addButton(); } else { - print('JBP SELF ALREADY HAS A BUTTON!!') + //print(' SELF ALREADY HAS A BUTTON!!') } } } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js index b7aad5e652..3f6067693c 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js @@ -12,7 +12,6 @@ var version = 3; this.preload = function(entityId) { - print('JBP SHOW IDENTIFICATION PRELOAD') this.soundPlaying = null; this.entityId = entityId; self.initTimeout = null; diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js index d075966524..da41ec64ba 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js @@ -14,7 +14,6 @@ this.entered = true; this.preload = function(entityID) { - print('JBP Zoom PRELOAD') this.entityId = entityID; this.initialize(entityID); this.initTimeout = null; diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index bf112f5bad..db50635f93 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 = 1041; +var version = 1043; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -609,12 +609,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,8 +643,6 @@ function createLayoutLights() { } function CreateNavigationButton(scene, number) { - print('JBP NAVIGATION CREATING NAV!!' +scene.name + " " + number) - Entities.addEntity({ type: "Box", name: scene.name + " navigation button", @@ -656,11 +652,11 @@ function CreateNavigationButton(scene, number) { blue: 0 }, dimensions: { - x: 14000, - y: 14000, - z: 14000 + x: 16000, + y: 16000, + z: 16000 }, - visible: true, + visible: false, userData: JSON.stringify({ name: scene.name, entryPoint: scene.entryPoint, From 214723f1bfdf86cf1821265742e53d016be628a0 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 18 Feb 2016 14:27:47 -0800 Subject: [PATCH 04/34] baton for moving vesicles" " --- .../CellScience/Scripts/colorRandomly.js | 104 +++++ .../CellScience/Scripts/moveRandomly.js | 71 ---- .../CellScience/Scripts/moveRandomly2.js | 95 +++++ .../CellScience/Scripts/virtualBaton.js | 381 ++++++++++++++++++ .../Scripts/zoomAndMoveRandomly.js | 48 ++- .../CellScience/importCellScience.js | 10 +- 6 files changed, 618 insertions(+), 91 deletions(-) create mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js delete mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js create mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js create mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js new file mode 100644 index 0000000000..cf4ee810e7 --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js @@ -0,0 +1,104 @@ +// 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() { + + Script.include(Script.resolvePath('virtualBaton.js')); + + var self = this; + + var baton; + var iOwn = false; + var currentInterval; + var _entityId; + + function startUpdate() { + iOwn = true; + print('i am the owner ' + _entityId) + } + + function stopUpdateAndReclaim() { + print('i released the object ' + _entityId) + iOwn = false; + baton.claim(startUpdate, stopUpdateAndReclaim); + } + + this.preload = function(entityId) { + this.isConnected = false; + this.entityId = entityId; + _entityId = entityId; + this.minVelocity = 1; + this.maxVelocity = 5; + this.minAngularVelocity = 0.01; + this.maxAngularVelocity = 0.03; + baton = virtualBaton({ + batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity + }); + stopUpdateAndReclaim(); + currentInterval = Script.setInterval(self.move, self.getTotalWait()) + } + + + this.getTotalWait = function() { + return (Math.random() * 5000) * 2; + // var avatars = AvatarList.getAvatarIdentifiers(); + // var avatarCount = avatars.length; + // var random = Math.random() * 5000; + // var totalWait = random * (avatarCount * 2); + // print('cellscience color avatarcount, totalwait: ', avatarCount, totalWait) + // return totalWait + } + + + this.move = function() { + if (!iOwn) { + return; + } + + var properties = Entities.getEntityProperties(self.entityId); + var color = properties.color; + + var newColor; + var red = { + red: 255, + green: 0, + blue: 0 + } + var green = { + red: 0, + green: 255, + blue: 0 + } + var blue = { + red: 0, + green: 0, + blue: 255 + } + if (color.red > 0) { + newColor = green; + } + if (color.green > 0) { + newColor = blue; + } + if (color.blue > 0) { + newColor = red + } + Entities.editEntity(self.entityId, { + color: newColor + }); + + + } + + + this.unload = function() { + baton.release(function() {}); + Script.clearTimeout(currentInterval); + } + + + +}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js deleted file mode 100644 index cc822ddf8a..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js +++ /dev/null @@ -1,71 +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){ - this.isConnected = false; - this.entityId = entityId; - this.minVelocity = 1; - this.maxVelocity = 5; - this.minAngularVelocity = 0.01; - this.maxAngularVelocity = 0.03; - Script.setTimeout(self.move,self.getTotalWait()) - } - - - this.getTotalWait = function() { - var avatars = AvatarList.getAvatarIdentifiers(); - var avatarCount = avatars.length; - var random = Math.random() * 5000; - var totalWait = random * (avatarCount * 2); - - return totalWait - } - - - this.move = function() { - 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)) - }); - - - 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)) - - }); - - - - Script.setTimeout(self.move,self.getTotalWait()) - } - - - this.unload = function() { - - } - - - -}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js new file mode 100644 index 0000000000..f720ca91cc --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js @@ -0,0 +1,95 @@ +// 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() { + + Script.include('virtualBaton.js'); + + var self = this; + + var baton; + var iOwn = false; + var currentInterval; + var _entityId; + + function startUpdate() { + iOwn = true; + print('i am the owner ' + _entityId) + } + + function stopUpdateAndReclaim() { + print('i released the object ' + _entityId) + iOwn = false; + baton.claim(startUpdate, stopUpdateAndReclaim); + } + + this.preload = function(entityId) { + this.isConnected = false; + this.entityId = entityId; + _entityId = entityId; + this.minVelocity = 1; + this.maxVelocity = 5; + this.minAngularVelocity = 0.01; + this.maxAngularVelocity = 0.03; + baton = virtualBaton({ + batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity + }); + stopUpdateAndReclaim(); + currentInterval = Script.setInterval(self.move, self.getTotalWait()) + } + + + this.getTotalWait = function() { + return (Math.random() * 5000) * 2; + // var avatars = AvatarList.getAvatarIdentifiers(); + // var avatarCount = avatars.length; + // var random = Math.random() * 5000; + // var totalWait = random * (avatarCount * 2); + // print('cellscience color avatarcount, totalwait: ', avatarCount, totalWait) + // return totalWait + } + + + this.move = function() { + if (!iOwn) { + return; + } + + 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); + + 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, { + velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), + angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) + + }); + + + } + + + this.unload = function() { + baton.release(function() {}); + Script.clearInterval(currentInterval); + } + + + +}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js b/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js new file mode 100644 index 0000000000..63f96a5c1e --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js @@ -0,0 +1,381 @@ +"use strict"; +/*jslint nomen: true, plusplus: true, vars: true */ +/*global Messages, Script, MyAvatar, AvatarList, Entities, print */ + +// Created by Howard Stearns +// 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 +// +// Allows cooperating scripts to pass a "virtual baton" between them, +// which is useful when part of a script should only be executed by +// the one participant that is holding this particular baton. +// +// A virtual baton is simply any string agreed upon by the scripts +// that use it. Only one script at a time can hold the baton, and it +// holds it until that script releases it, or the other scripts +// determine that the holding script is not responding. The script +// automatically determines who among claimants has the baton, if anyone, +// and holds an "election" if necessary. +// +// See entityScript/tribble.js as an example, and the functions +// virtualBaton(), claim(), release(). +// + +// Answers a new virtualBaton for the given parameters, of which 'key' +// is required. +function virtualBatonf(options) { + // Answer averages (number +/- variability). Avoids having everyone act in lockstep. + function randomize(number, variability) { + var allowedDeviation = number * variability; // one side of the deviation range + var allowedDeviationRange = allowedDeviation * 2; // total range for +/- deviation + var randomDeviation = Math.random() * allowedDeviationRange; + var result = number - allowedDeviation + randomDeviation; + return result; + } + // Allow testing outside in a harness outside of High Fidelity. + // See sourceCodeSandbox/tests/mocha/test/testVirtualBaton.js + var globals = options.globals || {}, + messages = globals.Messages || Messages, + myAvatar = globals.MyAvatar || MyAvatar, + avatarList = globals.AvatarList || AvatarList, + entities = globals.Entities || Entities, + timers = globals.Script || Script, + log = globals.print || print; + + var batonName = options.batonName, // The identify of the baton. + // instanceId is the identify of this particular copy of the script among all copies using the same batonName + // in the domain. For example, if you wanted only one entity among multiple entity scripts to hold the baton, + // you could specify virtualBaton({batonName: 'someBatonName', instanceId: MyAvatar.sessionUUID + entityID}). + instanceId = options.instanceId || myAvatar.sessionUUID, + // virtualBaton() returns the exports object with properties. You can pass in an object to be side-effected. + exports = options.exports || {}, + // Handy to set false if we believe the optimizations are wrong, or to use both values in a test harness. + useOptimizations = (options.useOptimizations === undefined) ? true : options.useOptimizations, + electionTimeout = options.electionTimeout || randomize(500, 0.2), // ms. If no winner in this time, hold a new election. + recheckInterval = options.recheckInterval || randomize(500, 0.2), // ms. Check that winners remain connected. + // If you supply your own instanceId, you might also supply a connectionTest that answers + // truthy iff the given id is still valid and connected, and is run at recheckInterval. You + // can use exports.validId (see below), and the default answers truthy if id is valid or a + // concatenation of two valid ids. (This handles the most common cases of instanceId being + // either (the default) MyAvatar.sessionUUID, an entityID, or the concatenation (in either + // order) of both.) + connectionTest = options.connectionTest || function connectionTest(id) { + var idLength = 38; + if (id.length === idLength) { + return exports.validId(id); + } + return (id.length === 2 * idLength) && exports.validId(id.slice(0, idLength)) && exports.validId(id.slice(idLength)); + }; + + if (!batonName) { + throw new Error("A virtualBaton must specify a batonName."); + } + // Truthy if id exists as either a connected avatar or valid entity. + exports.validId = function validId(id) { + var avatar = avatarList.getAvatar(id); + if (avatar && (avatar.sessionUUID === id)) { + return true; + } + var properties = entities.getEntityProperties(id, ['type']); + return properties && properties.type; + }; + + // Various logging, controllable through options. + function debug() { // Display the arguments not just [Object object]. + log.apply(null, [].map.call(arguments, JSON.stringify)); + } + function debugFlow() { + if (options.debugFlow) { + debug.apply(null, arguments); + } + } + function debugSend(destination, operation, data) { + if (options.debugSend) { + debug('baton:', batonName, instanceId, 's=>', destination, operation, data); + } + } + function debugReceive(senderID, operation, data) { // senderID is client sessionUUID -- not necessarily instanceID! + if (options.debugReceive) { + debug('baton:', batonName, senderID, '=>r', instanceId, operation, data); + } + } + + // Messages: Just synactic sugar for hooking things up to Messages system. + // We create separate subchannel strings for each operation within our general channelKey, instead of using + // a switch in the receiver. + var channelKey = "io.highfidelity.virtualBaton:" + batonName, + subchannelHandlers = {}, // Message channel string => {receiver, op} + subchannelKeys = {}; // operation => Message channel string + function subchannelKey(operation) { + return channelKey + ':' + operation; + } + function receive(operation, handler) { // Record a handler for an operation on our channelKey + var subKey = subchannelKey(operation); + subchannelHandlers[subKey] = {receiver: handler, op: operation}; + subchannelKeys[operation] = subKey; + messages.subscribe(subKey); + } + function sendHelper(subchannel, data) { + var message = JSON.stringify(data); + messages.sendMessage(subchannel, message); + } + function send1(operation, destination, data) { // Send data for an operation to just one destination on our channelKey. + debugSend(destination, operation, data); + sendHelper(subchannelKey(operation) + destination, data); + } + function send(operation, data) { // Send data for an operation on our channelKey. + debugSend('-', operation, data); + sendHelper(subchannelKeys[operation], data); + } + function messageHandler(channel, messageString, senderID) { + var handler = subchannelHandlers[channel]; + if (!handler) { + return; + } + var data = JSON.parse(messageString); + debugReceive(senderID, handler.op, data); + handler.receiver(data); + } + messages.messageReceived.connect(messageHandler); + + var nPromises = 0, nAccepted = 0, electionWatchdog; + + // It would be great if we had a way to know how many subscribers our channel has. Failing that... + var nNack = 0, previousNSubscribers = 0, lastGathering = 0, thisTimeout = electionTimeout; + function nSubscribers() { // Answer the number of subscribers. + // To find nQuorum, we need to know how many scripts are being run using this batonName, which isn't + // the same as the number of clients! + // + // If we overestimate by too much, we may fail to reach consensus, which triggers a new + // election proposal, so we take the number of acceptors to be the max(nPromises, nAccepted) + // + nNack reported in the previous round. + // + // If we understimate by too much, there can be different pockets on the Internet that each + // believe they have agreement on different holders of the baton, which is precisely what + // the virtualBaton is supposed to avoid. Therefore we need to allow 'nack' to gather stragglers. + + var now = Date.now(), elapsed = now - lastGathering; + if (elapsed >= thisTimeout) { + previousNSubscribers = Math.max(nPromises, nAccepted) + nNack; + lastGathering = now; + } // ...otherwise we use the previous value unchanged. + + // On startup, we do one proposal that we cannot possibly close, so that we'll + // lock things up for the full electionTimeout to gather responses. + if (!previousNSubscribers) { + var LARGE_INTEGER = Number.MAX_SAFE_INTEGER || (-1 >>> 1); // QT doesn't define the ECMA constant. Max int will do for our purposes. + previousNSubscribers = LARGE_INTEGER; + } + return previousNSubscribers; + } + + // MAIN ALGORITHM + // + // Internally, this uses the Paxos algorith to hold elections. + // Alternatively, we could have the message server pick and maintain a winner, but it would + // still have to deal with the same issues of verification in the presence of lost/delayed/reordered messages. + // Paxos is known to be optimal under these circumstances, except that its best to have a dedicated proposer + // (such as the server). + function betterNumber(number, best) { + return (number.number || 0) > best.number; + } + // Paxos Proposer behavior + var proposalNumber = 0, + nQuorum = 0, + bestPromise = {number: 0}, + claimCallback, + releaseCallback; + function propose() { // Make a new proposal, so that we learn/update the proposalNumber and winner. + // Even though we send back a 'nack' if the proposal is obsolete, with network errors + // there's no way to know for certain that we've failed. The electionWatchdog will try a new + // proposal if we have not been accepted by a quorum after election Timeout. + if (electionWatchdog) { + // If we had a means of determining nSubscribers other than by counting, we could just + // timers.clearTimeout(electionWatchdog) and not return. + return; + } + thisTimeout = randomize(electionTimeout, 0.5); // Note use in nSubcribers. + electionWatchdog = timers.setTimeout(function () { + electionWatchdog = null; + propose(); + }, thisTimeout); + var nAcceptors = nSubscribers(); + nQuorum = Math.floor(nAcceptors / 2) + 1; + + proposalNumber = Math.max(proposalNumber, bestPromise.number) + 1; + debugFlow('baton:', batonName, instanceId, 'propose', proposalNumber, + 'claim:', !!claimCallback, 'nAcceptors:', nAcceptors, nPromises, nAccepted, nNack); + nPromises = nAccepted = nNack = 0; + send('prepare!', {number: proposalNumber, proposerId: instanceId}); + } + // We create a distinguished promise subchannel for our id, because promises need only be sent to the proposer. + receive('promise' + instanceId, function (data) { + if (betterNumber(data, bestPromise)) { + bestPromise = data; + } + if ((data.proposalNumber === proposalNumber) && (++nPromises >= nQuorum)) { // Note check for not being a previous round + var answer = {number: data.proposalNumber, proposerId: data.proposerId, winner: bestPromise.winner}; // Not data.number. + if (!answer.winner || (answer.winner === instanceId)) { // We get to pick. + answer.winner = claimCallback ? instanceId : null; + } + send('accept!', answer); + } + }); + receive('nack' + instanceId, function (data) { // An acceptor reports more recent data... + if (data.proposalNumber === proposalNumber) { + nNack++; // For updating nQuorum. + // IWBNI if we started our next proposal right now/here, but we need a decent nNack count. + // Lets save that optimization for another day... + } + }); + // Paxos Acceptor behavior + var bestProposal = {number: 0}, accepted = {}; + function acceptedId() { + return accepted && accepted.winner; + } + receive('prepare!', function (data) { + var response = {proposalNumber: data.number, proposerId: data.proposerId}; + if (betterNumber(data, bestProposal)) { + bestProposal = data; + if (accepted.winner && connectionTest(accepted.winner)) { + response.number = accepted.number; + response.winner = accepted.winner; + } + send1('promise', data.proposerId, response); + } else { + send1('nack', data.proposerId, response); + } + }); + receive('accept!', function (data) { + if (!betterNumber(bestProposal, data)) { + bestProposal = accepted = data; // Update both with current data. Might have missed the proposal earlier. + if (useOptimizations) { + // The Paxos literature describes every acceptor sending 'accepted' to + // every proposer and learner. In our case, these are the same nodes that received + // the 'accept!' message, so we can send to just the originating proposer and invoke + // our own accepted handler directly. + // Note that this optimization cannot be used with Byzantine Paxos (which needs another + // multi-broadcast to detect lying and collusion). + debugSend('/', 'accepted', data); + debugReceive(instanceId, 'accepted', data); // direct on next line, which doesn't get logging. + subchannelHandlers[subchannelKey('accepted') + instanceId].receiver(data); + if (data.proposerId !== instanceId) { // i.e., we didn't already do it directly on the line above. + send1('accepted', data.proposerId, data); + } + } else { + send('accepted', data); + } + } else { + send1('nack', data.proposerId, {proposalNumber: data.number}); + } + }); + // Paxos Learner behavior. + function localRelease() { + var callback = releaseCallback; + debugFlow('baton:', batonName, 'localRelease', 'callback:', !!releaseCallback); + if (!releaseCallback) { + return; + } // Already released, but we might still receive a stale message. That's ok. + releaseCallback = undefined; + callback(batonName); // Pass batonName so that clients may use the same handler for different batons. + } + receive('accepted' + (useOptimizations ? instanceId : ''), function (data) { // See note in 'accept!' regarding use of instanceId here. + if (betterNumber(accepted, data)) { // Especially when !useOptimizations, we can receive other acceptances late. + return; + } + var oldAccepted = accepted; + debugFlow('baton:', batonName, instanceId, 'accepted', data.number, data.winner); + accepted = data; + // If we are proposer, make sure we get a quorum of acceptances. + if ((data.proposerId === instanceId) && (data.number === proposalNumber) && (++nAccepted >= nQuorum)) { + if (electionWatchdog) { + timers.clearTimeout(electionWatchdog); + electionWatchdog = null; + } + } + // If we are the winner -- regardless of whether we were the proposer. + if (acceptedId() === instanceId) { + if (claimCallback) { + var callback = claimCallback; + claimCallback = undefined; + callback(batonName); + } else if (!releaseCallback) { // We won, but have been released and are no longer interested. + // Propose that someone else take the job. + timers.setTimeout(propose, 0); // Asynchronous to queue message handling if some are synchronous and others not. + } + } else if (releaseCallback && (oldAccepted.winner === instanceId)) { // We've been released by someone else! + localRelease(); // This can happen if enough people thought we'd disconnected. + } + }); + + // Public Interface + // + // Registers an intent to hold the baton: + // Calls onElection(batonName) once, if you are elected by the scripts + // to be the unique holder of the baton, which may be never. + // Calls onRelease(batonName) once, if the baton held by you is released, + // whether this is by you calling release(), or by losing + // an election when you become disconnected. + // You may claim again at any time after the start of onRelease + // being called. + exports.claim = function claim(onElection, onRelease) { + debugFlow('baton:', batonName, instanceId, 'claim'); + if (claimCallback) { + log("Ignoring attempt to claim virtualBaton " + batonName + ", which is already waiting for claim."); + return; + } + if (releaseCallback) { + log("Ignoring attempt to claim virtualBaton " + batonName + ", which is somehow incorrect released, and that should not happen."); + return; + } + claimCallback = onElection; + releaseCallback = onRelease; + propose(); + return exports; // Allows chaining. e.g., var baton = virtualBaton({batonName: 'foo'}.claim(onClaim, onRelease); + }; + // Release the baton you hold, or just log that you are not holding it. + exports.release = function release(optionalReplacementOnRelease) { + debugFlow('baton:', batonName, instanceId, 'release'); + if (optionalReplacementOnRelease) { // If you want to change. + releaseCallback = optionalReplacementOnRelease; + } + if (acceptedId() !== instanceId) { + log("Ignoring attempt to release virtualBaton " + batonName + ", which is not being held."); + return; + } + localRelease(); + if (!claimCallback) { // No claim set in release callback. + propose(); + } + return exports; + }; + exports.recheckWatchdog = timers.setInterval(function recheck() { + var holder = acceptedId(); // If we're waiting and we notice the holder is gone, ... + if (holder && claimCallback && !electionWatchdog && !connectionTest(holder)) { + bestPromise.winner = null; // used if the quorum agrees that old winner is not there + propose(); // ... propose an election. + } + }, recheckInterval); + exports.unload = function unload() { // Disconnect from everything. + messages.messageReceived.disconnect(messageHandler); + timers.clearInterval(exports.recheckWatchdog); + if (electionWatchdog) { + timers.clearTimeout(electionWatchdog); + } + electionWatchdog = claimCallback = releaseCallback = null; + Object.keys(subchannelHandlers).forEach(messages.unsubscribe); + debugFlow('baton:', batonName, instanceId, 'unload'); + return exports; + }; + + // Gather nAcceptors by making two proposals with some gathering time, even without a claim. + propose(); + return exports; +} +if (typeof module !== 'undefined') { // Allow testing in nodejs. + module.exports = virtualBatonf; +} else { + virtualBaton = virtualBatonf; +} diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index e4ee59cb6b..16c83b29dd 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -9,19 +9,42 @@ var teleport; var portalDestination; var animationURL; - var self = this; this.entered = true; + Script.include('virtualBaton.js'); + + var self = this; + var baton; + var iOwn = false; + var currentInterval; + var _entityId; + + function startUpdate() { + iOwn = true; + print('i am the owner ' + _entityId) + } + + function stopUpdateAndReclaim() { + print('i released the object ' + _entityId) + iOwn = false; + baton.claim(startUpdate, stopUpdateAndReclaim); + } this.preload = function(entityID) { this.entityId = entityID; + _entityId = entityID; this.initialize(entityID); this.initTimeout = null; this.minVelocity = 1; this.maxVelocity = 5; this.minAngularVelocity = 0.01; this.maxAngularVelocity = 0.03; - Script.setTimeout(self.move, self.getTotalWait()) + baton = virtualBaton({ + batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity + }); + stopUpdateAndReclaim(); + currentInterval = Script.setInterval(self.move, self.getTotalWait()) + } this.initialize = function(entityID) { @@ -104,6 +127,8 @@ if (this.initTimeout !== null) { Script.clearTimeout(this.initTimeout); } + baton.release(function() {}); + Script.clearInterval(currentInterval); } this.hoverEnterEntity = function(entityID) { @@ -114,16 +139,13 @@ } this.getTotalWait = function() { - var avatars = AvatarList.getAvatarIdentifiers(); - var avatarCount = avatars.length; - var random = Math.random() * 2000; - var totalWait = random * (avatarCount * 2); - - return totalWait + return (Math.random() * 5000) * 2; } - this.move = function() { + if (!iOwn) { + return; + } var magnitudeV = self.maxVelocity; var directionV = { @@ -133,11 +155,6 @@ }; //print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); - Entities.editEntity(self.entityId, { - velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)) - }); - - var magnitudeAV = self.maxAngularVelocity; @@ -148,11 +165,12 @@ }; //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(self.entityId, { + velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) }); - Script.setTimeout(self.move, self.getTotalWait()) + } }) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index db50635f93..63f99c53a3 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 = 1043; +var version = 1049; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -194,7 +194,7 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly.js?" + version, + script: "moveRandomly2.js?" + version, visible: true }, { //golgi vesicles model: "vesicle", @@ -238,7 +238,7 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly.js?" + version, + script: "moveRandomly2.js?" + version, visible: true }, { model: "vesicle", @@ -304,7 +304,7 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly.js?" + version, + script: "moveRandomly2.js?" + version, visible: true }, { //outer vesicles model: "vesicle", @@ -326,7 +326,7 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly.js?" + version, + script: "moveRandomly2.js?" + version, visible: true }, // {//wigglies From f0d8ffce6582fc63e6adf9486a10c1d511f94250 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 22 Feb 2016 10:25:56 -0800 Subject: [PATCH 05/34] cleanup errors --- .../DomainContent/CellScience/Scripts/moveRandomly2.js | 10 +++------- .../CellScience/Scripts/zoomAndMoveRandomly.js | 7 +++++-- .../DomainContent/CellScience/importCellScience.js | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js index f720ca91cc..ec7b249db0 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js @@ -44,12 +44,6 @@ this.getTotalWait = function() { return (Math.random() * 5000) * 2; - // var avatars = AvatarList.getAvatarIdentifiers(); - // var avatarCount = avatars.length; - // var random = Math.random() * 5000; - // var totalWait = random * (avatarCount * 2); - // print('cellscience color avatarcount, totalwait: ', avatarCount, totalWait) - // return totalWait } @@ -86,7 +80,9 @@ this.unload = function() { - baton.release(function() {}); + if (baton) { + baton.release(function() {}); + } Script.clearInterval(currentInterval); } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index 16c83b29dd..21e585cd91 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -40,7 +40,7 @@ this.minAngularVelocity = 0.01; this.maxAngularVelocity = 0.03; baton = virtualBaton({ - batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity + batonName: 'io.highfidelity.vesicles:' + entityID, // One winner for each entity }); stopUpdateAndReclaim(); currentInterval = Script.setInterval(self.move, self.getTotalWait()) @@ -127,7 +127,10 @@ if (this.initTimeout !== null) { Script.clearTimeout(this.initTimeout); } - baton.release(function() {}); + if (baton) { + baton.release(function() {}); + } + Script.clearInterval(currentInterval); } diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 63f99c53a3..900a54d9e3 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 = 1049; +var version = 1051; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; From f7b3da078b2ec28209118bbd60ccd5ba2e41cb4a Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 22 Feb 2016 11:36:53 -0800 Subject: [PATCH 06/34] dont move cells in space, just angular velocity --- .../CellScience/Scripts/zoomAndMoveRandomly.js | 14 +++++++------- .../DomainContent/CellScience/importCellScience.js | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index 21e585cd91..bf249a4644 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -150,12 +150,12 @@ return; } - var magnitudeV = self.maxVelocity; - var directionV = { - x: Math.random() - 0.5, - y: Math.random() - 0.5, - z: Math.random() - 0.5 - }; + // 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); @@ -168,7 +168,7 @@ }; //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(self.entityId, { - velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), + // velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) }); diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 900a54d9e3..b061dc6931 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 = 1051; +var version = 1052; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; From e4bc0ce69103ccdd950793255384f9a6b3719a66 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 22 Feb 2016 13:08:58 -0800 Subject: [PATCH 07/34] tests --- .../DomainContent/CellScience/Scripts/zoom.js | 12 ---------- .../Scripts/zoomAndMoveRandomly.js | 23 +++++++------------ .../CellScience/importCellScience.js | 2 +- 3 files changed, 9 insertions(+), 28 deletions(-) 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/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index bf249a4644..703c4ead33 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -15,18 +15,19 @@ var self = this; var baton; - var iOwn = false; + + this.iOwn = false; var currentInterval; var _entityId; function startUpdate() { - iOwn = true; + self.iOwn = true; print('i am the owner ' + _entityId) } function stopUpdateAndReclaim() { print('i released the object ' + _entityId) - iOwn = false; + self.iOwn = false; baton.claim(startUpdate, stopUpdateAndReclaim); } @@ -40,7 +41,7 @@ this.minAngularVelocity = 0.01; this.maxAngularVelocity = 0.03; baton = virtualBaton({ - batonName: 'io.highfidelity.vesicles:' + entityID, // One winner for each entity + batonName: 'io.highfidelity.cells:' + entityID, // One winner for each entity }); stopUpdateAndReclaim(); currentInterval = Script.setInterval(self.move, self.getTotalWait()) @@ -146,19 +147,11 @@ } this.move = function() { - if (!iOwn) { + if (self.iOwn===false) { + print('cell is not owned by me...') return; } - // 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); - var magnitudeAV = self.maxAngularVelocity; var directionAV = { @@ -166,7 +159,7 @@ y: Math.random() - 0.5, z: Math.random() - 0.5 }; - //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(self.entityId, { // velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index b061dc6931..4ae5e5de36 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 = 1052; +var version = 1055; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; From 46aebabd9b2330567dc89feca3f57a1ed42a0e66 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 22 Feb 2016 17:54:45 -0800 Subject: [PATCH 08/34] switch branches --- .../Scripts/zoomAndMoveRandomly.js | 20 ++++++------------- .../CellScience/importCellScience.js | 10 +++++----- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index 703c4ead33..dd6a48c617 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -38,8 +38,8 @@ this.initTimeout = null; this.minVelocity = 1; this.maxVelocity = 5; - this.minAngularVelocity = 0.01; - this.maxAngularVelocity = 0.03; + this.minAngularVelocity = 0.03; + this.maxAngularVelocity = 0.10; baton = virtualBaton({ batonName: 'io.highfidelity.cells:' + entityID, // One winner for each entity }); @@ -69,7 +69,7 @@ }; self.teleportSound = SoundCache.getSound("https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/whoosh.wav"); - // print(" portal destination is " + self.portalDestination); + } } @@ -81,13 +81,6 @@ 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{ - - // } } } @@ -143,11 +136,11 @@ } this.getTotalWait = function() { - return (Math.random() * 5000) * 2; + return (Math.random() * 5000) * 3; } this.move = function() { - if (self.iOwn===false) { + if (self.iOwn === false) { print('cell is not owned by me...') return; } @@ -159,9 +152,8 @@ y: Math.random() - 0.5, z: Math.random() - 0.5 }; - print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(self.entityId, { - // velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) }); diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 4ae5e5de36..25323495d1 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 = 1055; +var version = 1057; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -103,16 +103,16 @@ var scenes = [{ instances: [{ model: "Cell", dimensions: { - x: 550, - y: 620, - z: 550 + x: 500, + y: 570, + z: 500 }, offset: { x: 0, y: 0, z: 0 }, - radius: 500, + radius: 450, number: 10, userData: JSON.stringify({ entryPoint: locations.cellLayout[1], From 6fd149f22dbc63075243af6f42ba93c4a4ccf3d2 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 23 Feb 2016 12:27:05 -0800 Subject: [PATCH 09/34] no avatar --- .../DomainContent/CellScience/motorProteinControllerAC.js | 2 -- 1 file changed, 2 deletions(-) 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, From 46fbf38b5d38e7e7a1a9447d1e9e805fdc477ea7 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 24 Feb 2016 12:36:18 -0800 Subject: [PATCH 10/34] ac movers --- .../CellScience/Scripts/colorRandomly.js | 104 ----- .../CellScience/Scripts/moveRandomly2.js | 91 ----- .../Scripts/showButtonToPlaySound.js | 4 - .../CellScience/Scripts/virtualBaton.js | 381 ------------------ .../Scripts/zoomAndMoveRandomly.js | 164 -------- .../CellScience/importCellScience.js | 43 +- .../DomainContent/CellScience/moveCellsAC.js | 96 +++++ .../CellScience/moveVesiclesAC.js | 106 +++++ 8 files changed, 212 insertions(+), 777 deletions(-) delete mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js delete mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js delete mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js delete mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js create mode 100644 unpublishedScripts/DomainContent/CellScience/moveCellsAC.js create mode 100644 unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js deleted file mode 100644 index cf4ee810e7..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js +++ /dev/null @@ -1,104 +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() { - - Script.include(Script.resolvePath('virtualBaton.js')); - - var self = this; - - var baton; - var iOwn = false; - var currentInterval; - var _entityId; - - function startUpdate() { - iOwn = true; - print('i am the owner ' + _entityId) - } - - function stopUpdateAndReclaim() { - print('i released the object ' + _entityId) - iOwn = false; - baton.claim(startUpdate, stopUpdateAndReclaim); - } - - this.preload = function(entityId) { - this.isConnected = false; - this.entityId = entityId; - _entityId = entityId; - this.minVelocity = 1; - this.maxVelocity = 5; - this.minAngularVelocity = 0.01; - this.maxAngularVelocity = 0.03; - baton = virtualBaton({ - batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity - }); - stopUpdateAndReclaim(); - currentInterval = Script.setInterval(self.move, self.getTotalWait()) - } - - - this.getTotalWait = function() { - return (Math.random() * 5000) * 2; - // var avatars = AvatarList.getAvatarIdentifiers(); - // var avatarCount = avatars.length; - // var random = Math.random() * 5000; - // var totalWait = random * (avatarCount * 2); - // print('cellscience color avatarcount, totalwait: ', avatarCount, totalWait) - // return totalWait - } - - - this.move = function() { - if (!iOwn) { - return; - } - - var properties = Entities.getEntityProperties(self.entityId); - var color = properties.color; - - var newColor; - var red = { - red: 255, - green: 0, - blue: 0 - } - var green = { - red: 0, - green: 255, - blue: 0 - } - var blue = { - red: 0, - green: 0, - blue: 255 - } - if (color.red > 0) { - newColor = green; - } - if (color.green > 0) { - newColor = blue; - } - if (color.blue > 0) { - newColor = red - } - Entities.editEntity(self.entityId, { - color: newColor - }); - - - } - - - this.unload = function() { - baton.release(function() {}); - Script.clearTimeout(currentInterval); - } - - - -}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js deleted file mode 100644 index ec7b249db0..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js +++ /dev/null @@ -1,91 +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() { - - Script.include('virtualBaton.js'); - - var self = this; - - var baton; - var iOwn = false; - var currentInterval; - var _entityId; - - function startUpdate() { - iOwn = true; - print('i am the owner ' + _entityId) - } - - function stopUpdateAndReclaim() { - print('i released the object ' + _entityId) - iOwn = false; - baton.claim(startUpdate, stopUpdateAndReclaim); - } - - this.preload = function(entityId) { - this.isConnected = false; - this.entityId = entityId; - _entityId = entityId; - this.minVelocity = 1; - this.maxVelocity = 5; - this.minAngularVelocity = 0.01; - this.maxAngularVelocity = 0.03; - baton = virtualBaton({ - batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity - }); - stopUpdateAndReclaim(); - currentInterval = Script.setInterval(self.move, self.getTotalWait()) - } - - - this.getTotalWait = function() { - return (Math.random() * 5000) * 2; - } - - - this.move = function() { - if (!iOwn) { - return; - } - - 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); - - 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, { - velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), - angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) - - }); - - - } - - - this.unload = function() { - if (baton) { - baton.release(function() {}); - } - Script.clearInterval(currentInterval); - } - - - -}) \ No newline at end of file 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/virtualBaton.js b/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js deleted file mode 100644 index 63f96a5c1e..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js +++ /dev/null @@ -1,381 +0,0 @@ -"use strict"; -/*jslint nomen: true, plusplus: true, vars: true */ -/*global Messages, Script, MyAvatar, AvatarList, Entities, print */ - -// Created by Howard Stearns -// 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 -// -// Allows cooperating scripts to pass a "virtual baton" between them, -// which is useful when part of a script should only be executed by -// the one participant that is holding this particular baton. -// -// A virtual baton is simply any string agreed upon by the scripts -// that use it. Only one script at a time can hold the baton, and it -// holds it until that script releases it, or the other scripts -// determine that the holding script is not responding. The script -// automatically determines who among claimants has the baton, if anyone, -// and holds an "election" if necessary. -// -// See entityScript/tribble.js as an example, and the functions -// virtualBaton(), claim(), release(). -// - -// Answers a new virtualBaton for the given parameters, of which 'key' -// is required. -function virtualBatonf(options) { - // Answer averages (number +/- variability). Avoids having everyone act in lockstep. - function randomize(number, variability) { - var allowedDeviation = number * variability; // one side of the deviation range - var allowedDeviationRange = allowedDeviation * 2; // total range for +/- deviation - var randomDeviation = Math.random() * allowedDeviationRange; - var result = number - allowedDeviation + randomDeviation; - return result; - } - // Allow testing outside in a harness outside of High Fidelity. - // See sourceCodeSandbox/tests/mocha/test/testVirtualBaton.js - var globals = options.globals || {}, - messages = globals.Messages || Messages, - myAvatar = globals.MyAvatar || MyAvatar, - avatarList = globals.AvatarList || AvatarList, - entities = globals.Entities || Entities, - timers = globals.Script || Script, - log = globals.print || print; - - var batonName = options.batonName, // The identify of the baton. - // instanceId is the identify of this particular copy of the script among all copies using the same batonName - // in the domain. For example, if you wanted only one entity among multiple entity scripts to hold the baton, - // you could specify virtualBaton({batonName: 'someBatonName', instanceId: MyAvatar.sessionUUID + entityID}). - instanceId = options.instanceId || myAvatar.sessionUUID, - // virtualBaton() returns the exports object with properties. You can pass in an object to be side-effected. - exports = options.exports || {}, - // Handy to set false if we believe the optimizations are wrong, or to use both values in a test harness. - useOptimizations = (options.useOptimizations === undefined) ? true : options.useOptimizations, - electionTimeout = options.electionTimeout || randomize(500, 0.2), // ms. If no winner in this time, hold a new election. - recheckInterval = options.recheckInterval || randomize(500, 0.2), // ms. Check that winners remain connected. - // If you supply your own instanceId, you might also supply a connectionTest that answers - // truthy iff the given id is still valid and connected, and is run at recheckInterval. You - // can use exports.validId (see below), and the default answers truthy if id is valid or a - // concatenation of two valid ids. (This handles the most common cases of instanceId being - // either (the default) MyAvatar.sessionUUID, an entityID, or the concatenation (in either - // order) of both.) - connectionTest = options.connectionTest || function connectionTest(id) { - var idLength = 38; - if (id.length === idLength) { - return exports.validId(id); - } - return (id.length === 2 * idLength) && exports.validId(id.slice(0, idLength)) && exports.validId(id.slice(idLength)); - }; - - if (!batonName) { - throw new Error("A virtualBaton must specify a batonName."); - } - // Truthy if id exists as either a connected avatar or valid entity. - exports.validId = function validId(id) { - var avatar = avatarList.getAvatar(id); - if (avatar && (avatar.sessionUUID === id)) { - return true; - } - var properties = entities.getEntityProperties(id, ['type']); - return properties && properties.type; - }; - - // Various logging, controllable through options. - function debug() { // Display the arguments not just [Object object]. - log.apply(null, [].map.call(arguments, JSON.stringify)); - } - function debugFlow() { - if (options.debugFlow) { - debug.apply(null, arguments); - } - } - function debugSend(destination, operation, data) { - if (options.debugSend) { - debug('baton:', batonName, instanceId, 's=>', destination, operation, data); - } - } - function debugReceive(senderID, operation, data) { // senderID is client sessionUUID -- not necessarily instanceID! - if (options.debugReceive) { - debug('baton:', batonName, senderID, '=>r', instanceId, operation, data); - } - } - - // Messages: Just synactic sugar for hooking things up to Messages system. - // We create separate subchannel strings for each operation within our general channelKey, instead of using - // a switch in the receiver. - var channelKey = "io.highfidelity.virtualBaton:" + batonName, - subchannelHandlers = {}, // Message channel string => {receiver, op} - subchannelKeys = {}; // operation => Message channel string - function subchannelKey(operation) { - return channelKey + ':' + operation; - } - function receive(operation, handler) { // Record a handler for an operation on our channelKey - var subKey = subchannelKey(operation); - subchannelHandlers[subKey] = {receiver: handler, op: operation}; - subchannelKeys[operation] = subKey; - messages.subscribe(subKey); - } - function sendHelper(subchannel, data) { - var message = JSON.stringify(data); - messages.sendMessage(subchannel, message); - } - function send1(operation, destination, data) { // Send data for an operation to just one destination on our channelKey. - debugSend(destination, operation, data); - sendHelper(subchannelKey(operation) + destination, data); - } - function send(operation, data) { // Send data for an operation on our channelKey. - debugSend('-', operation, data); - sendHelper(subchannelKeys[operation], data); - } - function messageHandler(channel, messageString, senderID) { - var handler = subchannelHandlers[channel]; - if (!handler) { - return; - } - var data = JSON.parse(messageString); - debugReceive(senderID, handler.op, data); - handler.receiver(data); - } - messages.messageReceived.connect(messageHandler); - - var nPromises = 0, nAccepted = 0, electionWatchdog; - - // It would be great if we had a way to know how many subscribers our channel has. Failing that... - var nNack = 0, previousNSubscribers = 0, lastGathering = 0, thisTimeout = electionTimeout; - function nSubscribers() { // Answer the number of subscribers. - // To find nQuorum, we need to know how many scripts are being run using this batonName, which isn't - // the same as the number of clients! - // - // If we overestimate by too much, we may fail to reach consensus, which triggers a new - // election proposal, so we take the number of acceptors to be the max(nPromises, nAccepted) - // + nNack reported in the previous round. - // - // If we understimate by too much, there can be different pockets on the Internet that each - // believe they have agreement on different holders of the baton, which is precisely what - // the virtualBaton is supposed to avoid. Therefore we need to allow 'nack' to gather stragglers. - - var now = Date.now(), elapsed = now - lastGathering; - if (elapsed >= thisTimeout) { - previousNSubscribers = Math.max(nPromises, nAccepted) + nNack; - lastGathering = now; - } // ...otherwise we use the previous value unchanged. - - // On startup, we do one proposal that we cannot possibly close, so that we'll - // lock things up for the full electionTimeout to gather responses. - if (!previousNSubscribers) { - var LARGE_INTEGER = Number.MAX_SAFE_INTEGER || (-1 >>> 1); // QT doesn't define the ECMA constant. Max int will do for our purposes. - previousNSubscribers = LARGE_INTEGER; - } - return previousNSubscribers; - } - - // MAIN ALGORITHM - // - // Internally, this uses the Paxos algorith to hold elections. - // Alternatively, we could have the message server pick and maintain a winner, but it would - // still have to deal with the same issues of verification in the presence of lost/delayed/reordered messages. - // Paxos is known to be optimal under these circumstances, except that its best to have a dedicated proposer - // (such as the server). - function betterNumber(number, best) { - return (number.number || 0) > best.number; - } - // Paxos Proposer behavior - var proposalNumber = 0, - nQuorum = 0, - bestPromise = {number: 0}, - claimCallback, - releaseCallback; - function propose() { // Make a new proposal, so that we learn/update the proposalNumber and winner. - // Even though we send back a 'nack' if the proposal is obsolete, with network errors - // there's no way to know for certain that we've failed. The electionWatchdog will try a new - // proposal if we have not been accepted by a quorum after election Timeout. - if (electionWatchdog) { - // If we had a means of determining nSubscribers other than by counting, we could just - // timers.clearTimeout(electionWatchdog) and not return. - return; - } - thisTimeout = randomize(electionTimeout, 0.5); // Note use in nSubcribers. - electionWatchdog = timers.setTimeout(function () { - electionWatchdog = null; - propose(); - }, thisTimeout); - var nAcceptors = nSubscribers(); - nQuorum = Math.floor(nAcceptors / 2) + 1; - - proposalNumber = Math.max(proposalNumber, bestPromise.number) + 1; - debugFlow('baton:', batonName, instanceId, 'propose', proposalNumber, - 'claim:', !!claimCallback, 'nAcceptors:', nAcceptors, nPromises, nAccepted, nNack); - nPromises = nAccepted = nNack = 0; - send('prepare!', {number: proposalNumber, proposerId: instanceId}); - } - // We create a distinguished promise subchannel for our id, because promises need only be sent to the proposer. - receive('promise' + instanceId, function (data) { - if (betterNumber(data, bestPromise)) { - bestPromise = data; - } - if ((data.proposalNumber === proposalNumber) && (++nPromises >= nQuorum)) { // Note check for not being a previous round - var answer = {number: data.proposalNumber, proposerId: data.proposerId, winner: bestPromise.winner}; // Not data.number. - if (!answer.winner || (answer.winner === instanceId)) { // We get to pick. - answer.winner = claimCallback ? instanceId : null; - } - send('accept!', answer); - } - }); - receive('nack' + instanceId, function (data) { // An acceptor reports more recent data... - if (data.proposalNumber === proposalNumber) { - nNack++; // For updating nQuorum. - // IWBNI if we started our next proposal right now/here, but we need a decent nNack count. - // Lets save that optimization for another day... - } - }); - // Paxos Acceptor behavior - var bestProposal = {number: 0}, accepted = {}; - function acceptedId() { - return accepted && accepted.winner; - } - receive('prepare!', function (data) { - var response = {proposalNumber: data.number, proposerId: data.proposerId}; - if (betterNumber(data, bestProposal)) { - bestProposal = data; - if (accepted.winner && connectionTest(accepted.winner)) { - response.number = accepted.number; - response.winner = accepted.winner; - } - send1('promise', data.proposerId, response); - } else { - send1('nack', data.proposerId, response); - } - }); - receive('accept!', function (data) { - if (!betterNumber(bestProposal, data)) { - bestProposal = accepted = data; // Update both with current data. Might have missed the proposal earlier. - if (useOptimizations) { - // The Paxos literature describes every acceptor sending 'accepted' to - // every proposer and learner. In our case, these are the same nodes that received - // the 'accept!' message, so we can send to just the originating proposer and invoke - // our own accepted handler directly. - // Note that this optimization cannot be used with Byzantine Paxos (which needs another - // multi-broadcast to detect lying and collusion). - debugSend('/', 'accepted', data); - debugReceive(instanceId, 'accepted', data); // direct on next line, which doesn't get logging. - subchannelHandlers[subchannelKey('accepted') + instanceId].receiver(data); - if (data.proposerId !== instanceId) { // i.e., we didn't already do it directly on the line above. - send1('accepted', data.proposerId, data); - } - } else { - send('accepted', data); - } - } else { - send1('nack', data.proposerId, {proposalNumber: data.number}); - } - }); - // Paxos Learner behavior. - function localRelease() { - var callback = releaseCallback; - debugFlow('baton:', batonName, 'localRelease', 'callback:', !!releaseCallback); - if (!releaseCallback) { - return; - } // Already released, but we might still receive a stale message. That's ok. - releaseCallback = undefined; - callback(batonName); // Pass batonName so that clients may use the same handler for different batons. - } - receive('accepted' + (useOptimizations ? instanceId : ''), function (data) { // See note in 'accept!' regarding use of instanceId here. - if (betterNumber(accepted, data)) { // Especially when !useOptimizations, we can receive other acceptances late. - return; - } - var oldAccepted = accepted; - debugFlow('baton:', batonName, instanceId, 'accepted', data.number, data.winner); - accepted = data; - // If we are proposer, make sure we get a quorum of acceptances. - if ((data.proposerId === instanceId) && (data.number === proposalNumber) && (++nAccepted >= nQuorum)) { - if (electionWatchdog) { - timers.clearTimeout(electionWatchdog); - electionWatchdog = null; - } - } - // If we are the winner -- regardless of whether we were the proposer. - if (acceptedId() === instanceId) { - if (claimCallback) { - var callback = claimCallback; - claimCallback = undefined; - callback(batonName); - } else if (!releaseCallback) { // We won, but have been released and are no longer interested. - // Propose that someone else take the job. - timers.setTimeout(propose, 0); // Asynchronous to queue message handling if some are synchronous and others not. - } - } else if (releaseCallback && (oldAccepted.winner === instanceId)) { // We've been released by someone else! - localRelease(); // This can happen if enough people thought we'd disconnected. - } - }); - - // Public Interface - // - // Registers an intent to hold the baton: - // Calls onElection(batonName) once, if you are elected by the scripts - // to be the unique holder of the baton, which may be never. - // Calls onRelease(batonName) once, if the baton held by you is released, - // whether this is by you calling release(), or by losing - // an election when you become disconnected. - // You may claim again at any time after the start of onRelease - // being called. - exports.claim = function claim(onElection, onRelease) { - debugFlow('baton:', batonName, instanceId, 'claim'); - if (claimCallback) { - log("Ignoring attempt to claim virtualBaton " + batonName + ", which is already waiting for claim."); - return; - } - if (releaseCallback) { - log("Ignoring attempt to claim virtualBaton " + batonName + ", which is somehow incorrect released, and that should not happen."); - return; - } - claimCallback = onElection; - releaseCallback = onRelease; - propose(); - return exports; // Allows chaining. e.g., var baton = virtualBaton({batonName: 'foo'}.claim(onClaim, onRelease); - }; - // Release the baton you hold, or just log that you are not holding it. - exports.release = function release(optionalReplacementOnRelease) { - debugFlow('baton:', batonName, instanceId, 'release'); - if (optionalReplacementOnRelease) { // If you want to change. - releaseCallback = optionalReplacementOnRelease; - } - if (acceptedId() !== instanceId) { - log("Ignoring attempt to release virtualBaton " + batonName + ", which is not being held."); - return; - } - localRelease(); - if (!claimCallback) { // No claim set in release callback. - propose(); - } - return exports; - }; - exports.recheckWatchdog = timers.setInterval(function recheck() { - var holder = acceptedId(); // If we're waiting and we notice the holder is gone, ... - if (holder && claimCallback && !electionWatchdog && !connectionTest(holder)) { - bestPromise.winner = null; // used if the quorum agrees that old winner is not there - propose(); // ... propose an election. - } - }, recheckInterval); - exports.unload = function unload() { // Disconnect from everything. - messages.messageReceived.disconnect(messageHandler); - timers.clearInterval(exports.recheckWatchdog); - if (electionWatchdog) { - timers.clearTimeout(electionWatchdog); - } - electionWatchdog = claimCallback = releaseCallback = null; - Object.keys(subchannelHandlers).forEach(messages.unsubscribe); - debugFlow('baton:', batonName, instanceId, 'unload'); - return exports; - }; - - // Gather nAcceptors by making two proposals with some gathering time, even without a claim. - propose(); - return exports; -} -if (typeof module !== 'undefined') { // Allow testing in nodejs. - module.exports = virtualBatonf; -} else { - virtualBaton = virtualBatonf; -} diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js deleted file mode 100644 index dd6a48c617..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ /dev/null @@ -1,164 +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 teleport; - var portalDestination; - var animationURL; - - this.entered = true; - Script.include('virtualBaton.js'); - - var self = this; - var baton; - - this.iOwn = false; - var currentInterval; - var _entityId; - - function startUpdate() { - self.iOwn = true; - print('i am the owner ' + _entityId) - } - - function stopUpdateAndReclaim() { - print('i released the object ' + _entityId) - self.iOwn = false; - baton.claim(startUpdate, stopUpdateAndReclaim); - } - - this.preload = function(entityID) { - this.entityId = entityID; - _entityId = entityID; - this.initialize(entityID); - this.initTimeout = null; - this.minVelocity = 1; - this.maxVelocity = 5; - this.minAngularVelocity = 0.03; - this.maxAngularVelocity = 0.10; - baton = virtualBaton({ - batonName: 'io.highfidelity.cells:' + entityID, // One winner for each entity - }); - stopUpdateAndReclaim(); - currentInterval = Script.setInterval(self.move, self.getTotalWait()) - - } - - this.initialize = function(entityID) { - // print(' should initialize') - 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(' has userData') - self.portalDestination = properties.userData; - animationURL = properties.modelURL; - self.soundOptions = { - stereo: true, - loop: false, - localOnly: false, - position: properties.position, - volume: 0.5 - }; - - self.teleportSound = SoundCache.getSound("https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/whoosh.wav"); - - } - } - - this.enterEntity = function(entityID) { - //print('ENTERED A BOUNDARY ENTITY, SHOULD ZOOM', entityID) - var data = JSON.parse(Entities.getEntityProperties(this.entityId).userData); - //print('DATA IS::' + data) - if (data != null) { - print("Teleporting to (" + data.location.x + ", " + data.location.y + ", " + data.location.z + ")"); - - MyAvatar.position = data.location; - } - - } - - this.lookAtTarget = function(entryPoint, target) { - //print('SHOULD LOOK AT TARGET') - var direction = Vec3.normalize(Vec3.subtract(entryPoint, target)); - var pitch = Quat.angleAxis(Math.asin(-direction.y) * 180.0 / Math.PI, { - x: 1, - y: 0, - z: 0 - }); - var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * 180.0 / Math.PI, { - x: 0, - y: 1, - z: 0 - }); - - MyAvatar.goToLocation(entryPoint, true, yaw); - - MyAvatar.headYaw = 0; - - } - - this.leaveEntity = function(entityID) { - Entities.editEntity(entityID, { - animationURL: animationURL, - animationSettings: '{ "frameIndex": 1, "running": false }' - }); - this.entered = false; - if (this.initTimeout !== null) { - Script.clearTimeout(this.initTimeout); - } - //playSound(); - } - - this.unload = function() { - if (this.initTimeout !== null) { - Script.clearTimeout(this.initTimeout); - } - if (baton) { - baton.release(function() {}); - } - - Script.clearInterval(currentInterval); - } - - this.hoverEnterEntity = function(entityID) { - Entities.editEntity(entityID, { - animationURL: animationURL, - animationSettings: '{ "fps": 24, "firstFrame": 1, "lastFrame": 25, "frameIndex": 1, "running": true, "hold": true }' - }); - } - - this.getTotalWait = function() { - return (Math.random() * 5000) * 3; - } - - this.move = function() { - if (self.iOwn === false) { - print('cell is not owned by me...') - return; - } - - 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)) - - }); - - - } - -}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 25323495d1..55b09cd4a7 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -120,7 +120,7 @@ var scenes = [{ location: locations.cellLayout[1], baseURL: baseLocation }), - script: "zoomAndMoveRandomly.js?" + version, + script: "zoom.js?" + version, visible: true }], boundary: { @@ -194,7 +194,6 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly2.js?" + version, visible: true }, { //golgi vesicles model: "vesicle", @@ -238,7 +237,6 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly2.js?" + version, visible: true }, { model: "vesicle", @@ -304,7 +302,6 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly2.js?" + version, visible: true }, { //outer vesicles model: "vesicle", @@ -326,32 +323,8 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly2.js?" + version, visible: true - }, - // {//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, @@ -813,7 +786,7 @@ function CreateInstances(scene) { x: 0, y: 0, z: 0 - }, idBounds, 150); + }, idBounds, 150, scene.instances[i]); } //print('SCRIPT AT CREATE ENTITY: ' + script) @@ -824,8 +797,11 @@ function CreateInstances(scene) { -function CreateIdentification(name, position, rotation, dimensions, showDistance) { +function CreateIdentification(name, position, rotation, dimensions, showDistance, parentID) { //print ("creating ID for " + name); + if (parentID === undefined) { + parentID = "{00000000-0000-0000-0000-000000000000}"; + } Entities.addEntity({ type: "Sphere", name: "ID for " + name, @@ -834,6 +810,7 @@ function CreateIdentification(name, position, rotation, dimensions, showDistance green: 0, blue: 0 }, + parentID: parentID, dimensions: dimensions, position: position, rotation: rotation, @@ -9042,7 +9019,7 @@ Script.scriptEnding.connect(function() { Entities.addingEntity.disconnect(makeUngrabbable); }); -Script.setTimeout(function(){ +Script.setTimeout(function() { print('JBP stopping cell science import'); Script.stop(); -},30000) \ No newline at end of file +}, 30000) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js new file mode 100644 index 0000000000..30e83108d6 --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js @@ -0,0 +1,96 @@ +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..ce8da54eb2 --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js @@ -0,0 +1,106 @@ +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; + print('name is:: ' + 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) { + + // 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 VESICLES!!!') + sinceLastUpdate = 0; + findVesicles(); + } 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 From baa030b7b07a24612953807d5a116398e8354f17 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 24 Feb 2016 13:18:01 -0800 Subject: [PATCH 11/34] cleanup and submit --- .../CellScience/importCellScience.js | 2 +- .../DomainContent/CellScience/moveCellsAC.js | 21 ++++++++++++------- .../CellScience/moveVesiclesAC.js | 20 +++++++++++------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 55b09cd4a7..6a6de23f4e 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 = 1057; +var version = 1100; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; diff --git a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js index 30e83108d6..881f8e981c 100644 --- a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js +++ b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js @@ -1,3 +1,10 @@ +// 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, @@ -17,21 +24,21 @@ var THROTTLE_RATE = 5000; var sinceLastUpdate = 0; -print('cells script') +//print('cells script') function findCells() { var results = Entities.findEntities(basePosition, 60000); if (results.length === 0) { - print('no entities found') + // print('no entities found') return; } results.forEach(function(v) { var name = Entities.getEntityProperties(v, 'name').name; - print('name is:: ' + name) + // print('name is:: ' + name) if (name === 'Cell') { - print('found a cell!!' + v) + // print('found a cell!!' + v) Script.setTimeout(function() { moveCell(v); }, Math.random() * THROTTLE_RATE) @@ -44,7 +51,7 @@ var minAngularVelocity = 0.01; var maxAngularVelocity = 0.03; function moveCell(entityId) { - print('moving a cell! ' + entityId) + // print('moving a cell! ' + entityId) var magnitudeAV = maxAngularVelocity; @@ -53,7 +60,7 @@ function moveCell(entityId) { y: Math.random() - 0.5, z: Math.random() - 0.5 }; - print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(entityId, { angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) }); @@ -77,7 +84,7 @@ function update(deltaTime) { if (THROTTLE === true) { sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; if (sinceLastUpdate > THROTTLE_RATE) { - print('SHOULD FIND CELLS!!!') + // print('SHOULD FIND CELLS!!!') sinceLastUpdate = 0; findCells(); } else { diff --git a/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js index ce8da54eb2..3e70934cba 100644 --- a/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js +++ b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js @@ -1,3 +1,10 @@ +// 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, @@ -17,7 +24,7 @@ var THROTTLE_RATE = 5000; var sinceLastUpdate = 0; -print('vesicle script') +//print('vesicle script') function findVesicles() { var results = Entities.findEntities(basePosition, 60000); @@ -31,7 +38,7 @@ function findVesicles() { var name = Entities.getEntityProperties(v, 'name').name; print('name is:: ' + name) if (name === 'vesicle') { - print('found a vesicle!!' + v) + // print('found a vesicle!!' + v) Script.setTimeout(function() { moveVesicle(v); }, Math.random() * THROTTLE_RATE) @@ -45,7 +52,7 @@ var minAngularVelocity = 0.01; var maxAngularVelocity = 0.03; function moveVesicle(entityId) { - print('moving a vesicle! ' + entityId) + // print('moving a vesicle! ' + entityId) var magnitudeV = maxVelocity; var directionV = { x: Math.random() - 0.5, @@ -53,7 +60,7 @@ function moveVesicle(entityId) { z: Math.random() - 0.5 }; - print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); + // print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); var magnitudeAV = maxAngularVelocity; @@ -62,7 +69,7 @@ function moveVesicle(entityId) { y: Math.random() - 0.5, z: Math.random() - 0.5 }; - print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + // 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)) @@ -71,7 +78,6 @@ function moveVesicle(entityId) { } function update(deltaTime) { - // print('deltaTime',deltaTime) if (!initialized) { print("checking for servers..."); @@ -87,7 +93,7 @@ function update(deltaTime) { if (THROTTLE === true) { sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; if (sinceLastUpdate > THROTTLE_RATE) { - print('SHOULD FIND VESICLES!!!') + // print('SHOULD FIND VESICLES!!!') sinceLastUpdate = 0; findVesicles(); } else { From 5828c320416c6f3f30f901c016384815e76bcff4 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 25 Feb 2016 08:31:11 -0800 Subject: [PATCH 12/34] add toggleOverlays menu item and action --- interface/src/Application.cpp | 11 ++++++++--- interface/src/Application.h | 2 ++ interface/src/Menu.cpp | 3 +++ interface/src/Menu.h | 1 + libraries/controllers/src/controllers/Actions.cpp | 1 + libraries/controllers/src/controllers/Actions.h | 1 + 6 files changed, 16 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7314bce0bd..45fa27db78 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -817,6 +817,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : } else if (action == controller::toInt(controller::Action::RETICLE_Y)) { auto oldPos = _compositor.getReticlePosition(); _compositor.setReticlePosition({ oldPos.x, oldPos.y + state }); + } else if (action == controller::toInt(controller::Action::TOGGLE_OVERLAY)) { + _overlayConductor.setEnabled(!_overlayConductor.getEnabled()); } } }); @@ -2030,9 +2032,7 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)); cameraMenuChanged(); break; - case Qt::Key_O: - _overlayConductor.setEnabled(!_overlayConductor.getEnabled()); - break; + case Qt::Key_Slash: Menu::getInstance()->triggerOption(MenuOption::Stats); break; @@ -2993,6 +2993,11 @@ void Application::updateThreads(float deltaTime) { } } +void Application::toggleOverlays() { + auto overlaysVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays); + _overlayConductor.setEnabled(overlaysVisible); +} + void Application::cycleCamera() { auto menu = Menu::getInstance(); if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 51b90bcb99..13dab6137e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -149,6 +149,7 @@ public: const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; } ApplicationCompositor& getApplicationCompositor() { return _compositor; } const ApplicationCompositor& getApplicationCompositor() const { return _compositor; } + Overlays& getOverlays() { return _overlays; } bool isForeground() const { return _isForeground; } @@ -270,6 +271,7 @@ public slots: void cycleCamera(); void cameraMenuChanged(); + void toggleOverlays(); void reloadResourceCaches(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9c7788851c..bf8cd2e61e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -255,6 +255,9 @@ Menu::Menu() { 0, true, qApp, SLOT(rotationModeChanged()), UNSPECIFIED_POSITION, "Advanced"); + // View > Overlays + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Overlays, 0, true, + qApp, SLOT(toggleOverlays())); // Navigate menu ---------------------------------- MenuWrapper* navigateMenu = addMenu("Navigate"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 44a24ee895..ca5bf295db 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -247,6 +247,7 @@ namespace MenuOption { const QString OnePointCalibration = "1 Point Calibration"; const QString OnlyDisplayTopTen = "Only Display Top Ten"; const QString OutputMenu = "Display"; + const QString Overlays = "Overlays"; const QString PackageModel = "Package Model..."; const QString Pair = "Pair"; const QString PhysicsShowHulls = "Draw Collision Hulls"; diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp index e6662caa37..dba856cbaa 100644 --- a/libraries/controllers/src/controllers/Actions.cpp +++ b/libraries/controllers/src/controllers/Actions.cpp @@ -61,6 +61,7 @@ namespace controller { makeButtonPair(Action::CONTEXT_MENU, "ContextMenu"), makeButtonPair(Action::TOGGLE_MUTE, "ToggleMute"), makeButtonPair(Action::CYCLE_CAMERA, "CycleCamera"), + makeButtonPair(Action::TOGGLE_OVERLAY, "ToggleOverlay"), makeAxisPair(Action::RETICLE_CLICK, "ReticleClick"), makeAxisPair(Action::RETICLE_X, "ReticleX"), diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h index e77e5e5a93..efdc45cb3d 100644 --- a/libraries/controllers/src/controllers/Actions.h +++ b/libraries/controllers/src/controllers/Actions.h @@ -52,6 +52,7 @@ enum class Action { CONTEXT_MENU, TOGGLE_MUTE, CYCLE_CAMERA, + TOGGLE_OVERLAY, SHIFT, From 526f9dc2481940d0bf11e5f5020eecc23030d99e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 25 Feb 2016 08:41:38 -0800 Subject: [PATCH 13/34] check/uncheck the overlays menu when you toggle the overlays via some other mechanism --- interface/src/ui/OverlayConductor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp index f777e5d4dc..4cc5e6d534 100644 --- a/interface/src/ui/OverlayConductor.cpp +++ b/interface/src/ui/OverlayConductor.cpp @@ -110,6 +110,8 @@ void OverlayConductor::setEnabled(bool enabled) { return; } + Menu::getInstance()->setIsOptionChecked(MenuOption::Overlays, enabled); + if (_enabled) { // alpha fadeOut the overlay mesh. qApp->getApplicationCompositor().fadeOut(); From b4edfe2390d5821d13e76aae5e9c77af8bc3324a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 25 Feb 2016 12:06:22 -0800 Subject: [PATCH 14/34] no expiry for simulation ownership --- .../src/entities/EntityServer.cpp | 11 +- assignment-client/src/entities/EntityServer.h | 8 +- .../entities/src/SimpleEntitySimulation.cpp | 122 ++++++++++++------ .../entities/src/SimpleEntitySimulation.h | 7 +- libraries/physics/src/EntityMotionState.cpp | 23 ++-- 5 files changed, 106 insertions(+), 65 deletions(-) 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/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index bdf27f4440..693d80b27d 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,46 @@ 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(); + _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; From 626b1702072163d2ddd6076db0d7fe15aeb2a655 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 25 Feb 2016 14:10:23 -0800 Subject: [PATCH 15/34] Crash fix for RenderableBoxEntityItem::render --- libraries/entities-renderer/src/RenderableBoxEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index 2d054ec31b..671043813e 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -62,7 +62,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { } batch.setModelTransform(transToCenter); // we want to include the scale as well - if (_procedural->ready()) { + if (_procedural && _procedural->ready()) { _procedural->prepare(batch, getPosition(), getDimensions()); auto color = _procedural->getColor(cubeColor); batch._glColor4f(color.r, color.g, color.b, color.a); From 366aa39be8cc27d0545dc57740b97e893e4ecccd Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 25 Feb 2016 14:46:08 -0800 Subject: [PATCH 16/34] handle startup overlay visibility correctly --- interface/src/Application.cpp | 16 +++++++++++++++- interface/src/Application.h | 1 + interface/src/Menu.cpp | 2 +- interface/src/ui/ApplicationCompositor.h | 2 +- interface/src/ui/ApplicationOverlay.cpp | 4 ---- interface/src/ui/OverlayConductor.cpp | 9 ++++----- interface/src/ui/OverlayConductor.h | 4 ++-- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 45fa27db78..6845524631 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1200,7 +1200,6 @@ void Application::initializeUi() { // OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to // support the window management and scripting proxies for VR use offscreenUi->createDesktop(QString("hifi/Desktop.qml")); - connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop); // FIXME either expose so that dialogs can set this themselves or // do better detection in the offscreen UI of what has focus @@ -2435,6 +2434,17 @@ void Application::idle(uint64_t now) { if (_aboutToQuit) { return; // bail early, nothing to do here. } + + Stats::getInstance()->updateStats(); + AvatarInputs::getInstance()->update(); + + static bool firstIdle = true; + if (firstIdle) { + firstIdle = false; + auto offscreenUi = DependencyManager::get(); + connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop); + } + auto displayPlugin = getActiveDisplayPlugin(); // depending on whether we're throttling or not. @@ -2998,6 +3008,10 @@ void Application::toggleOverlays() { _overlayConductor.setEnabled(overlaysVisible); } +void Application::setOverlaysVisible(bool visible) { + _overlayConductor.setEnabled(visible); +} + void Application::cycleCamera() { auto menu = Menu::getInstance(); if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 13dab6137e..aacf0b5b08 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -272,6 +272,7 @@ public slots: void cycleCamera(); void cameraMenuChanged(); void toggleOverlays(); + void setOverlaysVisible(bool visible); void reloadResourceCaches(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index bf8cd2e61e..a5795c5a3b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -257,7 +257,7 @@ Menu::Menu() { // View > Overlays addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Overlays, 0, true, - qApp, SLOT(toggleOverlays())); + qApp, SLOT(setOverlaysVisible(bool))); // Navigate menu ---------------------------------- MenuWrapper* navigateMenu = addMenu("Navigate"); diff --git a/interface/src/ui/ApplicationCompositor.h b/interface/src/ui/ApplicationCompositor.h index 7bdb97727f..b94afd2cce 100644 --- a/interface/src/ui/ApplicationCompositor.h +++ b/interface/src/ui/ApplicationCompositor.h @@ -131,7 +131,7 @@ private: float _textureAspectRatio { 1.0f }; int _hemiVerticesID { GeometryCache::UNKNOWN_ID }; - float _alpha { 1.0f }; + float _alpha { 0.0f }; // hidden by default float _prevAlpha { 1.0f }; float _fadeInAlpha { true }; float _oculusUIRadius { 1.0f }; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 67b5135e0c..998a64d81a 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -58,10 +58,6 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { CHECK_GL_ERROR(); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); - // TODO move to Application::idle()? - Stats::getInstance()->updateStats(); - AvatarInputs::getInstance()->update(); - buildFramebufferObject(); if (!_overlayFramebuffer) { diff --git a/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp index 4cc5e6d534..21b1aa879e 100644 --- a/interface/src/ui/OverlayConductor.cpp +++ b/interface/src/ui/OverlayConductor.cpp @@ -110,9 +110,12 @@ void OverlayConductor::setEnabled(bool enabled) { return; } + qDebug() << "OverlayConductor::setEnabled() enabled:" << enabled; Menu::getInstance()->setIsOptionChecked(MenuOption::Overlays, enabled); - if (_enabled) { + _enabled = enabled; // set the new value + + if (!_enabled) { // alpha fadeOut the overlay mesh. qApp->getApplicationCompositor().fadeOut(); @@ -122,8 +125,6 @@ void OverlayConductor::setEnabled(bool enabled) { // disable QML events auto offscreenUi = DependencyManager::get(); offscreenUi->getRootItem()->setEnabled(false); - - _enabled = false; } else { // alpha fadeIn the overlay mesh. qApp->getApplicationCompositor().fadeIn(); @@ -144,8 +145,6 @@ void OverlayConductor::setEnabled(bool enabled) { t.setRotation(glm::quat_cast(camMat)); qApp->getApplicationCompositor().setModelTransform(t); } - - _enabled = true; } } diff --git a/interface/src/ui/OverlayConductor.h b/interface/src/ui/OverlayConductor.h index 4b8c0134b5..b94c5be7dd 100644 --- a/interface/src/ui/OverlayConductor.h +++ b/interface/src/ui/OverlayConductor.h @@ -29,8 +29,8 @@ private: STANDING }; - Mode _mode = FLAT; - bool _enabled = true; + Mode _mode { FLAT }; + bool _enabled { false }; }; #endif From 8f304d95b39aeda6e2e20d6a5b1dfc0eea7caba9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 25 Feb 2016 15:26:42 -0800 Subject: [PATCH 17/34] rather than computing a velocity for entities held by others as a way to keep it active in local bullet, just call activateBody over and over --- interface/src/avatar/AvatarActionHold.cpp | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 5b493c4215..03842ca5f9 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -153,32 +153,10 @@ 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; position = palmPosition + rotation * _relativePosition; - - // update linearVelocity based on offset via _relativePosition; - linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition); }); return holdingAvatar; @@ -278,6 +256,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { }); forceBodyNonStatic(); + activateBody(true); } bool AvatarActionHold::updateArguments(QVariantMap arguments) { From 74452bc89009753af163f6fefb2322cdb6baf45f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 25 Feb 2016 15:34:50 -0800 Subject: [PATCH 18/34] put back some code that shouldn't have been removed --- interface/src/avatar/AvatarActionHold.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 03842ca5f9..b62cae1d58 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -157,6 +157,9 @@ std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::qu rotation = palmRotation * _relativeRotation; position = palmPosition + rotation * _relativePosition; + + // update linearVelocity based on offset via _relativePosition; + linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition); }); return holdingAvatar; From 519a90f2bdca815177b208c97d59ac3bc5e93271 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 25 Feb 2016 16:02:05 -0800 Subject: [PATCH 19/34] fix the overlays visible on startup case --- interface/src/Application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6845524631..df7b203bea 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2438,11 +2438,14 @@ void Application::idle(uint64_t now) { Stats::getInstance()->updateStats(); AvatarInputs::getInstance()->update(); + // These tasks need to be done on our first idle, because we don't want the showing of + // overlay subwindows to do a showDesktop() until after the first time through static bool firstIdle = true; if (firstIdle) { firstIdle = false; auto offscreenUi = DependencyManager::get(); connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop); + _overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays)); } From e58081ca9c2d2dcfd3afb83edfd019edef888d03 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 25 Feb 2016 16:23:12 -0800 Subject: [PATCH 20/34] remove extra debug code --- interface/src/ui/OverlayConductor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp index 21b1aa879e..324ec8583b 100644 --- a/interface/src/ui/OverlayConductor.cpp +++ b/interface/src/ui/OverlayConductor.cpp @@ -110,7 +110,6 @@ void OverlayConductor::setEnabled(bool enabled) { return; } - qDebug() << "OverlayConductor::setEnabled() enabled:" << enabled; Menu::getInstance()->setIsOptionChecked(MenuOption::Overlays, enabled); _enabled = enabled; // set the new value From bf0fb7258a49f59b29a5df740d49026e4f9e32c5 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 25 Feb 2016 22:01:10 -0800 Subject: [PATCH 21/34] CR feedback --- interface/src/Application.cpp | 7 ++++--- interface/src/ui/OverlayConductor.cpp | 23 ++++++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b072867400..64a9ef2029 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -818,7 +818,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : auto oldPos = _compositor.getReticlePosition(); _compositor.setReticlePosition({ oldPos.x, oldPos.y + state }); } else if (action == controller::toInt(controller::Action::TOGGLE_OVERLAY)) { - _overlayConductor.setEnabled(!_overlayConductor.getEnabled()); + toggleOverlays(); } } }); @@ -3003,8 +3003,9 @@ void Application::updateThreads(float deltaTime) { } void Application::toggleOverlays() { - auto overlaysVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays); - _overlayConductor.setEnabled(overlaysVisible); + auto newOverlaysVisible = !_overlayConductor.getEnabled(); + Menu::getInstance()->setIsOptionChecked(MenuOption::Overlays, newOverlaysVisible); + _overlayConductor.setEnabled(newOverlaysVisible); } void Application::setOverlaysVisible(bool visible) { diff --git a/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp index 324ec8583b..113dad1ab5 100644 --- a/interface/src/ui/OverlayConductor.cpp +++ b/interface/src/ui/OverlayConductor.cpp @@ -114,17 +114,8 @@ void OverlayConductor::setEnabled(bool enabled) { _enabled = enabled; // set the new value - if (!_enabled) { - // alpha fadeOut the overlay mesh. - qApp->getApplicationCompositor().fadeOut(); - - // disable mouse clicks from script - qApp->getOverlays().disable(); - - // disable QML events - auto offscreenUi = DependencyManager::get(); - offscreenUi->getRootItem()->setEnabled(false); - } else { + // if the new state is visible/enabled... + if (_enabled) { // alpha fadeIn the overlay mesh. qApp->getApplicationCompositor().fadeIn(); @@ -144,6 +135,16 @@ void OverlayConductor::setEnabled(bool enabled) { t.setRotation(glm::quat_cast(camMat)); qApp->getApplicationCompositor().setModelTransform(t); } + } else { // other wise, if the new state is hidden/not enabled + // alpha fadeOut the overlay mesh. + qApp->getApplicationCompositor().fadeOut(); + + // disable mouse clicks from script + qApp->getOverlays().disable(); + + // disable QML events + auto offscreenUi = DependencyManager::get(); + offscreenUi->getRootItem()->setEnabled(false); } } From 6b427e59ae34be73a149ecdd18bc4b3eecd6ccae Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 26 Feb 2016 10:12:23 -0800 Subject: [PATCH 22/34] show the overlays when the context menu is shown --- libraries/ui/src/OffscreenUi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 1c41827795..999f9ef2f7 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -460,6 +460,7 @@ void OffscreenUi::unfocusWindows() { } void OffscreenUi::toggleMenu(const QPoint& screenPosition) { + emit showDesktop(); // we really only want to do this if you're showing the menu, but for now this works auto virtualPos = mapToVirtualScreen(screenPosition, nullptr); QMetaObject::invokeMethod(_desktop, "toggleMenu", Q_ARG(QVariant, virtualPos)); } From 6c9cf386a698422ac4f03c777981a0e702ffebac Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 26 Feb 2016 10:14:09 -0800 Subject: [PATCH 23/34] when trigger is squeezed, check for things stuck to hand and unhook them --- examples/controllers/handControllerGrab.js | 13 +++++++++ .../entities/src/EntityScriptingInterface.cpp | 27 +++++++++++++++++++ .../entities/src/EntityScriptingInterface.h | 2 +- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 04e93334cb..9eac023ac4 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -801,6 +801,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; @@ -1751,6 +1753,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: " + 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/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index d7a47136b5..4857fb8529 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,32 @@ 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) { + 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); From b0cb4b719994a2e825c7b56f0bf515544e8ef61f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 26 Feb 2016 10:26:02 -0800 Subject: [PATCH 24/34] disable boundaries --- .../CellScience/importCellScience.js | 513 +++++++++--------- 1 file changed, 248 insertions(+), 265 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 6a6de23f4e..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 = 1100; +var version = 1112; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -112,7 +112,7 @@ var scenes = [{ y: 0, z: 0 }, - radius: 450, + radius: 500, number: 10, userData: JSON.stringify({ entryPoint: locations.cellLayout[1], @@ -151,267 +151,253 @@ var scenes = [{ skybox: "cosmos_skybox_blurred" }, instances: [{ - model: "translation", - dimensions: { - x: 10, - y: 16, - z: 10 + 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 }, - offset: { - x: 0, - y: 0, - z: 0 + 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: 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 + 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: 0, - y: 0, - z: 0 + 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: 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 - }, - 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 - }, - 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], @@ -573,7 +559,7 @@ function ImportScene(scene) { CreateZone(scene); CreateInstances(scene); - CreateBoundary(scene); + // CreateBoundary(scene); // print("done " + scene.name); @@ -797,11 +783,9 @@ function CreateInstances(scene) { -function CreateIdentification(name, position, rotation, dimensions, showDistance, parentID) { +function CreateIdentification(name, position, rotation, dimensions, showDistance) { //print ("creating ID for " + name); - if (parentID === undefined) { - parentID = "{00000000-0000-0000-0000-000000000000}"; - } + Entities.addEntity({ type: "Sphere", name: "ID for " + name, @@ -810,7 +794,6 @@ function CreateIdentification(name, position, rotation, dimensions, showDistance green: 0, blue: 0 }, - parentID: parentID, dimensions: dimensions, position: position, rotation: rotation, From 5594f1e4e586fbc3967c1ce13526915cfcc457cd Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 26 Feb 2016 10:27:34 -0800 Subject: [PATCH 25/34] if equipped entity vanishes, reset grab state --- examples/controllers/handControllerGrab.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 9eac023ac4..45d27cbbb9 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1446,6 +1446,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. From 6c6ea3f0a76ce9bdc433216f3e3bcb6ad5d678e0 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 26 Feb 2016 10:42:45 -0800 Subject: [PATCH 26/34] code cleanup --- .../DomainContent/CellScience/moveCellsAC.js | 14 +++++++------- .../DomainContent/CellScience/moveVesiclesAC.js | 10 +++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js index 881f8e981c..cf35e081e0 100644 --- a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js +++ b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js @@ -30,18 +30,18 @@ function findCells() { var results = Entities.findEntities(basePosition, 60000); if (results.length === 0) { - // print('no entities found') + // print('no entities found') return; } results.forEach(function(v) { var name = Entities.getEntityProperties(v, 'name').name; - // print('name is:: ' + name) + // print('name is:: ' + name) if (name === 'Cell') { - // print('found a cell!!' + v) + // print('found a cell!!' + v) Script.setTimeout(function() { moveCell(v); - }, Math.random() * THROTTLE_RATE) + }, Math.random() * THROTTLE_RATE); } }); } @@ -51,7 +51,7 @@ var minAngularVelocity = 0.01; var maxAngularVelocity = 0.03; function moveCell(entityId) { - // print('moving a cell! ' + entityId) + // print('moving a cell! ' + entityId) var magnitudeAV = maxAngularVelocity; @@ -60,7 +60,7 @@ function moveCell(entityId) { y: Math.random() - 0.5, z: Math.random() - 0.5 }; - // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(entityId, { angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) }); @@ -84,7 +84,7 @@ function update(deltaTime) { if (THROTTLE === true) { sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; if (sinceLastUpdate > THROTTLE_RATE) { - // print('SHOULD FIND CELLS!!!') + // print('SHOULD FIND CELLS!!!') sinceLastUpdate = 0; findCells(); } else { diff --git a/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js index 3e70934cba..922f0d94cf 100644 --- a/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js +++ b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js @@ -30,18 +30,17 @@ function findVesicles() { var results = Entities.findEntities(basePosition, 60000); if (results.length === 0) { - print('no entities found') + // print('no entities found'); return; } results.forEach(function(v) { var name = Entities.getEntityProperties(v, 'name').name; - print('name is:: ' + name) if (name === 'vesicle') { - // print('found a vesicle!!' + v) + //print('found a vesicle!!' + v) Script.setTimeout(function() { moveVesicle(v); - }, Math.random() * THROTTLE_RATE) + }, Math.random() * THROTTLE_RATE); } }); } @@ -78,7 +77,6 @@ function moveVesicle(entityId) { } function update(deltaTime) { - // print('deltaTime',deltaTime) if (!initialized) { print("checking for servers..."); if (Entities.serversExist() && Entities.canRez()) { @@ -93,11 +91,9 @@ function update(deltaTime) { if (THROTTLE === true) { sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; if (sinceLastUpdate > THROTTLE_RATE) { - // print('SHOULD FIND VESICLES!!!') sinceLastUpdate = 0; findVesicles(); } else { - // print('returning in update ' + sinceLastUpdate) return; } } From 712cf911b19c5019f743d6ac3232a3887ac84b62 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 26 Feb 2016 11:06:02 -0800 Subject: [PATCH 27/34] Differentiate global sun and skyStage sun --- libraries/model/src/model/Stage.cpp | 2 ++ .../render-utils/src/DeferredLightingEffect.cpp | 15 +++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 6a1e95936b..c976e5c396 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -142,6 +142,8 @@ SunSkyStage::SunSkyStage() : _skybox(std::make_shared()) { _sunLight->setType(Light::SUN); + // Default ambient sphere (for lack of skybox) + _sunLight->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset::OLD_TOWN_SQUARE); setSunIntensity(1.0f); setSunAmbientIntensity(0.5f); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e0cbab67bc..c1c7240f20 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -87,14 +87,11 @@ void DeferredLightingEffect::init() { _allocatedLights.push_back(std::make_shared()); model::LightPointer lp = _allocatedLights[0]; + lp->setType(model::Light::SUN); + // Add the global light to the light stage (for later shadow rendering) _lightStage.addLight(lp); - lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f)); - lp->setColor(glm::vec3(1.0f)); - lp->setIntensity(1.0f); - lp->setType(model::Light::SUN); - lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); } void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color, @@ -560,7 +557,13 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo } void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light, const gpu::TexturePointer& skyboxTexture) { - _allocatedLights.front() = light; + auto globalLight = _allocatedLights.front(); + globalLight->setDirection(light->getDirection()); + globalLight->setColor(light->getColor()); + globalLight->setIntensity(light->getIntensity()); + globalLight->setAmbientIntensity(light->getAmbientIntensity()); + globalLight->setAmbientSphere(light->getAmbientSphere()); + _skyboxTexture = skyboxTexture; } From c0c5084149f9724a6dbab7e587e28d99e03bee4a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 26 Feb 2016 14:05:02 -0800 Subject: [PATCH 28/34] handle parenting loops --- libraries/shared/src/SpatiallyNestable.cpp | 31 ++++++++++++++-------- libraries/shared/src/SpatiallyNestable.h | 6 ++--- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 557b25d9b2..1a897021f1 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,30 @@ 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."; + getThisPointer()->setParentID(QUuid()); + return jointInWorldFrame; + } + + Transform worldTransform = getTransform(success, depth); worldTransform.setScale(1.0f); // TODO -- scale; if (!success) { return jointInWorldFrame; 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; From 9a01c933221c5a65499e75442668adc08c804474 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 26 Feb 2016 14:28:27 -0800 Subject: [PATCH 29/34] Avatar: fix for rendering avatar attachments --- interface/src/avatar/Avatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; } From 01ef5aabcb0b2f685db9e3a151158437bdc24c86 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 26 Feb 2016 14:38:35 -0800 Subject: [PATCH 30/34] OpenVR: More reliable detection of left and right hands --- plugins/openvr/src/ViveControllerManager.cpp | 110 +++++++++---------- plugins/openvr/src/ViveControllerManager.h | 15 +-- 2 files changed, 61 insertions(+), 64 deletions(-) diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 071d5fd631..749c9ea2e4 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(leftHandDeviceIndex, inputCalibrationData, true); + handleHandController(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(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(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(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(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand); } } } - - _trackedControllers = numTrackedControllers; } void ViveControllerManager::InputDevice::focusOutEvent() { @@ -284,42 +284,38 @@ 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(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; + _axisStateMap[isLeftHand ? LX : RX] = x; + _axisStateMap[isLeftHand ? LY : RY] = 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(uint32_t button, bool pressed, bool isLeftHand) { if (!pressed) { return; } if (button == vr::k_EButton_ApplicationMenu) { - _buttonPressedMap.insert(left ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB); + _buttonPressedMap.insert(isLeftHand ? controller::LEFT_PRIMARY_THUMB : controller::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 ? controller::LB : controller::RB); } else if (button == vr::k_EButton_SteamVR_Trigger) { - _buttonPressedMap.insert(left ? controller::LT : controller::RT); + _buttonPressedMap.insert(isLeftHand ? controller::LT : controller::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 ? controller::LS : controller::RS); } } void ViveControllerManager::InputDevice::handlePoseEvent(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 +380,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 +395,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..2240a528a9 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,13 +58,14 @@ 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 handleHandController(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand); + void handleButtonEvent(uint32_t button, bool pressed, bool isLeftHand); + void handleAxisEvent(uint32_t axis, float x, float y, bool isLeftHand); void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, - const vec3& linearVelocity, const vec3& angularVelocity, bool left); + const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand); int _trackedControllers { 0 }; - vr::IVRSystem*& _hmd; + vr::IVRSystem*& _system; friend class ViveControllerManager; }; @@ -81,8 +82,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; From 89885805d22ddf3a2c952533a8d97206d95de26e Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 26 Feb 2016 18:34:33 -0800 Subject: [PATCH 31/34] OpenVR: Added hysteresis to the touch pad dead spot This should make using the Vive touch pad for movement more reliable. --- plugins/openvr/src/ViveControllerManager.cpp | 38 ++++++++++++-------- plugins/openvr/src/ViveControllerManager.h | 37 +++++++++++++++---- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 749c9ea2e4..0de8f6891d 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -234,8 +234,8 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle auto rightHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand); if (!jointsCaptured) { - handleHandController(leftHandDeviceIndex, inputCalibrationData, true); - handleHandController(rightHandDeviceIndex, inputCalibrationData, false); + handleHandController(deltaTime, leftHandDeviceIndex, inputCalibrationData, true); + handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false); } int numTrackedControllers = 0; @@ -248,7 +248,7 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle _trackedControllers = numTrackedControllers; } -void ViveControllerManager::InputDevice::handleHandController(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand) { +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 && @@ -258,7 +258,7 @@ void ViveControllerManager::InputDevice::handleHandController(uint32_t deviceInd const mat4& mat = _trackedDevicePoseMat4[deviceIndex]; const vec3 linearVelocity = _trackedDeviceLinearVelocities[deviceIndex]; const vec3 angularVelocity = _trackedDeviceAngularVelocities[deviceIndex]; - handlePoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity, isLeftHand); + handlePoseEvent(deltaTime, inputCalibrationData, mat, linearVelocity, angularVelocity, isLeftHand); vr::VRControllerState_t controllerState = vr::VRControllerState_t(); if (_system->GetControllerState(deviceIndex, &controllerState)) { @@ -267,12 +267,12 @@ void ViveControllerManager::InputDevice::handleHandController(uint32_t deviceInd 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, isLeftHand); + 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, isLeftHand); + handleAxisEvent(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand); } } } @@ -284,36 +284,44 @@ 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 isLeftHand) { +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[isLeftHand ? LX : RX] = x; - _axisStateMap[isLeftHand ? 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[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 isLeftHand) { +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(isLeftHand ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB); + _buttonPressedMap.insert(isLeftHand ? LEFT_PRIMARY_THUMB : RIGHT_PRIMARY_THUMB); } else if (button == vr::k_EButton_Grip) { - _buttonPressedMap.insert(isLeftHand ? controller::LB : controller::RB); + _buttonPressedMap.insert(isLeftHand ? LB : RB); } else if (button == vr::k_EButton_SteamVR_Trigger) { - _buttonPressedMap.insert(isLeftHand ? controller::LT : controller::RT); + _buttonPressedMap.insert(isLeftHand ? LT : RT); } else if (button == vr::k_EButton_SteamVR_Touchpad) { - _buttonPressedMap.insert(isLeftHand ? controller::LS : controller::RS); + _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 isLeftHand) { // When the sensor-to-world rotation is identity the coordinate axes look like this: diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 2240a528a9..480fbfeb90 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -58,12 +58,39 @@ private: virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; - void handleHandController(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand); - void handleButtonEvent(uint32_t button, bool pressed, bool isLeftHand); - void handleAxisEvent(uint32_t axis, float x, float y, bool isLeftHand); - void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, + 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*& _system; friend class ViveControllerManager; @@ -71,8 +98,6 @@ private: void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign); - - bool _registeredWithInputMapper { false }; bool _modelLoaded { false }; model::Geometry _modelGeometry; From 5bf8670bc2e3f6def32d4fddf237b1c1c490a040 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 28 Feb 2016 12:15:26 -0800 Subject: [PATCH 32/34] fix SpatiallyNestable::getChildren --- examples/controllers/handControllerGrab.js | 3 ++- libraries/entities/src/EntityScriptingInterface.cpp | 4 +++- libraries/shared/src/SpatiallyNestable.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 45d27cbbb9..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 @@ -1766,7 +1767,7 @@ function MyController(hand) { 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: " + childID); + print("disconnecting stray child of hand: (" + _this.hand + ") " + childID); Entities.editEntity(childID, {parentID: NULL_UUID}); }); } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 4857fb8529..26f73eb65a 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1084,7 +1084,9 @@ QVector EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& pare return; } parent->forEachChild([&](SpatiallyNestablePointer child) { - result.push_back(child->getID()); + if (child->getParentJointIndex() == jointIndex) { + result.push_back(child->getID()); + } }); }); return result; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 557b25d9b2..2704a8bc21 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -682,7 +682,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; } } From a933935e2d6af70dea252a2707efa2d3ce8d7675 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 28 Feb 2016 15:13:49 -0800 Subject: [PATCH 33/34] lock mutex in clearEntitiesInernal() --- libraries/entities/src/SimpleEntitySimulation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 693d80b27d..6bf25f767d 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -127,6 +127,7 @@ void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) { } void SimpleEntitySimulation::clearEntitiesInternal() { + QMutexLocker lock(&_mutex); _entitiesWithSimulationOwner.clear(); _entitiesThatNeedSimulationOwner.clear(); } From bb9d1556c6e148f19449ab0398655da9b8a90085 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 29 Feb 2016 11:07:02 -0800 Subject: [PATCH 34/34] when breaking a parenting loop, make an effort to keep the object near where it was when the loop was created --- libraries/shared/src/SpatiallyNestable.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 1a897021f1..56532c04f4 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -519,7 +519,13 @@ const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, i success = false; // someone created a loop. break it... qDebug() << "Parenting loop detected."; - getThisPointer()->setParentID(QUuid()); + SpatiallyNestablePointer _this = getThisPointer(); + _this->setParentID(QUuid()); + bool setPositionSuccess; + AACube aaCube = getQueryAACube(setPositionSuccess); + if (setPositionSuccess) { + _this->setPosition(aaCube.calcCenter()); + } return jointInWorldFrame; }