overte/script-archive/libraries/overlayManager.js

405 lines
12 KiB
JavaScript

//
// overlayManager.js
// examples/libraries
//
// Created by Zander Otavka on 7/24/15
// Copyright 2015 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
//
// Manage overlays with object oriented goodness, instead of ugly `Overlays.h` methods.
// Instead of:
//
// var billboard = Overlays.addOverlay("image3d", { visible: false });
// ...
// Overlays.editOverlay(billboard, { visible: true });
// ...
// Overlays.deleteOverlay(billboard);
//
// You can now do:
//
// var billboard = new Image3DOverlay({ visible: false });
// ...
// billboard.visible = true;
// ...
// billboard.destroy();
//
// More on usage below. Examples in `examples/example/overlayPanelExample.js`.
//
// Note that including this file will delete `Overlays` from the global scope. All the
// functionality of `Overlays` is represented here, just better. If you try to use `Overlays`
// in tandem, there may be performance problems or nasty surprises.
//
(function() {
// Delete `Overlays` from the global scope.
var Overlays = this.Overlays;
delete this.Overlays;
var ABSTRACT = null;
var overlays = {};
var panels = {};
var overlayTypes = {};
function generateOverlayClass(superclass, type, properties) {
var that;
if (type == ABSTRACT) {
that = function(type, params) {
superclass.call(this, type, params);
};
} else {
that = function(params) {
superclass.call(this, type, params);
};
overlayTypes[type] = that;
}
that.prototype = new superclass();
that.prototype.constructor = that;
properties.forEach(function(prop) {
Object.defineProperty(that.prototype, prop, {
get: function() {
//V8TODO:
return Overlays.getProperty(this._id, prop);
},
set: function(newValue) {
var keyValuePair = {};
keyValuePair[prop] = newValue;
this.setProperties(keyValuePair);
},
configurable: false
});
});
return that;
}
//
// Create a new JavaScript object for an overlay of given ID.
//
function makeOverlayFromId(id) {
var type = Overlays.getOverlayType(id);
if (!type) {
return null;
}
var overlay = new overlayTypes[type]();
overlay._id = id;
overlays[id] = overlay;
return overlay;
}
//
// Get or create an overlay object from the id.
//
// @param knownOverlaysOnly (Optional: Boolean)
// If true, a new object will not be created.
// @param searchList (Optional: Object)
// Map of overlay id's and overlay objects. Can be generated with
// `OverlayManager.makeSearchList`.
//
function findOverlay(id, knownOverlaysOnly, searchList) {
if (id > 0) {
knownOverlaysOnly = Boolean(knownOverlaysOnly);
searchList = searchList || overlays;
var foundOverlay = searchList[id];
if (foundOverlay) {
return foundOverlay;
}
if (!knownOverlaysOnly) {
return makeOverlayFromId(id);
}
}
return null;
}
//
// Create a new JavaScript object for a panel of given ID.
//
function makePanelFromId(id) {
if (!Overlays.isAddedPanel(id)) {
return null;
}
var panel = new OverlayPanel();
panel._id = id;
overlays[id] = overlay;
return overlay;
}
//
// Get or create a panel object from the id.
//
// @param knownOverlaysOnly (Optional: Boolean)
// If true, a new object will not be created.
// @param searchList (Optional: Object)
// Map of overlay id's and overlay objects. Can be generated with
// `OverlayManager.makeSearchList`.
//
function findPanel(id, knownPanelsOnly, searchList) {
if (id > 0) {
knownPanelsOnly = Boolean(knownPanelsOnly);
searchList = searchList || panels;
var foundPanel = searchList[id];
if (foundPanel) {
return foundPanel;
}
if (!knownPanelsOnly) {
return makePanelFromId(id);
}
}
return null;
}
function findOverlayOrPanel(id, knownObjectsOnly, searchList) {
return findOverlay(id, knownObjectsOnly, searchList) ||
findPanel(id, knownObjectsOnly, searchList);
}
var Overlay = (function() {
var that = function(type, params) {
if (type && params) {
this._id = Overlays.addOverlay(type, params);
overlays[this._id] = this;
} else {
this._id = 0;
}
};
that.prototype.constructor = that;
Object.defineProperty(that.prototype, "isLoaded", {
get: function() {
return Overlays.isLoaded(this._id);
}
});
Object.defineProperty(that.prototype, "parentPanel", {
get: function() {
return findPanel(Overlays.getParentPanel(this._id));
}
});
that.prototype.getTextSize = function(text) {
return Overlays.textSize(this._id, text);
};
that.prototype.setProperties = function(properties) {
Overlays.editOverlay(this._id, properties);
};
that.prototype.clone = function() {
return makeOverlayFromId(Overlays.cloneOverlay(this._id));
};
that.prototype.destroy = function() {
Overlays.deleteOverlay(this._id);
};
that.prototype.isPanelAttachable = function() {
return false;
};
return generateOverlayClass(that, ABSTRACT, [
"alpha", "pulseMax", "pulseMin", "pulsePeriod",
"alphaPulse", "colorPulse", "visible", "anchor"
]);
})();
// Supports multiple inheritance of properties. Just `concat` them onto the end of the
// properties list.
var PanelAttachable = ["offsetPosition", "offsetRotation", "offsetScale"];
var Billboardable = ["isFacingAvatar"];
var Overlay2D = generateOverlayClass(Overlay, ABSTRACT, [
"bounds", "x", "y", "width", "height"
]);
var Base3DOverlay = generateOverlayClass(Overlay, ABSTRACT, [
"position", "lineWidth", "rotation", "isSolid", "isFilled", "isWire", "isDashedLine",
"ignoreRayIntersection", "drawInFront"
]);
var Planar3DOverlay = generateOverlayClass(Base3DOverlay, ABSTRACT, [
"dimensions"
]);
var Billboard3DOverlay = generateOverlayClass(Planar3DOverlay, ABSTRACT, [
].concat(PanelAttachable).concat(Billboardable));
Billboard3DOverlay.prototype.isPanelAttachable = function() { return true; };
var Volume3DOverlay = generateOverlayClass(Base3DOverlay, ABSTRACT, [
"dimensions"
]);
Image3DOverlay = generateOverlayClass(Billboard3DOverlay, "image3d", [
"url", "subImage"
]);
Text3DOverlay = generateOverlayClass(Billboard3DOverlay, "text3d", [
"text", "backgroundColor", "backgroundAlpha", "lineHeight", "leftMargin", "topMargin",
"rightMargin", "bottomMargin"
]);
Cube3DOverlay = generateOverlayClass(Volume3DOverlay, "cube", [
"borderSize"
]);
Sphere3DOverlay = generateOverlayClass(Volume3DOverlay, "sphere", [
]);
Circle3DOverlay = generateOverlayClass(Planar3DOverlay, "circle3d", [
"startAt", "endAt", "outerRadius", "innerRadius", "hasTickMarks",
"majorTickMarksAngle", "minorTickMarksAngle", "majorTickMarksLength",
"minorTickMarksLength", "majorTickMarksColor", "minorTickMarksColor"
]);
Rectangle3DOverlay = generateOverlayClass(Planar3DOverlay, "rectangle3d", [
]);
Line3DOverlay = generateOverlayClass(Base3DOverlay, "line3d", [
"start", "end"
]);
Grid3DOverlay = generateOverlayClass(Planar3DOverlay, "grid", [
"minorGridWidth", "majorGridEvery"
]);
ModelOverlay = generateOverlayClass(Volume3DOverlay, "model", [
"url", "dimensions", "textures"
]);
OverlayPanel = (function() {
var that = function(params) {
this._id = Overlays.addPanel(params);
panels[this._id] = this;
};
that.prototype.constructor = that;
var props = [
"anchorPosition", "anchorPositionBinding", "anchorRotation", "anchorRotationBinding", "anchorScale", "visible"
].concat(PanelAttachable).concat(Billboardable)
props.forEach(function(prop) {
Object.defineProperty(that.prototype, prop, {
get: function() {
return Overlays.getPanelProperty(this._id, prop);
},
set: function(newValue) {
var keyValuePair = {};
keyValuePair[prop] = newValue;
this.setProperties(keyValuePair);
},
configurable: false
});
});
Object.defineProperty(that.prototype, "parentPanel", {
get: function() {
return findPanel(Overlays.getParentPanel(this._id));
}
});
Object.defineProperty(that.prototype, "children", {
get: function() {
var idArray = Overlays.getPanelProperty(this._id, "children");
var objArray = [];
for (var i = 0; i < idArray.length; i++) {
objArray[i] = findOverlayOrPanel(idArray[i]);
}
return objArray;
}
});
that.prototype.addChild = function(child) {
Overlays.setParentPanel(child._id, this._id);
return child;
};
that.prototype.removeChild = function(child) {
if (child.parentPanel === this) {
Overlays.setParentPanel(child._id, 0);
}
};
that.prototype.setProperties = function(properties) {
Overlays.editPanel(this._id, properties);
};
that.prototype.setChildrenVisible = function() {
this.children.forEach(function(child) {
child.visible = true;
if (child.setChildrenVisible !== undefined) {
child.setChildrenVisible();
}
});
};
that.prototype.destroy = function() {
Overlays.deletePanel(this._id);
};
return that;
})();
OverlayManager = {
findOnRay: function(pickRay, knownOverlaysOnly, searchList) {
var rayPickResult = Overlays.findRayIntersection(pickRay);
if (rayPickResult.intersects) {
return findOverlay(rayPickResult.overlayID, knownOverlaysOnly, searchList);
}
return null;
},
findAtPoint: function(point, knownOverlaysOnly, searchList) {
var foundID = Overlays.getOverlayAtPoint(point);
if (foundID) {
return findOverlay(foundID, knownOverlaysOnly, searchList);
} else {
var pickRay = Camera.computePickRay(point.x, point.y);
return OverlayManager.findOnRay(pickRay, knownOverlaysOnly, searchList);
}
},
makeSearchList: function(array) {
var searchList = {};
array.forEach(function(object) {
searchList[object._id] = object;
});
return searchList;
},
findRayIntersection: function(pickRay) {
return Overlays.findRayIntersection(pickRay);
}
};
// Threadsafe cleanup of JavaScript objects.
function onOverlayDeleted(id) {
if (id in overlays) {
if (overlays[id].parentPanel) {
overlays[id].parentPanel.removeChild(overlays[id]);
}
delete overlays[id];
}
}
function onPanelDeleted(id) {
if (id in panels) {
if (panels[id].parentPanel) {
panels[id].parentPanel.removeChild(panels[id]);
}
delete panels[id];
}
}
Overlays.overlayDeleted.connect(onOverlayDeleted);
Overlays.panelDeleted.connect(onPanelDeleted);
})();