diff --git a/examples/edit.js b/examples/edit.js index 2b32769337..59dcbaad19 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -28,6 +28,7 @@ Script.include([ "libraries/gridTool.js", "libraries/entityList.js", "libraries/lightOverlayManager.js", + "libraries/zoneOverlayManager.js", ]); var selectionDisplay = SelectionDisplay; @@ -35,6 +36,7 @@ var selectionManager = SelectionManager; var entityPropertyDialogBox = EntityPropertyDialogBox; var lightOverlayManager = new LightOverlayManager(); +var zoneOverlayManager = new ZoneOverlayManager(); var cameraManager = new CameraManager(); @@ -47,6 +49,7 @@ var entityListTool = EntityListTool(); selectionManager.addEventListener(function() { selectionDisplay.updateHandles(); lightOverlayManager.updatePositions(); + zoneOverlayManager.updatePositions(); }); var windowDimensions = Controller.getViewportDimensions(); @@ -77,11 +80,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_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_ZONES_IN_EDIT_MODE = "showZonesInEditMode"; var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain." var INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG = "You do not have the necessary permissions to place items on this domain." @@ -135,6 +140,7 @@ var toolBar = (function () { newSphereButton, newLightButton, newTextButton, + newZoneButton, browseMarketplaceButton; function initialize() { @@ -201,6 +207,14 @@ var toolBar = (function () { alpha: 0.9, visible: false }); + newZoneButton = toolBar.addTool({ + imageURL: toolIconUrl + "zonecube3.svg", + subImage: { x: 0, y: Tool.IMAGE_WIDTH + 208, width: 256, height: 256 }, + width: toolWidth, + height: toolHeight, + alpha: 0.9, + visible: false + }); that.setActive(false); } @@ -232,6 +246,7 @@ var toolBar = (function () { } toolBar.selectTool(activeButton, isActive); lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE)); + zoneOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); }; // Sets visibility of tool buttons, excluding the power button @@ -241,6 +256,7 @@ var toolBar = (function () { toolBar.showTool(newSphereButton, doShow); toolBar.showTool(newLightButton, doShow); toolBar.showTool(newTextButton, doShow); + toolBar.showTool(newZoneButton, doShow); }; var RESIZE_INTERVAL = 50; @@ -412,6 +428,21 @@ var toolBar = (function () { return true; } + if (newZoneButton === toolBar.clicked(clickedOverlay)) { + var position = getPositionToCreateEntity(); + + if (position.x > 0 && position.y > 0 && position.z > 0) { + placingEntityID = Entities.addEntity({ + type: "Zone", + position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS), + dimensions: { x: 10, y: 10, z: 10 }, + }); + } else { + print("Can't create box: Text would be out of bounds."); + } + return true; + } + return false; }; @@ -486,12 +517,22 @@ function rayPlaneIntersection(pickRay, point, normal) { } function findClickedEntity(event) { + var pickZones = event.isControl; + + if (pickZones) { + Entities.setZonesArePickable(true); + } + var pickRay = Camera.computePickRay(event.x, event.y); var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking var lightResult = lightOverlayManager.findRayIntersection(pickRay); lightResult.accurate = true; + if (pickZones) { + Entities.setZonesArePickable(false); + } + var result; if (!entityResult.intersects && !lightResult.intersects) { @@ -776,6 +817,8 @@ function setupModelMenus() { isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" }); Menu.addMenuItem({ menuName: "View", menuItemName: MENU_SHOW_LIGHTS_IN_EDIT_MODE, afterItem: MENU_EASE_ON_FOCUS, isCheckable: true, isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE) == "true" }); + Menu.addMenuItem({ menuName: "View", menuItemName: MENU_SHOW_ZONES_IN_EDIT_MODE, afterItem: MENU_SHOW_LIGHTS_IN_EDIT_MODE, + isCheckable: true, isChecked: Settings.getValue(SETTING_SHOW_ZONES_IN_EDIT_MODE) == "true" }); Entities.setLightsArePickable(false); } @@ -804,12 +847,14 @@ function cleanupModelMenus() { Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT); Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS); Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE); + Menu.removeMenuItem("View", MENU_SHOW_ZONES_IN_EDIT_MODE); } Script.scriptEnding.connect(function() { 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_ZONES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); progressDialog.cleanup(); toolBar.cleanup(); @@ -942,6 +987,8 @@ function handeMenuEvent(menuItem) { 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_ZONES_IN_EDIT_MODE) { + zoneOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); } tooltip.show(false); } diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index dd5bced393..348dc00df4 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -182,6 +182,23 @@ var elTextBackgroundColorGreen = document.getElementById("property-text-background-color-green"); var elTextBackgroundColorBlue = document.getElementById("property-text-background-color-blue"); + var elZoneSections = document.querySelectorAll(".zone-section"); + var elZoneStageSunModelEnabled = document.getElementById("property-zone-stage-sun-model-enabled"); + var elZoneKeyLightColorRed = document.getElementById("property-zone-key-light-color-red"); + var elZoneKeyLightColorGreen = document.getElementById("property-zone-key-light-color-green"); + var elZoneKeyLightColorBlue = document.getElementById("property-zone-key-light-color-blue"); + var elZoneKeyLightIntensity = document.getElementById("property-zone-key-intensity"); + var elZoneKeyLightAmbientIntensity = document.getElementById("property-zone-key-ambient-intensity"); + var elZoneKeyLightDirectionX = document.getElementById("property-zone-key-light-direction-x"); + var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y"); + var elZoneKeyLightDirectionZ = document.getElementById("property-zone-key-light-direction-z"); + + var elZoneStageLatitude = document.getElementById("property-zone-stage-latitude"); + var elZoneStageLongitude = document.getElementById("property-zone-stage-longitude"); + var elZoneStageAltitude = document.getElementById("property-zone-stage-altitude"); + var elZoneStageDay = document.getElementById("property-zone-stage-day"); + var elZoneStageHour = document.getElementById("property-zone-stage-hour"); + if (window.EventBridge !== undefined) { EventBridge.scriptEventReceived.connect(function(data) { data = JSON.parse(data); @@ -356,6 +373,32 @@ elLightCutoff.value = properties.cutoff; } + if (properties.type != "Zone") { + for (var i = 0; i < elZoneSections.length; i++) { + elZoneSections[i].style.display = 'none'; + } + } else { + for (var i = 0; i < elZoneSections.length; i++) { + elZoneSections[i].style.display = 'block'; + } + + elZoneStageSunModelEnabled.checked = properties.stageSunModelEnabled; + elZoneKeyLightColorRed.value = properties.keyLightColor.red; + elZoneKeyLightColorGreen.value = properties.keyLightColor.green; + elZoneKeyLightColorBlue.value = properties.keyLightColor.blue; + elZoneKeyLightIntensity.value = properties.keyLightIntensity; + elZoneKeyLightAmbientIntensity.value = properties.keyLightAmbientIntensity; + elZoneKeyLightDirectionX.value = properties.keyLightDirection.x.toFixed(2); + elZoneKeyLightDirectionY.value = properties.keyLightDirection.y.toFixed(2); + elZoneKeyLightDirectionZ.value = properties.keyLightDirection.z.toFixed(2); + + elZoneStageLatitude.value = properties.stageLatitude.toFixed(2); + elZoneStageLongitude.value = properties.stageLongitude.toFixed(2); + elZoneStageAltitude.value = properties.stageAltitude.toFixed(2); + elZoneStageDay.value = properties.stageDay; + elZoneStageHour.value = properties.stageHour; + } + if (selected) { activeElement.focus(); activeElement.select(); @@ -468,6 +511,26 @@ elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction); elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction); + elZoneStageSunModelEnabled.addEventListener('change', createEmitCheckedPropertyUpdateFunction('stageSunModelEnabled')); + var zoneKeyLightColorChangeFunction = createEmitColorPropertyUpdateFunction( + 'keyLightColor', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue); + elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction); + elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction); + elZoneKeyLightColorBlue.addEventListener('change', zoneKeyLightColorChangeFunction); + elZoneKeyLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('keyLightIntensity')); + elZoneKeyLightAmbientIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('keyLightAmbientIntensity')); + var zoneKeyLightDirectionChangeFunction = createEmitVec3PropertyUpdateFunction( + 'keyLightDirection', elZoneKeyLightDirectionX, elZoneKeyLightDirectionY, elZoneKeyLightDirectionZ); + elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction); + elZoneKeyLightDirectionY.addEventListener('change', zoneKeyLightDirectionChangeFunction); + elZoneKeyLightDirectionZ.addEventListener('change', zoneKeyLightDirectionChangeFunction); + + elZoneStageLatitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageLatitude')); + elZoneStageLongitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageLongitude')); + elZoneStageAltitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageAltitude')); + elZoneStageDay.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageDay')); + elZoneStageHour.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageHour')); + elMoveSelectionToGrid.addEventListener("click", function() { EventBridge.emitWebEvent(JSON.stringify({ type: "action", @@ -833,6 +896,73 @@ + +
+ Stage Sun Model Enabled + + + +
+ +
+
Key Light Color
+
+
R
+
G
+
B
+
+
+
+
Key Light Intensity
+
+ +
+
+
+
Key Light Ambient Intensity
+
+ +
+
+
+
Key Light Direction
+
+
Pitch
+
Yaw
+
Roll
+
+
+ +
+
Stage Latitude
+
+ +
+
+
+
Stage Longitude
+
+ +
+
+
+
Stage Altitude
+
+ +
+
+
+
Stage Day
+
+ +
+
+
+
Stage Hour
+
+ +
+
diff --git a/examples/libraries/lightOverlayManager.js b/examples/libraries/lightOverlayManager.js index 8032d77c49..a140461a27 100644 --- a/examples/libraries/lightOverlayManager.js +++ b/examples/libraries/lightOverlayManager.js @@ -122,7 +122,7 @@ LightOverlayManager = function() { Entities.clearingEntities.connect(clearEntities); // Add existing entities - var ids = Entities.findEntities(MyAvatar.position, 100); + var ids = Entities.findEntities(MyAvatar.position, 64000); for (var i = 0; i < ids.length; i++) { addEntity(ids[i]); } diff --git a/examples/libraries/zoneOverlayManager.js b/examples/libraries/zoneOverlayManager.js new file mode 100644 index 0000000000..9898b888fa --- /dev/null +++ b/examples/libraries/zoneOverlayManager.js @@ -0,0 +1,145 @@ +ZoneOverlayManager = function(isEntityFunc, entityAddedFunc, entityRemovedFunc, entityMovedFunc) { + var self = this; + + var visible = false; + + // List of all created overlays + var allOverlays = []; + + // List of overlays not currently being used + var unusedOverlays = []; + + // Map from EntityItemID.id to overlay id + var entityOverlays = {}; + + // Map from EntityItemID.id to EntityItemID object + var entityIDs = {}; + + this.updatePositions = function(ids) { + for (var id in entityIDs) { + var entityID = entityIDs[id]; + var properties = Entities.getEntityProperties(entityID); + Overlays.editOverlay(entityOverlays[entityID.id].solid, { + position: properties.position, + rotation: properties.rotation, + dimensions: properties.dimensions, + }); + Overlays.editOverlay(entityOverlays[entityID.id].outline, { + position: properties.position, + rotation: properties.rotation, + dimensions: properties.dimensions, + }); + } + }; + + this.setVisible = function(isVisible) { + if (visible != isVisible) { + visible = isVisible; + for (var id in entityOverlays) { + Overlays.editOverlay(entityOverlays[id].solid, { visible: visible }); + Overlays.editOverlay(entityOverlays[id].outline, { visible: visible }); + } + } + }; + + // Allocate or get an unused overlay + function getOverlay() { + if (unusedOverlays.length == 0) { + var overlay = Overlays.addOverlay("cube", { + }); + allOverlays.push(overlay); + } else { + var overlay = unusedOverlays.pop(); + }; + return overlay; + } + + function releaseOverlay(overlay) { + unusedOverlays.push(overlay); + Overlays.editOverlay(overlay, { visible: false }); + } + + function addEntity(entityID) { + var properties = Entities.getEntityProperties(entityID); + if (properties.type == "Zone" && !(entityID.id in entityOverlays)) { + var overlaySolid = getOverlay(); + var overlayOutline = getOverlay(); + + entityOverlays[entityID.id] = { + solid: overlaySolid, + outline: overlayOutline, + } + entityIDs[entityID.id] = entityID; + + var color = { + red: Math.round(Math.random() * 255), + green: Math.round(Math.random() * 255), + blue: Math.round(Math.random() * 255) + }; + Overlays.editOverlay(overlaySolid, { + position: properties.position, + rotation: properties.rotation, + dimensions: properties.dimensions, + visible: visible, + solid: true, + alpha: 0.1, + color: color, + ignoreRayIntersection: true, + }); + Overlays.editOverlay(overlayOutline, { + position: properties.position, + rotation: properties.rotation, + dimensions: properties.dimensions, + visible: visible, + solid: false, + dashed: false, + lineWidth: 2.0, + alpha: 1.0, + color: color, + ignoreRayIntersection: true, + }); + } + } + + function deleteEntity(entityID) { + if (entityID.id in entityOverlays) { + releaseOverlay(entityOverlays[entityID.id].outline); + releaseOverlay(entityOverlays[entityID.id].solid); + delete entityOverlays[entityID.id]; + } + } + + function changeEntityID(oldEntityID, newEntityID) { + entityOverlays[newEntityID.id] = entityOverlays[oldEntityID.id]; + entityIDs[newEntityID.id] = newEntityID; + + delete entityOverlays[oldEntityID.id]; + delete entityIDs[oldEntityID.id]; + } + + function clearEntities() { + for (var id in entityOverlays) { + releaseOverlay(entityOverlays[id].outline); + releaseOverlay(entityOverlays[id].solid); + } + entityOverlays = {}; + entityIDs = {}; + } + + Entities.addingEntity.connect(addEntity); + Entities.changingEntityID.connect(changeEntityID); + Entities.deletingEntity.connect(deleteEntity); + Entities.clearingEntities.connect(clearEntities); + + // Add existing entities + var ids = Entities.findEntities(MyAvatar.position, 64000); + for (var i = 0; i < ids.length; i++) { + addEntity(ids[i]); + } + + Script.scriptEnding.connect(function() { + for (var i = 0; i < allOverlays.length; i++) { + Overlays.deleteOverlay(allOverlays[i]); + } + }); +}; diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index a9bfbae8dd..60f985b083 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -77,7 +77,7 @@ void Cube3DOverlay::render(RenderArgs* args) { if (_drawOnHUD) { DependencyManager::get()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha)); } else { - DependencyManager::get()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha)); + DependencyManager::get()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha)); } glPopMatrix(); @@ -89,7 +89,7 @@ void Cube3DOverlay::render(RenderArgs* args) { if (_drawOnHUD) { DependencyManager::get()->renderSolidCube(1.0f, cubeColor); } else { - DependencyManager::get()->renderSolidCube(1.0f, cubeColor); + DependencyManager::get()->renderSolidCube(1.0f, cubeColor); } glPopMatrix(); } else { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 53335beda0..13e6b83393 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -15,6 +15,7 @@ #include "EntityTree.h" #include "LightEntityItem.h" #include "ModelEntityItem.h" +#include "ZoneEntityItem.h" EntityScriptingInterface::EntityScriptingInterface() : @@ -315,6 +316,14 @@ bool EntityScriptingInterface::getLightsArePickable() const { return LightEntityItem::getLightsArePickable(); } +void EntityScriptingInterface::setZonesArePickable(bool value) { + ZoneEntityItem::setZonesArePickable(value); +} + +bool EntityScriptingInterface::getZonesArePickable() const { + return ZoneEntityItem::getZonesArePickable(); +} + void EntityScriptingInterface::setSendPhysicsUpdates(bool value) { EntityItem::setSendPhysicsUpdates(value); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 075f5a712b..151036e926 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -111,6 +111,9 @@ public slots: Q_INVOKABLE void setLightsArePickable(bool value); Q_INVOKABLE bool getLightsArePickable() const; + Q_INVOKABLE void setZonesArePickable(bool value); + Q_INVOKABLE bool getZonesArePickable() const; + Q_INVOKABLE void setSendPhysicsUpdates(bool value); Q_INVOKABLE bool getSendPhysicsUpdates() const; diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index e0fe238c57..60a61e4e89 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -185,3 +185,9 @@ void ZoneEntityItem::debugDump() const { qCDebug(entities) << " _stageHour:" << _stageHour; } +bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject, bool precisionPicking) const { + + return _zonesArePickable; +} diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 8f1b15d174..bc1d77ab65 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -91,7 +91,11 @@ public: static bool getZonesArePickable() { return _zonesArePickable; } static void setZonesArePickable(bool value) { _zonesArePickable = value; } - + + virtual bool supportsDetailedRayIntersection() const { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject, bool precisionPicking) const; virtual void debugDump() const;