/*global define*/ define([ '../Core/AssociativeArray', '../Core/defined', '../Core/destroyObject', '../Core/DeveloperError', './ColorMaterialProperty', './StaticGeometryColorBatch', './StaticGeometryPerMaterialBatch', './StaticOutlineGeometryBatch' ], function( AssociativeArray, defined, destroyObject, DeveloperError, ColorMaterialProperty, StaticGeometryColorBatch, StaticGeometryPerMaterialBatch, StaticOutlineGeometryBatch) { "use strict"; var emptyArray = []; var DynamicGeometryBatch = function(primitives) { this._primitives = primitives; this._dynamicUpdaters = new AssociativeArray(); }; DynamicGeometryBatch.prototype.add = function(time, updater) { this._dynamicUpdaters.set(updater.entity.id, updater.createDynamicUpdater(this._primitives)); }; DynamicGeometryBatch.prototype.remove = function(updater) { var id = updater.entity.id; var dynamicUpdater = this._dynamicUpdaters.get(id); if (defined(dynamicUpdater)) { this._dynamicUpdaters.remove(id); dynamicUpdater.destroy(); } }; DynamicGeometryBatch.prototype.update = function(time) { var geometries = this._dynamicUpdaters.values; for (var i = 0, len = geometries.length; i < len; i++) { geometries[i].update(time); } return true; }; DynamicGeometryBatch.prototype.removeAllPrimitives = function() { var geometries = this._dynamicUpdaters.values; for (var i = 0, len = geometries.length; i < len; i++) { geometries[i].destroy(); } this._dynamicUpdaters.removeAll(); }; function removeUpdater(that, updater) { //We don't keep track of which batch an updater is in, so just remove it from all of them. that._outlineBatch.remove(updater); that._closedColorBatch.remove(updater); that._closedMaterialBatch.remove(updater); that._openColorBatch.remove(updater); that._openMaterialBatch.remove(updater); that._dynamicBatch.remove(updater); } function insertUpdaterIntoBatch(that, time, updater) { if (updater.isDynamic) { that._dynamicBatch.add(time, updater); return; } if (updater.outlineEnabled) { that._outlineBatch.add(time, updater); } if (updater.fillEnabled) { if (updater.isClosed) { if (updater.fillMaterialProperty instanceof ColorMaterialProperty) { that._closedColorBatch.add(time, updater); } else { that._closedMaterialBatch.add(time, updater); } } else { if (updater.fillMaterialProperty instanceof ColorMaterialProperty) { that._openColorBatch.add(time, updater); } else { that._openMaterialBatch.add(time, updater); } } } } /** * A general purpose visualizer for geometry represented by {@link Primitive} instances. * @alias GeometryVisualizer * @constructor * * @param {GeometryUpdater} type The updater to be used for creating the geometry. * @param {Scene} scene The scene the primitives will be rendered in. * @param {EntityCollection} entityCollection The entityCollection to visualize. */ var GeometryVisualizer = function(type, scene, entityCollection) { //>>includeStart('debug', pragmas.debug); if (!defined(type)) { throw new DeveloperError('type is required.'); } if (!defined(scene)) { throw new DeveloperError('scene is required.'); } if (!defined(entityCollection)) { throw new DeveloperError('entityCollection is required.'); } //>>includeEnd('debug'); this._type = type; var primitives = scene.primitives; this._scene = scene; this._primitives = primitives; this._entityCollection = undefined; this._addedObjects = new AssociativeArray(); this._removedObjects = new AssociativeArray(); this._changedObjects = new AssociativeArray(); this._outlineBatch = new StaticOutlineGeometryBatch(primitives, scene); this._closedColorBatch = new StaticGeometryColorBatch(primitives, type.perInstanceColorAppearanceType, true); this._closedMaterialBatch = new StaticGeometryPerMaterialBatch(primitives, type.materialAppearanceType, true); this._openColorBatch = new StaticGeometryColorBatch(primitives, type.perInstanceColorAppearanceType, false); this._openMaterialBatch = new StaticGeometryPerMaterialBatch(primitives, type.materialAppearanceType, false); this._dynamicBatch = new DynamicGeometryBatch(primitives); this._subscriptions = new AssociativeArray(); this._updaters = new AssociativeArray(); this._entityCollection = entityCollection; entityCollection.collectionChanged.addEventListener(GeometryVisualizer.prototype._onCollectionChanged, this); this._onCollectionChanged(entityCollection, entityCollection.entities, emptyArray); }; /** * Updates all of the primitives created by this visualizer to match their * Entity counterpart at the given time. * * @param {JulianDate} time The time to update to. * @returns {Boolean} True if the visualizer successfully updated to the provided time, * false if the visualizer is waiting for asynchronous primitives to be created. */ GeometryVisualizer.prototype.update = function(time) { //>>includeStart('debug', pragmas.debug); if (!defined(time)) { throw new DeveloperError('time is required.'); } //>>includeEnd('debug'); var addedObjects = this._addedObjects; var added = addedObjects.values; var removedObjects = this._removedObjects; var removed = removedObjects.values; var changedObjects = this._changedObjects; var changed = changedObjects.values; var i; var entity; var id; var updater; for (i = removed.length - 1; i > -1; i--) { entity = removed[i]; id = entity.id; updater = this._updaters.get(id); removeUpdater(this, updater); updater.destroy(); this._updaters.remove(id); this._subscriptions.get(id)(); this._subscriptions.remove(id); } for (i = added.length - 1; i > -1; i--) { entity = added[i]; id = entity.id; updater = new this._type(entity, this._scene); this._updaters.set(id, updater); insertUpdaterIntoBatch(this, time, updater); this._subscriptions.set(id, updater.geometryChanged.addEventListener(GeometryVisualizer._onGeometryChanged, this)); } for (i = changed.length - 1; i > -1; i--) { entity = changed[i]; id = entity.id; updater = this._updaters.get(id); removeUpdater(this, updater); insertUpdaterIntoBatch(this, time, updater); } addedObjects.removeAll(); removedObjects.removeAll(); changedObjects.removeAll(); var isUpdated = this._closedColorBatch.update(time); isUpdated = this._closedMaterialBatch.update(time) && isUpdated; isUpdated = this._openColorBatch.update(time) && isUpdated; isUpdated = this._openMaterialBatch.update(time) && isUpdated; isUpdated = this._dynamicBatch.update(time) && isUpdated; isUpdated = this._outlineBatch.update(time) && isUpdated; return isUpdated; }; /** * Returns true if this object was destroyed; otherwise, false. * * @returns {Boolean} True if this object was destroyed; otherwise, false. */ GeometryVisualizer.prototype.isDestroyed = function() { return false; }; /** * Removes and destroys all primitives created by this instance. */ GeometryVisualizer.prototype.destroy = function() { this._entityCollection.collectionChanged.removeEventListener(GeometryVisualizer.prototype._onCollectionChanged, this); this._addedObjects.removeAll(); this._removedObjects.removeAll(); this._outlineBatch.removeAllPrimitives(); this._closedColorBatch.removeAllPrimitives(); this._closedMaterialBatch.removeAllPrimitives(); this._openColorBatch.removeAllPrimitives(); this._openMaterialBatch.removeAllPrimitives(); this._dynamicBatch.removeAllPrimitives(); var subscriptions = this._subscriptions.values; var len = subscriptions.length; for (var i = 0; i < len; i++) { subscriptions[i](); } this._subscriptions.removeAll(); return destroyObject(this); }; /** * @private */ GeometryVisualizer._onGeometryChanged = function(updater) { var removedObjects = this._removedObjects; var changedObjects = this._changedObjects; var entity = updater.entity; var id = entity.id; if (!defined(removedObjects.get(id)) && !defined(changedObjects.get(id))) { changedObjects.set(id, entity); } }; /** * @private */ GeometryVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed) { var addedObjects = this._addedObjects; var removedObjects = this._removedObjects; var changedObjects = this._changedObjects; var i; var id; var entity; for (i = removed.length - 1; i > -1; i--) { entity = removed[i]; id = entity.id; if (!addedObjects.remove(id)) { removedObjects.set(id, entity); changedObjects.remove(id); } } for (i = added.length - 1; i > -1; i--) { entity = added[i]; id = entity.id; if (removedObjects.remove(id)) { changedObjects.set(id, entity); } else { addedObjects.set(id, entity); } } }; return GeometryVisualizer; });