Merge pull request #4677 from huffman/edit-zones

Zone editing
This commit is contained in:
Brad Hefta-Gaub 2015-04-23 11:39:41 -07:00
commit f036992da6
9 changed files with 348 additions and 4 deletions

View file

@ -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);
}

View file

@ -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 @@
<input class="coord" type='number' id="property-light-cutoff"></input>
</div>
</div>
<div class="zone-section property">
<span class="label">Stage Sun Model Enabled</span>
<span class="value">
<input type='checkbox' id="property-zone-stage-sun-model-enabled">
</span>
</div>
<div class="zone-section property">
<div class="label">Key Light Color</div>
<div class="value">
<div class="input-area">R <input class="coord" type='number' id="property-zone-key-light-color-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-zone-key-light-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-zone-key-light-color-blue"></input></div>
</div>
</div>
<div class="zone-section property">
<div class="label">Key Light Intensity</div>
<div class="value">
<input class="coord" type='number' id="property-zone-key-intensity"></input>
</div>
</div>
<div class="zone-section property">
<div class="label">Key Light Ambient Intensity</div>
<div class="value">
<input class="coord" type='number' id="property-zone-key-ambient-intensity"></input>
</div>
</div>
<div class="zone-section property">
<div class="label">Key Light Direction</div>
<div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-zone-key-light-direction-x"></input></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-zone-key-light-direction-y"></input></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-zone-key-light-direction-z"></input></div>
</div>
</div>
<div class="zone-section property">
<div class="label">Stage Latitude</div>
<div class="value">
<input class="coord" type='number' id="property-zone-stage-latitude"></input>
</div>
</div>
<div class="zone-section property">
<div class="label">Stage Longitude</div>
<div class="value">
<input class="coord" type='number' id="property-zone-stage-longitude"></input>
</div>
</div>
<div class="zone-section property">
<div class="label">Stage Altitude</div>
<div class="value">
<input class="coord" type='number' id="property-zone-stage-altitude"></input>
</div>
</div>
<div class="zone-section property">
<div class="label">Stage Day</div>
<div class="value">
<input class="coord" type='number' id="property-zone-stage-day"></input>
</div>
</div>
<div class="zone-section property">
<div class="label">Stage Hour</div>
<div class="value">
<input class="coord" type='number' id="property-zone-stage-hour"></input>
</div>
</div>
</div>
</body>

View file

@ -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]);
}

View file

@ -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]);
}
});
};

View file

@ -77,7 +77,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
if (_drawOnHUD) {
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
} else {
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
DependencyManager::get<GeometryCache>()->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<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
} else {
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(1.0f, cubeColor);
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
}
glPopMatrix();
} else {

View file

@ -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);
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;