From ce5ee429617caa63cfbee068eba08ed8b6e95e97 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Feb 2017 10:07:46 -0800 Subject: [PATCH 01/16] Update LightOverlayManager to work with particles --- scripts/system/edit.js | 18 +++++++++++-- ...Manager.js => entityIconOverlayManager.js} | 26 ++++++++++++------- 2 files changed, 32 insertions(+), 12 deletions(-) rename scripts/system/libraries/{lightOverlayManager.js => entityIconOverlayManager.js} (80%) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index a440fec1ac..d195864ed6 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -33,13 +33,27 @@ Script.include([ "libraries/gridTool.js", "libraries/entityList.js", "particle_explorer/particleExplorerTool.js", - "libraries/lightOverlayManager.js" + "libraries/entityIconOverlayManager.js" ]); var selectionDisplay = SelectionDisplay; var selectionManager = SelectionManager; -var lightOverlayManager = new LightOverlayManager(); +const PARTICLE_SYSTEM_URL = Script.resolvePath("assets/images/icon-particles.svg"); +const POINT_LIGHT_URL = Script.resolvePath("assets/images/icon-point-light.svg"); +const SPOT_LIGHT_URL = Script.resolvePath("assets/images/icon-spot-light.svg"); +var lightOverlayManager = new EntityIconOverlayManager(['Light', 'ParticleEffect'], function(entityID) { + var properties = Entities.getEntityProperties(entityID, ['type', 'isSpotlight']); + if (properties.type === 'Light') { + return { + url: properties.isSpotlight ? SPOT_LIGHT_URL : POINT_LIGHT_URL, + } + } else { + return { + url: PARTICLE_SYSTEM_URL, + } + } +}); var cameraManager = new CameraManager(); diff --git a/scripts/system/libraries/lightOverlayManager.js b/scripts/system/libraries/entityIconOverlayManager.js similarity index 80% rename from scripts/system/libraries/lightOverlayManager.js rename to scripts/system/libraries/entityIconOverlayManager.js index 2d3618096b..aafb0725f3 100644 --- a/scripts/system/libraries/lightOverlayManager.js +++ b/scripts/system/libraries/entityIconOverlayManager.js @@ -1,7 +1,4 @@ -var POINT_LIGHT_URL = "http://s3.amazonaws.com/hifi-public/images/tools/point-light.svg"; -var SPOT_LIGHT_URL = "http://s3.amazonaws.com/hifi-public/images/tools/spot-light.svg"; - -LightOverlayManager = function() { +EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) { var self = this; var visible = false; @@ -79,24 +76,33 @@ LightOverlayManager = function() { } function addEntity(entityID) { - var properties = Entities.getEntityProperties(entityID); - if (properties.type == "Light" && !(entityID in entityOverlays)) { + var properties = Entities.getEntityProperties(entityID, ['position', 'type']); + if (entityTypes.indexOf(properties.type) > -1 && !(entityID in entityOverlays)) { var overlay = getOverlay(); entityOverlays[entityID] = overlay; entityIDs[entityID] = entityID; - Overlays.editOverlay(overlay, { + var overlayProperties = { position: properties.position, - url: properties.isSpotlight ? SPOT_LIGHT_URL : POINT_LIGHT_URL, rotation: Quat.fromPitchYawRollDegrees(0, 0, 270), visible: visible, alpha: 0.9, scale: 0.5, + drawInFront: true, + isFacingAvatar: true, color: { red: 255, green: 255, blue: 255 } - }); + }; + if (getOverlayPropertiesFunc) { + var customProperties = getOverlayPropertiesFunc(entityID, properties); + for (var key in customProperties) { + overlayProperties[key] = customProperties[key]; + } + } + print("overlay:", properties.type, JSON.stringify(overlayProperties)); + Overlays.editOverlay(overlay, overlayProperties); } } @@ -130,4 +136,4 @@ LightOverlayManager = function() { Overlays.deleteOverlay(allOverlays[i]); } }); -}; \ No newline at end of file +}; From 86116aaad7ba4ef035a078081c3ead090f4c80d4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Feb 2017 10:20:24 -0800 Subject: [PATCH 02/16] Update light/particel icons to be shown by default in edit mode --- scripts/system/edit.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index d195864ed6..d77b5804c8 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -96,13 +96,13 @@ var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS); var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select"; var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus"; -var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode"; +var MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE = "Show Lights and Particle Systems in Edit Mode"; var MENU_SHOW_ZONES_IN_EDIT_MODE = "Show Zones in Edit Mode"; var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled"; var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect"; var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus"; -var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode"; +var SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE = "showLightsAndParticlesInEditMode"; var SETTING_SHOW_ZONES_IN_EDIT_MODE = "showZonesInEditMode"; @@ -520,7 +520,7 @@ var toolBar = (function () { toolBar.writeProperty("shown", false); toolBar.writeProperty("shown", true); } - lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE)); + lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE)); Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); }; @@ -959,18 +959,18 @@ function setupModelMenus() { }); Menu.addMenuItem({ menuName: "Edit", - menuItemName: MENU_SHOW_LIGHTS_IN_EDIT_MODE, + menuItemName: MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE, afterItem: MENU_EASE_ON_FOCUS, isCheckable: true, - isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE) === "true", + isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE) !== "false", grouping: "Advanced" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: MENU_SHOW_ZONES_IN_EDIT_MODE, - afterItem: MENU_SHOW_LIGHTS_IN_EDIT_MODE, + afterItem: MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE, isCheckable: true, - isChecked: Settings.getValue(SETTING_SHOW_ZONES_IN_EDIT_MODE) === "true", + isChecked: Settings.getValue(SETTING_SHOW_ZONES_IN_EDIT_MODE) !== "false", grouping: "Advanced" }); @@ -1001,7 +1001,7 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", MENU_AUTO_FOCUS_ON_SELECT); Menu.removeMenuItem("Edit", MENU_EASE_ON_FOCUS); - Menu.removeMenuItem("Edit", MENU_SHOW_LIGHTS_IN_EDIT_MODE); + Menu.removeMenuItem("Edit", MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE); Menu.removeMenuItem("Edit", MENU_SHOW_ZONES_IN_EDIT_MODE); } @@ -1009,7 +1009,7 @@ Script.scriptEnding.connect(function () { toolBar.setActive(false); Settings.setValue(SETTING_AUTO_FOCUS_ON_SELECT, Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)); Settings.setValue(SETTING_EASE_ON_FOCUS, Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); - Settings.setValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE)); + Settings.setValue(SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE)); Settings.setValue(SETTING_SHOW_ZONES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); progressDialog.cleanup(); @@ -1297,8 +1297,8 @@ function handeMenuEvent(menuItem) { selectAllEtitiesInCurrentSelectionBox(false); } else if (menuItem === "Select All Entities Touching Box") { selectAllEtitiesInCurrentSelectionBox(true); - } else if (menuItem === MENU_SHOW_LIGHTS_IN_EDIT_MODE) { - lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE)); + } else if (menuItem === MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE) { + lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE)); } else if (menuItem === MENU_SHOW_ZONES_IN_EDIT_MODE) { Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); } From 42d518fafbfd10ec2426a6bbeef8fb793838e6cf Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Feb 2017 10:24:55 -0800 Subject: [PATCH 03/16] Remove debug log in entityIconOverlayManager --- scripts/system/libraries/entityIconOverlayManager.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/system/libraries/entityIconOverlayManager.js b/scripts/system/libraries/entityIconOverlayManager.js index aafb0725f3..2623b6d6cb 100644 --- a/scripts/system/libraries/entityIconOverlayManager.js +++ b/scripts/system/libraries/entityIconOverlayManager.js @@ -101,7 +101,6 @@ EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) { overlayProperties[key] = customProperties[key]; } } - print("overlay:", properties.type, JSON.stringify(overlayProperties)); Overlays.editOverlay(overlay, overlayProperties); } } From dbcd7fd9e9479ccb136640a89c86582e962777d9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 21 Feb 2017 10:31:44 -0800 Subject: [PATCH 04/16] Fix light icon overlay not updating to represent light type --- scripts/system/libraries/entityIconOverlayManager.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/system/libraries/entityIconOverlayManager.js b/scripts/system/libraries/entityIconOverlayManager.js index 2623b6d6cb..ec86057ab0 100644 --- a/scripts/system/libraries/entityIconOverlayManager.js +++ b/scripts/system/libraries/entityIconOverlayManager.js @@ -19,9 +19,16 @@ EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) { for (var id in entityIDs) { var entityID = entityIDs[id]; var properties = Entities.getEntityProperties(entityID); - Overlays.editOverlay(entityOverlays[entityID], { + var overlayProperties = { position: properties.position - }); + }; + if (getOverlayPropertiesFunc) { + var customProperties = getOverlayPropertiesFunc(entityID, properties); + for (var key in customProperties) { + overlayProperties[key] = customProperties[key]; + } + } + Overlays.editOverlay(entityOverlays[entityID], overlayProperties); } }; From c2564800dc50d7afcf1c2f3a41fd1bedb13fee06 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Feb 2017 15:18:08 -0800 Subject: [PATCH 05/16] Add edit.js particle + light icons --- .../system/assets/images/icon-particles.svg | 29 ++++++++++ .../system/assets/images/icon-point-light.svg | 57 +++++++++++++++++++ .../system/assets/images/icon-spot-light.svg | 37 ++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 scripts/system/assets/images/icon-particles.svg create mode 100644 scripts/system/assets/images/icon-point-light.svg create mode 100644 scripts/system/assets/images/icon-spot-light.svg diff --git a/scripts/system/assets/images/icon-particles.svg b/scripts/system/assets/images/icon-particles.svg new file mode 100644 index 0000000000..5e0105d7cd --- /dev/null +++ b/scripts/system/assets/images/icon-particles.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + diff --git a/scripts/system/assets/images/icon-point-light.svg b/scripts/system/assets/images/icon-point-light.svg new file mode 100644 index 0000000000..896c35b63b --- /dev/null +++ b/scripts/system/assets/images/icon-point-light.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/system/assets/images/icon-spot-light.svg b/scripts/system/assets/images/icon-spot-light.svg new file mode 100644 index 0000000000..ac2f87bb27 --- /dev/null +++ b/scripts/system/assets/images/icon-spot-light.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b7783dcffe4c5bbf9e4cc2649be57ed505dfc0c4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 13 Mar 2017 11:26:34 -0700 Subject: [PATCH 06/16] Update edit.js light/particle overlays to be clickable when behind something --- scripts/system/edit.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index d77b5804c8..2f7e0fabd7 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -594,18 +594,12 @@ function findClickedEntity(event) { var result; - if (!entityResult.intersects && !lightResult.intersects) { - return null; - } else if (entityResult.intersects && !lightResult.intersects) { - result = entityResult; - } else if (!entityResult.intersects && lightResult.intersects) { + if (lightResult.intersects) { result = lightResult; + } else if (entityResult.intersects) { + result = entityResult; } else { - if (entityResult.distance < lightResult.distance) { - result = entityResult; - } else { - result = lightResult; - } + return null; } if (!result.accurate) { From d4ade8278c1d4f8305c3b02ccdc153f3ccfc5ad0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 13 Mar 2017 11:27:12 -0700 Subject: [PATCH 07/16] Fix js linting errors in entityIconOverlayManager.js --- .../libraries/entityIconOverlayManager.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/system/libraries/entityIconOverlayManager.js b/scripts/system/libraries/entityIconOverlayManager.js index ec86057ab0..7f7a293bc3 100644 --- a/scripts/system/libraries/entityIconOverlayManager.js +++ b/scripts/system/libraries/entityIconOverlayManager.js @@ -1,6 +1,6 @@ -EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) { - var self = this; +/* globals EntityIconOverlayManager:true */ +EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) { var visible = false; // List of all created overlays @@ -38,7 +38,7 @@ EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) { if (result.intersects) { for (var id in entityOverlays) { - if (result.overlayID == entityOverlays[id]) { + if (result.overlayID === entityOverlays[id]) { result.entityID = entityIDs[id]; found = true; break; @@ -54,7 +54,7 @@ EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) { }; this.setVisible = function(isVisible) { - if (visible != isVisible) { + if (visible !== isVisible) { visible = isVisible; for (var id in entityOverlays) { Overlays.editOverlay(entityOverlays[id], { @@ -66,12 +66,13 @@ EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) { // Allocate or get an unused overlay function getOverlay() { - if (unusedOverlays.length == 0) { - var overlay = Overlays.addOverlay("image3d", {}); + var overlay; + if (unusedOverlays.length === 0) { + overlay = Overlays.addOverlay("image3d", {}); allOverlays.push(overlay); } else { - var overlay = unusedOverlays.pop(); - }; + overlay = unusedOverlays.pop(); + } return overlay; } From 9880d40cfbaee075a2177ae684724c0677e5ffec Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 13 Mar 2017 14:38:56 -0700 Subject: [PATCH 08/16] Update edit.js light icons to now use the name entityIcon --- scripts/system/edit.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 2f7e0fabd7..acf22018b8 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -42,7 +42,7 @@ var selectionManager = SelectionManager; const PARTICLE_SYSTEM_URL = Script.resolvePath("assets/images/icon-particles.svg"); const POINT_LIGHT_URL = Script.resolvePath("assets/images/icon-point-light.svg"); const SPOT_LIGHT_URL = Script.resolvePath("assets/images/icon-spot-light.svg"); -var lightOverlayManager = new EntityIconOverlayManager(['Light', 'ParticleEffect'], function(entityID) { +var entityIconOverlayManager = new EntityIconOverlayManager(['Light', 'ParticleEffect'], function(entityID) { var properties = Entities.getEntityProperties(entityID, ['type', 'isSpotlight']); if (properties.type === 'Light') { return { @@ -67,7 +67,7 @@ var entityListTool = new EntityListTool(); selectionManager.addEventListener(function () { selectionDisplay.updateHandles(); - lightOverlayManager.updatePositions(); + entityIconOverlayManager.updatePositions(); }); const KEY_P = 80; //Key code for letter p used for Parenting hotkey. @@ -520,7 +520,7 @@ var toolBar = (function () { toolBar.writeProperty("shown", false); toolBar.writeProperty("shown", true); } - lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE)); + entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE)); Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); }; @@ -585,8 +585,8 @@ function findClickedEntity(event) { } var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking - var lightResult = lightOverlayManager.findRayIntersection(pickRay); - lightResult.accurate = true; + var iconResult = entityIconOverlayManager.findRayIntersection(pickRay); + iconResult.accurate = true; if (pickZones) { Entities.setZonesArePickable(false); @@ -594,8 +594,8 @@ function findClickedEntity(event) { var result; - if (lightResult.intersects) { - result = lightResult; + if (iconResult.intersects) { + result = iconResult; } else if (entityResult.intersects) { result = entityResult; } else { @@ -1292,7 +1292,7 @@ function handeMenuEvent(menuItem) { } else if (menuItem === "Select All Entities Touching Box") { selectAllEtitiesInCurrentSelectionBox(true); } else if (menuItem === MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE) { - lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE)); + entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE)); } else if (menuItem === MENU_SHOW_ZONES_IN_EDIT_MODE) { Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); } From 8a1bd781f083a42dab34ba93fb713d0f041e3872 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 13 Mar 2017 14:44:14 -0700 Subject: [PATCH 09/16] Fix overlay findRayIntersection not properly handing multiple drawInFront overlays --- interface/src/ui/overlays/Overlays.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index ad7fbd6cc2..2b52f0817e 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -431,7 +431,9 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR if (thisOverlay->findRayIntersectionExtraInfo(ray.origin, ray.direction, thisDistance, thisFace, thisSurfaceNormal, thisExtraInfo)) { bool isDrawInFront = thisOverlay->getDrawInFront(); - if (thisDistance < bestDistance && (!bestIsFront || isDrawInFront)) { + if ((bestIsFront && isDrawInFront && thisDistance < bestDistance) + || (!bestIsFront && (isDrawInFront || thisDistance < bestDistance))) { + bestIsFront = isDrawInFront; bestDistance = thisDistance; result.intersects = true; From 8246dbafabe8e529688c572ba253af0033211f44 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 13 Mar 2017 15:15:36 -0700 Subject: [PATCH 10/16] Update particle explorer to work outside of entity list --- scripts/system/edit.js | 74 +++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index acf22018b8..42ebb1b8db 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -68,6 +68,44 @@ var entityListTool = new EntityListTool(); selectionManager.addEventListener(function () { selectionDisplay.updateHandles(); entityIconOverlayManager.updatePositions(); + + // Update particle explorer + var needToDestroyParticleExplorer = false; + if (selectionManager.selections.length === 1) { + var selectedEntityID = selectionManager.selections[0]; + if (selectedEntityID === selectedParticleEntityID) { + return; + } + var type = Entities.getEntityProperties(selectedEntityID, "type").type; + if (type === "ParticleEffect") { + // Destroy the old particles web view first + particleExplorerTool.destroyWebView(); + particleExplorerTool.createWebView(); + var properties = Entities.getEntityProperties(selectedEntityID); + var particleData = { + messageType: "particle_settings", + currentProperties: properties + }; + selectedParticleEntityID = selectedEntityID; + particleExplorerTool.setActiveParticleEntity(selectedParticleEntityID); + + particleExplorerTool.webView.webEventReceived.connect(function (data) { + data = JSON.parse(data); + if (data.messageType === "page_loaded") { + particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData)); + } + }); + } else { + needToDestroyParticleExplorer = true; + } + } else { + needToDestroyParticleExplorer = true; + } + + if (needToDestroyParticleExplorer && selectedParticleEntityID !== null) { + selectedParticleEntityID = null; + particleExplorerTool.destroyWebView(); + } }); const KEY_P = 80; //Key code for letter p used for Parenting hotkey. @@ -1192,7 +1230,7 @@ function parentSelectedEntities() { } function deleteSelectedEntities() { if (SelectionManager.hasSelection()) { - selectedParticleEntity = 0; + selectedParticleEntityID = null; particleExplorerTool.destroyWebView(); SelectionManager.saveProperties(); var savedProperties = []; @@ -1967,43 +2005,13 @@ var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace"); var propertiesTool = new PropertiesTool(); var particleExplorerTool = new ParticleExplorerTool(); -var selectedParticleEntity = 0; +var selectedParticleEntityID = null; entityListTool.webView.webEventReceived.connect(function (data) { data = JSON.parse(data); - if(data.type === 'parent') { + if (data.type === 'parent') { parentSelectedEntities(); } else if(data.type === 'unparent') { unparentSelectedEntities(); - } else if (data.type === "selectionUpdate") { - var ids = data.entityIds; - if (ids.length === 1) { - if (Entities.getEntityProperties(ids[0], "type").type === "ParticleEffect") { - if (JSON.stringify(selectedParticleEntity) === JSON.stringify(ids[0])) { - // This particle entity is already selected, so return - return; - } - // Destroy the old particles web view first - particleExplorerTool.destroyWebView(); - particleExplorerTool.createWebView(); - var properties = Entities.getEntityProperties(ids[0]); - var particleData = { - messageType: "particle_settings", - currentProperties: properties - }; - selectedParticleEntity = ids[0]; - particleExplorerTool.setActiveParticleEntity(ids[0]); - - particleExplorerTool.webView.webEventReceived.connect(function (data) { - data = JSON.parse(data); - if (data.messageType === "page_loaded") { - particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData)); - } - }); - } else { - selectedParticleEntity = 0; - particleExplorerTool.destroyWebView(); - } - } } }); From df644edde4f2048276201bc648f1438e67b85547 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 20 Mar 2017 09:45:50 -0700 Subject: [PATCH 11/16] Fix hand controller not able to select light/particle icons --- scripts/system/edit.js | 2 +- scripts/system/libraries/entitySelectionTool.js | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 42ebb1b8db..fb5a3c2f73 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -42,7 +42,7 @@ var selectionManager = SelectionManager; const PARTICLE_SYSTEM_URL = Script.resolvePath("assets/images/icon-particles.svg"); const POINT_LIGHT_URL = Script.resolvePath("assets/images/icon-point-light.svg"); const SPOT_LIGHT_URL = Script.resolvePath("assets/images/icon-spot-light.svg"); -var entityIconOverlayManager = new EntityIconOverlayManager(['Light', 'ParticleEffect'], function(entityID) { +entityIconOverlayManager = new EntityIconOverlayManager(['Light', 'ParticleEffect'], function(entityID) { var properties = Entities.getEntityProperties(entityID, ['type', 'isSpotlight']); if (properties.type === 'Light') { return { diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index d68a525458..a8c4300fbe 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1032,10 +1032,12 @@ SelectionDisplay = (function() { var pickRay = controllerComputePickRay(); if (pickRay) { var entityIntersection = Entities.findRayIntersection(pickRay, true); - - + var iconIntersection = entityIconOverlayManager.findRayIntersection(pickRay); var overlayIntersection = Overlays.findRayIntersection(pickRay); - if (entityIntersection.intersects && + + if (iconIntersection.intersects) { + selectionManager.setSelections([iconIntersection.entityID]); + } else if (entityIntersection.intersects && (!overlayIntersection.intersects || (entityIntersection.distance < overlayIntersection.distance))) { if (HMD.tabletID === entityIntersection.entityID) { From 20022ebdc881d0884873b85e536373e31e255773 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Mar 2017 17:44:35 -0700 Subject: [PATCH 12/16] use deleteLater for ESS script engine on nodeKilled --- assignment-client/src/scripts/EntityScriptServer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index f674ab006c..a47919bdd7 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -395,7 +395,8 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) { void EntityScriptServer::resetEntitiesScriptEngine() { auto engineName = QString("about:Entities %1").arg(++_entitiesScriptEngineCount); - auto newEngine = QSharedPointer(new ScriptEngine(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName)); + auto newEngine = QSharedPointer(new ScriptEngine(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName), + &ScriptEngine::deleteLater); auto webSocketServerConstructorValue = newEngine->newFunction(WebSocketServerClass::constructor); newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); From a4d72c4e6766208ea323a2a8fe323758fe99234c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 16 Mar 2017 10:29:22 -0700 Subject: [PATCH 13/16] make AudioScriptingInterface a Dependency --- .../src/scripts/EntityScriptServer.cpp | 2 ++ interface/src/Application.cpp | 21 ++++++++++--------- .../src/AudioScriptingInterface.cpp | 5 ----- .../src/AudioScriptingInterface.h | 9 +++++--- libraries/script-engine/src/ScriptEngine.cpp | 6 +++++- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index a47919bdd7..cea2d24534 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -58,6 +58,8 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig DependencyManager::registerInheritance(); + DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 02fe2a2dd3..9157bb7144 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -740,23 +740,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); - auto& audioScriptingInterface = AudioScriptingInterface::getInstance(); + auto audioScriptingInterface = DependencyManager::set(); connect(audioThread, &QThread::started, audioIO.data(), &AudioClient::start); connect(audioIO.data(), &AudioClient::destroyed, audioThread, &QThread::quit); connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); connect(audioIO.data(), &AudioClient::muteToggled, this, &Application::audioMuteToggled); - connect(audioIO.data(), &AudioClient::mutedByMixer, &audioScriptingInterface, &AudioScriptingInterface::mutedByMixer); - connect(audioIO.data(), &AudioClient::receivedFirstPacket, &audioScriptingInterface, &AudioScriptingInterface::receivedFirstPacket); - connect(audioIO.data(), &AudioClient::disconnected, &audioScriptingInterface, &AudioScriptingInterface::disconnected); + connect(audioIO.data(), &AudioClient::mutedByMixer, audioScriptingInterface.data(), &AudioScriptingInterface::mutedByMixer); + connect(audioIO.data(), &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), &AudioScriptingInterface::receivedFirstPacket); + connect(audioIO.data(), &AudioClient::disconnected, audioScriptingInterface.data(), &AudioScriptingInterface::disconnected); connect(audioIO.data(), &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) { auto audioClient = DependencyManager::get(); + auto audioScriptingInterface = DependencyManager::get(); auto myAvatarPosition = DependencyManager::get()->getMyAvatar()->getPosition(); float distance = glm::distance(myAvatarPosition, position); bool shouldMute = !audioClient->isMuted() && (distance < radius); if (shouldMute) { audioClient->toggleMute(); - AudioScriptingInterface::getInstance().environmentMuted(); + audioScriptingInterface->environmentMuted(); } }); @@ -1181,10 +1182,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // set the local loopback interface for local sounds AudioInjector::setLocalAudioInterface(audioIO.data()); - AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data()); - connect(audioIO.data(), &AudioClient::noiseGateOpened, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::noiseGateOpened); - connect(audioIO.data(), &AudioClient::noiseGateClosed, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::noiseGateClosed); - connect(audioIO.data(), &AudioClient::inputReceived, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::inputReceived); + audioScriptingInterface->setLocalAudioInterface(audioIO.data()); + connect(audioIO.data(), &AudioClient::noiseGateOpened, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateOpened); + connect(audioIO.data(), &AudioClient::noiseGateClosed, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateClosed); + connect(audioIO.data(), &AudioClient::inputReceived, audioScriptingInterface.data(), &AudioScriptingInterface::inputReceived); this->installEventFilter(this); @@ -1949,7 +1950,7 @@ void Application::initializeUi() { // For some reason there is already an "Application" object in the QML context, // though I can't find it. Hence, "ApplicationInterface" rootContext->setContextProperty("ApplicationInterface", this); - rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); + rootContext->setContextProperty("Audio", DependencyManager::get().data()); rootContext->setContextProperty("AudioStats", DependencyManager::get()->getStats().data()); rootContext->setContextProperty("AudioScope", DependencyManager::get().data()); diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index fcc1f201f9..8452494d95 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -19,11 +19,6 @@ void registerAudioMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue); } -AudioScriptingInterface& AudioScriptingInterface::getInstance() { - static AudioScriptingInterface staticInstance; - return staticInstance; -} - AudioScriptingInterface::AudioScriptingInterface() : _localAudioInterface(NULL) { diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 6cce78d48f..e97bc329c6 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -14,18 +14,20 @@ #include #include +#include #include class ScriptAudioInjector; -class AudioScriptingInterface : public QObject { +class AudioScriptingInterface : public QObject, public Dependency { Q_OBJECT -public: - static AudioScriptingInterface& getInstance(); + SINGLETON_DEPENDENCY +public: void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; } protected: + // this method is protected to stop C++ callers from calling, but invokable from script Q_INVOKABLE ScriptAudioInjector* playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); @@ -42,6 +44,7 @@ signals: private: AudioScriptingInterface(); + AbstractAudioInterface* _localAudioInterface; }; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 3e4e070717..1b3d5057f5 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -627,6 +627,9 @@ void ScriptEngine::init() { qScriptRegisterMetaType(this, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue); qScriptRegisterMetaType(this, wscReadyStateToScriptValue, wscReadyStateFromScriptValue); + // NOTE: You do not want to end up creating new instances of singletons here. They will be on the ScriptEngine thread + // and are likely to be unusable if we "reset" the ScriptEngine by creating a new one (on a whole new thread). + registerGlobalObject("Script", this); { @@ -638,7 +641,8 @@ void ScriptEngine::init() { resetModuleCache(); } - registerGlobalObject("Audio", &AudioScriptingInterface::getInstance()); + registerGlobalObject("Audio", DependencyManager::get().data()); + registerGlobalObject("Entities", entityScriptingInterface.data()); registerGlobalObject("Quat", &_quatLibrary); registerGlobalObject("Vec3", &_vec3Library); From c63a2c9cda223f8eeba2ed13c3dbf778ba57cd2b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 16 Mar 2017 15:07:54 -0700 Subject: [PATCH 14/16] remove requirement of ScriptEngine in ScriptEngines slots --- libraries/script-engine/src/ScriptEngine.cpp | 8 ++++---- libraries/script-engine/src/ScriptEngine.h | 8 ++++---- libraries/script-engine/src/ScriptEngines.cpp | 20 +++++-------------- libraries/script-engine/src/ScriptEngines.h | 10 +++++----- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 1b3d5057f5..a5c94c1bb4 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -464,17 +464,17 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { void ScriptEngine::scriptErrorMessage(const QString& message) { qCCritical(scriptengine) << qPrintable(message); - emit errorMessage(message); + emit errorMessage(message, getFilename()); } void ScriptEngine::scriptWarningMessage(const QString& message) { qCWarning(scriptengine) << message; - emit warningMessage(message); + emit warningMessage(message, getFilename()); } void ScriptEngine::scriptInfoMessage(const QString& message) { qCInfo(scriptengine) << message; - emit infoMessage(message); + emit infoMessage(message, getFilename()); } // Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of @@ -1351,7 +1351,7 @@ QUrl ScriptEngine::resourcesPath() const { } void ScriptEngine::print(const QString& message) { - emit printedMessage(message); + emit printedMessage(message, getFilename()); } // Script.require.resolve -- like resolvePath, but performs more validation and throws exceptions on invalid module identifiers (for consistency with Node.js) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 95f377d92b..5ea8d052e9 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -236,10 +236,10 @@ signals: void scriptEnding(); void finished(const QString& fileNameString, ScriptEngine* engine); void cleanupMenuItem(const QString& menuItemString); - void printedMessage(const QString& message); - void errorMessage(const QString& message); - void warningMessage(const QString& message); - void infoMessage(const QString& message); + void printedMessage(const QString& message, const QString& scriptName); + void errorMessage(const QString& message, const QString& scriptName); + void warningMessage(const QString& message, const QString& scriptName); + void infoMessage(const QString& message, const QString& scriptName); void runningStateChanged(); void loadScript(const QString& scriptName, bool isUserLoaded); void reloadScript(const QString& scriptName, bool isUserLoaded); diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 57887d2d96..88b0e0b7b5 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -34,34 +34,24 @@ ScriptsModel& getScriptsModel() { return scriptsModel; } -void ScriptEngines::onPrintedMessage(const QString& message) { - auto scriptEngine = qobject_cast(sender()); - auto scriptName = scriptEngine ? scriptEngine->getFilename() : ""; +void ScriptEngines::onPrintedMessage(const QString& message, const QString& scriptName) { emit printedMessage(message, scriptName); } -void ScriptEngines::onErrorMessage(const QString& message) { - auto scriptEngine = qobject_cast(sender()); - auto scriptName = scriptEngine ? scriptEngine->getFilename() : ""; +void ScriptEngines::onErrorMessage(const QString& message, const QString& scriptName) { emit errorMessage(message, scriptName); } -void ScriptEngines::onWarningMessage(const QString& message) { - auto scriptEngine = qobject_cast(sender()); - auto scriptName = scriptEngine ? scriptEngine->getFilename() : ""; +void ScriptEngines::onWarningMessage(const QString& message, const QString& scriptName) { emit warningMessage(message, scriptName); } -void ScriptEngines::onInfoMessage(const QString& message) { - auto scriptEngine = qobject_cast(sender()); - auto scriptName = scriptEngine ? scriptEngine->getFilename() : ""; +void ScriptEngines::onInfoMessage(const QString& message, const QString& scriptName) { emit infoMessage(message, scriptName); } void ScriptEngines::onErrorLoadingScript(const QString& url) { - auto scriptEngine = qobject_cast(sender()); - auto scriptName = scriptEngine ? scriptEngine->getFilename() : ""; - emit errorLoadingScript(url, scriptName); + emit errorLoadingScript(url); } ScriptEngines::ScriptEngines(ScriptEngine::Context context) diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 2fadfc81f8..63b7e8f11c 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -79,13 +79,13 @@ signals: void errorMessage(const QString& message, const QString& engineName); void warningMessage(const QString& message, const QString& engineName); void infoMessage(const QString& message, const QString& engineName); - void errorLoadingScript(const QString& url, const QString& engineName); + void errorLoadingScript(const QString& url); public slots: - void onPrintedMessage(const QString& message); - void onErrorMessage(const QString& message); - void onWarningMessage(const QString& message); - void onInfoMessage(const QString& message); + void onPrintedMessage(const QString& message, const QString& scriptName); + void onErrorMessage(const QString& message, const QString& scriptName); + void onWarningMessage(const QString& message, const QString& scriptName); + void onInfoMessage(const QString& message, const QString& scriptName); void onErrorLoadingScript(const QString& url); protected slots: From 0a118bd268d0033fd35ce6c99891b7bb9092379d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 16 Mar 2017 18:41:26 -0700 Subject: [PATCH 15/16] add a guard for trading entity servers by checking node count --- .../src/scripts/EntityScriptServer.cpp | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index cea2d24534..c46d658c52 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -326,7 +326,26 @@ void EntityScriptServer::nodeActivated(SharedNodePointer activatedNode) { void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) { switch (killedNode->getType()) { case NodeType::EntityServer: { - clear(); + // Before we clear, make sure this was our only entity server. + // Otherwise we're assuming that we have "trading" entity servers + // (an old one going away and a new one coming onboard) + // and that we shouldn't clear here because we're still doing work. + bool hasAnotherEntityServer = false; + auto nodeList = DependencyManager::get(); + + nodeList->eachNodeBreakable([&hasAnotherEntityServer, &killedNode](const SharedNodePointer& node){ + if (node->getType() == NodeType::EntityServer && node->getUUID() != killedNode->getUUID()) { + // we're talking to > 1 entity servers, we know we won't clear + hasAnotherEntityServer = true; + return false; + } + + return true; + }); + + if (hasAnotherEntityServer) { + clear(); + } break; } From 96cf6b8c0418ca4e8548792d921405d70c81db30 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 17 Mar 2017 13:19:59 -0700 Subject: [PATCH 16/16] fix clear check for missing other entity servers --- assignment-client/src/scripts/EntityScriptServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index c46d658c52..954c25a342 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -343,7 +343,7 @@ void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) { return true; }); - if (hasAnotherEntityServer) { + if (!hasAnotherEntityServer) { clear(); }