From bfc619497e735861ccd9ae4f956a51df2cb6becd Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 13:33:19 -0800 Subject: [PATCH 01/74] spawning model --- .../whiteboardV2/whiteboardSpawner.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 examples/homeContent/whiteboardV2/whiteboardSpawner.js diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js new file mode 100644 index 0000000000..76992062dc --- /dev/null +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -0,0 +1,32 @@ +// +// whiteboardSpawner.js +// examples/homeContent/whiteboardV2 +// +// Created by Eric Levina on 2/17/16 +// Copyright 2016 High Fidelity, Inc. +// +// Run this script to spawn a whiteboard and associated acoutrements that one can paint on usignmarkers +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + + +var orientation = Camera.getOrientation(); +orientation = Quat.safeEulerAngles(orientation); +orientation.x = 0; +orientation = Quat.fromVec3Degrees(orientation); +var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); + +var WHITEBOARD_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard-3.fbx"; +var whiteboard = Entities.addEntity({ + type: "Model", + modelURL: WHITEBOARD_MODEL_URL, + position: center +}); + + +function cleanup() { + Entities.deleteEntity(whiteboard); +} + +Script.scriptEnding.connect(cleanup); \ No newline at end of file From bb2fd0072c1533881780ec7c2cf3688e7b1ef882 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 13:41:58 -0800 Subject: [PATCH 02/74] collision hull --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 76992062dc..7cdbef5a7a 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -17,11 +17,16 @@ orientation.x = 0; orientation = Quat.fromVec3Degrees(orientation); var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); + var WHITEBOARD_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard-3.fbx"; +var WHITEBOARD_COLLISION_HULL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard.obj"; var whiteboard = Entities.addEntity({ type: "Model", modelURL: WHITEBOARD_MODEL_URL, - position: center + position: center, + shapeType: 'compound', + compoundShapeURL: WHITEBOARD_COLLISION_HULL_URL, + dimensions: { x: 0.4636, y: 2.7034, z: 1.8653} }); From 9e8d123b1664a6a189859eaeef9c31fe957f2451 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 13:58:04 -0800 Subject: [PATCH 03/74] spawning marker and whiteboard correctly --- .../whiteboardV2/whiteboardSpawner.js | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 7cdbef5a7a..c101d3df9a 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -14,24 +14,41 @@ var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); orientation.x = 0; +var whiteboardRotation = Quat.fromVec3Degrees({x: orientation.x, y: orientation.y - 90, z: orientation.z}); orientation = Quat.fromVec3Degrees(orientation); -var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); +var whiteboardPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); var WHITEBOARD_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard-3.fbx"; var WHITEBOARD_COLLISION_HULL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard.obj"; var whiteboard = Entities.addEntity({ type: "Model", modelURL: WHITEBOARD_MODEL_URL, - position: center, + position: whiteboardPosition, + rotation: whiteboardRotation, shapeType: 'compound', compoundShapeURL: WHITEBOARD_COLLISION_HULL_URL, dimensions: { x: 0.4636, y: 2.7034, z: 1.8653} }); +var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); +var MARKER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/marker-blue.fbx"; +var marker = Entities.addEntity({ + type: "Model", + modelURL: MARKER_MODEL_URL, + shapeType: "box", + dynamic: true, + gravity: {x: 0, y: -1, z: 0}, + rotation: whiteboardRotation, + velocity: {x: 0, y: -0.1, z: 0}, + position: markerPosition, + dimensions: {x: 0.0270, y: 0.0272, z: 0.1641} +}); + function cleanup() { Entities.deleteEntity(whiteboard); + Entities.deleteEntity(marker); } Script.scriptEnding.connect(cleanup); \ No newline at end of file From 073661b78de92f751e3160a3d03e0caa6aa7a46c Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 14:25:21 -0800 Subject: [PATCH 04/74] markers in right spot --- .../whiteboardV2/whiteboardSpawner.js | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index c101d3df9a..a8796f56fb 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -14,7 +14,11 @@ var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); orientation.x = 0; -var whiteboardRotation = Quat.fromVec3Degrees({x: orientation.x, y: orientation.y - 90, z: orientation.z}); +var whiteboardRotation = Quat.fromVec3Degrees({ + x: orientation.x, + y: orientation.y - 90, + z: orientation.z +}); orientation = Quat.fromVec3Degrees(orientation); @@ -28,7 +32,11 @@ var whiteboard = Entities.addEntity({ rotation: whiteboardRotation, shapeType: 'compound', compoundShapeURL: WHITEBOARD_COLLISION_HULL_URL, - dimensions: { x: 0.4636, y: 2.7034, z: 1.8653} + dimensions: { + x: 0.4636, + y: 2.7034, + z: 1.8653 + } }); var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); @@ -38,11 +46,49 @@ var marker = Entities.addEntity({ modelURL: MARKER_MODEL_URL, shapeType: "box", dynamic: true, - gravity: {x: 0, y: -1, z: 0}, + gravity: { + x: 0, + y: -1, + z: 0 + }, rotation: whiteboardRotation, - velocity: {x: 0, y: -0.1, z: 0}, + velocity: { + x: 0, + y: -0.1, + z: 0 + }, position: markerPosition, - dimensions: {x: 0.0270, y: 0.0272, z: 0.1641} + dimensions: { + x: 0.0270, + y: 0.0272, + z: 0.1641 + }, + userData: JSON.stringify({ + wearable: { + joints: { + RightHand: [{ + "x": 0.03257002681493759, + "y": 0.15036098659038544, + "z": 0.051217660307884216 + }, { + "x": -0.5274277329444885, + "y": -0.23446641862392426, + "z": -0.05400913953781128, + "w": 0.8148180246353149 + }], + LeftHand: [{ + "x": -0.031699854880571365, + "y": 0.15150733292102814, + "z": 0.041107177734375 + }, { + "x": 0.649201512336731, + "y": 0.1007731482386589, + "z": 0.3215889632701874, + "w": -0.6818817853927612 + }] + } + } + }) }); From df84a166e483439d842ded12065b4e690c7eda43 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 15:08:42 -0800 Subject: [PATCH 05/74] spawning marker tips- parenting to markers --- .../homeContent/whiteboardV2/whiteboardSpawner.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index a8796f56fb..4a1a89c250 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -51,7 +51,7 @@ var marker = Entities.addEntity({ y: -1, z: 0 }, - rotation: whiteboardRotation, + // rotation: whiteboardRotation, velocity: { x: 0, y: -0.1, @@ -91,10 +91,20 @@ var marker = Entities.addEntity({ }) }); +var markerTip = Entities.addEntity({ + type: "Box", + dimensions: {x: 0.05, y: 0.05, z: 0.05}, + position: Vec3.sum(markerPosition, {x: 0.0, y: 0.001, z: 0.1}), + parentID: marker, + color: {red: 200, green: 10, blue: 200}, + collisionless: true +}) + function cleanup() { Entities.deleteEntity(whiteboard); Entities.deleteEntity(marker); + Entities.deleteEntity(markerTip); } Script.scriptEnding.connect(cleanup); \ No newline at end of file From 7f23ee04be9995f11b55731c48103ddcada0315b Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 17:16:43 -0800 Subject: [PATCH 06/74] basic marker entity script --- .../whiteboardV2/markerEntityScript.js | 35 +++++++++++++++++++ .../whiteboardV2/whiteboardSpawner.js | 12 ++----- 2 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 examples/homeContent/whiteboardV2/markerEntityScript.js diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js new file mode 100644 index 0000000000..43a7ec1788 --- /dev/null +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -0,0 +1,35 @@ +// +// markerTipEntityScript.js +// examples/homeContent/markerTipEntityScript +// +// Created by Eric Levin on 2/17/15. +// 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("../../libraries/utils.js"); + + MarkerTip = function() { + _this = this; + }; + + MarkerTip.prototype = { + + continueNearGrab: function() { + print("EBL Conintue ") + }, + + preload: function(entityID) { + this.entityID = entityID; + + } + }; + + // entity scripts always need to return a newly constructed object of our type + return new MarkerTip(); +}); diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 4a1a89c250..a699bcafa2 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -41,6 +41,7 @@ var whiteboard = Entities.addEntity({ var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); var MARKER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/marker-blue.fbx"; +var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); var marker = Entities.addEntity({ type: "Model", modelURL: MARKER_MODEL_URL, @@ -51,7 +52,6 @@ var marker = Entities.addEntity({ y: -1, z: 0 }, - // rotation: whiteboardRotation, velocity: { x: 0, y: -0.1, @@ -63,6 +63,7 @@ var marker = Entities.addEntity({ y: 0.0272, z: 0.1641 }, + script: MARKER_SCRIPT_URL, userData: JSON.stringify({ wearable: { joints: { @@ -91,20 +92,11 @@ var marker = Entities.addEntity({ }) }); -var markerTip = Entities.addEntity({ - type: "Box", - dimensions: {x: 0.05, y: 0.05, z: 0.05}, - position: Vec3.sum(markerPosition, {x: 0.0, y: 0.001, z: 0.1}), - parentID: marker, - color: {red: 200, green: 10, blue: 200}, - collisionless: true -}) function cleanup() { Entities.deleteEntity(whiteboard); Entities.deleteEntity(marker); - Entities.deleteEntity(markerTip); } Script.scriptEnding.connect(cleanup); \ No newline at end of file From 728e8c763d43033f4d788821fc8fe57cc959173a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 17:30:01 -0800 Subject: [PATCH 07/74] ray cast --- .../whiteboardV2/markerEntityScript.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 43a7ec1788..ef6f6b005d 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -21,12 +21,25 @@ MarkerTip.prototype = { continueNearGrab: function() { - print("EBL Conintue ") + + // cast a ray from marker and see if it hits anything + + var props = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); + + var pickRay = { + origin: props.position, + direction: Quat.getFront(props.rotation) + } + + var intersection = Entities.findRayIntersection(pickRay, true); + + if (intersection.intersects) { + print("INTERSECTION!") + } }, preload: function(entityID) { this.entityID = entityID; - } }; From 39d4fbf19dba163eda9b7bcd3e685cab55ff4e50 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 18 Feb 2016 15:23:32 -0800 Subject: [PATCH 08/74] refactoring --- .../whiteboardV2/markerEntityScript.js | 17 +++++++---- .../whiteboardV2/whiteboardSpawner.js | 30 ++----------------- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index ef6f6b005d..3ed89e82c1 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -13,7 +13,7 @@ (function() { Script.include("../../libraries/utils.js"); - + MarkerTip = function() { _this = this; }; @@ -22,22 +22,29 @@ continueNearGrab: function() { + _this.continueHolding(); + }, + + continueEquip: function() { + _this.continueHolding(); + }, + + continueHolding: function() { // cast a ray from marker and see if it hits anything var props = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); var pickRay = { - origin: props.position, + origin: props.position, direction: Quat.getFront(props.rotation) } var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects) { - print("INTERSECTION!") } }, - + preload: function(entityID) { this.entityID = entityID; } @@ -45,4 +52,4 @@ // entity scripts always need to return a newly constructed object of our type return new MarkerTip(); -}); +}); \ No newline at end of file diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index a699bcafa2..535c817121 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -40,7 +40,7 @@ var whiteboard = Entities.addEntity({ }); var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); -var MARKER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/marker-blue.fbx"; +var MARKER_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-blue.fbx"; var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); var marker = Entities.addEntity({ type: "Model", @@ -63,33 +63,7 @@ var marker = Entities.addEntity({ y: 0.0272, z: 0.1641 }, - script: MARKER_SCRIPT_URL, - userData: JSON.stringify({ - wearable: { - joints: { - RightHand: [{ - "x": 0.03257002681493759, - "y": 0.15036098659038544, - "z": 0.051217660307884216 - }, { - "x": -0.5274277329444885, - "y": -0.23446641862392426, - "z": -0.05400913953781128, - "w": 0.8148180246353149 - }], - LeftHand: [{ - "x": -0.031699854880571365, - "y": 0.15150733292102814, - "z": 0.041107177734375 - }, { - "x": 0.649201512336731, - "y": 0.1007731482386589, - "z": 0.3215889632701874, - "w": -0.6818817853927612 - }] - } - } - }) + script: MARKER_SCRIPT_URL }); From f4ee9acb9c0ea5eca8271fc0cf9d69a913cd272a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 09:49:22 -0800 Subject: [PATCH 09/74] intersecting --- examples/homeContent/whiteboardV2/markerEntityScript.js | 5 ++++- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 3ed89e82c1..4faf64b542 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -39,14 +39,17 @@ direction: Quat.getFront(props.rotation) } - var intersection = Entities.findRayIntersection(pickRay, true); + var intersection = Entities.findRayIntersection(pickRay, true, [], [_this.entityID]); if (intersection.intersects) { + var name = Entities.getEntityProperties(intersection.entityID); + print("intersection") } }, preload: function(entityID) { this.entityID = entityID; + print("EBL PRELOAD"); } }; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 535c817121..68c4422364 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -27,6 +27,7 @@ var WHITEBOARD_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteb var WHITEBOARD_COLLISION_HULL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard.obj"; var whiteboard = Entities.addEntity({ type: "Model", + name: "whiteboard", modelURL: WHITEBOARD_MODEL_URL, position: whiteboardPosition, rotation: whiteboardRotation, @@ -63,6 +64,7 @@ var marker = Entities.addEntity({ y: 0.0272, z: 0.1641 }, + name: "marker", script: MARKER_SCRIPT_URL }); From 6765973a4a98d2b4b310c52cbb4c538bcabe7af7 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 09:56:30 -0800 Subject: [PATCH 10/74] correct positioning on equip --- .../whiteboardV2/markerEntityScript.js | 3 +- .../whiteboardV2/whiteboardSpawner.js | 28 ++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 4faf64b542..47a308d564 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -39,11 +39,10 @@ direction: Quat.getFront(props.rotation) } - var intersection = Entities.findRayIntersection(pickRay, true, [], [_this.entityID]); + var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects) { var name = Entities.getEntityProperties(intersection.entityID); - print("intersection") } }, diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 68c4422364..fdecb01f21 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -65,7 +65,33 @@ var marker = Entities.addEntity({ z: 0.1641 }, name: "marker", - script: MARKER_SCRIPT_URL + script: MARKER_SCRIPT_URL, + userData: JSON.stringify({ + wearable: { + joints: { + RightHand: [{ + x: 0.001109793782234192, + y: 0.13991504907608032, + z: 0.05035984516143799 + }, { + x: -0.7360993027687073, + y: -0.04330085217952728, + z: -0.10863728821277618, + w: -0.6666942238807678 + }], + LeftHand: [{ + x: 0.007193896919488907, + y: 0.15147076547145844, + z: 0.06174466013908386 + }, { + x: -0.4174973964691162, + y: 0.631147563457489, + z: -0.3890438377857208, + w: -0.52535080909729 + }] + } + } + }) }); From 8e9cd3ae2a62f2f414183f32ccbb4e6c5d10e62b Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 10:38:13 -0800 Subject: [PATCH 11/74] passing whiteboard in to marker --- examples/homeContent/whiteboardV2/markerEntityScript.js | 8 ++++++++ examples/homeContent/whiteboardV2/whiteboardSpawner.js | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 47a308d564..d3a4f97fe9 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -43,12 +43,20 @@ if (intersection.intersects) { var name = Entities.getEntityProperties(intersection.entityID); + + this.paint() } }, preload: function(entityID) { this.entityID = entityID; print("EBL PRELOAD"); + }, + + setWhiteboard: function(myId, data) { + _this.whiteboard = JSON.parse(data[0]); + var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); + Entities.editEntity(_this.whiteboard, {position: {x: 0, y: 1, z: 0}}); } }; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index fdecb01f21..b5d1c07959 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -94,6 +94,10 @@ var marker = Entities.addEntity({ }) }); +Script.setTimeout(function() { + Entities.callEntityMethod(marker, "setWhiteboard", [JSON.stringify(whiteboard)]); +}, 1000) + function cleanup() { From ddce8d5a3a8a63a95774a9404ed8edbc014029da Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 10:59:05 -0800 Subject: [PATCH 12/74] Marker basics working, now just need to tweak --- .../whiteboardV2/markerEntityScript.js | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index d3a4f97fe9..e879b71144 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -16,6 +16,7 @@ MarkerTip = function() { _this = this; + _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/paintStroke.png"; }; MarkerTip.prototype = { @@ -42,12 +43,48 @@ var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects) { - var name = Entities.getEntityProperties(intersection.entityID); - this.paint() + this.paint(intersection.intersection) } }, + newStroke: function(position) { + _this.strokeBasePosition = position; + _this.currentStroke = Entities.addEntity({ + type: "PolyLine", + name: "marker stroke", + dimensions: { + x: 10, + y: 10, + z: 10 + }, + position: position, + textures: _this.MARKER_TEXTURE_URL, + color: {red: 0, green: 10, blue: 200} + }); + + _this.linePoints = []; + _this.normals = []; + _this.strokeWidths = []; + }, + + paint: function(position) { + if (!_this.currentStroke) { + _this.newStroke(position); + } + + var localPoint = Vec3.subtract(position, this.strokeBasePosition); + _this.linePoints.push(localPoint); + _this.normals.push(_this._whiteboardNormal); + this.strokeWidths.push(0.02); + + Entities.editEntity(_this.currentStroke, { + linePoints: _this.linePoints, + normals: _this.normals, + strokeWidths: _this.strokeWidths + }); + }, + preload: function(entityID) { this.entityID = entityID; print("EBL PRELOAD"); @@ -56,7 +93,7 @@ setWhiteboard: function(myId, data) { _this.whiteboard = JSON.parse(data[0]); var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - Entities.editEntity(_this.whiteboard, {position: {x: 0, y: 1, z: 0}}); + this._whiteboardNormal = Vec3.multiply(Quat.getFront(props.rotation), -1); } }; From b58026bf4bf83ab071b61558887090dcc9f32f75 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 11:04:17 -0800 Subject: [PATCH 13/74] max points --- .../homeContent/whiteboardV2/markerEntityScript.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index e879b71144..81e65cacb9 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -14,6 +14,8 @@ (function() { Script.include("../../libraries/utils.js"); + var MAX_POINTS_PER_STROKE = 40; + MarkerTip = function() { _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/paintStroke.png"; @@ -40,7 +42,7 @@ direction: Quat.getFront(props.rotation) } - var intersection = Entities.findRayIntersection(pickRay, true); + var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); if (intersection.intersects) { @@ -83,6 +85,10 @@ normals: _this.normals, strokeWidths: _this.strokeWidths }); + + if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { + _this.currentStroke = null; + } }, preload: function(entityID) { @@ -93,7 +99,7 @@ setWhiteboard: function(myId, data) { _this.whiteboard = JSON.parse(data[0]); var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - this._whiteboardNormal = Vec3.multiply(Quat.getFront(props.rotation), -1); + this._whiteboardNormal = Vec3.multiply(Quat.getRight(props.rotation), -1); } }; From 94bf15f3284e8a5c13fb466556474c2b3cf7c09a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 11:21:17 -0800 Subject: [PATCH 14/74] need to fix zfighting --- .../homeContent/whiteboardV2/markerEntityScript.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 81e65cacb9..73e8ce86db 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -18,7 +18,9 @@ MarkerTip = function() { _this = this; - _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/paintStroke.png"; + _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; + this.strokeForwardOffset = 0.0005; + this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; }; MarkerTip.prototype = { @@ -76,8 +78,11 @@ } var localPoint = Vec3.subtract(position, this.strokeBasePosition); + // localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); + _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; + _this.linePoints.push(localPoint); - _this.normals.push(_this._whiteboardNormal); + _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(0.02); Entities.editEntity(_this.currentStroke, { @@ -99,7 +104,7 @@ setWhiteboard: function(myId, data) { _this.whiteboard = JSON.parse(data[0]); var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - this._whiteboardNormal = Vec3.multiply(Quat.getRight(props.rotation), -1); + _this.whiteboardNormal = Vec3.multiply(Quat.getRight(props.rotation), -1); } }; From 9a8b76df476547c4b4cf51e9ee5d371a226d701a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 11:32:13 -0800 Subject: [PATCH 15/74] no more zfighting --- examples/homeContent/whiteboardV2/markerEntityScript.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 73e8ce86db..a2ab8ac285 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -21,6 +21,7 @@ _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; this.strokeForwardOffset = 0.0005; this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; + this.STROKE_WIDTH = 0.003; }; MarkerTip.prototype = { @@ -78,12 +79,12 @@ } var localPoint = Vec3.subtract(position, this.strokeBasePosition); - // localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); - _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; + localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); + // _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); - this.strokeWidths.push(0.02); + this.strokeWidths.push(_this.STROKE_WIDTH); Entities.editEntity(_this.currentStroke, { linePoints: _this.linePoints, @@ -104,7 +105,7 @@ setWhiteboard: function(myId, data) { _this.whiteboard = JSON.parse(data[0]); var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - _this.whiteboardNormal = Vec3.multiply(Quat.getRight(props.rotation), -1); + _this.whiteboardNormal = Quat.getRight(props.rotation); } }; From 0564cd8145848d0f24f85277b03f75c4bdf53976 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 12:02:34 -0800 Subject: [PATCH 16/74] returning if less than min distance --- .../whiteboardV2/markerEntityScript.js | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index a2ab8ac285..d4bd7bc272 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -21,7 +21,11 @@ _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; this.strokeForwardOffset = 0.0005; this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; - this.STROKE_WIDTH = 0.003; + this.STROKE_WIDTH = 0.003 + _this.MAX_MARKER_TO_BOARD_DISTANCE = 0.5; + _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; + _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; + _this.strokes = []; }; MarkerTip.prototype = { @@ -38,18 +42,20 @@ continueHolding: function() { // cast a ray from marker and see if it hits anything - var props = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); + var markerProps = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); + var pickRay = { - origin: props.position, - direction: Quat.getFront(props.rotation) + origin: markerProps.position, + direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - if (intersection.intersects) { - + if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { this.paint(intersection.intersection) + } else { + _this.currentStroke = null; } }, @@ -71,6 +77,8 @@ _this.linePoints = []; _this.normals = []; _this.strokeWidths = []; + + _this.strokes.push(_this.currentStroke); }, paint: function(position) { @@ -82,6 +90,15 @@ localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); // _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; + if (_this.linePoints.length > 0) { + var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length-1]); + if (distance < _this.MIN_DISTANCE_BETWEEN_POINTS) { + print("EBL not enough distance") + return; + } + } + + _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(_this.STROKE_WIDTH); @@ -99,13 +116,14 @@ preload: function(entityID) { this.entityID = entityID; + print("EBL PRELOAD"); }, setWhiteboard: function(myId, data) { _this.whiteboard = JSON.parse(data[0]); - var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - _this.whiteboardNormal = Quat.getRight(props.rotation); + var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); + _this.whiteboardNormal = Quat.getRight(whiteboardProps.rotation); } }; From 40176b04244dedaa5bcea1170c72c7f9e6102ce5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 14:06:55 -0800 Subject: [PATCH 17/74] no gaps --- .../homeContent/whiteboardV2/markerEntityScript.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index d4bd7bc272..1bd7acf1d9 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -22,7 +22,7 @@ this.strokeForwardOffset = 0.0005; this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; this.STROKE_WIDTH = 0.003 - _this.MAX_MARKER_TO_BOARD_DISTANCE = 0.5; + _this.MAX_MARKER_TO_BOARD_DISTANCE = 0.2; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; _this.strokes = []; @@ -56,6 +56,7 @@ this.paint(intersection.intersection) } else { _this.currentStroke = null; + _this.oldPosition = null; } }, @@ -82,11 +83,16 @@ }, paint: function(position) { + var basePosition = position; if (!_this.currentStroke) { - _this.newStroke(position); + if (_this.oldPosition) { + basePosition = _this.oldPosition; + print("EBL USE OLD POSITION FOR NEW STROKE!") + } + _this.newStroke(basePosition); } - var localPoint = Vec3.subtract(position, this.strokeBasePosition); + var localPoint = Vec3.subtract(basePosition, this.strokeBasePosition); localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); // _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; @@ -111,6 +117,7 @@ if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { _this.currentStroke = null; + _this.oldPosition = position; } }, From 9ae1ccee50016f4cb03590ff3f39d556f746bd01 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 14:15:55 -0800 Subject: [PATCH 18/74] passing marker color accross --- examples/homeContent/whiteboardV2/markerEntityScript.js | 8 +++++--- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 6 +++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 1bd7acf1d9..bc5304ea7f 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -72,7 +72,7 @@ }, position: position, textures: _this.MARKER_TEXTURE_URL, - color: {red: 0, green: 10, blue: 200} + color: _this.markerColor }); _this.linePoints = []; @@ -127,10 +127,12 @@ print("EBL PRELOAD"); }, - setWhiteboard: function(myId, data) { - _this.whiteboard = JSON.parse(data[0]); + setProperties: function(myId, data) { + var data = JSON.parse(data); + _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); _this.whiteboardNormal = Quat.getRight(whiteboardProps.rotation); + _this.markerColor = data.markerColor; } }; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index b5d1c07959..24b5d2a046 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -95,7 +95,11 @@ var marker = Entities.addEntity({ }); Script.setTimeout(function() { - Entities.callEntityMethod(marker, "setWhiteboard", [JSON.stringify(whiteboard)]); + var data = { + whiteboard: whiteboard, + markerColor: {red: 10, green: 10, blue: 200} + } + Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); }, 1000) From 756b7e223d96508d03ec17ef2e59dfd5646396d0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 15:56:12 -0800 Subject: [PATCH 19/74] need to figure out why only one marker working --- .../whiteboardV2/markerEntityScript.js | 3 +- .../whiteboardV2/whiteboardSpawner.js | 173 +++++++++++------- 2 files changed, 110 insertions(+), 66 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index bc5304ea7f..66ca061c05 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -99,12 +99,10 @@ if (_this.linePoints.length > 0) { var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length-1]); if (distance < _this.MIN_DISTANCE_BETWEEN_POINTS) { - print("EBL not enough distance") return; } } - _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(_this.STROKE_WIDTH); @@ -131,6 +129,7 @@ var data = JSON.parse(data); _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); + print("EBL: MARKER COLOR " + JSON.stringify(data.markerColor)); _this.whiteboardNormal = Quat.getRight(whiteboardProps.rotation); _this.markerColor = data.markerColor; } diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 24b5d2a046..33b559838b 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -13,13 +13,19 @@ var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); -orientation.x = 0; -var whiteboardRotation = Quat.fromVec3Degrees({ - x: orientation.x, +var markerRotation = Quat.fromVec3Degrees({ + x: orientation.x + 10, y: orientation.y - 90, z: orientation.z +}) +orientation.x = 0; +var whiteboardRotation = Quat.fromVec3Degrees({ + x: 0, + y: orientation.y - 90, + z: 0 }); orientation = Quat.fromVec3Degrees(orientation); +var markers = []; var whiteboardPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); @@ -40,73 +46,112 @@ var whiteboard = Entities.addEntity({ } }); -var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); -var MARKER_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-blue.fbx"; -var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); -var marker = Entities.addEntity({ - type: "Model", - modelURL: MARKER_MODEL_URL, - shapeType: "box", - dynamic: true, - gravity: { - x: 0, - y: -1, - z: 0 - }, - velocity: { - x: 0, - y: -0.1, - z: 0 - }, - position: markerPosition, - dimensions: { - x: 0.0270, - y: 0.0272, - z: 0.1641 - }, - name: "marker", - script: MARKER_SCRIPT_URL, - userData: JSON.stringify({ - wearable: { - joints: { - RightHand: [{ - x: 0.001109793782234192, - y: 0.13991504907608032, - z: 0.05035984516143799 - }, { - x: -0.7360993027687073, - y: -0.04330085217952728, - z: -0.10863728821277618, - w: -0.6666942238807678 - }], - LeftHand: [{ - x: 0.007193896919488907, - y: 0.15147076547145844, - z: 0.06174466013908386 - }, { - x: -0.4174973964691162, - y: 0.631147563457489, - z: -0.3890438377857208, - w: -0.52535080909729 - }] - } - } - }) -}); +createMarkers(); +function createMarkers() { + var modelURLS = [ + "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-blue.fbx", + "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-red.fbx", + "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-black.fbx", + ]; -Script.setTimeout(function() { - var data = { - whiteboard: whiteboard, - markerColor: {red: 10, green: 10, blue: 200} - } - Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); -}, 1000) + var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); + + createMarker(modelURLS[0], markerPosition, { + red: 10, + green: 10, + blue: 200 + }); + + markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); + createMarker(modelURLS[1], markerPosition, { + red: 200, + green: 10, + blue: 10 + }); + + markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation))); + createMarker(modelURLS[2], markerPosition, { + red: 10, + green: 10, + blue: 10 + }); +} + + +function createMarker(modelURL, markerPosition, markerColor) { + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); + var marker = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + rotation: markerRotation, + shapeType: "box", + dynamic: true, + gravity: { + x: 0, + y: -1, + z: 0 + }, + velocity: { + x: 0, + y: -0.1, + z: 0 + }, + position: markerPosition, + dimensions: { + x: 0.0270, + y: 0.0272, + z: 0.1641 + }, + name: "marker", + script: MARKER_SCRIPT_URL, + userData: JSON.stringify({ + wearable: { + joints: { + RightHand: [{ + x: 0.001109793782234192, + y: 0.13991504907608032, + z: 0.05035984516143799 + }, { + x: -0.7360993027687073, + y: -0.04330085217952728, + z: -0.10863728821277618, + w: -0.6666942238807678 + }], + LeftHand: [{ + x: 0.007193896919488907, + y: 0.15147076547145844, + z: 0.06174466013908386 + }, { + x: -0.4174973964691162, + y: 0.631147563457489, + z: -0.3890438377857208, + w: -0.52535080909729 + }] + } + } + }) + }); + + markers.push(marker); + + Script.setTimeout(function() { + var data = { + whiteboard: whiteboard, + markerColor: markerColor + } + Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); + }, 1000) + + +} function cleanup() { Entities.deleteEntity(whiteboard); - Entities.deleteEntity(marker); + markers.forEach(function(marker){ + Entities.deleteEntity(marker); + }); } Script.scriptEnding.connect(cleanup); \ No newline at end of file From 68e289b433db8836cda12d857a36de047a30bbe1 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 17:32:33 -0800 Subject: [PATCH 20/74] Fixed bug where spawning one marker would destroy the other --- .../whiteboardV2/markerEntityScript.js | 15 ++++++--- .../whiteboardV2/whiteboardSpawner.js | 33 ++++++++++++------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 66ca061c05..d905db07dd 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -15,7 +15,7 @@ Script.include("../../libraries/utils.js"); var MAX_POINTS_PER_STROKE = 40; - +var _this; MarkerTip = function() { _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; @@ -49,12 +49,17 @@ origin: markerProps.position, direction: Quat.getFront(markerProps.rotation) } - + print('MARKER ID'+_this.entityID) + print('MARKER POSITION'+JSON.stringify(markerProps.position)) var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - + print('WHITEBOARD AT CONTINUE:: '+_this.whiteboard); + print('DOES INTERSECT??'+intersection.intersects) + print('MARKER DISTANCE::'+Vec3.distance(intersection.intersection, markerProps.position)) + print('MAX DISTANCE::'+_this.MAX_MARKER_TO_BOARD_DISTANCE) if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { this.paint(intersection.intersection) } else { + print('not painting because intersection') _this.currentStroke = null; _this.oldPosition = null; } @@ -103,6 +108,7 @@ } } + print("PAINT " + JSON.stringify(_this.markerColor)); _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(_this.STROKE_WIDTH); @@ -127,9 +133,10 @@ setProperties: function(myId, data) { var data = JSON.parse(data); + print("EBL SET PROPERTIES! ON " + JSON.stringify(data.markerColor)+ "id:"+ JSON.stringify(myId)); + _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - print("EBL: MARKER COLOR " + JSON.stringify(data.markerColor)); _this.whiteboardNormal = Quat.getRight(whiteboardProps.rotation); _this.markerColor = data.markerColor; } diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 33b559838b..c3dcd3e6d7 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -10,6 +10,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +Script.include("../../libraries/utils.js") var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); @@ -62,19 +63,23 @@ function createMarkers() { blue: 200 }); - markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); - createMarker(modelURLS[1], markerPosition, { - red: 200, - green: 10, - blue: 10 - }); - markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation))); - createMarker(modelURLS[2], markerPosition, { - red: 10, - green: 10, - blue: 10 - }); + Script.setTimeout(function() { + + markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); + createMarker(modelURLS[1], markerPosition, { + red: 200, + green: 10, + blue: 10 + }); + }, 1000); + + // markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation))); + // createMarker(modelURLS[2], markerPosition, { + // red: 10, + // green: 10, + // blue: 10 + // }); } @@ -139,6 +144,10 @@ function createMarker(modelURL, markerPosition, markerColor) { whiteboard: whiteboard, markerColor: markerColor } + var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; + print("EBL MARKER URL " + JSON.stringify(modelURL)) + print("EBL MARKER COLOR " + JSON.stringify(markerColor)) + Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); }, 1000) From 6fe9730897c4c62a79595d82f6fac09e3d097136 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 17:33:54 -0800 Subject: [PATCH 21/74] all three markers --- .../whiteboardV2/whiteboardSpawner.js | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index c3dcd3e6d7..a566e69f52 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -15,7 +15,7 @@ Script.include("../../libraries/utils.js") var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); var markerRotation = Quat.fromVec3Degrees({ - x: orientation.x + 10, + x: orientation.x + 10, y: orientation.y - 90, z: orientation.z }) @@ -48,6 +48,7 @@ var whiteboard = Entities.addEntity({ }); createMarkers(); + function createMarkers() { var modelURLS = [ "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-blue.fbx", @@ -64,22 +65,20 @@ function createMarkers() { }); - Script.setTimeout(function() { - markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); - createMarker(modelURLS[1], markerPosition, { - red: 200, - green: 10, - blue: 10 - }); - }, 1000); + markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); + createMarker(modelURLS[1], markerPosition, { + red: 200, + green: 10, + blue: 10 + }); - // markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation))); - // createMarker(modelURLS[2], markerPosition, { - // red: 10, - // green: 10, - // blue: 10 - // }); + markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation))); + createMarker(modelURLS[2], markerPosition, { + red: 10, + green: 10, + blue: 10 + }); } @@ -147,7 +146,7 @@ function createMarker(modelURL, markerPosition, markerColor) { var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; print("EBL MARKER URL " + JSON.stringify(modelURL)) print("EBL MARKER COLOR " + JSON.stringify(markerColor)) - + Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); }, 1000) @@ -158,7 +157,7 @@ function createMarker(modelURL, markerPosition, markerColor) { function cleanup() { Entities.deleteEntity(whiteboard); - markers.forEach(function(marker){ + markers.forEach(function(marker) { Entities.deleteEntity(marker); }); } From ec369959088612210df8761b53d8f963ff04e0cf Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 17:36:02 -0800 Subject: [PATCH 22/74] moar whiteboard logging removal --- .../homeContent/whiteboardV2/markerEntityScript.js | 11 ----------- .../homeContent/whiteboardV2/whiteboardSpawner.js | 2 -- 2 files changed, 13 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index d905db07dd..74b7746514 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -49,17 +49,10 @@ var _this; origin: markerProps.position, direction: Quat.getFront(markerProps.rotation) } - print('MARKER ID'+_this.entityID) - print('MARKER POSITION'+JSON.stringify(markerProps.position)) var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - print('WHITEBOARD AT CONTINUE:: '+_this.whiteboard); - print('DOES INTERSECT??'+intersection.intersects) - print('MARKER DISTANCE::'+Vec3.distance(intersection.intersection, markerProps.position)) - print('MAX DISTANCE::'+_this.MAX_MARKER_TO_BOARD_DISTANCE) if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { this.paint(intersection.intersection) } else { - print('not painting because intersection') _this.currentStroke = null; _this.oldPosition = null; } @@ -92,7 +85,6 @@ var _this; if (!_this.currentStroke) { if (_this.oldPosition) { basePosition = _this.oldPosition; - print("EBL USE OLD POSITION FOR NEW STROKE!") } _this.newStroke(basePosition); } @@ -108,7 +100,6 @@ var _this; } } - print("PAINT " + JSON.stringify(_this.markerColor)); _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(_this.STROKE_WIDTH); @@ -128,12 +119,10 @@ var _this; preload: function(entityID) { this.entityID = entityID; - print("EBL PRELOAD"); }, setProperties: function(myId, data) { var data = JSON.parse(data); - print("EBL SET PROPERTIES! ON " + JSON.stringify(data.markerColor)+ "id:"+ JSON.stringify(myId)); _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index a566e69f52..26d373266b 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -144,8 +144,6 @@ function createMarker(modelURL, markerPosition, markerColor) { markerColor: markerColor } var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; - print("EBL MARKER URL " + JSON.stringify(modelURL)) - print("EBL MARKER COLOR " + JSON.stringify(markerColor)) Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); }, 1000) From 69dc9ef68f8a6da5751a76b7809d5078a9c6df08 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 09:06:35 -0800 Subject: [PATCH 23/74] added lifetime --- examples/homeContent/whiteboardV2/markerEntityScript.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 74b7746514..155077af9c 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -70,7 +70,8 @@ var _this; }, position: position, textures: _this.MARKER_TEXTURE_URL, - color: _this.markerColor + color: _this.markerColor, + lifetime: 1000 }); _this.linePoints = []; From b5ec79fd6db48c5317759a7f355173e1873349ea Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 09:53:20 -0800 Subject: [PATCH 24/74] marker only draws when equipped and held down --- .../whiteboardV2/markerEntityScript.js | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 155077af9c..d19e09bb34 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -13,9 +13,12 @@ (function() { Script.include("../../libraries/utils.js"); - + var TRIGGER_CONTROLS = [ + Controller.Standard.LT, + Controller.Standard.RT, + ]; var MAX_POINTS_PER_STROKE = 40; -var _this; + var _this; MarkerTip = function() { _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; @@ -30,21 +33,25 @@ var _this; MarkerTip.prototype = { - continueNearGrab: function() { - - _this.continueHolding(); + startEquip: function(id, params) { + _this.equipped = true; + _this.hand = params[0] == "left" ? 0 : 1; }, - continueEquip: function() { - _this.continueHolding(); + this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); + if (_this.triggerValue > 0.2) { + print("EBL PAINZT"); + _this.continueHolding(); + } else { + _this.currentStroke = null; + } }, + continueHolding: function() { // cast a ray from marker and see if it hits anything - var markerProps = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); - var pickRay = { origin: markerProps.position, direction: Quat.getFront(markerProps.rotation) @@ -87,7 +94,7 @@ var _this; if (_this.oldPosition) { basePosition = _this.oldPosition; } - _this.newStroke(basePosition); + _this.newStroke(basePosition); } var localPoint = Vec3.subtract(basePosition, this.strokeBasePosition); @@ -95,7 +102,7 @@ var _this; // _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; if (_this.linePoints.length > 0) { - var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length-1]); + var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length - 1]); if (distance < _this.MIN_DISTANCE_BETWEEN_POINTS) { return; } @@ -119,7 +126,7 @@ var _this; preload: function(entityID) { this.entityID = entityID; - + }, setProperties: function(myId, data) { From 81ed89531da0ce3eb52372c017f2406e7e8c0f50 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 10:11:13 -0800 Subject: [PATCH 25/74] whiteboard surface parented to whiteboard --- .../whiteboardV2/markerEntityScript.js | 23 ++++++++++++------- .../whiteboardV2/whiteboardSpawner.js | 15 +++++++++++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index d19e09bb34..ae8e19c759 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -29,6 +29,7 @@ _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; _this.strokes = []; + _this.PAINTING_TRIGGER_THRESHOLD = 0.2; }; MarkerTip.prototype = { @@ -39,14 +40,17 @@ }, continueEquip: function() { this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); - if (_this.triggerValue > 0.2) { - print("EBL PAINZT"); + if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { _this.continueHolding(); } else { - _this.currentStroke = null; + _this.resetStroke(); } }, + releaseEquip: function() { + _this.resetStroke(); + }, + continueHolding: function() { // cast a ray from marker and see if it hits anything @@ -60,8 +64,7 @@ if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { this.paint(intersection.intersection) } else { - _this.currentStroke = null; - _this.oldPosition = null; + _this.resetStroke(); } }, @@ -119,11 +122,15 @@ }); if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { - _this.currentStroke = null; - _this.oldPosition = position; + _this.resetStroke(); } }, + resetStroke: function() { + _this.currentStroke = null; + _this.oldPosition = position; + }, + preload: function(entityID) { this.entityID = entityID; @@ -134,7 +141,7 @@ _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - _this.whiteboardNormal = Quat.getRight(whiteboardProps.rotation); + _this.whiteboardNormal = Quat.getFront(whiteboardProps.rotation); _this.markerColor = data.markerColor; } }; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 26d373266b..90476a3b3d 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -47,6 +47,18 @@ var whiteboard = Entities.addEntity({ } }); +var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, {x: 0.0, y: 0.45, z: 0.0}) +var whiteboardDrawingSurface = Entities.addEntity({ + type: "Box", + name: "whiteboardDrawingSurface", + dimensions: {x: 1.85, y: 1.8, z: 0.03}, + color: {red: 200, green: 10, blue: 200}, + position: whiteboardSurfacePosition, + rotation: orientation, + visible: false, + parentID: whiteboard +}); + createMarkers(); function createMarkers() { @@ -140,7 +152,7 @@ function createMarker(modelURL, markerPosition, markerColor) { Script.setTimeout(function() { var data = { - whiteboard: whiteboard, + whiteboard: whiteboardDrawingSurface, markerColor: markerColor } var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; @@ -155,6 +167,7 @@ function createMarker(modelURL, markerPosition, markerColor) { function cleanup() { Entities.deleteEntity(whiteboard); + Entities.deleteEntity(whiteboardDrawingSurface); markers.forEach(function(marker) { Entities.deleteEntity(marker); }); From 6682b9bd580892e492a598246cb3701f4e8436ea Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 10:36:17 -0800 Subject: [PATCH 26/74] eraser is spawing --- .../whiteboardV2/whiteboardSpawner.js | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 90476a3b3d..b408fcc126 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -47,18 +47,61 @@ var whiteboard = Entities.addEntity({ } }); -var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, {x: 0.0, y: 0.45, z: 0.0}) +var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { + x: 0.0, + y: 0.45, + z: 0.0 +}) var whiteboardDrawingSurface = Entities.addEntity({ type: "Box", name: "whiteboardDrawingSurface", - dimensions: {x: 1.85, y: 1.8, z: 0.03}, - color: {red: 200, green: 10, blue: 200}, + dimensions: { + x: 1.85, + y: 1.8, + z: 0.03 + }, + color: { + red: 200, + green: 10, + blue: 200 + }, position: whiteboardSurfacePosition, rotation: orientation, visible: false, parentID: whiteboard }); + +var WHITEBOARD_RACK_DEPTH = 1.9; + +var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser.fbx"; +var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); +eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getFront(whiteboardRotation))); + +var eraser = Entities.addEntity({ + type: "Model", + modelURL: ERASER_MODEL_URL, + position: eraserPosition, + shapeType: "box", + dimensions: { + x: 0.0858, + y: 0.0393, + z: 0.2083 + }, + rotation: whiteboardRotation, + dynamic: true, + gravity: { + x: 0, + y: -1, + z: 0 + }, + velocity: { + x: 0, + y: -0.1, + z: 0 + } +}); + createMarkers(); function createMarkers() { @@ -68,7 +111,7 @@ function createMarkers() { "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-black.fbx", ]; - var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); + var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); createMarker(modelURLS[0], markerPosition, { red: 10, @@ -168,6 +211,7 @@ function createMarker(modelURL, markerPosition, markerColor) { function cleanup() { Entities.deleteEntity(whiteboard); Entities.deleteEntity(whiteboardDrawingSurface); + Entities.deleteEntity(eraser); markers.forEach(function(marker) { Entities.deleteEntity(marker); }); From 20fd79fc43f1370c8e65050d1de953d4f1679294 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 11:25:46 -0800 Subject: [PATCH 27/74] Lines markers --- examples/homeContent/whiteboardV2/markerEntityScript.js | 7 ++++--- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index ae8e19c759..3b734cc2ad 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -25,7 +25,7 @@ this.strokeForwardOffset = 0.0005; this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; this.STROKE_WIDTH = 0.003 - _this.MAX_MARKER_TO_BOARD_DISTANCE = 0.2; + _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; _this.strokes = []; @@ -122,13 +122,14 @@ }); if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { - _this.resetStroke(); + _this.currentStroke = null; + _this.oldPosition = position; } }, resetStroke: function() { _this.currentStroke = null; - _this.oldPosition = position; + _this.oldPosition = null; }, preload: function(entityID) { diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index b408fcc126..e714070bff 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -44,7 +44,8 @@ var whiteboard = Entities.addEntity({ x: 0.4636, y: 2.7034, z: 1.8653 - } + }, + // visible: false }); var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { @@ -58,7 +59,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ dimensions: { x: 1.85, y: 1.8, - z: 0.03 + z: 0.04 }, color: { red: 200, @@ -68,7 +69,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ position: whiteboardSurfacePosition, rotation: orientation, visible: false, - parentID: whiteboard + // parentID: whiteboard }); From 8d058c2bb380a170062060b661263d2a05483997 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 11:53:27 -0800 Subject: [PATCH 28/74] eraser working --- .../whiteboardV2/eraserEntityScript.js | 80 +++++++++++++++++++ .../whiteboardV2/markerEntityScript.js | 3 +- .../whiteboardV2/whiteboardSpawner.js | 2 + 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 examples/homeContent/whiteboardV2/eraserEntityScript.js diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js new file mode 100644 index 0000000000..5662fdafc5 --- /dev/null +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -0,0 +1,80 @@ +// +// eraserEntityScript.js +// examples/homeContent/eraserEntityScript +// +// Created by Eric Levin on 2/17/15. +// Copyright 2016 High Fidelity, Inc. +// +// This entity script provides logic for an object with attached script to erase nearby marker strokes +// 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("../../libraries/utils.js"); + var TRIGGER_CONTROLS = [ + Controller.Standard.LT, + Controller.Standard.RT, + ]; + var _this; + Eraser = function() { + _this = this; + + _this.ERASER_TRIGGER_THRESHOLD = 0.1; + _this.STROKE_NAME = "hifi-marker-stroke"; + _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.2; + }; + + Eraser.prototype = { + + startEquip: function(id, params) { + _this.equipped = true; + _this.hand = params[0] == "left" ? 0 : 1; + // We really only need to grab position of marker strokes once, and then just check to see if eraser comes near enough to those strokes + var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; + var strokeIDs = Entities.findEntities(eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS); + // Create a map of stroke entities and their positions + _this.strokeMap = []; + strokeIDs.forEach(function(strokeID) { + var strokeProps = Entities.getEntityProperties(strokeID, ["position", "name"]); + if (strokeProps.name === _this.STROKE_NAME) { + _this.strokeMap.push({ + strokeID: strokeID, + strokePosition: strokeProps.position + }); + } + }); + }, + continueEquip: function() { + this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); + if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) { + _this.continueHolding(); + } else {} + }, + + releaseEquip: function() {}, + + + continueHolding: function() { + // search for marker strokes within certain radius of eraser + var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; + _this.strokeMap.forEach(function(strokeData, index) { + if (Vec3.distance(eraserPosition, strokeData.strokePosition) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) { + Entities.deleteEntity(strokeData.strokeID); + _this.strokeMap.splice(index, 1); + } + }) + + }, + + + preload: function(entityID) { + this.entityID = entityID; + + }, + }; + + // entity scripts always need to return a newly constructed object of our type + return new Eraser(); +}); \ No newline at end of file diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 3b734cc2ad..da37983d74 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -30,6 +30,7 @@ _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; _this.strokes = []; _this.PAINTING_TRIGGER_THRESHOLD = 0.2; + this.STROKE_NAME = "hifi-marker-stroke"; }; MarkerTip.prototype = { @@ -72,7 +73,7 @@ _this.strokeBasePosition = position; _this.currentStroke = Entities.addEntity({ type: "PolyLine", - name: "marker stroke", + name: _this.STROKE_NAME, dimensions: { x: 10, y: 10, diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index e714070bff..e1ccc16c89 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -76,6 +76,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ var WHITEBOARD_RACK_DEPTH = 1.9; var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser.fbx"; +var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js?v1" + Math.random()); var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getFront(whiteboardRotation))); @@ -83,6 +84,7 @@ var eraser = Entities.addEntity({ type: "Model", modelURL: ERASER_MODEL_URL, position: eraserPosition, + script: ERASER_SCRIPT_URL, shapeType: "box", dimensions: { x: 0.0858, From a2ece772ef3491a580732518b316669464f898b0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 12:08:51 -0800 Subject: [PATCH 29/74] refactor for laser pointer --- .../whiteboardV2/markerEntityScript.js | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index da37983d74..685accfb13 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -40,12 +40,8 @@ _this.hand = params[0] == "left" ? 0 : 1; }, continueEquip: function() { - this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); - if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { - _this.continueHolding(); - } else { - _this.resetStroke(); - } + _this.continueHolding(); + }, releaseEquip: function() { @@ -62,13 +58,22 @@ direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - this.paint(intersection.intersection) + + if (intersection.intersects) { + _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); + if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { + _this.paint(intersection.intersection) + } else { + _this.resetStroke(); + } } else { - _this.resetStroke(); + _this.resetStroke(); } + }, + + newStroke: function(position) { _this.strokeBasePosition = position; _this.currentStroke = Entities.addEntity({ @@ -103,7 +108,7 @@ var localPoint = Vec3.subtract(basePosition, this.strokeBasePosition); localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); - // _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; + _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; if (_this.linePoints.length > 0) { var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length - 1]); @@ -138,12 +143,25 @@ }, + unload: function() { + Overlays.deleteOverlay(_this.laserPointer); + }, + setProperties: function(myId, data) { var data = JSON.parse(data); _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); _this.whiteboardNormal = Quat.getFront(whiteboardProps.rotation); + _this.laserPointer = Overlays.addOverlay("circle3d", { + color: { + red: 200, + green: 10, + blue: 10 + }, + solid: true, + rotation: whiteboardProps.rotation + }); _this.markerColor = data.markerColor; } }; From 5e0de4bdee04b648e8bdc84580fa57ffd9c3d5c3 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 12:16:22 -0800 Subject: [PATCH 30/74] tweaks --- .../whiteboardV2/eraserEntityScript.js | 3 +-- .../whiteboardV2/markerEntityScript.js | 16 ++++++++++------ .../whiteboardV2/whiteboardSpawner.js | 10 +++++----- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index 5662fdafc5..89ce4aded6 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -23,7 +23,7 @@ _this.ERASER_TRIGGER_THRESHOLD = 0.1; _this.STROKE_NAME = "hifi-marker-stroke"; - _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.2; + _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.4; }; Eraser.prototype = { @@ -68,7 +68,6 @@ }, - preload: function(entityID) { this.entityID = entityID; diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 685accfb13..4bf90b6562 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -5,6 +5,7 @@ // Created by Eric Levin on 2/17/15. // Copyright 2016 High Fidelity, Inc. // +// This script provides the logic for an object to draw marker strokes on its associated whiteboard // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -39,17 +40,13 @@ _this.equipped = true; _this.hand = params[0] == "left" ? 0 : 1; }, - continueEquip: function() { - _this.continueHolding(); - - }, releaseEquip: function() { _this.resetStroke(); }, - continueHolding: function() { + continueEquip: function() { // cast a ray from marker and see if it hits anything var markerProps = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); @@ -58,8 +55,11 @@ direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - if (intersection.intersects) { + Overlays.editOverlay(_this.laserPointer, { + visible: true, + position: intersection.intersection + }) _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { _this.paint(intersection.intersection) @@ -68,6 +68,9 @@ } } else { _this.resetStroke(); + Overlays.editOverlay(_this.laserPointer, { + visible: true + }) } }, @@ -160,6 +163,7 @@ blue: 10 }, solid: true, + size: 0.01, rotation: whiteboardProps.rotation }); _this.markerColor = data.markerColor; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index e1ccc16c89..05aaff3565 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -5,7 +5,8 @@ // Created by Eric Levina on 2/17/16 // Copyright 2016 High Fidelity, Inc. // -// Run this script to spawn a whiteboard and associated acoutrements that one can paint on usignmarkers +// Run this script to spawn a whiteboard, markers, and an eraser. +// To draw on the whiteboard, equip a marker and hold down trigger with marker tip pointed at whiteboard // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -45,7 +46,6 @@ var whiteboard = Entities.addEntity({ y: 2.7034, z: 1.8653 }, - // visible: false }); var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { @@ -69,14 +69,14 @@ var whiteboardDrawingSurface = Entities.addEntity({ position: whiteboardSurfacePosition, rotation: orientation, visible: false, - // parentID: whiteboard + parentID: whiteboard }); var WHITEBOARD_RACK_DEPTH = 1.9; var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser.fbx"; -var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js?v1" + Math.random()); +var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js"); var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getFront(whiteboardRotation))); @@ -141,7 +141,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, From d1d4a9d6b1f6dacbfe9fdf9789e93fcbf00d66b0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 14:48:45 -0800 Subject: [PATCH 31/74] adjusted surface position --- .../whiteboardV2/markerEntityScript.js | 17 +++++++++-------- .../whiteboardV2/whiteboardSpawner.js | 11 ++++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 4bf90b6562..618a190587 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -23,7 +23,7 @@ MarkerTip = function() { _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; - this.strokeForwardOffset = 0.0005; + this.strokeForwardOffset = 0.0001; this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; this.STROKE_WIDTH = 0.003 _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; @@ -43,6 +43,9 @@ releaseEquip: function() { _this.resetStroke(); + Overlays.editOverlay(_this.laserPointer, { + visible: false + }); }, @@ -69,14 +72,12 @@ } else { _this.resetStroke(); Overlays.editOverlay(_this.laserPointer, { - visible: true - }) + visible: false + }); } }, - - newStroke: function(position) { _this.strokeBasePosition = position; _this.currentStroke = Entities.addEntity({ @@ -158,9 +159,9 @@ _this.whiteboardNormal = Quat.getFront(whiteboardProps.rotation); _this.laserPointer = Overlays.addOverlay("circle3d", { color: { - red: 200, - green: 10, - blue: 10 + red: 220, + green: 35, + blue: 53 }, solid: true, size: 0.01, diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 05aaff3565..378bd9ff5c 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -13,7 +13,7 @@ Script.include("../../libraries/utils.js") -var orientation = Camera.getOrientation(); +var orientation = MyAvatar.orientation; orientation = Quat.safeEulerAngles(orientation); var markerRotation = Quat.fromVec3Degrees({ x: orientation.x + 10, @@ -52,12 +52,13 @@ var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { x: 0.0, y: 0.45, z: 0.0 -}) +}); +whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(orientation))); var whiteboardDrawingSurface = Entities.addEntity({ type: "Box", name: "whiteboardDrawingSurface", dimensions: { - x: 1.85, + x: 1.82, y: 1.8, z: 0.04 }, @@ -75,7 +76,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ var WHITEBOARD_RACK_DEPTH = 1.9; -var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser.fbx"; +var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser-2.fbx"; var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js"); var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getFront(whiteboardRotation))); @@ -102,7 +103,7 @@ var eraser = Entities.addEntity({ x: 0, y: -0.1, z: 0 - } + }, }); createMarkers(); From 0b569a0fabf2e67120233c00ae08257cd6f9c421 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 16:49:03 -0800 Subject: [PATCH 32/74] only show overlay if within painting range --- .../homeContent/whiteboardV2/markerEntityScript.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 618a190587..3461e31076 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -58,13 +58,14 @@ direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - if (intersection.intersects) { + + if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection }) _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); - if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { + if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { _this.paint(intersection.intersection) } else { _this.resetStroke(); @@ -91,7 +92,7 @@ position: position, textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, - lifetime: 1000 + lifetime: 200 }); _this.linePoints = []; @@ -149,6 +150,9 @@ unload: function() { Overlays.deleteOverlay(_this.laserPointer); + _this.strokes.forEach( function(stroke) { + Entities.deleteEntity(stroke); + }); }, setProperties: function(myId, data) { From 045d542f11d2ffe7766090814bc985e28fd5ebbf Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 18:03:38 -0800 Subject: [PATCH 33/74] lines no longer disapear after drawing for a while --- examples/homeContent/whiteboardV2/markerEntityScript.js | 7 +++---- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 3461e31076..8f22910d4f 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -92,7 +92,7 @@ position: position, textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, - lifetime: 200 + lifetime: 10 }); _this.linePoints = []; @@ -111,9 +111,9 @@ _this.newStroke(basePosition); } - var localPoint = Vec3.subtract(basePosition, this.strokeBasePosition); + var localPoint = Vec3.subtract(basePosition, _this.strokeBasePosition); localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); - _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; + _this.strokeForwardOffset -= _this.STROKE_FORWARD_OFFSET_INCRERMENT; if (_this.linePoints.length > 0) { var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length - 1]); @@ -121,7 +121,6 @@ return; } } - _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(_this.STROKE_WIDTH); diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 378bd9ff5c..6d5c74e273 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -142,12 +142,13 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, rotation: markerRotation, shapeType: "box", + name: "marker", dynamic: true, gravity: { x: 0, From 0ff820199420d4c3510dbe5b43523c6e07a53bf0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 18:45:41 -0800 Subject: [PATCH 34/74] fixed line gaps --- .../acAudioSearching/howardAcAudio.js | 248 ++++++++++++++++++ .../acAudioSearching/howardSpawner.js | 248 ++++++++++++++++++ .../whiteboardV2/markerEntityScript.js | 7 +- 3 files changed, 500 insertions(+), 3 deletions(-) create mode 100644 examples/audioExamples/acAudioSearching/howardAcAudio.js create mode 100644 examples/audioExamples/acAudioSearching/howardSpawner.js diff --git a/examples/audioExamples/acAudioSearching/howardAcAudio.js b/examples/audioExamples/acAudioSearching/howardAcAudio.js new file mode 100644 index 0000000000..f5b1302e06 --- /dev/null +++ b/examples/audioExamples/acAudioSearching/howardAcAudio.js @@ -0,0 +1,248 @@ +"use strict"; +/*jslint nomen: true, plusplus: true, vars: true*/ +/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/ +// +// ACAudioSearchAndInject.js +// audio +// +// Created by Eric Levin and Howard Stearns 2/1/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData. +// Inject as many as practical into the audio mixer. +// See acAudioSearchAndCompatibilityEntitySpawner.js. +// +// This implementation takes some precautions to scale well: +// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars. +// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only +// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities). +// This implementation tries to use all the available injectors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key. +var old_sound_data_key = "soundKey"; // For backwards compatibility. +var QUERY_RADIUS = 50; // meters +var UPDATE_TIME = 100; // ms. We'll update just one thing on this period. +var EXPIRATION_TIME = 5 * 1000; // ms. Remove sounds that have been out of range for this time. +var RECHECK_TIME = 10 * 1000; // ms. Check for new userData properties this often when not currently playing. +// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.) +var UPDATES_PER_STATS_LOG = 50; + +var DEFAULT_SOUND_DATA = { + volume: 0.5, // userData cannot specify zero volume with our current method of defaulting. + loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value. + playbackGap: 1000, // in ms + playbackGapRange: 0 // in ms +}; + +Script.include("../../libraries/utils.js"); +Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. + +function ignore() {} + +function debug() { // Display the arguments not just [Object object]. + //print.apply(null, [].map.call(arguments, JSON.stringify)); +} + +EntityViewer.setKeyholeRadius(QUERY_RADIUS); + +// ENTITY DATA CACHE +// +var entityCache = {}; // A dictionary of unexpired EntityData objects. + +function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. + // This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer. + var that = this; + that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data + // State Transitions: + // no data => no data | sound data | expired + // expired => stop => remove + // sound data => downloading + // downloading => downloading | waiting + // waiting => playing | waiting (if too many already playing) + // playing => update position etc | no data + that.stop = function stop() { + if (!that.sound) { + return; + } + print("stopping sound", entityIdentifier, that.url); + delete that.sound; + delete that.url; + if (!that.injector) { + return; + } + that.injector.stop(); + delete that.injector; + }; + this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) { + if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE + that.stop(); // Alternatively, we could fade out and then stop... + delete entityCache[entityIdentifier]; + return; + } + var properties, soundData; // Latest data, pulled from local octree. + // getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results. + // Most entity updates are fast and only a very few do getEntityProperties. + + function ensureSoundData() { // We only getEntityProperities when we need to. + if (properties) { + return; + } + properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']); + debug("updating", that, properties); + try { + var userData = properties.userData && JSON.parse(properties.userData); + soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare. + that.lastUserDataUpdate = now; // But do update these ... + that.url = soundData && soundData.url; + that.playAfter = that.url && now; + } catch (err) { + print(err, properties.userData); + } + } + // Stumbling on big new pile of entities will do a lot of getEntityProperties. Once. + if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA + ensureSoundData(); + } + if (!that.url) { // NO DATA => NO DATA + return that.stop(); + } + if (!that.sound) { // SOUND DATA => DOWNLOADING + that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can. + } + if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING + return; + } + if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING + return; + } + ensureSoundData(); // We'll play and will need position, so we might as well get soundData, too. + if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around) + return that.stop(); + } + var options = { + position: properties.position, + loop: soundData.loop || DEFAULT_SOUND_DATA.loop, + volume: soundData.volume || DEFAULT_SOUND_DATA.volume + }; + if (!that.injector) { // WAITING => PLAYING | WAITING + debug("starting", that, options); + that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later. + if (that.injector) { + print("started", entityIdentifier, that.url); + } else { // Don't hammer ensureSoundData or injector manager. + that.playAfter = now + (soundData.playbackGap || RECHECK_TIME); + } + return; + } + that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC + if (!that.injector.isPlaying) { // Subtle: a looping sound will not check playbackGap. + var gap = soundData.playbackGap || DEFAULT_SOUND_DATA; + if (gap) { // WAITING => PLAYING + gap = gap + randFloat(-Math.max(gap, soundData.playbackGapRange), soundData.playbackGapRange); // gapRange is bad name. Meant as +/- value. + // Setup next play just once, now. Changes won't be looked at while we wait. + that.playAfter = now + (that.sound.duration * 1000) + gap; + // Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter. + that.injector.restart(); + } else { // PLAYING => NO DATA + that.playAfter = Infinity; + } + } + }; +} + +function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) { + ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play. + var entitySound = entityCache[entityIdentifier]; + if (!entitySound) { + entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier); + } + entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine. +} +var nUpdates = UPDATES_PER_STATS_LOG, + lastStats = Date.now(); + +function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds. + var now = Date.now(), + expirationCutoff = now - EXPIRATION_TIME, + userDataRecheckCutoff = now - RECHECK_TIME; + Object.keys(entityCache).forEach(function(entityIdentifier) { + entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now); + }); + if (nUpdates-- <= 0) { // Report statistics. + // My figures using acAudioSearchCompatibleEntitySpawner.js with ONE user, N_SOUNDS = 2000, N_SILENT_ENTITIES_PER_SOUND = 5: + // audio-mixer: 23% of cpu (on Mac Activity Monitor) + // this script's assignment client: 106% of cpu. (overloaded) + // entities:12003 + // sounds:2000 + // playing:40 (correct) + // millisecondsPerUpdate:135 (100 requested, so behind by 35%. It would be nice to dig into why...) + var stats = { + entities: 0, + sounds: 0, + playing: 0, + millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG + }; + nUpdates = UPDATES_PER_STATS_LOG; + lastStats = now; + Object.keys(entityCache).forEach(function(entityIdentifier) { + var datum = entityCache[entityIdentifier]; + stats.entities++; + if (datum.url) { + stats.sounds++; + if (datum.injector && datum.injector.isPlaying) { + stats.playing++; + } + } + }); + print(JSON.stringify(stats)); + } +} + +// Update the set of which EntityData we know about. +// + +function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work. + // This does at most: + // one queryOctree request of the entity server, and + // one findEntities geometry query of our own octree, and + // a quick internEntityDatum of each of what may be a large number of entityIdentifiers. + // The idea is that this is a nice bounded piece of work that should not be done too frequently. + // However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip. + var avatar = AvatarList.getAvatar(avatarIdentifier), + avatarPosition = avatar && avatar.position; + if (!avatarPosition) { // No longer here. + return; + } + var timestamp = Date.now(); + EntityViewer.setPosition(avatarPosition); + EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results. + var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS); + debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition); + entities.forEach(function(entityIdentifier) { + internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar); + }); +} + +// Slowly update the set of data we have to work with. +// +var workQueue = []; + +function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates + workQueue = AvatarList.getAvatarIdentifiers().map(function(avatarIdentifier) { + return function() { + updateEntiesForAvatar(avatarIdentifier); + }; + }); +} +Script.setInterval(function() { + // There might be thousands of EntityData known to us, but only a few will require any work to update. + updateAllEntityData(); // i.e., this better be pretty fast. + // Each interval, we do no more than one updateEntitiesforAvatar. + if (!workQueue.length) { + workQueue = [updateWorkQueueForAvatarsPresent]; + } + workQueue.pop()(); // There's always one +}, UPDATE_TIME); \ No newline at end of file diff --git a/examples/audioExamples/acAudioSearching/howardSpawner.js b/examples/audioExamples/acAudioSearching/howardSpawner.js new file mode 100644 index 0000000000..f5b1302e06 --- /dev/null +++ b/examples/audioExamples/acAudioSearching/howardSpawner.js @@ -0,0 +1,248 @@ +"use strict"; +/*jslint nomen: true, plusplus: true, vars: true*/ +/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/ +// +// ACAudioSearchAndInject.js +// audio +// +// Created by Eric Levin and Howard Stearns 2/1/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData. +// Inject as many as practical into the audio mixer. +// See acAudioSearchAndCompatibilityEntitySpawner.js. +// +// This implementation takes some precautions to scale well: +// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars. +// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only +// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities). +// This implementation tries to use all the available injectors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key. +var old_sound_data_key = "soundKey"; // For backwards compatibility. +var QUERY_RADIUS = 50; // meters +var UPDATE_TIME = 100; // ms. We'll update just one thing on this period. +var EXPIRATION_TIME = 5 * 1000; // ms. Remove sounds that have been out of range for this time. +var RECHECK_TIME = 10 * 1000; // ms. Check for new userData properties this often when not currently playing. +// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.) +var UPDATES_PER_STATS_LOG = 50; + +var DEFAULT_SOUND_DATA = { + volume: 0.5, // userData cannot specify zero volume with our current method of defaulting. + loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value. + playbackGap: 1000, // in ms + playbackGapRange: 0 // in ms +}; + +Script.include("../../libraries/utils.js"); +Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. + +function ignore() {} + +function debug() { // Display the arguments not just [Object object]. + //print.apply(null, [].map.call(arguments, JSON.stringify)); +} + +EntityViewer.setKeyholeRadius(QUERY_RADIUS); + +// ENTITY DATA CACHE +// +var entityCache = {}; // A dictionary of unexpired EntityData objects. + +function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. + // This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer. + var that = this; + that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data + // State Transitions: + // no data => no data | sound data | expired + // expired => stop => remove + // sound data => downloading + // downloading => downloading | waiting + // waiting => playing | waiting (if too many already playing) + // playing => update position etc | no data + that.stop = function stop() { + if (!that.sound) { + return; + } + print("stopping sound", entityIdentifier, that.url); + delete that.sound; + delete that.url; + if (!that.injector) { + return; + } + that.injector.stop(); + delete that.injector; + }; + this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) { + if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE + that.stop(); // Alternatively, we could fade out and then stop... + delete entityCache[entityIdentifier]; + return; + } + var properties, soundData; // Latest data, pulled from local octree. + // getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results. + // Most entity updates are fast and only a very few do getEntityProperties. + + function ensureSoundData() { // We only getEntityProperities when we need to. + if (properties) { + return; + } + properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']); + debug("updating", that, properties); + try { + var userData = properties.userData && JSON.parse(properties.userData); + soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare. + that.lastUserDataUpdate = now; // But do update these ... + that.url = soundData && soundData.url; + that.playAfter = that.url && now; + } catch (err) { + print(err, properties.userData); + } + } + // Stumbling on big new pile of entities will do a lot of getEntityProperties. Once. + if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA + ensureSoundData(); + } + if (!that.url) { // NO DATA => NO DATA + return that.stop(); + } + if (!that.sound) { // SOUND DATA => DOWNLOADING + that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can. + } + if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING + return; + } + if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING + return; + } + ensureSoundData(); // We'll play and will need position, so we might as well get soundData, too. + if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around) + return that.stop(); + } + var options = { + position: properties.position, + loop: soundData.loop || DEFAULT_SOUND_DATA.loop, + volume: soundData.volume || DEFAULT_SOUND_DATA.volume + }; + if (!that.injector) { // WAITING => PLAYING | WAITING + debug("starting", that, options); + that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later. + if (that.injector) { + print("started", entityIdentifier, that.url); + } else { // Don't hammer ensureSoundData or injector manager. + that.playAfter = now + (soundData.playbackGap || RECHECK_TIME); + } + return; + } + that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC + if (!that.injector.isPlaying) { // Subtle: a looping sound will not check playbackGap. + var gap = soundData.playbackGap || DEFAULT_SOUND_DATA; + if (gap) { // WAITING => PLAYING + gap = gap + randFloat(-Math.max(gap, soundData.playbackGapRange), soundData.playbackGapRange); // gapRange is bad name. Meant as +/- value. + // Setup next play just once, now. Changes won't be looked at while we wait. + that.playAfter = now + (that.sound.duration * 1000) + gap; + // Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter. + that.injector.restart(); + } else { // PLAYING => NO DATA + that.playAfter = Infinity; + } + } + }; +} + +function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) { + ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play. + var entitySound = entityCache[entityIdentifier]; + if (!entitySound) { + entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier); + } + entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine. +} +var nUpdates = UPDATES_PER_STATS_LOG, + lastStats = Date.now(); + +function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds. + var now = Date.now(), + expirationCutoff = now - EXPIRATION_TIME, + userDataRecheckCutoff = now - RECHECK_TIME; + Object.keys(entityCache).forEach(function(entityIdentifier) { + entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now); + }); + if (nUpdates-- <= 0) { // Report statistics. + // My figures using acAudioSearchCompatibleEntitySpawner.js with ONE user, N_SOUNDS = 2000, N_SILENT_ENTITIES_PER_SOUND = 5: + // audio-mixer: 23% of cpu (on Mac Activity Monitor) + // this script's assignment client: 106% of cpu. (overloaded) + // entities:12003 + // sounds:2000 + // playing:40 (correct) + // millisecondsPerUpdate:135 (100 requested, so behind by 35%. It would be nice to dig into why...) + var stats = { + entities: 0, + sounds: 0, + playing: 0, + millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG + }; + nUpdates = UPDATES_PER_STATS_LOG; + lastStats = now; + Object.keys(entityCache).forEach(function(entityIdentifier) { + var datum = entityCache[entityIdentifier]; + stats.entities++; + if (datum.url) { + stats.sounds++; + if (datum.injector && datum.injector.isPlaying) { + stats.playing++; + } + } + }); + print(JSON.stringify(stats)); + } +} + +// Update the set of which EntityData we know about. +// + +function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work. + // This does at most: + // one queryOctree request of the entity server, and + // one findEntities geometry query of our own octree, and + // a quick internEntityDatum of each of what may be a large number of entityIdentifiers. + // The idea is that this is a nice bounded piece of work that should not be done too frequently. + // However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip. + var avatar = AvatarList.getAvatar(avatarIdentifier), + avatarPosition = avatar && avatar.position; + if (!avatarPosition) { // No longer here. + return; + } + var timestamp = Date.now(); + EntityViewer.setPosition(avatarPosition); + EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results. + var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS); + debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition); + entities.forEach(function(entityIdentifier) { + internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar); + }); +} + +// Slowly update the set of data we have to work with. +// +var workQueue = []; + +function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates + workQueue = AvatarList.getAvatarIdentifiers().map(function(avatarIdentifier) { + return function() { + updateEntiesForAvatar(avatarIdentifier); + }; + }); +} +Script.setInterval(function() { + // There might be thousands of EntityData known to us, but only a few will require any work to update. + updateAllEntityData(); // i.e., this better be pretty fast. + // Each interval, we do no more than one updateEntitiesforAvatar. + if (!workQueue.length) { + workQueue = [updateWorkQueueForAvatarsPresent]; + } + workQueue.pop()(); // There's always one +}, UPDATE_TIME); \ No newline at end of file diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 8f22910d4f..761ef00e33 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -57,7 +57,7 @@ origin: markerProps.position, direction: Quat.getFront(markerProps.rotation) } - var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); + var intersection = Entities.findRayIntersectionBlocking(pickRay, true, [_this.whiteboard]); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { Overlays.editOverlay(_this.laserPointer, { @@ -71,7 +71,8 @@ _this.resetStroke(); } } else { - _this.resetStroke(); + _this.resetStroke(); + Overlays.editOverlay(_this.laserPointer, { visible: false }); @@ -92,7 +93,7 @@ position: position, textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, - lifetime: 10 + lifetime: 500 }); _this.linePoints = []; From 67ec1732b348e44539770bfddeeaa9239ab429fc Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 18:46:38 -0800 Subject: [PATCH 35/74] increased eraser range --- examples/homeContent/whiteboardV2/eraserEntityScript.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index 89ce4aded6..66399a9b8e 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -21,9 +21,9 @@ Eraser = function() { _this = this; - _this.ERASER_TRIGGER_THRESHOLD = 0.1; + _this.ERASER_TRIGGER_THRESHOLD = 0.2; _this.STROKE_NAME = "hifi-marker-stroke"; - _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.4; + _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.7; }; Eraser.prototype = { From ef85d0451a4008bf94333dee674858f220244a7e Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 14:24:06 -0800 Subject: [PATCH 36/74] removed files that shouldn't be there --- .../acAudioSearching/howardAcAudio.js | 248 ------------------ .../acAudioSearching/howardSpawner.js | 248 ------------------ 2 files changed, 496 deletions(-) delete mode 100644 examples/audioExamples/acAudioSearching/howardAcAudio.js delete mode 100644 examples/audioExamples/acAudioSearching/howardSpawner.js diff --git a/examples/audioExamples/acAudioSearching/howardAcAudio.js b/examples/audioExamples/acAudioSearching/howardAcAudio.js deleted file mode 100644 index f5b1302e06..0000000000 --- a/examples/audioExamples/acAudioSearching/howardAcAudio.js +++ /dev/null @@ -1,248 +0,0 @@ -"use strict"; -/*jslint nomen: true, plusplus: true, vars: true*/ -/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/ -// -// ACAudioSearchAndInject.js -// audio -// -// Created by Eric Levin and Howard Stearns 2/1/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData. -// Inject as many as practical into the audio mixer. -// See acAudioSearchAndCompatibilityEntitySpawner.js. -// -// This implementation takes some precautions to scale well: -// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars. -// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only -// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities). -// This implementation tries to use all the available injectors. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key. -var old_sound_data_key = "soundKey"; // For backwards compatibility. -var QUERY_RADIUS = 50; // meters -var UPDATE_TIME = 100; // ms. We'll update just one thing on this period. -var EXPIRATION_TIME = 5 * 1000; // ms. Remove sounds that have been out of range for this time. -var RECHECK_TIME = 10 * 1000; // ms. Check for new userData properties this often when not currently playing. -// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.) -var UPDATES_PER_STATS_LOG = 50; - -var DEFAULT_SOUND_DATA = { - volume: 0.5, // userData cannot specify zero volume with our current method of defaulting. - loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value. - playbackGap: 1000, // in ms - playbackGapRange: 0 // in ms -}; - -Script.include("../../libraries/utils.js"); -Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. - -function ignore() {} - -function debug() { // Display the arguments not just [Object object]. - //print.apply(null, [].map.call(arguments, JSON.stringify)); -} - -EntityViewer.setKeyholeRadius(QUERY_RADIUS); - -// ENTITY DATA CACHE -// -var entityCache = {}; // A dictionary of unexpired EntityData objects. - -function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. - // This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer. - var that = this; - that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data - // State Transitions: - // no data => no data | sound data | expired - // expired => stop => remove - // sound data => downloading - // downloading => downloading | waiting - // waiting => playing | waiting (if too many already playing) - // playing => update position etc | no data - that.stop = function stop() { - if (!that.sound) { - return; - } - print("stopping sound", entityIdentifier, that.url); - delete that.sound; - delete that.url; - if (!that.injector) { - return; - } - that.injector.stop(); - delete that.injector; - }; - this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) { - if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE - that.stop(); // Alternatively, we could fade out and then stop... - delete entityCache[entityIdentifier]; - return; - } - var properties, soundData; // Latest data, pulled from local octree. - // getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results. - // Most entity updates are fast and only a very few do getEntityProperties. - - function ensureSoundData() { // We only getEntityProperities when we need to. - if (properties) { - return; - } - properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']); - debug("updating", that, properties); - try { - var userData = properties.userData && JSON.parse(properties.userData); - soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare. - that.lastUserDataUpdate = now; // But do update these ... - that.url = soundData && soundData.url; - that.playAfter = that.url && now; - } catch (err) { - print(err, properties.userData); - } - } - // Stumbling on big new pile of entities will do a lot of getEntityProperties. Once. - if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA - ensureSoundData(); - } - if (!that.url) { // NO DATA => NO DATA - return that.stop(); - } - if (!that.sound) { // SOUND DATA => DOWNLOADING - that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can. - } - if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING - return; - } - if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING - return; - } - ensureSoundData(); // We'll play and will need position, so we might as well get soundData, too. - if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around) - return that.stop(); - } - var options = { - position: properties.position, - loop: soundData.loop || DEFAULT_SOUND_DATA.loop, - volume: soundData.volume || DEFAULT_SOUND_DATA.volume - }; - if (!that.injector) { // WAITING => PLAYING | WAITING - debug("starting", that, options); - that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later. - if (that.injector) { - print("started", entityIdentifier, that.url); - } else { // Don't hammer ensureSoundData or injector manager. - that.playAfter = now + (soundData.playbackGap || RECHECK_TIME); - } - return; - } - that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC - if (!that.injector.isPlaying) { // Subtle: a looping sound will not check playbackGap. - var gap = soundData.playbackGap || DEFAULT_SOUND_DATA; - if (gap) { // WAITING => PLAYING - gap = gap + randFloat(-Math.max(gap, soundData.playbackGapRange), soundData.playbackGapRange); // gapRange is bad name. Meant as +/- value. - // Setup next play just once, now. Changes won't be looked at while we wait. - that.playAfter = now + (that.sound.duration * 1000) + gap; - // Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter. - that.injector.restart(); - } else { // PLAYING => NO DATA - that.playAfter = Infinity; - } - } - }; -} - -function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) { - ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play. - var entitySound = entityCache[entityIdentifier]; - if (!entitySound) { - entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier); - } - entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine. -} -var nUpdates = UPDATES_PER_STATS_LOG, - lastStats = Date.now(); - -function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds. - var now = Date.now(), - expirationCutoff = now - EXPIRATION_TIME, - userDataRecheckCutoff = now - RECHECK_TIME; - Object.keys(entityCache).forEach(function(entityIdentifier) { - entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now); - }); - if (nUpdates-- <= 0) { // Report statistics. - // My figures using acAudioSearchCompatibleEntitySpawner.js with ONE user, N_SOUNDS = 2000, N_SILENT_ENTITIES_PER_SOUND = 5: - // audio-mixer: 23% of cpu (on Mac Activity Monitor) - // this script's assignment client: 106% of cpu. (overloaded) - // entities:12003 - // sounds:2000 - // playing:40 (correct) - // millisecondsPerUpdate:135 (100 requested, so behind by 35%. It would be nice to dig into why...) - var stats = { - entities: 0, - sounds: 0, - playing: 0, - millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG - }; - nUpdates = UPDATES_PER_STATS_LOG; - lastStats = now; - Object.keys(entityCache).forEach(function(entityIdentifier) { - var datum = entityCache[entityIdentifier]; - stats.entities++; - if (datum.url) { - stats.sounds++; - if (datum.injector && datum.injector.isPlaying) { - stats.playing++; - } - } - }); - print(JSON.stringify(stats)); - } -} - -// Update the set of which EntityData we know about. -// - -function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work. - // This does at most: - // one queryOctree request of the entity server, and - // one findEntities geometry query of our own octree, and - // a quick internEntityDatum of each of what may be a large number of entityIdentifiers. - // The idea is that this is a nice bounded piece of work that should not be done too frequently. - // However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip. - var avatar = AvatarList.getAvatar(avatarIdentifier), - avatarPosition = avatar && avatar.position; - if (!avatarPosition) { // No longer here. - return; - } - var timestamp = Date.now(); - EntityViewer.setPosition(avatarPosition); - EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results. - var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS); - debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition); - entities.forEach(function(entityIdentifier) { - internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar); - }); -} - -// Slowly update the set of data we have to work with. -// -var workQueue = []; - -function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates - workQueue = AvatarList.getAvatarIdentifiers().map(function(avatarIdentifier) { - return function() { - updateEntiesForAvatar(avatarIdentifier); - }; - }); -} -Script.setInterval(function() { - // There might be thousands of EntityData known to us, but only a few will require any work to update. - updateAllEntityData(); // i.e., this better be pretty fast. - // Each interval, we do no more than one updateEntitiesforAvatar. - if (!workQueue.length) { - workQueue = [updateWorkQueueForAvatarsPresent]; - } - workQueue.pop()(); // There's always one -}, UPDATE_TIME); \ No newline at end of file diff --git a/examples/audioExamples/acAudioSearching/howardSpawner.js b/examples/audioExamples/acAudioSearching/howardSpawner.js deleted file mode 100644 index f5b1302e06..0000000000 --- a/examples/audioExamples/acAudioSearching/howardSpawner.js +++ /dev/null @@ -1,248 +0,0 @@ -"use strict"; -/*jslint nomen: true, plusplus: true, vars: true*/ -/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/ -// -// ACAudioSearchAndInject.js -// audio -// -// Created by Eric Levin and Howard Stearns 2/1/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData. -// Inject as many as practical into the audio mixer. -// See acAudioSearchAndCompatibilityEntitySpawner.js. -// -// This implementation takes some precautions to scale well: -// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars. -// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only -// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities). -// This implementation tries to use all the available injectors. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key. -var old_sound_data_key = "soundKey"; // For backwards compatibility. -var QUERY_RADIUS = 50; // meters -var UPDATE_TIME = 100; // ms. We'll update just one thing on this period. -var EXPIRATION_TIME = 5 * 1000; // ms. Remove sounds that have been out of range for this time. -var RECHECK_TIME = 10 * 1000; // ms. Check for new userData properties this often when not currently playing. -// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.) -var UPDATES_PER_STATS_LOG = 50; - -var DEFAULT_SOUND_DATA = { - volume: 0.5, // userData cannot specify zero volume with our current method of defaulting. - loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value. - playbackGap: 1000, // in ms - playbackGapRange: 0 // in ms -}; - -Script.include("../../libraries/utils.js"); -Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. - -function ignore() {} - -function debug() { // Display the arguments not just [Object object]. - //print.apply(null, [].map.call(arguments, JSON.stringify)); -} - -EntityViewer.setKeyholeRadius(QUERY_RADIUS); - -// ENTITY DATA CACHE -// -var entityCache = {}; // A dictionary of unexpired EntityData objects. - -function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. - // This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer. - var that = this; - that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data - // State Transitions: - // no data => no data | sound data | expired - // expired => stop => remove - // sound data => downloading - // downloading => downloading | waiting - // waiting => playing | waiting (if too many already playing) - // playing => update position etc | no data - that.stop = function stop() { - if (!that.sound) { - return; - } - print("stopping sound", entityIdentifier, that.url); - delete that.sound; - delete that.url; - if (!that.injector) { - return; - } - that.injector.stop(); - delete that.injector; - }; - this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) { - if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE - that.stop(); // Alternatively, we could fade out and then stop... - delete entityCache[entityIdentifier]; - return; - } - var properties, soundData; // Latest data, pulled from local octree. - // getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results. - // Most entity updates are fast and only a very few do getEntityProperties. - - function ensureSoundData() { // We only getEntityProperities when we need to. - if (properties) { - return; - } - properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']); - debug("updating", that, properties); - try { - var userData = properties.userData && JSON.parse(properties.userData); - soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare. - that.lastUserDataUpdate = now; // But do update these ... - that.url = soundData && soundData.url; - that.playAfter = that.url && now; - } catch (err) { - print(err, properties.userData); - } - } - // Stumbling on big new pile of entities will do a lot of getEntityProperties. Once. - if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA - ensureSoundData(); - } - if (!that.url) { // NO DATA => NO DATA - return that.stop(); - } - if (!that.sound) { // SOUND DATA => DOWNLOADING - that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can. - } - if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING - return; - } - if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING - return; - } - ensureSoundData(); // We'll play and will need position, so we might as well get soundData, too. - if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around) - return that.stop(); - } - var options = { - position: properties.position, - loop: soundData.loop || DEFAULT_SOUND_DATA.loop, - volume: soundData.volume || DEFAULT_SOUND_DATA.volume - }; - if (!that.injector) { // WAITING => PLAYING | WAITING - debug("starting", that, options); - that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later. - if (that.injector) { - print("started", entityIdentifier, that.url); - } else { // Don't hammer ensureSoundData or injector manager. - that.playAfter = now + (soundData.playbackGap || RECHECK_TIME); - } - return; - } - that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC - if (!that.injector.isPlaying) { // Subtle: a looping sound will not check playbackGap. - var gap = soundData.playbackGap || DEFAULT_SOUND_DATA; - if (gap) { // WAITING => PLAYING - gap = gap + randFloat(-Math.max(gap, soundData.playbackGapRange), soundData.playbackGapRange); // gapRange is bad name. Meant as +/- value. - // Setup next play just once, now. Changes won't be looked at while we wait. - that.playAfter = now + (that.sound.duration * 1000) + gap; - // Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter. - that.injector.restart(); - } else { // PLAYING => NO DATA - that.playAfter = Infinity; - } - } - }; -} - -function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) { - ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play. - var entitySound = entityCache[entityIdentifier]; - if (!entitySound) { - entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier); - } - entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine. -} -var nUpdates = UPDATES_PER_STATS_LOG, - lastStats = Date.now(); - -function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds. - var now = Date.now(), - expirationCutoff = now - EXPIRATION_TIME, - userDataRecheckCutoff = now - RECHECK_TIME; - Object.keys(entityCache).forEach(function(entityIdentifier) { - entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now); - }); - if (nUpdates-- <= 0) { // Report statistics. - // My figures using acAudioSearchCompatibleEntitySpawner.js with ONE user, N_SOUNDS = 2000, N_SILENT_ENTITIES_PER_SOUND = 5: - // audio-mixer: 23% of cpu (on Mac Activity Monitor) - // this script's assignment client: 106% of cpu. (overloaded) - // entities:12003 - // sounds:2000 - // playing:40 (correct) - // millisecondsPerUpdate:135 (100 requested, so behind by 35%. It would be nice to dig into why...) - var stats = { - entities: 0, - sounds: 0, - playing: 0, - millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG - }; - nUpdates = UPDATES_PER_STATS_LOG; - lastStats = now; - Object.keys(entityCache).forEach(function(entityIdentifier) { - var datum = entityCache[entityIdentifier]; - stats.entities++; - if (datum.url) { - stats.sounds++; - if (datum.injector && datum.injector.isPlaying) { - stats.playing++; - } - } - }); - print(JSON.stringify(stats)); - } -} - -// Update the set of which EntityData we know about. -// - -function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work. - // This does at most: - // one queryOctree request of the entity server, and - // one findEntities geometry query of our own octree, and - // a quick internEntityDatum of each of what may be a large number of entityIdentifiers. - // The idea is that this is a nice bounded piece of work that should not be done too frequently. - // However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip. - var avatar = AvatarList.getAvatar(avatarIdentifier), - avatarPosition = avatar && avatar.position; - if (!avatarPosition) { // No longer here. - return; - } - var timestamp = Date.now(); - EntityViewer.setPosition(avatarPosition); - EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results. - var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS); - debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition); - entities.forEach(function(entityIdentifier) { - internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar); - }); -} - -// Slowly update the set of data we have to work with. -// -var workQueue = []; - -function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates - workQueue = AvatarList.getAvatarIdentifiers().map(function(avatarIdentifier) { - return function() { - updateEntiesForAvatar(avatarIdentifier); - }; - }); -} -Script.setInterval(function() { - // There might be thousands of EntityData known to us, but only a few will require any work to update. - updateAllEntityData(); // i.e., this better be pretty fast. - // Each interval, we do no more than one updateEntitiesforAvatar. - if (!workQueue.length) { - workQueue = [updateWorkQueueForAvatarsPresent]; - } - workQueue.pop()(); // There's always one -}, UPDATE_TIME); \ No newline at end of file From e9ad06fca767f0d7e899b025a159e1a67d3c55a5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 14:25:12 -0800 Subject: [PATCH 37/74] removed query string --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 6d5c74e273..17c44eae41 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -142,7 +142,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, From 338427ed3e11a5556d401b6ca46c1a1b865575cc Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 14:28:35 -0800 Subject: [PATCH 38/74] wait longer before sending message --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 17c44eae41..3d63eb4643 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -206,7 +206,7 @@ function createMarker(modelURL, markerPosition, markerColor) { var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); - }, 1000) + }, 2000) } From 22a5f3dcc0aca96ee2439be2ad62590013dfe3a6 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 14:28:48 -0800 Subject: [PATCH 39/74] wait even longer --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 3d63eb4643..2974db8f59 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -206,7 +206,7 @@ function createMarker(modelURL, markerPosition, markerColor) { var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); - }, 2000) + }, 3000) } From 4de951242cb63558d06e62ec1af83766083c8712 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 14:54:34 -0800 Subject: [PATCH 40/74] eraser positioned correctly --- .../whiteboardV2/whiteboardSpawner.js | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 2974db8f59..3fcf93e628 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -104,6 +104,32 @@ var eraser = Entities.addEntity({ y: -0.1, z: 0 }, + userData: JSON.stringify({ + wearable: { + joints: { + RightHand: [{ + x: 0.0207, + y: 0.1202, + z: 0.0493 + }, { + x: 0.1004, + y: 0.6424, + z: 0.717, + w: 0.250 + }], + LeftHand: [{ + x: -0.005, + y: 0.1101, + z: 0.053 + }, { + x: 0.7234, + y: 0.289, + z: 0.142, + w: 0.610 + }] + } + } + }) }); createMarkers(); @@ -206,7 +232,7 @@ function createMarker(modelURL, markerPosition, markerColor) { var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); - }, 3000) + }, 5000) } From ddae2d4f749a8aa1cd30bbcb75145367908dbb47 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 15:00:54 -0800 Subject: [PATCH 41/74] only erase stroke map on release and preload --- examples/homeContent/whiteboardV2/eraserEntityScript.js | 9 ++++++--- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 -- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index 66399a9b8e..c78707e129 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -24,6 +24,7 @@ _this.ERASER_TRIGGER_THRESHOLD = 0.2; _this.STROKE_NAME = "hifi-marker-stroke"; _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.7; + _this.strokeMap = []; }; Eraser.prototype = { @@ -35,10 +36,10 @@ var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; var strokeIDs = Entities.findEntities(eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS); // Create a map of stroke entities and their positions - _this.strokeMap = []; + strokeIDs.forEach(function(strokeID) { var strokeProps = Entities.getEntityProperties(strokeID, ["position", "name"]); - if (strokeProps.name === _this.STROKE_NAME) { + if (strokeProps.name === _this.STROKE_NAME) { _this.strokeMap.push({ strokeID: strokeID, strokePosition: strokeProps.position @@ -53,7 +54,9 @@ } else {} }, - releaseEquip: function() {}, + releaseEquip: function() { + _this.strokeMap = []; + }, continueHolding: function() { diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 3fcf93e628..8402b241ed 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -149,8 +149,6 @@ function createMarkers() { blue: 200 }); - - markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); createMarker(modelURLS[1], markerPosition, { red: 200, From 24bf4f851f52fff5620b8462eaefcb2b3a8c775d Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 15:23:02 -0800 Subject: [PATCH 42/74] can erase any stroke at any time --- .../whiteboardV2/eraserEntityScript.js | 42 ++++++------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index c78707e129..da67288829 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -24,7 +24,6 @@ _this.ERASER_TRIGGER_THRESHOLD = 0.2; _this.STROKE_NAME = "hifi-marker-stroke"; _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.7; - _this.strokeMap = []; }; Eraser.prototype = { @@ -33,43 +32,28 @@ _this.equipped = true; _this.hand = params[0] == "left" ? 0 : 1; // We really only need to grab position of marker strokes once, and then just check to see if eraser comes near enough to those strokes + + }, + continueEquip: function() { + this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); + if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) { + _this.continueHolding(); + } + }, + + + continueHolding: function() { var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; var strokeIDs = Entities.findEntities(eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS); // Create a map of stroke entities and their positions strokeIDs.forEach(function(strokeID) { var strokeProps = Entities.getEntityProperties(strokeID, ["position", "name"]); - if (strokeProps.name === _this.STROKE_NAME) { - _this.strokeMap.push({ - strokeID: strokeID, - strokePosition: strokeProps.position - }); + if (strokeProps.name === _this.STROKE_NAME && Vec3.distance(eraserPosition, strokeProps.position) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) { + Entities.deleteEntity(strokeID); } }); }, - continueEquip: function() { - this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); - if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) { - _this.continueHolding(); - } else {} - }, - - releaseEquip: function() { - _this.strokeMap = []; - }, - - - continueHolding: function() { - // search for marker strokes within certain radius of eraser - var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; - _this.strokeMap.forEach(function(strokeData, index) { - if (Vec3.distance(eraserPosition, strokeData.strokePosition) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) { - Entities.deleteEntity(strokeData.strokeID); - _this.strokeMap.splice(index, 1); - } - }) - - }, preload: function(entityID) { this.entityID = entityID; From 668894b3e06714be35da275127858f1505a7bfd0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 16:05:03 -0800 Subject: [PATCH 43/74] should work multiuser now --- .../whiteboardV2/markerEntityScript.js | 58 ++++++++++--------- .../whiteboardV2/whiteboardSpawner.js | 16 +---- 2 files changed, 34 insertions(+), 40 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 761ef00e33..80ba1cea7e 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -23,22 +23,34 @@ MarkerTip = function() { _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; - this.strokeForwardOffset = 0.0001; - this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; - this.STROKE_WIDTH = 0.003 + _this.strokeForwardOffset = 0.0001; + _this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; + _this.STROKE_WIDTH = 0.003 _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; _this.strokes = []; _this.PAINTING_TRIGGER_THRESHOLD = 0.2; - this.STROKE_NAME = "hifi-marker-stroke"; + _this.STROKE_NAME = "hifi-marker-stroke"; + _this.WHITEBOARD_SURFACE_NAME = "hifi-whiteboardDrawingSurface"; }; MarkerTip.prototype = { startEquip: function(id, params) { + _this.whiteboards = []; _this.equipped = true; _this.hand = params[0] == "left" ? 0 : 1; + _this.markerColor = getEntityUserData(_this.entityID).markerColor; + // search for whiteboards + var markerPosition = Entities.getEntityProperties(_this.entityID, "position").position; + var entities = Entities.findEntities(markerPosition, 10); + entities.forEach(function(entity) { + var entityName = Entities.getEntityProperties(entity, "name").name; + if (entityName === _this.WHITEBOARD_SURFACE_NAME) { + _this.whiteboards.push(entity); + } + }); }, releaseEquip: function() { @@ -57,12 +69,14 @@ origin: markerProps.position, direction: Quat.getFront(markerProps.rotation) } - var intersection = Entities.findRayIntersectionBlocking(pickRay, true, [_this.whiteboard]); - + var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); + _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { + print("EBL HIT") Overlays.editOverlay(_this.laserPointer, { visible: true, - position: intersection.intersection + position: intersection.intersection, + rotation: intersection.properties.rotation }) _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { @@ -71,8 +85,8 @@ _this.resetStroke(); } } else { - _this.resetStroke(); - + _this.resetStroke(); + Overlays.editOverlay(_this.laserPointer, { visible: false }); @@ -145,22 +159,6 @@ preload: function(entityID) { this.entityID = entityID; - - }, - - unload: function() { - Overlays.deleteOverlay(_this.laserPointer); - _this.strokes.forEach( function(stroke) { - Entities.deleteEntity(stroke); - }); - }, - - setProperties: function(myId, data) { - var data = JSON.parse(data); - - _this.whiteboard = data.whiteboard; - var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - _this.whiteboardNormal = Quat.getFront(whiteboardProps.rotation); _this.laserPointer = Overlays.addOverlay("circle3d", { color: { red: 220, @@ -169,9 +167,15 @@ }, solid: true, size: 0.01, - rotation: whiteboardProps.rotation }); - _this.markerColor = data.markerColor; + + }, + + unload: function() { + Overlays.deleteOverlay(_this.laserPointer); + _this.strokes.forEach(function(stroke) { + Entities.deleteEntity(stroke); + }); } }; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 8402b241ed..08cd2b5a5f 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -56,7 +56,7 @@ var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(orientation))); var whiteboardDrawingSurface = Entities.addEntity({ type: "Box", - name: "whiteboardDrawingSurface", + name: "hifi-whiteboardDrawingSurface", dimensions: { x: 1.82, y: 1.8, @@ -166,7 +166,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, @@ -193,6 +193,7 @@ function createMarker(modelURL, markerPosition, markerColor) { name: "marker", script: MARKER_SCRIPT_URL, userData: JSON.stringify({ + markerColor: markerColor, wearable: { joints: { RightHand: [{ @@ -222,17 +223,6 @@ function createMarker(modelURL, markerPosition, markerColor) { markers.push(marker); - Script.setTimeout(function() { - var data = { - whiteboard: whiteboardDrawingSurface, - markerColor: markerColor - } - var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; - - Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); - }, 5000) - - } From a79d334beda04001f48626fc4058b4a98ba131d2 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 16:12:34 -0800 Subject: [PATCH 44/74] no query string --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 08cd2b5a5f..a5cc219240 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -166,7 +166,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?"); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, From 0602bf7f1af7c3176874538da11d1afc4372d1cf Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 16:20:35 -0800 Subject: [PATCH 45/74] logging --- examples/homeContent/whiteboardV2/markerEntityScript.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 80ba1cea7e..a9b8173097 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -48,9 +48,12 @@ entities.forEach(function(entity) { var entityName = Entities.getEntityProperties(entity, "name").name; if (entityName === _this.WHITEBOARD_SURFACE_NAME) { + _this.whiteboards.push(entity); } }); + + print("intersectable entities " + JSON.stringify(_this.whiteboards)) }, releaseEquip: function() { @@ -72,7 +75,6 @@ var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - print("EBL HIT") Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, From 4d2a65926ca81c68b810d53e650265d8186a8802 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 18:06:13 -0800 Subject: [PATCH 46/74] test --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index a5cc219240..ff2c593ea1 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -166,7 +166,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?"); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, From 0ce4385554d4461db0d6b91af79fd64a798dc89a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 18:22:54 -0800 Subject: [PATCH 47/74] no offset increment --- examples/homeContent/whiteboardV2/markerEntityScript.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index a9b8173097..82ea1a2b69 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -24,7 +24,6 @@ _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; _this.strokeForwardOffset = 0.0001; - _this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; _this.STROKE_WIDTH = 0.003 _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; @@ -130,7 +129,6 @@ var localPoint = Vec3.subtract(basePosition, _this.strokeBasePosition); localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); - _this.strokeForwardOffset -= _this.STROKE_FORWARD_OFFSET_INCRERMENT; if (_this.linePoints.length > 0) { var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length - 1]); From 25a2d1eb93e28f35190b5e89cb2e02353def2b64 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 10:14:27 -0800 Subject: [PATCH 48/74] fixed rotation --- .../whiteboardV2/markerEntityScript.js | 2 +- .../whiteboardV2/whiteboardSpawner.js | 56 +++++++++---------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 82ea1a2b69..e6f7e3cf81 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -72,8 +72,8 @@ direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); - _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { + _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index ff2c593ea1..6689672095 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -23,7 +23,7 @@ var markerRotation = Quat.fromVec3Degrees({ orientation.x = 0; var whiteboardRotation = Quat.fromVec3Degrees({ x: 0, - y: orientation.y - 90, + y: orientation.y, z: 0 }); orientation = Quat.fromVec3Degrees(orientation); @@ -31,8 +31,8 @@ var markers = []; var whiteboardPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); -var WHITEBOARD_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard-3.fbx"; -var WHITEBOARD_COLLISION_HULL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard.obj"; +var WHITEBOARD_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/Whiteboard-3+(1).fbx"; +var WHITEBOARD_COLLISION_HULL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/whiteboardCollisionHull.obj"; var whiteboard = Entities.addEntity({ type: "Model", name: "whiteboard", @@ -42,9 +42,9 @@ var whiteboard = Entities.addEntity({ shapeType: 'compound', compoundShapeURL: WHITEBOARD_COLLISION_HULL_URL, dimensions: { - x: 0.4636, - y: 2.7034, - z: 1.8653 + x: 1.86, + y: 2.7, + z: 0.4636 }, }); @@ -68,7 +68,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ blue: 200 }, position: whiteboardSurfacePosition, - rotation: orientation, + rotation: whiteboardRotation, visible: false, parentID: whiteboard }); @@ -108,9 +108,9 @@ var eraser = Entities.addEntity({ wearable: { joints: { RightHand: [{ - x: 0.0207, - y: 0.1202, - z: 0.0493 + x: 0.020, + y: 0.120, + z: 0.049 }, { x: 0.1004, y: 0.6424, @@ -122,7 +122,7 @@ var eraser = Entities.addEntity({ y: 0.1101, z: 0.053 }, { - x: 0.7234, + x: 0.723, y: 0.289, z: 0.142, w: 0.610 @@ -186,9 +186,9 @@ function createMarker(modelURL, markerPosition, markerColor) { }, position: markerPosition, dimensions: { - x: 0.0270, - y: 0.0272, - z: 0.1641 + x: 0.027, + y: 0.027, + z: 0.164 }, name: "marker", script: MARKER_SCRIPT_URL, @@ -197,24 +197,24 @@ function createMarker(modelURL, markerPosition, markerColor) { wearable: { joints: { RightHand: [{ - x: 0.001109793782234192, - y: 0.13991504907608032, - z: 0.05035984516143799 + x: 0.001, + y: 0.139, + z: 0.050 }, { - x: -0.7360993027687073, - y: -0.04330085217952728, - z: -0.10863728821277618, - w: -0.6666942238807678 + x: -0.73, + y: -0.043, + z: -0.108, + w: -0.666 }], LeftHand: [{ - x: 0.007193896919488907, - y: 0.15147076547145844, - z: 0.06174466013908386 + x: 0.007, + y: 0.151, + z: 0.061 }, { - x: -0.4174973964691162, - y: 0.631147563457489, - z: -0.3890438377857208, - w: -0.52535080909729 + x: -0.417, + y: 0.631, + z: -0.389, + w: -0.525 }] } } From 83713898cc54ba47eaac53c8cc4f13c4ed166d83 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 26 Feb 2016 10:34:27 -0800 Subject: [PATCH 49/74] maze should delete stray balls --- unpublishedScripts/DomainContent/Home/tiltMaze/maze.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js b/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js index 557861ba30..f155c28b41 100644 --- a/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js +++ b/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js @@ -96,6 +96,9 @@ if (this.ballLocked === true) { return; } + if(this.ball!==null){ + Entities.deleteEntity(this.ball); + } var properties = { name: 'Hifi Tilt Maze Ball', From c81f3256ddc2d9376dd134bc531af38ca09a7c68 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 10:58:22 -0800 Subject: [PATCH 50/74] rotation --- .../whiteboardV2/eraserEntityScript.js | 26 +++++++++++++++---- .../whiteboardV2/markerEntityScript.js | 2 +- .../whiteboardV2/whiteboardSpawner.js | 10 +++---- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index da67288829..86e80659bf 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -32,9 +32,11 @@ _this.equipped = true; _this.hand = params[0] == "left" ? 0 : 1; // We really only need to grab position of marker strokes once, and then just check to see if eraser comes near enough to those strokes - + Overlays.editOverlay(_this.searchSphere, {visible: true}); }, continueEquip: function() { + _this.eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; + Overlays.editOverlay(_this.searchSphere, {position: _this.eraserPosition}); this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) { _this.continueHolding(); @@ -43,22 +45,36 @@ continueHolding: function() { - var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; - var strokeIDs = Entities.findEntities(eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS); + var strokeIDs = Entities.findEntities(_this.eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS); // Create a map of stroke entities and their positions strokeIDs.forEach(function(strokeID) { var strokeProps = Entities.getEntityProperties(strokeID, ["position", "name"]); - if (strokeProps.name === _this.STROKE_NAME && Vec3.distance(eraserPosition, strokeProps.position) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) { + if (strokeProps.name === _this.STROKE_NAME && Vec3.distance(_this.eraserPosition, strokeProps.position) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) { Entities.deleteEntity(strokeID); } }); }, + releaseEquip: function() { + Overlays.editOverlay(_this.searchSphere, {visible: false}); + }, + preload: function(entityID) { - this.entityID = entityID; + _this.entityID = entityID; + _this.searchSphere = Overlays.addOverlay('sphere', { + size: _this.ERASER_TO_STROKE_SEARCH_RADIUS, + color: {red: 200, green: 10, blue: 10}, + alpha: 0.2, + solid: true, + visible: false + }) }, + + unload: function() { + Overlays.deleteOverlay(_this.searchSphere); + } }; // entity scripts always need to return a newly constructed object of our type diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index e6f7e3cf81..e379fac016 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -73,7 +73,7 @@ } var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); + _this.whiteboardNormal = Quat.getRight(intersection.properties.rotation); Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 6689672095..8826c8387a 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -31,7 +31,7 @@ var markers = []; var whiteboardPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); -var WHITEBOARD_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/Whiteboard-3+(1).fbx"; +var WHITEBOARD_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/Whiteboard-4.fbx"; var WHITEBOARD_COLLISION_HULL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/whiteboardCollisionHull.obj"; var whiteboard = Entities.addEntity({ type: "Model", @@ -69,7 +69,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ }, position: whiteboardSurfacePosition, rotation: whiteboardRotation, - visible: false, + // visible: false, parentID: whiteboard }); @@ -78,8 +78,8 @@ var WHITEBOARD_RACK_DEPTH = 1.9; var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser-2.fbx"; var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js"); -var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); -eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getFront(whiteboardRotation))); +var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(whiteboardRotation))); +eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getRight(whiteboardRotation))); var eraser = Entities.addEntity({ type: "Model", @@ -92,7 +92,7 @@ var eraser = Entities.addEntity({ y: 0.0393, z: 0.2083 }, - rotation: whiteboardRotation, + rotation: markerRotation, dynamic: true, gravity: { x: 0, From 1542b9da12841408836026160d2e18592d88bcf3 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 11:33:59 -0800 Subject: [PATCH 51/74] rotation works right now --- examples/homeContent/whiteboardV2/markerEntityScript.js | 6 +++--- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index e379fac016..fc4cbba1bd 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -24,7 +24,7 @@ _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; _this.strokeForwardOffset = 0.0001; - _this.STROKE_WIDTH = 0.003 + _this.STROKE_WIDTH = 0.03 _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; @@ -73,11 +73,11 @@ } var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - _this.whiteboardNormal = Quat.getRight(intersection.properties.rotation); + _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, - rotation: intersection.properties.rotation + // rotation: intersection.properties.rotation }) _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 8826c8387a..da9aad4c33 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -69,7 +69,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ }, position: whiteboardSurfacePosition, rotation: whiteboardRotation, - // visible: false, + visible: false, parentID: whiteboard }); @@ -166,7 +166,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, From 6e0ddb39189bf588d42ab4e27f1a1cc55b52cac2 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 11:48:15 -0800 Subject: [PATCH 52/74] really fixed rotation --- examples/homeContent/whiteboardV2/markerEntityScript.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index fc4cbba1bd..064add57be 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -24,7 +24,7 @@ _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; _this.strokeForwardOffset = 0.0001; - _this.STROKE_WIDTH = 0.03 + _this.STROKE_WIDTH = 0.03; _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; @@ -72,12 +72,14 @@ direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); + if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); + var whiteboardRotation = Entities.getEntityProperties(intersection.entityID, "rotation").rotation; + _this.whiteboardNormal = Quat.getFront(whiteboardRotation); Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, - // rotation: intersection.properties.rotation + rotation: whiteboardRotation }) _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { From df3e26edd59fe8d3e93a610579e821054f5bb252 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 12:05:30 -0800 Subject: [PATCH 53/74] calligraphy --- .../whiteboardV2/markerEntityScript.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 064add57be..3943143185 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -24,7 +24,7 @@ _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; _this.strokeForwardOffset = 0.0001; - _this.STROKE_WIDTH = 0.03; + _this.STROKE_WIDTH_RANGE = {min: 0.002, max: 0.01}; _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; @@ -115,8 +115,6 @@ _this.linePoints = []; _this.normals = []; - _this.strokeWidths = []; - _this.strokes.push(_this.currentStroke); }, @@ -140,12 +138,20 @@ } _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); - this.strokeWidths.push(_this.STROKE_WIDTH); + + var strokeWidths = []; + for (var i = 0; i < _this.linePoints.length; i++) { + // Create a temp array of stroke widths for calligraphy effect - start and end should be less wide + var pointsFromCenter = Math.abs(_this.linePoints.length/2 - i); + print("EBL POINTS CENTER " + pointsFromCenter) + var pointWidth = map(pointsFromCenter, 0, this.linePoints.length/2, _this.STROKE_WIDTH_RANGE.max, this.STROKE_WIDTH_RANGE.min); + strokeWidths.push(pointWidth); + } Entities.editEntity(_this.currentStroke, { linePoints: _this.linePoints, normals: _this.normals, - strokeWidths: _this.strokeWidths + strokeWidths: strokeWidths }); if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { From ed9f279a6386823300279526e701a0f3b742bf02 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 12:12:27 -0800 Subject: [PATCH 54/74] moved whiteboard Surface up --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index da9aad4c33..f89789ab8b 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -53,14 +53,15 @@ var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { y: 0.45, z: 0.0 }); -whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(orientation))); +whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(whiteboardRotation))); +whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getFront(whiteboardRotation))); var whiteboardDrawingSurface = Entities.addEntity({ type: "Box", name: "hifi-whiteboardDrawingSurface", dimensions: { x: 1.82, y: 1.8, - z: 0.04 + z: 0.01 }, color: { red: 200, From e83c1f71a6059b1100fd94c63c145b0b762c4ebf Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 12:17:46 -0800 Subject: [PATCH 55/74] front and back --- .../whiteboardV2/whiteboardSpawner.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index f89789ab8b..f4f18a164d 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -54,8 +54,9 @@ var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { z: 0.0 }); whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(whiteboardRotation))); -whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getFront(whiteboardRotation))); -var whiteboardDrawingSurface = Entities.addEntity({ +var moveForwardDistance = 0.02; +whiteboardFrontSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-moveForwardDistance, Quat.getFront(whiteboardRotation))); +var whiteboardSurfaceSettings = { type: "Box", name: "hifi-whiteboardDrawingSurface", dimensions: { @@ -68,11 +69,18 @@ var whiteboardDrawingSurface = Entities.addEntity({ green: 10, blue: 200 }, - position: whiteboardSurfacePosition, + position: whiteboardFrontSurfacePosition, rotation: whiteboardRotation, visible: false, parentID: whiteboard -}); +} +var whiteboardFrontDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings); + + +whiteboardBackSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(moveForwardDistance, Quat.getFront(whiteboardRotation))); +whiteboardSurfaceSettings.position = whiteboardBackSurfacePosition; + +var whiteboardFrontDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings); var WHITEBOARD_RACK_DEPTH = 1.9; @@ -230,7 +238,8 @@ function createMarker(modelURL, markerPosition, markerColor) { function cleanup() { Entities.deleteEntity(whiteboard); - Entities.deleteEntity(whiteboardDrawingSurface); + Entities.deleteEntity(whiteboardFrontDrawingSurface); + Entities.deleteEntity(whiteboardBackDrawingSurface); Entities.deleteEntity(eraser); markers.forEach(function(marker) { Entities.deleteEntity(marker); From 48f03ba476e69a8f4b8a73d0ba3f6e25731ace8b Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 14:29:43 -0800 Subject: [PATCH 56/74] markers resetting --- .../whiteboardV2/markerEntityScript.js | 26 ++++++++++++++++--- .../whiteboardV2/whiteboardSpawner.js | 2 ++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 3943143185..de5d615dec 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -24,7 +24,10 @@ _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; _this.strokeForwardOffset = 0.0001; - _this.STROKE_WIDTH_RANGE = {min: 0.002, max: 0.01}; + _this.STROKE_WIDTH_RANGE = { + min: 0.002, + max: 0.01 + }; _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; @@ -32,6 +35,7 @@ _this.PAINTING_TRIGGER_THRESHOLD = 0.2; _this.STROKE_NAME = "hifi-marker-stroke"; _this.WHITEBOARD_SURFACE_NAME = "hifi-whiteboardDrawingSurface"; + _this.MARKER_RESET_WAIT_TIME = 3000; }; MarkerTip.prototype = { @@ -60,6 +64,20 @@ Overlays.editOverlay(_this.laserPointer, { visible: false }); + + // Once user releases marker, wait a bit then put marker back to its original position and rotation + Script.setTimeout(function() { + var userData = getEntityUserData(_this.entityID); + Entities.editEntity(_this.entityID, { + position: userData.originalPosition, + rotation: userData.originalRotation, + velocity: { + x: 0, + y: -0.01, + z: 0 + } + }); + }, _this.MARKER_RESET_WAIT_TIME); }, @@ -75,7 +93,7 @@ if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { var whiteboardRotation = Entities.getEntityProperties(intersection.entityID, "rotation").rotation; - _this.whiteboardNormal = Quat.getFront(whiteboardRotation); + _this.whiteboardNormal = Quat.getFront(whiteboardRotation); Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, @@ -142,9 +160,9 @@ var strokeWidths = []; for (var i = 0; i < _this.linePoints.length; i++) { // Create a temp array of stroke widths for calligraphy effect - start and end should be less wide - var pointsFromCenter = Math.abs(_this.linePoints.length/2 - i); + var pointsFromCenter = Math.abs(_this.linePoints.length / 2 - i); print("EBL POINTS CENTER " + pointsFromCenter) - var pointWidth = map(pointsFromCenter, 0, this.linePoints.length/2, _this.STROKE_WIDTH_RANGE.max, this.STROKE_WIDTH_RANGE.min); + var pointWidth = map(pointsFromCenter, 0, this.linePoints.length / 2, _this.STROKE_WIDTH_RANGE.max, this.STROKE_WIDTH_RANGE.min); strokeWidths.push(pointWidth); } diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index f4f18a164d..eb0886229a 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -202,6 +202,8 @@ function createMarker(modelURL, markerPosition, markerColor) { name: "marker", script: MARKER_SCRIPT_URL, userData: JSON.stringify({ + originalPosition: markerPosition, + originalRotation: markerRotation, markerColor: markerColor, wearable: { joints: { From d0752143dcaa16a2903b90e4da1339074b410259 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 14:49:48 -0800 Subject: [PATCH 57/74] markers and eraser reset to original positions after being dropped --- .../whiteboardV2/eraserEntityScript.js | 37 ++++++++++++++++--- .../whiteboardV2/markerEntityScript.js | 7 ++-- .../whiteboardV2/whiteboardSpawner.js | 9 +++-- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index 86e80659bf..9306c7a5ab 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -24,6 +24,7 @@ _this.ERASER_TRIGGER_THRESHOLD = 0.2; _this.STROKE_NAME = "hifi-marker-stroke"; _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.7; + _this.ERASER_RESET_WAIT_TIME = 3000; }; Eraser.prototype = { @@ -32,11 +33,15 @@ _this.equipped = true; _this.hand = params[0] == "left" ? 0 : 1; // We really only need to grab position of marker strokes once, and then just check to see if eraser comes near enough to those strokes - Overlays.editOverlay(_this.searchSphere, {visible: true}); + Overlays.editOverlay(_this.searchSphere, { + visible: true + }); }, continueEquip: function() { - _this.eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; - Overlays.editOverlay(_this.searchSphere, {position: _this.eraserPosition}); + _this.eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; + Overlays.editOverlay(_this.searchSphere, { + position: _this.eraserPosition + }); this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) { _this.continueHolding(); @@ -57,14 +62,36 @@ }, releaseEquip: function() { - Overlays.editOverlay(_this.searchSphere, {visible: false}); + Overlays.editOverlay(_this.searchSphere, { + visible: false + }); + + // Once user releases eraser, wait a bit then put marker back to its original position and rotation + Script.setTimeout(function() { + var userData = getEntityUserData(_this.entityID); + Entities.editEntity(_this.entityID, { + position: userData.originalPosition, + rotation: userData.originalRotation, + velocity: { + x: 0, + y: -0.01, + z: 0 + } + }); + }, _this.ERASER_RESET_WAIT_TIME); }, + + preload: function(entityID) { _this.entityID = entityID; _this.searchSphere = Overlays.addOverlay('sphere', { size: _this.ERASER_TO_STROKE_SEARCH_RADIUS, - color: {red: 200, green: 10, blue: 10}, + color: { + red: 200, + green: 10, + blue: 10 + }, alpha: 0.2, solid: true, visible: false diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index de5d615dec..64b906dda1 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -92,7 +92,8 @@ var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - var whiteboardRotation = Entities.getEntityProperties(intersection.entityID, "rotation").rotation; + _this.currentWhiteboard = intersection.entityID; + var whiteboardRotation = Entities.getEntityProperties(_this.currentWhiteboard, "rotation").rotation; _this.whiteboardNormal = Quat.getFront(whiteboardRotation); Overlays.editOverlay(_this.laserPointer, { visible: true, @@ -128,7 +129,8 @@ position: position, textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, - lifetime: 500 + lifetime: 500, + // parentID: _this.currentWhiteboard }); _this.linePoints = []; @@ -161,7 +163,6 @@ for (var i = 0; i < _this.linePoints.length; i++) { // Create a temp array of stroke widths for calligraphy effect - start and end should be less wide var pointsFromCenter = Math.abs(_this.linePoints.length / 2 - i); - print("EBL POINTS CENTER " + pointsFromCenter) var pointWidth = map(pointsFromCenter, 0, this.linePoints.length / 2, _this.STROKE_WIDTH_RANGE.max, this.STROKE_WIDTH_RANGE.min); strokeWidths.push(pointWidth); } diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index eb0886229a..32c207499a 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -80,15 +80,16 @@ var whiteboardFrontDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings whiteboardBackSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(moveForwardDistance, Quat.getFront(whiteboardRotation))); whiteboardSurfaceSettings.position = whiteboardBackSurfacePosition; -var whiteboardFrontDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings); +var whiteboardBackDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings); var WHITEBOARD_RACK_DEPTH = 1.9; var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser-2.fbx"; -var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js"); +var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js?v43"); var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(whiteboardRotation))); eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getRight(whiteboardRotation))); +var eraserRotation = markerRotation; var eraser = Entities.addEntity({ type: "Model", @@ -101,7 +102,7 @@ var eraser = Entities.addEntity({ y: 0.0393, z: 0.2083 }, - rotation: markerRotation, + rotation: eraserRotation, dynamic: true, gravity: { x: 0, @@ -114,6 +115,8 @@ var eraser = Entities.addEntity({ z: 0 }, userData: JSON.stringify({ + originalPosition: eraserPosition, + originalRotation: eraserRotation, wearable: { joints: { RightHand: [{ From 5762c33cfebb87b56bcacd172cc572759b995115 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 15:07:22 -0800 Subject: [PATCH 58/74] strokes are now parented to whiteboard surface --- .../homeContent/whiteboardV2/markerEntityScript.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 64b906dda1..d06d5cf8e9 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -107,7 +107,9 @@ _this.resetStroke(); } } else { - _this.resetStroke(); + if (_this.currentStroke) { + _this.resetStroke(); + } Overlays.editOverlay(_this.laserPointer, { visible: false @@ -130,7 +132,6 @@ textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, lifetime: 500, - // parentID: _this.currentWhiteboard }); _this.linePoints = []; @@ -174,13 +175,20 @@ }); if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { + Entities.editEntity(_this.currentStroke, { + parentID: _this.currentWhiteboard + }); _this.currentStroke = null; _this.oldPosition = position; } }, - resetStroke: function() { + + Entities.editEntity(_this.currentStroke, { + parentID: _this.currentWhiteboard + }); _this.currentStroke = null; + _this.oldPosition = null; }, From 8de4a5907861d689c450bfc4f5ab45d9bb57e917 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sun, 28 Feb 2016 13:06:49 -0800 Subject: [PATCH 59/74] add support for auto-hide reticle and seek lookat on auto-show of reticle --- examples/autoHideReticle.js | 70 ++++++++++++++++++++++ interface/src/ui/ApplicationCompositor.cpp | 26 ++++---- 2 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 examples/autoHideReticle.js diff --git a/examples/autoHideReticle.js b/examples/autoHideReticle.js new file mode 100644 index 0000000000..172dd9b9f7 --- /dev/null +++ b/examples/autoHideReticle.js @@ -0,0 +1,70 @@ +// autoHideReticle.js +// examples +// +// Created by Brad Hefta-Gaub on 2/23/16. +// Copyright 2016 High Fidelity, Inc. +// +// This script will auto-hide the reticle on inactivity... and then if it detects movement after being hidden +// it will automatically move the reticle to the look at position +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var MINIMUM_SEEK_DISTANCE = 0.01; +var NON_LINEAR_DIVISOR = 2; + +var lastMouseMove = Date.now(); +var HIDE_STATIC_MOUSE_AFTER = 5000; // 5 seconds +var seekToLookAt = false; + +Controller.mouseMoveEvent.connect(function(mouseEvent) { + lastMouseMove = Date.now(); + + // if the reticle is hidden, show it... + if (!Reticle.visible) { + Reticle.visible = true; + if (HMD.active) { + seekToLookAt = true; + } + } +}); + + + +Script.update.connect(function(deltaTime) { + + // if we're currently seeking the lookAt move the mouse toward the lookat + if (HMD.active && seekToLookAt) { + var lookAt2D = HMD.getHUDLookAtPosition2D(); + var currentReticlePosition = Reticle.position; + var distanceBetweenX = lookAt2D.x - Reticle.position.x; + var distanceBetweenY = lookAt2D.y - Reticle.position.y; + var moveX = distanceBetweenX / NON_LINEAR_DIVISOR; + var moveY = distanceBetweenY / NON_LINEAR_DIVISOR; + var newPosition = { x: Reticle.position.x + moveX, y: Reticle.position.y + moveY }; + var closeEnoughX = false; + var closeEnoughY = false; + if (moveX < MINIMUM_SEEK_DISTANCE) { + newPosition.x = lookAt2D.x; + closeEnoughX = true; + } + if (moveY < MINIMUM_SEEK_DISTANCE) { + newPosition.y = lookAt2D.y; + closeEnoughY = true; + } + if (closeEnoughX && closeEnoughY) { + seekToLookAt = false; + } + Reticle.position = newPosition; + } + + // if we haven't moved in a long period of time, hide the reticle + if (Reticle.visible) { + var now = Date.now(); + var timeSinceLastMouseMove = now - lastMouseMove; + if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) { + Reticle.visible = false; + } + } +}); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 59d794d7cb..e8e6a0a956 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -212,19 +212,21 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha)); //draw the mouse pointer - // Get the mouse coordinates and convert to NDC [-1, 1] - vec2 canvasSize = qApp->getCanvasSize(); // desktop, use actual canvas... - vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize); - // Invert the Y axis - mousePosition.y *= -1.0f; + if (getReticleVisible()) { + // Get the mouse coordinates and convert to NDC [-1, 1] + vec2 canvasSize = qApp->getCanvasSize(); // desktop, use actual canvas... + vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize); + // Invert the Y axis + mousePosition.y *= -1.0f; - Transform model; - model.setTranslation(vec3(mousePosition, 0)); - vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize; - model.setScale(vec3(mouseSize, 1.0f)); - batch.setModelTransform(model); - bindCursorTexture(batch); - geometryCache->renderUnitQuad(batch, vec4(1)); + Transform model; + model.setTranslation(vec3(mousePosition, 0)); + vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize; + model.setScale(vec3(mouseSize, 1.0f)); + batch.setModelTransform(model); + bindCursorTexture(batch); + geometryCache->renderUnitQuad(batch, vec4(1)); + } }); } From 4009f03c384a553dcb708941958f84df30da410f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 08:38:53 -0800 Subject: [PATCH 60/74] move autohide/show behavior to depthReticle, make it a default script --- examples/autoHideReticle.js | 70 ------------------------------------ examples/defaultScripts.js | 1 + examples/depthReticle.js | 71 ++++++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 71 deletions(-) delete mode 100644 examples/autoHideReticle.js diff --git a/examples/autoHideReticle.js b/examples/autoHideReticle.js deleted file mode 100644 index 172dd9b9f7..0000000000 --- a/examples/autoHideReticle.js +++ /dev/null @@ -1,70 +0,0 @@ -// autoHideReticle.js -// examples -// -// Created by Brad Hefta-Gaub on 2/23/16. -// Copyright 2016 High Fidelity, Inc. -// -// This script will auto-hide the reticle on inactivity... and then if it detects movement after being hidden -// it will automatically move the reticle to the look at position -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var MINIMUM_SEEK_DISTANCE = 0.01; -var NON_LINEAR_DIVISOR = 2; - -var lastMouseMove = Date.now(); -var HIDE_STATIC_MOUSE_AFTER = 5000; // 5 seconds -var seekToLookAt = false; - -Controller.mouseMoveEvent.connect(function(mouseEvent) { - lastMouseMove = Date.now(); - - // if the reticle is hidden, show it... - if (!Reticle.visible) { - Reticle.visible = true; - if (HMD.active) { - seekToLookAt = true; - } - } -}); - - - -Script.update.connect(function(deltaTime) { - - // if we're currently seeking the lookAt move the mouse toward the lookat - if (HMD.active && seekToLookAt) { - var lookAt2D = HMD.getHUDLookAtPosition2D(); - var currentReticlePosition = Reticle.position; - var distanceBetweenX = lookAt2D.x - Reticle.position.x; - var distanceBetweenY = lookAt2D.y - Reticle.position.y; - var moveX = distanceBetweenX / NON_LINEAR_DIVISOR; - var moveY = distanceBetweenY / NON_LINEAR_DIVISOR; - var newPosition = { x: Reticle.position.x + moveX, y: Reticle.position.y + moveY }; - var closeEnoughX = false; - var closeEnoughY = false; - if (moveX < MINIMUM_SEEK_DISTANCE) { - newPosition.x = lookAt2D.x; - closeEnoughX = true; - } - if (moveY < MINIMUM_SEEK_DISTANCE) { - newPosition.y = lookAt2D.y; - closeEnoughY = true; - } - if (closeEnoughX && closeEnoughY) { - seekToLookAt = false; - } - Reticle.position = newPosition; - } - - // if we haven't moved in a long period of time, hide the reticle - if (Reticle.visible) { - var now = Date.now(); - var timeSinceLastMouseMove = now - lastMouseMove; - if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) { - Reticle.visible = false; - } - } -}); diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 35af5f4eae..2c024c5bf0 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -22,3 +22,4 @@ Script.load("grab.js"); Script.load("directory.js"); Script.load("dialTone.js"); Script.load("attachedEntitiesManager.js"); +Script.load("depthReticle.js"); diff --git a/examples/depthReticle.js b/examples/depthReticle.js index 4b649f49b6..820125a3c7 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -5,6 +5,8 @@ // Copyright 2016 High Fidelity, Inc. // // When used in HMD, this script will make the reticle depth track to any clickable item in view. +// This script also handles auto-hiding the reticle after inactivity, as well as having the reticle +// seek the look at position upon waking up. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -17,8 +19,63 @@ var desiredDepth = APPARENT_2D_OVERLAY_DEPTH; var TIME_BETWEEN_DEPTH_CHECKS = 100; var MINIMUM_DEPTH_ADJUST = 0.01; var NON_LINEAR_DIVISOR = 2; +var MINIMUM_SEEK_DISTANCE = 0.01; -Script.update.connect(function(deltaTime) { +var lastMouseMove = Date.now(); +var HIDE_STATIC_MOUSE_AFTER = 3000; // 3 seconds +var shouldSeekToLookAt = false; + +Controller.mouseMoveEvent.connect(function(mouseEvent) { + lastMouseMove = Date.now(); + + // if the reticle is hidden, show it... + if (!Reticle.visible) { + Reticle.visible = true; + if (HMD.active) { + shouldSeekToLookAt = true; + } + } +}); + +function seekToLookAt() { + // if we're currently seeking the lookAt move the mouse toward the lookat + if (shouldSeekToLookAt) { + var lookAt2D = HMD.getHUDLookAtPosition2D(); + var currentReticlePosition = Reticle.position; + var distanceBetweenX = lookAt2D.x - Reticle.position.x; + var distanceBetweenY = lookAt2D.y - Reticle.position.y; + var moveX = distanceBetweenX / NON_LINEAR_DIVISOR; + var moveY = distanceBetweenY / NON_LINEAR_DIVISOR; + var newPosition = { x: Reticle.position.x + moveX, y: Reticle.position.y + moveY }; + var closeEnoughX = false; + var closeEnoughY = false; + if (moveX < MINIMUM_SEEK_DISTANCE) { + newPosition.x = lookAt2D.x; + closeEnoughX = true; + } + if (moveY < MINIMUM_SEEK_DISTANCE) { + newPosition.y = lookAt2D.y; + closeEnoughY = true; + } + if (closeEnoughX && closeEnoughY) { + shouldSeekToLookAt = false; + } + Reticle.position = newPosition; + } +} + +function autoHideReticle() { + // if we haven't moved in a long period of time, hide the reticle + if (Reticle.visible) { + var now = Date.now(); + var timeSinceLastMouseMove = now - lastMouseMove; + if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) { + Reticle.visible = false; + } + } +} + +function checkReticleDepth() { var now = Date.now(); var timeSinceLastDepthCheck = now - lastDepthCheckTime; if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) { @@ -56,6 +113,9 @@ Script.update.connect(function(deltaTime) { } } +} + +function moveToDesiredDepth() { // move the reticle toward the desired depth if (desiredDepth != Reticle.depth) { @@ -69,4 +129,13 @@ Script.update.connect(function(deltaTime) { Reticle.setDepth(newDepth); } +} + +Script.update.connect(function(deltaTime) { + autoHideReticle(); // auto hide reticle for desktop or HMD mode + if (HMD.active) { + seekToLookAt(); // handle moving the reticle toward the look at + checkReticleDepth(); // make sure reticle is at correct depth + moveToDesiredDepth(); // move the fade the reticle to the desired depth + } }); From a32452db8be85e56438500dd6cb4b1201a8e6abd Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 1 Mar 2016 10:41:43 +1300 Subject: [PATCH 61/74] Change Running Scripts reload, close, and tree buttons when pressed Provides visual feedback to user. --- interface/resources/qml/controls-uit/Table.qml | 6 ++++-- interface/resources/qml/controls-uit/Tree.qml | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/controls-uit/Table.qml b/interface/resources/qml/controls-uit/Table.qml index fc6c310612..de6950c07e 100644 --- a/interface/resources/qml/controls-uit/Table.qml +++ b/interface/resources/qml/controls-uit/Table.qml @@ -133,13 +133,14 @@ TableView { HiFiGlyphs { id: reloadButton text: hifi.glyphs.reloadSmall - color: parent.color + color: reloadButtonArea.pressed ? hifi.colors.white : parent.color anchors { top: parent.top right: stopButton.left verticalCenter: parent.verticalCenter } MouseArea { + id: reloadButtonArea anchors { fill: parent; margins: -2 } onClicked: reloadScript(model.url) } @@ -149,13 +150,14 @@ TableView { HiFiGlyphs { id: stopButton text: hifi.glyphs.closeSmall - color: parent.color + color: stopButtonArea.pressed ? hifi.colors.white : parent.color anchors { top: parent.top right: parent.right verticalCenter: parent.verticalCenter } MouseArea { + id: stopButtonArea anchors { fill: parent; margins: -2 } onClicked: stopScript(model.url) } diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index d100cdcd44..454218b116 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -56,14 +56,23 @@ TreeView { branchDelegate: HiFiGlyphs { text: styleData.isExpanded ? hifi.glyphs.disclosureCollapse : hifi.glyphs.disclosureExpand - size: hifi.fontSizes.tableText * 2.5 // tableText is in points; proportionately scale to pixels + size: hifi.fontSizes.tableText * 2.5 color: colorScheme == hifi.colorSchemes.light - ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) - : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) + ? (styleData.selected + ? hifi.colors.black + : (iconArea.pressed ? hifi.colors.white : hifi.colors.baseGrayHighlight)) + : (styleData.selected + ? hifi.colors.black + : (iconArea.pressed ? hifi.colors.white : hifi.colors.lightGrayText)) anchors { left: parent ? parent.left : undefined leftMargin: hifi.dimensions.tablePadding / 2 } + MouseArea { + id: iconArea + anchors.fill: parent + propagateComposedEvents: true + } } handle: Item { From dc4c4e8c945ff284919e04877d2ffaa5c8a31425 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 14:24:43 -0800 Subject: [PATCH 62/74] some tweaks to auto-hide --- examples/depthReticle.js | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/examples/depthReticle.js b/examples/depthReticle.js index 820125a3c7..14a5ba5ff3 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -22,11 +22,18 @@ var NON_LINEAR_DIVISOR = 2; var MINIMUM_SEEK_DISTANCE = 0.01; var lastMouseMove = Date.now(); +var lastMouseX = Reticle.position.x; +var lastMouseY = Reticle.position.y; var HIDE_STATIC_MOUSE_AFTER = 3000; // 3 seconds var shouldSeekToLookAt = false; +var fastMouseMoves = 0; +var averageMouseVelocity = 0; +var WEIGHTING = 1/20; // simple moving average over last 20 samples +var ONE_MINUS_WEIGHTING = 1 - WEIGHTING; +var AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO = 50; Controller.mouseMoveEvent.connect(function(mouseEvent) { - lastMouseMove = Date.now(); + var now = Date.now(); // if the reticle is hidden, show it... if (!Reticle.visible) { @@ -34,12 +41,30 @@ Controller.mouseMoveEvent.connect(function(mouseEvent) { if (HMD.active) { shouldSeekToLookAt = true; } + } else { + // even if the reticle is visible, if we're in HMD mode, and the person is moving their mouse quickly (shaking it) + // then they are probably looking for it, and we should move into seekToLookAt mode + if (HMD.active && !shouldSeekToLookAt) { + var dx = Reticle.position.x - lastMouseX; + var dy = Reticle.position.y - lastMouseY; + var dt = Math.max(1, (now - lastMouseMove)); // mSecs since last mouse move + var mouseMoveDistance = Math.sqrt((dx*dx) + (dy*dy)); + var mouseVelocity = mouseMoveDistance / dt; + averageMouseVelocity = (ONE_MINUS_WEIGHTING * averageMouseVelocity) + (WEIGHTING * mouseVelocity); + if (averageMouseVelocity > AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO) { + shouldSeekToLookAt = true; + } + } } + lastMouseMove = now; + lastMouseX = mouseEvent.x; + lastMouseY = mouseEvent.y; }); function seekToLookAt() { // if we're currently seeking the lookAt move the mouse toward the lookat if (shouldSeekToLookAt) { + averageMouseVelocity = 0; // reset this, these never count for movement... var lookAt2D = HMD.getHUDLookAtPosition2D(); var currentReticlePosition = Reticle.position; var distanceBetweenX = lookAt2D.x - Reticle.position.x; @@ -57,16 +82,17 @@ function seekToLookAt() { newPosition.y = lookAt2D.y; closeEnoughY = true; } + Reticle.position = newPosition; if (closeEnoughX && closeEnoughY) { shouldSeekToLookAt = false; } - Reticle.position = newPosition; } } function autoHideReticle() { - // if we haven't moved in a long period of time, hide the reticle - if (Reticle.visible) { + // if we haven't moved in a long period of time, and we're not pointing at some + // system overlay (like a window), then hide the reticle + if (Reticle.visible && !Reticle.pointingAtSystemOverlay) { var now = Date.now(); var timeSinceLastMouseMove = now - lastMouseMove; if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) { From 33fe2e9b36de111a215ea559ef28f70d1fa130b7 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Mon, 29 Feb 2016 16:11:08 -0800 Subject: [PATCH 63/74] Update markerEntityScript.js --- examples/homeContent/whiteboardV2/markerEntityScript.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index d06d5cf8e9..19907b283c 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -131,7 +131,7 @@ position: position, textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, - lifetime: 500, + lifetime: 5000, }); _this.linePoints = []; @@ -216,4 +216,4 @@ // entity scripts always need to return a newly constructed object of our type return new MarkerTip(); -}); \ No newline at end of file +}); From 2c3fdc995f70c9b0e4245d440dd89d629aaacbf1 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 20:23:06 -0800 Subject: [PATCH 64/74] Away improvements --- examples/away.js | 21 +++++++++--- interface/src/Application.cpp | 38 ++++++++++++++++++---- interface/src/Application.h | 7 ++++ interface/src/ui/ApplicationCompositor.cpp | 14 +++++++- interface/src/ui/ApplicationCompositor.h | 10 ++++++ 5 files changed, 78 insertions(+), 12 deletions(-) diff --git a/examples/away.js b/examples/away.js index 18a3fddfce..f22f9662a7 100644 --- a/examples/away.js +++ b/examples/away.js @@ -106,6 +106,12 @@ function goAway() { MyAvatar.setEnableMeshVisible(false); // just for our own display, without changing point of view playAwayAnimation(); // animation is still seen by others showOverlay(); + + // tell the Reticle, we want to stop capturing the mouse until we come back + Reticle.allowMouseCapture = false; + if (HMD.active) { + Reticle.visible = false; + } } function goActive() { if (!isAway) { @@ -119,13 +125,20 @@ function goActive() { MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting. stopAwayAnimation(); hideOverlay(); + + // tell the Reticle, we are ready to capture the mouse again and it should be visible + Reticle.allowMouseCapture = true; + Reticle.visible = true; + if (HMD.active) { + Reticle.position = HMD.getHUDLookAtPosition2D(); + } } function maybeGoActive(event) { if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it) return; } - if (!isAway && (event.text === '.')) { + if (!isAway && (event.text == 'ESC')) { goAway(); } else { goActive(); @@ -141,10 +154,8 @@ function maybeGoAway() { } } - // If the mouse has gone from captured, to non-captured state, - // then it likely means the person is still in the HMD, but has - // tabbed away from the application (meaning they don't have mouse - // control) and they likely want to go into an away state + // If the mouse has gone from captured, to non-captured state, then it likely means the person is still in the HMD, but + // tabbed away from the application (meaning they don't have mouse control) and they likely want to go into an away state if (Reticle.mouseCaptured !== wasMouseCaptured) { wasMouseCaptured = !wasMouseCaptured; if (!wasMouseCaptured) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21377fa945..15b1836173 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -661,15 +661,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _glWidget->setFocusPolicy(Qt::StrongFocus); _glWidget->setFocus(); + #ifdef Q_OS_MAC - // OSX doesn't seem to provide for hiding the cursor only on the GL widget - _window->setCursor(Qt::BlankCursor); + auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget #else - // On windows and linux, hiding the top level cursor also means it's invisible - // when hovering over the window menu, which is a pain, so only hide it for - // the GL surface - _glWidget->setCursor(Qt::BlankCursor); + // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the + // window menu, which is a pain, so only hide it for the GL surface + auto cursorTarget = _glWidget; #endif + cursorTarget->setCursor(Qt::BlankCursor); // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); @@ -981,6 +981,29 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _idleTimer->start(0); } + +void Application::checkChangeCursor() { + QMutexLocker locker(&_changeCursorLock); + if (_cursorNeedsChanging) { +#ifdef Q_OS_MAC + auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget +#else + // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the + // window menu, which is a pain, so only hide it for the GL surface + auto cursorTarget = _glWidget; +#endif + cursorTarget->setCursor(_desiredCursor); + + _cursorNeedsChanging = false; + } +} + +void Application::showCursor(const QCursor& cursor) { + QMutexLocker locker(&_changeCursorLock); + _desiredCursor = cursor; + _cursorNeedsChanging = true; +} + void Application::aboutToQuit() { emit beforeAboutToQuit(); @@ -2431,6 +2454,9 @@ void Application::idle(uint64_t now) { return; // bail early, nothing to do here. } + + checkChangeCursor(); + Stats::getInstance()->updateStats(); AvatarInputs::getInstance()->update(); diff --git a/interface/src/Application.h b/interface/src/Application.h index d205ce8041..b5a0894c3a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -120,6 +120,8 @@ public: QSize getDeviceSize() const; bool hasFocus() const; + void showCursor(const QCursor& cursor); + bool isThrottleRendering() const; Camera* getCamera() { return &_myCamera; } @@ -515,6 +517,11 @@ private: QTimer* _idleTimer { nullptr }; bool _fakedMouseEvent { false }; + + void checkChangeCursor(); + mutable QMutex _changeCursorLock { QMutex::Recursive }; + QCursor _desiredCursor{ Qt::BlankCursor }; + bool _cursorNeedsChanging { false }; }; #endif // hifi_Application_h diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 59d794d7cb..ff37d07e15 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -335,9 +335,21 @@ QPointF ApplicationCompositor::getMouseEventPosition(QMouseEvent* event) { bool ApplicationCompositor::shouldCaptureMouse() const { // if we're in HMD mode, and some window of ours is active, but we're not currently showing a popup menu - return qApp->isHMDMode() && QApplication::activeWindow() && !Menu::isSomeSubmenuShown(); + return _allowMouseCapture && qApp->isHMDMode() && QApplication::activeWindow() && !Menu::isSomeSubmenuShown(); } +void ApplicationCompositor::setAllowMouseCapture(bool capture) { + if (qApp->isHMDMode()) { + if (capture) { + qApp->showCursor(Qt::BlankCursor); + } else { + qApp->showCursor(Qt::ArrowCursor); + } + } + _allowMouseCapture = capture; +} + + void ApplicationCompositor::handleLeaveEvent() { if (shouldCaptureMouse()) { diff --git a/interface/src/ui/ApplicationCompositor.h b/interface/src/ui/ApplicationCompositor.h index 32835ace5a..324250deb1 100644 --- a/interface/src/ui/ApplicationCompositor.h +++ b/interface/src/ui/ApplicationCompositor.h @@ -106,6 +106,9 @@ public: bool shouldCaptureMouse() const; + bool getAllowMouseCapture() const { return _allowMouseCapture; } + void setAllowMouseCapture(bool capture); + /// if the reticle is pointing to a system overlay (a dialog box for example) then the function returns true otherwise false bool getReticleOverDesktop() const; void setReticleOverDesktop(bool value) { _isOverDesktop = value; } @@ -162,6 +165,8 @@ private: bool _reticleOverQml { false }; + bool _allowMouseCapture { true }; + ReticleInterface* _reticleInterface; }; @@ -173,12 +178,17 @@ class ReticleInterface : public QObject { Q_PROPERTY(float depth READ getDepth WRITE setDepth) Q_PROPERTY(glm::vec2 maximumPosition READ getMaximumPosition) Q_PROPERTY(bool mouseCaptured READ isMouseCaptured) + Q_PROPERTY(bool allowMouseCapture READ getAllowMouseCapture WRITE setAllowMouseCapture) Q_PROPERTY(bool pointingAtSystemOverlay READ isPointingAtSystemOverlay) public: ReticleInterface(ApplicationCompositor* outer) : QObject(outer), _compositor(outer) {} Q_INVOKABLE bool isMouseCaptured() { return _compositor->shouldCaptureMouse(); } + + Q_INVOKABLE bool getAllowMouseCapture() { return _compositor->getAllowMouseCapture(); } + Q_INVOKABLE void setAllowMouseCapture(bool value) { return _compositor->setAllowMouseCapture(value); } + Q_INVOKABLE bool isPointingAtSystemOverlay() { return !_compositor->getReticleOverDesktop(); } Q_INVOKABLE bool getVisible() { return _compositor->getReticleVisible(); } From 95c92f7a2793b47dc928120430cd6f8bec88ed24 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 20:35:25 -0800 Subject: [PATCH 65/74] tweak depthReticle to work better with away --- examples/depthReticle.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/depthReticle.js b/examples/depthReticle.js index 14a5ba5ff3..14215bff3d 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -35,8 +35,8 @@ var AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO = 50; Controller.mouseMoveEvent.connect(function(mouseEvent) { var now = Date.now(); - // if the reticle is hidden, show it... - if (!Reticle.visible) { + // if the reticle is hidden, and we're not in away mode... + if (!Reticle.visible && Reticle.allowMouseCapture) { Reticle.visible = true; if (HMD.active) { shouldSeekToLookAt = true; @@ -44,7 +44,7 @@ Controller.mouseMoveEvent.connect(function(mouseEvent) { } else { // even if the reticle is visible, if we're in HMD mode, and the person is moving their mouse quickly (shaking it) // then they are probably looking for it, and we should move into seekToLookAt mode - if (HMD.active && !shouldSeekToLookAt) { + if (HMD.active && !shouldSeekToLookAt && Reticle.allowMouseCapture) { var dx = Reticle.position.x - lastMouseX; var dy = Reticle.position.y - lastMouseY; var dt = Math.max(1, (now - lastMouseMove)); // mSecs since last mouse move From 501d23021ffef607d83e75c7c15916dfd2c90f21 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 20:53:18 -0800 Subject: [PATCH 66/74] slight improvement to Away to have the paused overlay follow your view in HMD --- examples/away.js | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/examples/away.js b/examples/away.js index f22f9662a7..9b84f46742 100644 --- a/examples/away.js +++ b/examples/away.js @@ -13,7 +13,9 @@ // // Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key. // See MAIN CONTROL, below, for what "paused" actually does. -var OVERLAY_RATIO = 1920 / 1080; +var OVERLAY_WIDTH = 1920; +var OVERLAY_HEIGHT = 1080; +var OVERLAY_RATIO = OVERLAY_WIDTH / OVERLAY_HEIGHT; var OVERLAY_DATA = { imageURL: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png", color: {red: 255, green: 255, blue: 255}, @@ -69,16 +71,25 @@ function showOverlay() { // Update for current screen size, keeping overlay proportions constant. screen = Controller.getViewportDimensions(), screenRatio = screen.x / screen.y; - if (screenRatio < OVERLAY_RATIO) { - properties.width = screen.x; - properties.height = screen.x / OVERLAY_RATIO; - properties.x = 0; - properties.y = (screen.y - properties.height) / 2; + + if (HMD.active) { + var lookAt = HMD.getHUDLookAtPosition2D(); + properties.width = OVERLAY_WIDTH; + properties.height = OVERLAY_HEIGHT; + properties.x = lookAt.x - OVERLAY_WIDTH / 2; + properties.y = lookAt.y - OVERLAY_HEIGHT / 2; } else { - properties.height = screen.y; - properties.width = screen.y * OVERLAY_RATIO; - properties.y = 0; - properties.x = (screen.x - properties.width) / 2; + if (screenRatio < OVERLAY_RATIO) { + properties.width = screen.x; + properties.height = screen.x / OVERLAY_RATIO; + properties.x = 0; + properties.y = (screen.y - properties.height) / 2; + } else { + properties.height = screen.y; + properties.width = screen.y * OVERLAY_RATIO; + properties.y = 0; + properties.x = (screen.x - properties.width) / 2; + } } Overlays.editOverlay(overlay, properties); } @@ -87,6 +98,17 @@ function hideOverlay() { } hideOverlay(); +function maybeMoveOverlay() { + if (HMD.active && isAway) { + var lookAt = HMD.getHUDLookAtPosition2D(); + var properties = {visible: true}; + properties.width = OVERLAY_WIDTH; + properties.height = OVERLAY_HEIGHT; + properties.x = lookAt.x - OVERLAY_WIDTH / 2; + properties.y = lookAt.y - OVERLAY_HEIGHT / 2; + Overlays.editOverlay(overlay, properties); + } +} // MAIN CONTROL var wasMuted, isAway; @@ -164,6 +186,8 @@ function maybeGoAway() { } } +Script.update.connect(maybeMoveOverlay); + Script.update.connect(maybeGoAway); Controller.mousePressEvent.connect(goActive); Controller.keyPressEvent.connect(maybeGoActive); From 52c38e56a493b0a1b02457808e19ca35ad7e4e8c Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 21:25:25 -0800 Subject: [PATCH 67/74] make the HMD away overlay 3d --- examples/away.js | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/examples/away.js b/examples/away.js index 9b84f46742..69d2f3fd12 100644 --- a/examples/away.js +++ b/examples/away.js @@ -22,6 +22,19 @@ var OVERLAY_DATA = { alpha: 1 }; +var OVERLAY_DATA_HMD = { + position: { x: 0, y: 0, z: 0}, + width: OVERLAY_WIDTH, + height: OVERLAY_HEIGHT, + url: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png", + color: {red: 255, green: 255, blue: 255}, + alpha: 1, + scale: 2, + isFacingAvatar: true, + drawInFront: true +}; + + // ANIMATION // We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect // using an animation graph with a state that we turn on and off through the animation var defined with that state. @@ -66,19 +79,17 @@ function stopAwayAnimation() { // OVERLAY var overlay = Overlays.addOverlay("image", OVERLAY_DATA); +var overlayHMD = Overlays.addOverlay("image3d", OVERLAY_DATA_HMD); function showOverlay() { - var properties = {visible: true}, - // Update for current screen size, keeping overlay proportions constant. - screen = Controller.getViewportDimensions(), - screenRatio = screen.x / screen.y; + var properties = {visible: true}; if (HMD.active) { - var lookAt = HMD.getHUDLookAtPosition2D(); - properties.width = OVERLAY_WIDTH; - properties.height = OVERLAY_HEIGHT; - properties.x = lookAt.x - OVERLAY_WIDTH / 2; - properties.y = lookAt.y - OVERLAY_HEIGHT / 2; + Overlays.editOverlay(overlayHMD, { visible: true, position : HMD.getHUDLookAtPosition3D() }); } else { + // Update for current screen size, keeping overlay proportions constant. + var screen = Controller.getViewportDimensions(), + screenRatio = screen.x / screen.y; + if (screenRatio < OVERLAY_RATIO) { properties.width = screen.x; properties.height = screen.x / OVERLAY_RATIO; @@ -90,23 +101,18 @@ function showOverlay() { properties.y = 0; properties.x = (screen.x - properties.width) / 2; } + Overlays.editOverlay(overlay, properties); } - Overlays.editOverlay(overlay, properties); } function hideOverlay() { Overlays.editOverlay(overlay, {visible: false}); + Overlays.editOverlay(overlayHMD, {visible: false}); } hideOverlay(); function maybeMoveOverlay() { if (HMD.active && isAway) { - var lookAt = HMD.getHUDLookAtPosition2D(); - var properties = {visible: true}; - properties.width = OVERLAY_WIDTH; - properties.height = OVERLAY_HEIGHT; - properties.x = lookAt.x - OVERLAY_WIDTH / 2; - properties.y = lookAt.y - OVERLAY_HEIGHT / 2; - Overlays.editOverlay(overlay, properties); + Overlays.editOverlay(overlayHMD, { position : HMD.getHUDLookAtPosition3D() }); } } From ba7b5c6e23529c540242a4c8377c3200c7883c2d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 1 Mar 2016 10:43:49 -0800 Subject: [PATCH 68/74] some improvements --- examples/away.js | 78 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/examples/away.js b/examples/away.js index 69d2f3fd12..8d561f2623 100644 --- a/examples/away.js +++ b/examples/away.js @@ -17,13 +17,16 @@ var OVERLAY_WIDTH = 1920; var OVERLAY_HEIGHT = 1080; var OVERLAY_RATIO = OVERLAY_WIDTH / OVERLAY_HEIGHT; var OVERLAY_DATA = { + width: OVERLAY_WIDTH, + height: OVERLAY_HEIGHT, imageURL: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png", color: {red: 255, green: 255, blue: 255}, alpha: 1 }; +var lastOverlayPosition = { x: 0, y: 0, z: 0}; var OVERLAY_DATA_HMD = { - position: { x: 0, y: 0, z: 0}, + position: lastOverlayPosition, width: OVERLAY_WIDTH, height: OVERLAY_HEIGHT, url: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png", @@ -31,10 +34,9 @@ var OVERLAY_DATA_HMD = { alpha: 1, scale: 2, isFacingAvatar: true, - drawInFront: true + drawInFront: true }; - // ANIMATION // We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect // using an animation graph with a state that we turn on and off through the animation var defined with that state. @@ -80,28 +82,39 @@ function stopAwayAnimation() { // OVERLAY var overlay = Overlays.addOverlay("image", OVERLAY_DATA); var overlayHMD = Overlays.addOverlay("image3d", OVERLAY_DATA_HMD); + +function moveCloserToCamera(positionAtHUD) { + // we don't actually want to render at the slerped look at... instead, we want to render + // slightly closer to the camera than that. + var MOVE_CLOSER_TO_CAMERA_BY = -0.25; + var cameraFront = Quat.getFront(Camera.orientation); + var closerToCamera = Vec3.multiply(cameraFront, MOVE_CLOSER_TO_CAMERA_BY); // slightly closer to camera + var slightlyCloserPosition = Vec3.sum(positionAtHUD, closerToCamera); + + return slightlyCloserPosition; +} + function showOverlay() { var properties = {visible: true}; if (HMD.active) { - Overlays.editOverlay(overlayHMD, { visible: true, position : HMD.getHUDLookAtPosition3D() }); - } else { - // Update for current screen size, keeping overlay proportions constant. - var screen = Controller.getViewportDimensions(), - screenRatio = screen.x / screen.y; + // make sure desktop version is hidden + Overlays.editOverlay(overlay, { visible: false }); - if (screenRatio < OVERLAY_RATIO) { - properties.width = screen.x; - properties.height = screen.x / OVERLAY_RATIO; - properties.x = 0; - properties.y = (screen.y - properties.height) / 2; - } else { - properties.height = screen.y; - properties.width = screen.y * OVERLAY_RATIO; - properties.y = 0; - properties.x = (screen.x - properties.width) / 2; - } - Overlays.editOverlay(overlay, properties); + lastOverlayPosition = HMD.getHUDLookAtPosition3D(); + var actualOverlayPositon = moveCloserToCamera(lastOverlayPosition); + Overlays.editOverlay(overlayHMD, { visible: true, position: actualOverlayPositon }); + } else { + // make sure HMD is hidden + Overlays.editOverlay(overlayHMD, { visible: false }); + + // Update for current screen size, keeping overlay proportions constant. + var screen = Controller.getViewportDimensions(); + + // keep the overlay it's natural size and always center it... + Overlays.editOverlay(overlay, { visible: true, + x: ((screen.x - OVERLAY_WIDTH) / 2), + y: ((screen.y - OVERLAY_HEIGHT) / 2) }); } } function hideOverlay() { @@ -111,8 +124,29 @@ function hideOverlay() { hideOverlay(); function maybeMoveOverlay() { - if (HMD.active && isAway) { - Overlays.editOverlay(overlayHMD, { position : HMD.getHUDLookAtPosition3D() }); + if (isAway) { + // if we switched from HMD to Desktop, make sure to hide our HUD overlay and show the + // desktop overlay + if (!HMD.active) { + showOverlay(); // this will also recenter appropriately + } + + if (HMD.active) { + // Note: instead of moving it directly to the lookAt, we will move it slightly toward the + // new look at. This will result in a more subtle slerp toward the look at and reduce jerkiness + var EASE_BY_RATIO = 0.1; + var lookAt = HMD.getHUDLookAtPosition3D(); + var lookAtChange = Vec3.subtract(lookAt, lastOverlayPosition); + var halfWayBetweenOldAndLookAt = Vec3.multiply(lookAtChange, EASE_BY_RATIO); + var newOverlayPosition = Vec3.sum(lastOverlayPosition, halfWayBetweenOldAndLookAt); + lastOverlayPosition = newOverlayPosition; + + var actualOverlayPositon = moveCloserToCamera(lastOverlayPosition); + Overlays.editOverlay(overlayHMD, { visible: true, position: actualOverlayPositon }); + + // make sure desktop version is hidden + Overlays.editOverlay(overlay, { visible: false }); + } } } From 2c1762526d3e859b3560db56491a48aec1316cdc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 25 Feb 2016 16:44:27 -0800 Subject: [PATCH 69/74] Move all resource requests to the same thread --- assignment-client/src/Agent.cpp | 18 ++----- interface/src/Application.cpp | 24 ++------- libraries/networking/src/AssetClient.cpp | 14 +++--- libraries/networking/src/AssetClient.h | 5 +- .../networking/src/AssetResourceRequest.h | 2 +- .../networking/src/FileResourceRequest.h | 2 +- .../networking/src/HTTPResourceRequest.cpp | 30 +++++++++--- .../networking/src/HTTPResourceRequest.h | 7 ++- libraries/networking/src/ResourceManager.cpp | 49 +++++++++++++++---- libraries/networking/src/ResourceManager.h | 7 +++ libraries/networking/src/ResourceRequest.cpp | 11 +++-- libraries/networking/src/ResourceRequest.h | 8 +-- 12 files changed, 106 insertions(+), 71 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 3ff7eafd6b..ccf296865a 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -55,14 +55,6 @@ Agent::Agent(ReceivedMessage& message) : { DependencyManager::get()->setPacketSender(&_entityEditSender); - auto assetClient = DependencyManager::set(); - - QThread* assetThread = new QThread; - assetThread->setObjectName("Asset Thread"); - assetClient->moveToThread(assetThread); - connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init); - assetThread->start(); - DependencyManager::registerInheritance(); DependencyManager::set(); @@ -81,6 +73,8 @@ Agent::Agent(ReceivedMessage& message) : { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); + + ResourceManager::init(); } void Agent::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { @@ -470,13 +464,9 @@ void Agent::aboutToFinish() { // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(nullptr); - - // cleanup the AssetClient thread - QThread* assetThread = DependencyManager::get()->thread(); - DependencyManager::destroy(); - assetThread->quit(); - assetThread->wait(); // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); + + ResourceManager::cleanup(); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 15b1836173..8e2b2175fe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -370,7 +370,6 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -528,13 +527,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : audioThread->start(); - // Setup AssetClient - auto assetClient = DependencyManager::get(); - QThread* assetThread = new QThread; - assetThread->setObjectName("Asset Thread"); - assetClient->moveToThread(assetThread); - connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init); - assetThread->start(); + ResourceManager::init(); // Setup MessagesClient auto messagesClient = DependencyManager::get(); @@ -644,13 +637,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(&identityPacketTimer, &QTimer::timeout, getMyAvatar(), &MyAvatar::sendIdentityPacket); identityPacketTimer.start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); - QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkDiskCache* cache = new QNetworkDiskCache(); - cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE); - cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); - networkAccessManager.setCache(cache); - ResourceCache::setRequestLimit(3); _glWidget = new GLCanvas(); @@ -1129,12 +1115,6 @@ Application::~Application() { DependencyManager::destroy(); DependencyManager::destroy(); - // cleanup the AssetClient thread - QThread* assetThread = DependencyManager::get()->thread(); - DependencyManager::destroy(); - assetThread->quit(); - assetThread->wait(); - QThread* nodeThread = DependencyManager::get()->thread(); // remove the NodeList from the DependencyManager @@ -1150,6 +1130,8 @@ Application::~Application() { ConnexionClient::getInstance().destroy(); #endif + ResourceManager::cleanup(); + qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages } diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 4e7e7f24ba..203d4d9ba6 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -47,22 +47,20 @@ AssetClient::AssetClient() { } void AssetClient::init() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "init", Qt::BlockingQueuedConnection); - } - + Q_ASSERT(QThread::currentThread() == thread()); + // Setup disk cache if not already - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + auto& networkAccessManager = NetworkAccessManager::getInstance(); if (!networkAccessManager.cache()) { QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); cachePath = !cachePath.isEmpty() ? cachePath : "interfaceCache"; - + QNetworkDiskCache* cache = new QNetworkDiskCache(); cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE); cache->setCacheDirectory(cachePath); networkAccessManager.setCache(cache); - qCDebug(asset_client) << "AssetClient disk cache setup at" << cachePath - << "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)"; + qDebug() << "ResourceManager disk cache setup at" << cachePath + << "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)"; } } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 58790ef926..67ce4daa8f 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -43,13 +43,14 @@ class AssetClient : public QObject, public Dependency { Q_OBJECT public: AssetClient(); - - Q_INVOKABLE void init(); Q_INVOKABLE AssetRequest* createRequest(const QString& hash, const QString& extension); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); +public slots: + void init(); + private slots: void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode); diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index 0024426be0..4d2ea56ca4 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -20,7 +20,7 @@ class AssetResourceRequest : public ResourceRequest { Q_OBJECT public: - AssetResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + AssetResourceRequest(const QUrl& url) : ResourceRequest(url) { } ~AssetResourceRequest(); protected: diff --git a/libraries/networking/src/FileResourceRequest.h b/libraries/networking/src/FileResourceRequest.h index 4ff0d2ecf2..547b754cb5 100644 --- a/libraries/networking/src/FileResourceRequest.h +++ b/libraries/networking/src/FileResourceRequest.h @@ -19,7 +19,7 @@ class FileResourceRequest : public ResourceRequest { Q_OBJECT public: - FileResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + FileResourceRequest(const QUrl& url) : ResourceRequest(url) { } protected: virtual void doSend() override; diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index 34c9c1dad2..11ab436933 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -28,6 +28,25 @@ HTTPResourceRequest::~HTTPResourceRequest() { } } +void HTTPResourceRequest::setupTimer() { + Q_ASSERT(!_sendTimer); + static const int TIMEOUT_MS = 10000; + + _sendTimer = new QTimer(); + connect(this, &QObject::destroyed, _sendTimer, &QTimer::deleteLater); + connect(_sendTimer, &QTimer::timeout, this, &HTTPResourceRequest::onTimeout); + + _sendTimer->setSingleShot(true); + _sendTimer->start(TIMEOUT_MS); +} + +void HTTPResourceRequest::cleanupTimer() { + Q_ASSERT(_sendTimer); + _sendTimer->disconnect(this); + _sendTimer->deleteLater(); + _sendTimer = nullptr; +} + void HTTPResourceRequest::doSend() { QNetworkRequest networkRequest(_url); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); @@ -42,18 +61,15 @@ void HTTPResourceRequest::doSend() { connect(_reply, &QNetworkReply::finished, this, &HTTPResourceRequest::onRequestFinished); connect(_reply, &QNetworkReply::downloadProgress, this, &HTTPResourceRequest::onDownloadProgress); - connect(&_sendTimer, &QTimer::timeout, this, &HTTPResourceRequest::onTimeout); - static const int TIMEOUT_MS = 10000; - _sendTimer.setSingleShot(true); - _sendTimer.start(TIMEOUT_MS); + setupTimer(); } void HTTPResourceRequest::onRequestFinished() { Q_ASSERT(_state == InProgress); Q_ASSERT(_reply); - _sendTimer.stop(); + cleanupTimer(); switch(_reply->error()) { case QNetworkReply::NoError: @@ -80,7 +96,7 @@ void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesT Q_ASSERT(_state == InProgress); // We've received data, so reset the timer - _sendTimer.start(); + _sendTimer->start(); emit progress(bytesReceived, bytesTotal); } @@ -91,6 +107,8 @@ void HTTPResourceRequest::onTimeout() { _reply->abort(); _reply->deleteLater(); _reply = nullptr; + + cleanupTimer(); _result = Timeout; _state = Finished; diff --git a/libraries/networking/src/HTTPResourceRequest.h b/libraries/networking/src/HTTPResourceRequest.h index f0d3bb82d9..cc628d8855 100644 --- a/libraries/networking/src/HTTPResourceRequest.h +++ b/libraries/networking/src/HTTPResourceRequest.h @@ -21,7 +21,7 @@ class HTTPResourceRequest : public ResourceRequest { Q_OBJECT public: - HTTPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + HTTPResourceRequest(const QUrl& url) : ResourceRequest(url) { } ~HTTPResourceRequest(); protected: @@ -33,7 +33,10 @@ private slots: void onRequestFinished(); private: - QTimer _sendTimer; + void setupTimer(); + void cleanupTimer(); + + QTimer* _sendTimer { nullptr }; QNetworkReply* _reply { nullptr }; }; diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index f195011290..1d41266f3a 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -11,12 +11,20 @@ #include "ResourceManager.h" -#include "AssetResourceRequest.h" -#include "FileResourceRequest.h" -#include "HTTPResourceRequest.h" +#include +#include +#include #include + +#include "AssetResourceRequest.h" +#include "FileResourceRequest.h" +#include "HTTPResourceRequest.h" +#include "NetworkAccessManager.h" + + +QThread ResourceManager::_thread; ResourceManager::PrefixMap ResourceManager::_prefixMap; QMutex ResourceManager::_prefixMapLock; @@ -67,18 +75,41 @@ QUrl ResourceManager::normalizeURL(const QUrl& originalUrl) { return url; } +void ResourceManager::init() { + _thread.setObjectName("Ressource Manager Thread"); + + auto assetClient = DependencyManager::set(); + assetClient->moveToThread(&_thread); + QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::init); + + _thread.start(); +} + +void ResourceManager::cleanup() { + // cleanup the AssetClient thread + DependencyManager::destroy(); + _thread.quit(); + _thread.wait(); +} + ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const QUrl& url) { auto normalizedURL = normalizeURL(url); auto scheme = normalizedURL.scheme(); + + ResourceRequest* request = nullptr; + if (scheme == URL_SCHEME_FILE) { - return new FileResourceRequest(parent, normalizedURL); + request = new FileResourceRequest(normalizedURL); } else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) { - return new HTTPResourceRequest(parent, normalizedURL); + request = new HTTPResourceRequest(normalizedURL); } else if (scheme == URL_SCHEME_ATP) { - return new AssetResourceRequest(parent, normalizedURL); + request = new AssetResourceRequest(normalizedURL); + } else { + qDebug() << "Unknown scheme (" << scheme << ") for URL: " << url.url(); + return nullptr; } + Q_ASSERT(request); - qDebug() << "Unknown scheme (" << scheme << ") for URL: " << url.url(); - - return nullptr; + request->moveToThread(&_thread); + return request; } diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h index c010c67f9b..162892abaf 100644 --- a/libraries/networking/src/ResourceManager.h +++ b/libraries/networking/src/ResourceManager.h @@ -29,8 +29,15 @@ public: static void setUrlPrefixOverride(const QString& prefix, const QString& replacement); static QString normalizeURL(const QString& urlString); static QUrl normalizeURL(const QUrl& url); + static ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url); + + static void init(); + static void cleanup(); + private: + static QThread _thread; + using PrefixMap = std::map; static PrefixMap _prefixMap; diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp index c6880636ea..e6402d6b25 100644 --- a/libraries/networking/src/ResourceRequest.cpp +++ b/libraries/networking/src/ResourceRequest.cpp @@ -11,12 +11,15 @@ #include "ResourceRequest.h" -ResourceRequest::ResourceRequest(QObject* parent, const QUrl& url) : - QObject(parent), - _url(url) { -} +#include + +ResourceRequest::ResourceRequest(const QUrl& url) : _url(url) { } void ResourceRequest::send() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection); + return; + } Q_ASSERT(_state == NotStarted); _state = InProgress; diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index b229951a49..f940221d9d 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -20,7 +20,7 @@ class ResourceRequest : public QObject { Q_OBJECT public: - ResourceRequest(QObject* parent, const QUrl& url); + ResourceRequest(const QUrl& url); enum State { NotStarted = 0, @@ -38,7 +38,6 @@ public: NotFound }; - void send(); QByteArray getData() { return _data; } State getState() const { return _state; } Result getResult() const { return _result; } @@ -47,8 +46,11 @@ public: void setCacheEnabled(bool value) { _cacheEnabled = value; } +public slots: + void send(); + signals: - void progress(uint64_t bytesReceived, uint64_t bytesTotal); + void progress(qint64 bytesReceived, qint64 bytesTotal); void finished(); protected: From 40d307a37b4e15be29fa94153e8bf12ce2ebc4ea Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 26 Feb 2016 10:37:19 -0800 Subject: [PATCH 70/74] Temporary fix to disk cache editor crash --- interface/src/Application.cpp | 6 ++---- interface/src/ui/DiskCacheEditor.cpp | 8 ++++---- libraries/networking/src/AssetClient.cpp | 9 +++++++++ libraries/networking/src/AssetClient.h | 1 + 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8e2b2175fe..36c882647f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1072,10 +1072,8 @@ void Application::cleanupBeforeQuit() { } void Application::emptyLocalCache() { - if (auto cache = NetworkAccessManager::getInstance().cache()) { - qDebug() << "DiskCacheEditor::clear(): Clearing disk cache."; - cache->clear(); - } + auto assetClient = DependencyManager::get(); + QMetaObject::invokeMethod(assetClient.data(), "clearCache", Qt::QueuedConnection); } Application::~Application() { diff --git a/interface/src/ui/DiskCacheEditor.cpp b/interface/src/ui/DiskCacheEditor.cpp index d3a40e6439..e2f64d8817 100644 --- a/interface/src/ui/DiskCacheEditor.cpp +++ b/interface/src/ui/DiskCacheEditor.cpp @@ -122,6 +122,7 @@ void DiskCacheEditor::refresh() { } return QString("%0 %1").arg(number).arg(UNITS[i]); }; + return; QNetworkDiskCache* cache = qobject_cast(NetworkAccessManager::getInstance().cache()); if (_path) { @@ -135,6 +136,7 @@ void DiskCacheEditor::refresh() { } } +#include void DiskCacheEditor::clear() { QMessageBox::StandardButton buttonClicked = OffscreenUi::question(_dialog, "Clearing disk cache", @@ -142,10 +144,8 @@ void DiskCacheEditor::clear() { "are you sure you want to do that?", QMessageBox::Ok | QMessageBox::Cancel); if (buttonClicked == QMessageBox::Ok) { - if (auto cache = NetworkAccessManager::getInstance().cache()) { - qDebug() << "DiskCacheEditor::clear(): Clearing disk cache."; - cache->clear(); - } + auto assetClient = DependencyManager::get(); + QMetaObject::invokeMethod(assetClient.data() , "clearCache", Qt::QueuedConnection); } refresh(); } diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 203d4d9ba6..28fb31fdfd 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -64,6 +64,15 @@ void AssetClient::init() { } } +void AssetClient::clearCache() { + Q_ASSERT(QThread::currentThread() == thread()); + + if (auto cache = NetworkAccessManager::getInstance().cache()) { + qDebug() << "AssetClient::clearCache(): Clearing disk cache."; + cache->clear(); + } +} + bool haveAssetServer() { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 67ce4daa8f..93b54d6df3 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -50,6 +50,7 @@ public: public slots: void init(); + void clearCache(); private slots: void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); From 6a4b93a4e7d4af8ae081375042ce0e7109d3c725 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 26 Feb 2016 11:22:28 -0800 Subject: [PATCH 71/74] Proper fix for DiskCacheInfo --- assignment-client/src/Agent.cpp | 8 ++-- interface/src/Application.cpp | 4 +- interface/src/ui/DiskCacheEditor.cpp | 54 +++++++++++------------- interface/src/ui/DiskCacheEditor.h | 3 ++ libraries/networking/src/AssetClient.cpp | 16 +++++++ libraries/networking/src/AssetClient.h | 2 + 6 files changed, 52 insertions(+), 35 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index ccf296865a..1955b8f0c8 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -55,6 +55,8 @@ Agent::Agent(ReceivedMessage& message) : { DependencyManager::get()->setPacketSender(&_entityEditSender); + ResourceManager::init(); + DependencyManager::registerInheritance(); DependencyManager::set(); @@ -73,8 +75,6 @@ Agent::Agent(ReceivedMessage& message) : { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); - - ResourceManager::init(); } void Agent::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { @@ -464,9 +464,9 @@ void Agent::aboutToFinish() { // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(nullptr); + + ResourceManager::cleanup(); // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); - - ResourceManager::cleanup(); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 36c882647f..bc98245f32 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1113,6 +1113,8 @@ Application::~Application() { DependencyManager::destroy(); DependencyManager::destroy(); + ResourceManager::cleanup(); + QThread* nodeThread = DependencyManager::get()->thread(); // remove the NodeList from the DependencyManager @@ -1128,8 +1130,6 @@ Application::~Application() { ConnexionClient::getInstance().destroy(); #endif - ResourceManager::cleanup(); - qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages } diff --git a/interface/src/ui/DiskCacheEditor.cpp b/interface/src/ui/DiskCacheEditor.cpp index e2f64d8817..a098616e0b 100644 --- a/interface/src/ui/DiskCacheEditor.cpp +++ b/interface/src/ui/DiskCacheEditor.cpp @@ -9,23 +9,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include "DiskCacheEditor.h" #include #include #include #include #include -#include +#include #include -#include +#include -#include "DiskCacheEditor.h" #include "OffscreenUi.h" DiskCacheEditor::DiskCacheEditor(QWidget* parent) : QObject(parent) { - } QWindow* DiskCacheEditor::windowHandle() { @@ -33,7 +31,6 @@ QWindow* DiskCacheEditor::windowHandle() { } void DiskCacheEditor::toggle() { - qDebug() << "DiskCacheEditor::toggle()"; if (!_dialog) { makeDialog(); } @@ -88,17 +85,15 @@ void DiskCacheEditor::makeDialog() { Q_CHECK_PTR(_maxSize); _maxSize->setAlignment(Qt::AlignLeft); layout->addWidget(_maxSize, 2, 1, 1, 3); - + refresh(); - - - QPushButton* refreshCacheButton = new QPushButton(_dialog); - Q_CHECK_PTR(refreshCacheButton); - refreshCacheButton->setText("Refresh"); - refreshCacheButton->setToolTip("Reload the cache stats."); - connect(refreshCacheButton, SIGNAL(clicked()), SLOT(refresh())); - layout->addWidget(refreshCacheButton, 3, 2); - + + _refreshTimer = new QTimer(_dialog); + _refreshTimer->setInterval(100); + _refreshTimer->setSingleShot(false); + QObject::connect(_refreshTimer, &QTimer::timeout, this, &DiskCacheEditor::refresh); + _refreshTimer->start(); + QPushButton* clearCacheButton = new QPushButton(_dialog); Q_CHECK_PTR(clearCacheButton); clearCacheButton->setText("Clear"); @@ -108,7 +103,13 @@ void DiskCacheEditor::makeDialog() { } void DiskCacheEditor::refresh() { - static const std::function stringify = [](qint64 number) { + auto assetClient = DependencyManager::get(); + QMetaObject::invokeMethod(assetClient.data() , "cacheInfoRequest", Qt::QueuedConnection, + Q_ARG(QObject*, this), Q_ARG(QString, "update")); +} + +void DiskCacheEditor::update(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize) { + static const auto stringify = [](qint64 number) { static const QStringList UNITS = QStringList() << "B" << "KB" << "MB" << "GB"; static const qint64 CHUNK = 1024; QString unit; @@ -122,30 +123,25 @@ void DiskCacheEditor::refresh() { } return QString("%0 %1").arg(number).arg(UNITS[i]); }; - return; - QNetworkDiskCache* cache = qobject_cast(NetworkAccessManager::getInstance().cache()); if (_path) { - _path->setText(cache->cacheDirectory()); + _path->setText(cacheDirectory); } if (_size) { - _size->setText(stringify(cache->cacheSize())); + _size->setText(stringify(cacheSize)); } if (_maxSize) { - _maxSize->setText(stringify(cache->maximumCacheSize())); + _maxSize->setText(stringify(maximumCacheSize)); } } -#include void DiskCacheEditor::clear() { - QMessageBox::StandardButton buttonClicked = - OffscreenUi::question(_dialog, "Clearing disk cache", - "You are about to erase all the content of the disk cache, " - "are you sure you want to do that?", - QMessageBox::Ok | QMessageBox::Cancel); + auto buttonClicked = OffscreenUi::question(_dialog, "Clearing disk cache", + "You are about to erase all the content of the disk cache, " + "are you sure you want to do that?", + QMessageBox::Ok | QMessageBox::Cancel); if (buttonClicked == QMessageBox::Ok) { auto assetClient = DependencyManager::get(); QMetaObject::invokeMethod(assetClient.data() , "clearCache", Qt::QueuedConnection); } - refresh(); } diff --git a/interface/src/ui/DiskCacheEditor.h b/interface/src/ui/DiskCacheEditor.h index 5d673c4285..8d1b84fa8d 100644 --- a/interface/src/ui/DiskCacheEditor.h +++ b/interface/src/ui/DiskCacheEditor.h @@ -18,6 +18,7 @@ class QDialog; class QLabel; class QWindow; +class QTimer; class DiskCacheEditor : public QObject { Q_OBJECT @@ -32,6 +33,7 @@ public slots: private slots: void refresh(); + void update(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize); void clear(); private: @@ -41,6 +43,7 @@ private: QPointer _path; QPointer _size; QPointer _maxSize; + QPointer _refreshTimer; }; #endif // hifi_DiskCacheEditor_h \ No newline at end of file diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 28fb31fdfd..66b89f78a3 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -64,12 +64,28 @@ void AssetClient::init() { } } + +void AssetClient::cacheInfoRequest(QObject* reciever, QString slot) { + Q_ASSERT(QThread::currentThread() == thread()); + + if (auto* cache = qobject_cast(NetworkAccessManager::getInstance().cache())) { + QMetaObject::invokeMethod(reciever, slot.toStdString().data(), Qt::QueuedConnection, + Q_ARG(QString, cache->cacheDirectory()), + Q_ARG(qint64, cache->cacheSize()), + Q_ARG(qint64, cache->maximumCacheSize())); + } else { + qCWarning(asset_client) << "No disk cache to get info from."; + } +} + void AssetClient::clearCache() { Q_ASSERT(QThread::currentThread() == thread()); if (auto cache = NetworkAccessManager::getInstance().cache()) { qDebug() << "AssetClient::clearCache(): Clearing disk cache."; cache->clear(); + } else { + qCWarning(asset_client) << "No disk cache to clear."; } } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 93b54d6df3..f66fe8adcc 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -50,6 +50,8 @@ public: public slots: void init(); + + void cacheInfoRequest(QObject* reciever, QString slot); void clearCache(); private slots: From f0ccada945afcacafc755666f7a5b1160f2b5cdf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 26 Feb 2016 15:51:32 -0800 Subject: [PATCH 72/74] Fix for Ubuntu --- interface/src/ui/DiskCacheEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/DiskCacheEditor.cpp b/interface/src/ui/DiskCacheEditor.cpp index a098616e0b..0ec7e79191 100644 --- a/interface/src/ui/DiskCacheEditor.cpp +++ b/interface/src/ui/DiskCacheEditor.cpp @@ -91,7 +91,7 @@ void DiskCacheEditor::makeDialog() { _refreshTimer = new QTimer(_dialog); _refreshTimer->setInterval(100); _refreshTimer->setSingleShot(false); - QObject::connect(_refreshTimer, &QTimer::timeout, this, &DiskCacheEditor::refresh); + QObject::connect(_refreshTimer.data(), &QTimer::timeout, this, &DiskCacheEditor::refresh); _refreshTimer->start(); QPushButton* clearCacheButton = new QPushButton(_dialog); From 4944d0a8d0205c093bd65b9bcd325f96f318e6fc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 26 Feb 2016 16:06:57 -0800 Subject: [PATCH 73/74] Handle threading inside AssetServer --- interface/src/Application.cpp | 7 +------ interface/src/Application.h | 2 -- interface/src/ui/DiskCacheEditor.cpp | 9 +++------ interface/src/ui/DiskCacheEditor.h | 4 ++-- libraries/networking/src/AssetClient.cpp | 12 ++++++++++-- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bc98245f32..bc04e111b0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1071,11 +1071,6 @@ void Application::cleanupBeforeQuit() { DependencyManager::destroy(); } -void Application::emptyLocalCache() { - auto assetClient = DependencyManager::get(); - QMetaObject::invokeMethod(assetClient.data(), "clearCache", Qt::QueuedConnection); -} - Application::~Application() { EntityTreePointer tree = getEntities()->getTree(); tree->setSimulation(NULL); @@ -3061,7 +3056,7 @@ void Application::reloadResourceCaches() { _viewFrustum.setOrientation(glm::quat()); queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions); - emptyLocalCache(); + DependencyManager::get()->clearCache(); DependencyManager::get()->refreshAll(); DependencyManager::get()->refreshAll(); diff --git a/interface/src/Application.h b/interface/src/Application.h index b5a0894c3a..7c92331d43 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -330,8 +330,6 @@ private: void cleanupBeforeQuit(); - void emptyLocalCache(); - void update(float deltaTime); void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue); diff --git a/interface/src/ui/DiskCacheEditor.cpp b/interface/src/ui/DiskCacheEditor.cpp index 0ec7e79191..f2720df22a 100644 --- a/interface/src/ui/DiskCacheEditor.cpp +++ b/interface/src/ui/DiskCacheEditor.cpp @@ -103,12 +103,10 @@ void DiskCacheEditor::makeDialog() { } void DiskCacheEditor::refresh() { - auto assetClient = DependencyManager::get(); - QMetaObject::invokeMethod(assetClient.data() , "cacheInfoRequest", Qt::QueuedConnection, - Q_ARG(QObject*, this), Q_ARG(QString, "update")); + DependencyManager::get()->cacheInfoRequest(this, "cacheInfoCallback"); } -void DiskCacheEditor::update(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize) { +void DiskCacheEditor::cacheInfoCallback(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize) { static const auto stringify = [](qint64 number) { static const QStringList UNITS = QStringList() << "B" << "KB" << "MB" << "GB"; static const qint64 CHUNK = 1024; @@ -141,7 +139,6 @@ void DiskCacheEditor::clear() { "are you sure you want to do that?", QMessageBox::Ok | QMessageBox::Cancel); if (buttonClicked == QMessageBox::Ok) { - auto assetClient = DependencyManager::get(); - QMetaObject::invokeMethod(assetClient.data() , "clearCache", Qt::QueuedConnection); + DependencyManager::get()->clearCache(); } } diff --git a/interface/src/ui/DiskCacheEditor.h b/interface/src/ui/DiskCacheEditor.h index 8d1b84fa8d..3f8fa1a883 100644 --- a/interface/src/ui/DiskCacheEditor.h +++ b/interface/src/ui/DiskCacheEditor.h @@ -33,9 +33,9 @@ public slots: private slots: void refresh(); - void update(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize); + void cacheInfoCallback(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize); void clear(); - + private: void makeDialog(); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 66b89f78a3..e70863f0b6 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -66,7 +66,12 @@ void AssetClient::init() { void AssetClient::cacheInfoRequest(QObject* reciever, QString slot) { - Q_ASSERT(QThread::currentThread() == thread()); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "cacheInfoRequest", Qt::QueuedConnection, + Q_ARG(QObject*, reciever), Q_ARG(QString, slot)); + return; + } + if (auto* cache = qobject_cast(NetworkAccessManager::getInstance().cache())) { QMetaObject::invokeMethod(reciever, slot.toStdString().data(), Qt::QueuedConnection, @@ -79,7 +84,10 @@ void AssetClient::cacheInfoRequest(QObject* reciever, QString slot) { } void AssetClient::clearCache() { - Q_ASSERT(QThread::currentThread() == thread()); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "clearCache", Qt::QueuedConnection); + return; + } if (auto cache = NetworkAccessManager::getInstance().cache()) { qDebug() << "AssetClient::clearCache(): Clearing disk cache."; From 14ae35e741a17d7f4998810f03fe068edc7c61fe Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Mar 2016 12:00:23 -0800 Subject: [PATCH 74/74] CR --- interface/src/ui/DiskCacheEditor.cpp | 4 +++- libraries/networking/src/AssetClient.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/DiskCacheEditor.cpp b/interface/src/ui/DiskCacheEditor.cpp index f2720df22a..ed85b87d63 100644 --- a/interface/src/ui/DiskCacheEditor.cpp +++ b/interface/src/ui/DiskCacheEditor.cpp @@ -88,8 +88,10 @@ void DiskCacheEditor::makeDialog() { refresh(); + + static const int REFRESH_INTERVAL = 100; // msec _refreshTimer = new QTimer(_dialog); - _refreshTimer->setInterval(100); + _refreshTimer->setInterval(REFRESH_INTERVAL); _refreshTimer->setSingleShot(false); QObject::connect(_refreshTimer.data(), &QTimer::timeout, this, &DiskCacheEditor::refresh); _refreshTimer->start(); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index e70863f0b6..9591828fef 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -60,7 +60,7 @@ void AssetClient::init() { cache->setCacheDirectory(cachePath); networkAccessManager.setCache(cache); qDebug() << "ResourceManager disk cache setup at" << cachePath - << "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)"; + << "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)"; } }