PointPrimitiveCollection.js 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202
  1. import BoundingSphere from "../Core/BoundingSphere.js";
  2. import Color from "../Core/Color.js";
  3. import ComponentDatatype from "../Core/ComponentDatatype.js";
  4. import defaultValue from "../Core/defaultValue.js";
  5. import defined from "../Core/defined.js";
  6. import destroyObject from "../Core/destroyObject.js";
  7. import DeveloperError from "../Core/DeveloperError.js";
  8. import EncodedCartesian3 from "../Core/EncodedCartesian3.js";
  9. import CesiumMath from "../Core/Math.js";
  10. import Matrix4 from "../Core/Matrix4.js";
  11. import PrimitiveType from "../Core/PrimitiveType.js";
  12. import WebGLConstants from "../Core/WebGLConstants.js";
  13. import BufferUsage from "../Renderer/BufferUsage.js";
  14. import ContextLimits from "../Renderer/ContextLimits.js";
  15. import DrawCommand from "../Renderer/DrawCommand.js";
  16. import Pass from "../Renderer/Pass.js";
  17. import RenderState from "../Renderer/RenderState.js";
  18. import ShaderProgram from "../Renderer/ShaderProgram.js";
  19. import ShaderSource from "../Renderer/ShaderSource.js";
  20. import VertexArrayFacade from "../Renderer/VertexArrayFacade.js";
  21. import PointPrimitiveCollectionFS from "../Shaders/PointPrimitiveCollectionFS.js";
  22. import PointPrimitiveCollectionVS from "../Shaders/PointPrimitiveCollectionVS.js";
  23. import BlendingState from "./BlendingState.js";
  24. import BlendOption from "./BlendOption.js";
  25. import PointPrimitive from "./PointPrimitive.js";
  26. import SceneMode from "./SceneMode.js";
  27. var SHOW_INDEX = PointPrimitive.SHOW_INDEX;
  28. var POSITION_INDEX = PointPrimitive.POSITION_INDEX;
  29. var COLOR_INDEX = PointPrimitive.COLOR_INDEX;
  30. var OUTLINE_COLOR_INDEX = PointPrimitive.OUTLINE_COLOR_INDEX;
  31. var OUTLINE_WIDTH_INDEX = PointPrimitive.OUTLINE_WIDTH_INDEX;
  32. var PIXEL_SIZE_INDEX = PointPrimitive.PIXEL_SIZE_INDEX;
  33. var SCALE_BY_DISTANCE_INDEX = PointPrimitive.SCALE_BY_DISTANCE_INDEX;
  34. var TRANSLUCENCY_BY_DISTANCE_INDEX =
  35. PointPrimitive.TRANSLUCENCY_BY_DISTANCE_INDEX;
  36. var DISTANCE_DISPLAY_CONDITION_INDEX =
  37. PointPrimitive.DISTANCE_DISPLAY_CONDITION_INDEX;
  38. var DISABLE_DEPTH_DISTANCE_INDEX = PointPrimitive.DISABLE_DEPTH_DISTANCE_INDEX;
  39. var NUMBER_OF_PROPERTIES = PointPrimitive.NUMBER_OF_PROPERTIES;
  40. var attributeLocations = {
  41. positionHighAndSize: 0,
  42. positionLowAndOutline: 1,
  43. compressedAttribute0: 2, // color, outlineColor, pick color
  44. compressedAttribute1: 3, // show, translucency by distance, some free space
  45. scaleByDistance: 4,
  46. distanceDisplayConditionAndDisableDepth: 5,
  47. };
  48. /**
  49. * A renderable collection of points.
  50. * <br /><br />
  51. * Points are added and removed from the collection using {@link PointPrimitiveCollection#add}
  52. * and {@link PointPrimitiveCollection#remove}.
  53. *
  54. * @alias PointPrimitiveCollection
  55. * @constructor
  56. *
  57. * @param {Object} [options] Object with the following properties:
  58. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each point from model to world coordinates.
  59. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  60. * @param {BlendOption} [options.blendOption=BlendOption.OPAQUE_AND_TRANSLUCENT] The point blending option. The default
  61. * is used for rendering both opaque and translucent points. However, if either all of the points are completely opaque or all are completely translucent,
  62. * setting the technique to BlendOption.OPAQUE or BlendOption.TRANSLUCENT can improve performance by up to 2x.
  63. *
  64. * @performance For best performance, prefer a few collections, each with many points, to
  65. * many collections with only a few points each. Organize collections so that points
  66. * with the same update frequency are in the same collection, i.e., points that do not
  67. * change should be in one collection; points that change every frame should be in another
  68. * collection; and so on.
  69. *
  70. *
  71. * @example
  72. * // Create a pointPrimitive collection with two points
  73. * var points = scene.primitives.add(new Cesium.PointPrimitiveCollection());
  74. * points.add({
  75. * position : new Cesium.Cartesian3(1.0, 2.0, 3.0),
  76. * color : Cesium.Color.YELLOW
  77. * });
  78. * points.add({
  79. * position : new Cesium.Cartesian3(4.0, 5.0, 6.0),
  80. * color : Cesium.Color.CYAN
  81. * });
  82. *
  83. * @see PointPrimitiveCollection#add
  84. * @see PointPrimitiveCollection#remove
  85. * @see PointPrimitive
  86. */
  87. function PointPrimitiveCollection(options) {
  88. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  89. this._sp = undefined;
  90. this._spTranslucent = undefined;
  91. this._rsOpaque = undefined;
  92. this._rsTranslucent = undefined;
  93. this._vaf = undefined;
  94. this._pointPrimitives = [];
  95. this._pointPrimitivesToUpdate = [];
  96. this._pointPrimitivesToUpdateIndex = 0;
  97. this._pointPrimitivesRemoved = false;
  98. this._createVertexArray = false;
  99. this._shaderScaleByDistance = false;
  100. this._compiledShaderScaleByDistance = false;
  101. this._shaderTranslucencyByDistance = false;
  102. this._compiledShaderTranslucencyByDistance = false;
  103. this._shaderDistanceDisplayCondition = false;
  104. this._compiledShaderDistanceDisplayCondition = false;
  105. this._shaderDisableDepthDistance = false;
  106. this._compiledShaderDisableDepthDistance = false;
  107. this._propertiesChanged = new Uint32Array(NUMBER_OF_PROPERTIES);
  108. this._maxPixelSize = 1.0;
  109. this._baseVolume = new BoundingSphere();
  110. this._baseVolumeWC = new BoundingSphere();
  111. this._baseVolume2D = new BoundingSphere();
  112. this._boundingVolume = new BoundingSphere();
  113. this._boundingVolumeDirty = false;
  114. this._colorCommands = [];
  115. /**
  116. * The 4x4 transformation matrix that transforms each point in this collection from model to world coordinates.
  117. * When this is the identity matrix, the pointPrimitives are drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  118. * Local reference frames can be used by providing a different transformation matrix, like that returned
  119. * by {@link Transforms.eastNorthUpToFixedFrame}.
  120. *
  121. * @type {Matrix4}
  122. * @default {@link Matrix4.IDENTITY}
  123. *
  124. *
  125. * @example
  126. * var center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
  127. * pointPrimitives.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
  128. * pointPrimitives.add({
  129. * color : Cesium.Color.ORANGE,
  130. * position : new Cesium.Cartesian3(0.0, 0.0, 0.0) // center
  131. * });
  132. * pointPrimitives.add({
  133. * color : Cesium.Color.YELLOW,
  134. * position : new Cesium.Cartesian3(1000000.0, 0.0, 0.0) // east
  135. * });
  136. * pointPrimitives.add({
  137. * color : Cesium.Color.GREEN,
  138. * position : new Cesium.Cartesian3(0.0, 1000000.0, 0.0) // north
  139. * });
  140. * pointPrimitives.add({
  141. * color : Cesium.Color.CYAN,
  142. * position : new Cesium.Cartesian3(0.0, 0.0, 1000000.0) // up
  143. * });
  144. *
  145. * @see Transforms.eastNorthUpToFixedFrame
  146. */
  147. this.modelMatrix = Matrix4.clone(
  148. defaultValue(options.modelMatrix, Matrix4.IDENTITY)
  149. );
  150. this._modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
  151. /**
  152. * This property is for debugging only; it is not for production use nor is it optimized.
  153. * <p>
  154. * Draws the bounding sphere for each draw command in the primitive.
  155. * </p>
  156. *
  157. * @type {Boolean}
  158. *
  159. * @default false
  160. */
  161. this.debugShowBoundingVolume = defaultValue(
  162. options.debugShowBoundingVolume,
  163. false
  164. );
  165. /**
  166. * The point blending option. The default is used for rendering both opaque and translucent points.
  167. * However, if either all of the points are completely opaque or all are completely translucent,
  168. * setting the technique to BlendOption.OPAQUE or BlendOption.TRANSLUCENT can improve
  169. * performance by up to 2x.
  170. * @type {BlendOption}
  171. * @default BlendOption.OPAQUE_AND_TRANSLUCENT
  172. */
  173. this.blendOption = defaultValue(
  174. options.blendOption,
  175. BlendOption.OPAQUE_AND_TRANSLUCENT
  176. );
  177. this._blendOption = undefined;
  178. this._mode = SceneMode.SCENE3D;
  179. this._maxTotalPointSize = 1;
  180. // The buffer usage for each attribute is determined based on the usage of the attribute over time.
  181. this._buffersUsage = [
  182. BufferUsage.STATIC_DRAW, // SHOW_INDEX
  183. BufferUsage.STATIC_DRAW, // POSITION_INDEX
  184. BufferUsage.STATIC_DRAW, // COLOR_INDEX
  185. BufferUsage.STATIC_DRAW, // OUTLINE_COLOR_INDEX
  186. BufferUsage.STATIC_DRAW, // OUTLINE_WIDTH_INDEX
  187. BufferUsage.STATIC_DRAW, // PIXEL_SIZE_INDEX
  188. BufferUsage.STATIC_DRAW, // SCALE_BY_DISTANCE_INDEX
  189. BufferUsage.STATIC_DRAW, // TRANSLUCENCY_BY_DISTANCE_INDEX
  190. BufferUsage.STATIC_DRAW, // DISTANCE_DISPLAY_CONDITION_INDEX
  191. ];
  192. var that = this;
  193. this._uniforms = {
  194. u_maxTotalPointSize: function () {
  195. return that._maxTotalPointSize;
  196. },
  197. };
  198. }
  199. Object.defineProperties(PointPrimitiveCollection.prototype, {
  200. /**
  201. * Returns the number of points in this collection. This is commonly used with
  202. * {@link PointPrimitiveCollection#get} to iterate over all the points
  203. * in the collection.
  204. * @memberof PointPrimitiveCollection.prototype
  205. * @type {Number}
  206. */
  207. length: {
  208. get: function () {
  209. removePointPrimitives(this);
  210. return this._pointPrimitives.length;
  211. },
  212. },
  213. });
  214. function destroyPointPrimitives(pointPrimitives) {
  215. var length = pointPrimitives.length;
  216. for (var i = 0; i < length; ++i) {
  217. if (pointPrimitives[i]) {
  218. pointPrimitives[i]._destroy();
  219. }
  220. }
  221. }
  222. /**
  223. * Creates and adds a point with the specified initial properties to the collection.
  224. * The added point is returned so it can be modified or removed from the collection later.
  225. *
  226. * @param {Object}[options] A template describing the point's properties as shown in Example 1.
  227. * @returns {PointPrimitive} The point that was added to the collection.
  228. *
  229. * @performance Calling <code>add</code> is expected constant time. However, the collection's vertex buffer
  230. * is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead. For
  231. * best performance, add as many pointPrimitives as possible before calling <code>update</code>.
  232. *
  233. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  234. *
  235. *
  236. * @example
  237. * // Example 1: Add a point, specifying all the default values.
  238. * var p = pointPrimitives.add({
  239. * show : true,
  240. * position : Cesium.Cartesian3.ZERO,
  241. * pixelSize : 10.0,
  242. * color : Cesium.Color.WHITE,
  243. * outlineColor : Cesium.Color.TRANSPARENT,
  244. * outlineWidth : 0.0,
  245. * id : undefined
  246. * });
  247. *
  248. * @example
  249. * // Example 2: Specify only the point's cartographic position.
  250. * var p = pointPrimitives.add({
  251. * position : Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
  252. * });
  253. *
  254. * @see PointPrimitiveCollection#remove
  255. * @see PointPrimitiveCollection#removeAll
  256. */
  257. PointPrimitiveCollection.prototype.add = function (options) {
  258. var p = new PointPrimitive(options, this);
  259. p._index = this._pointPrimitives.length;
  260. this._pointPrimitives.push(p);
  261. this._createVertexArray = true;
  262. return p;
  263. };
  264. /**
  265. * Removes a point from the collection.
  266. *
  267. * @param {PointPrimitive} pointPrimitive The point to remove.
  268. * @returns {Boolean} <code>true</code> if the point was removed; <code>false</code> if the point was not found in the collection.
  269. *
  270. * @performance Calling <code>remove</code> is expected constant time. However, the collection's vertex buffer
  271. * is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead. For
  272. * best performance, remove as many points as possible before calling <code>update</code>.
  273. * If you intend to temporarily hide a point, it is usually more efficient to call
  274. * {@link PointPrimitive#show} instead of removing and re-adding the point.
  275. *
  276. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  277. *
  278. *
  279. * @example
  280. * var p = pointPrimitives.add(...);
  281. * pointPrimitives.remove(p); // Returns true
  282. *
  283. * @see PointPrimitiveCollection#add
  284. * @see PointPrimitiveCollection#removeAll
  285. * @see PointPrimitive#show
  286. */
  287. PointPrimitiveCollection.prototype.remove = function (pointPrimitive) {
  288. if (this.contains(pointPrimitive)) {
  289. this._pointPrimitives[pointPrimitive._index] = null; // Removed later
  290. this._pointPrimitivesRemoved = true;
  291. this._createVertexArray = true;
  292. pointPrimitive._destroy();
  293. return true;
  294. }
  295. return false;
  296. };
  297. /**
  298. * Removes all points from the collection.
  299. *
  300. * @performance <code>O(n)</code>. It is more efficient to remove all the points
  301. * from a collection and then add new ones than to create a new collection entirely.
  302. *
  303. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  304. *
  305. *
  306. * @example
  307. * pointPrimitives.add(...);
  308. * pointPrimitives.add(...);
  309. * pointPrimitives.removeAll();
  310. *
  311. * @see PointPrimitiveCollection#add
  312. * @see PointPrimitiveCollection#remove
  313. */
  314. PointPrimitiveCollection.prototype.removeAll = function () {
  315. destroyPointPrimitives(this._pointPrimitives);
  316. this._pointPrimitives = [];
  317. this._pointPrimitivesToUpdate = [];
  318. this._pointPrimitivesToUpdateIndex = 0;
  319. this._pointPrimitivesRemoved = false;
  320. this._createVertexArray = true;
  321. };
  322. function removePointPrimitives(pointPrimitiveCollection) {
  323. if (pointPrimitiveCollection._pointPrimitivesRemoved) {
  324. pointPrimitiveCollection._pointPrimitivesRemoved = false;
  325. var newPointPrimitives = [];
  326. var pointPrimitives = pointPrimitiveCollection._pointPrimitives;
  327. var length = pointPrimitives.length;
  328. for (var i = 0, j = 0; i < length; ++i) {
  329. var pointPrimitive = pointPrimitives[i];
  330. if (pointPrimitive) {
  331. pointPrimitive._index = j++;
  332. newPointPrimitives.push(pointPrimitive);
  333. }
  334. }
  335. pointPrimitiveCollection._pointPrimitives = newPointPrimitives;
  336. }
  337. }
  338. PointPrimitiveCollection.prototype._updatePointPrimitive = function (
  339. pointPrimitive,
  340. propertyChanged
  341. ) {
  342. if (!pointPrimitive._dirty) {
  343. this._pointPrimitivesToUpdate[
  344. this._pointPrimitivesToUpdateIndex++
  345. ] = pointPrimitive;
  346. }
  347. ++this._propertiesChanged[propertyChanged];
  348. };
  349. /**
  350. * Check whether this collection contains a given point.
  351. *
  352. * @param {PointPrimitive} [pointPrimitive] The point to check for.
  353. * @returns {Boolean} true if this collection contains the point, false otherwise.
  354. *
  355. * @see PointPrimitiveCollection#get
  356. */
  357. PointPrimitiveCollection.prototype.contains = function (pointPrimitive) {
  358. return (
  359. defined(pointPrimitive) && pointPrimitive._pointPrimitiveCollection === this
  360. );
  361. };
  362. /**
  363. * Returns the point in the collection at the specified index. Indices are zero-based
  364. * and increase as points are added. Removing a point shifts all points after
  365. * it to the left, changing their indices. This function is commonly used with
  366. * {@link PointPrimitiveCollection#length} to iterate over all the points
  367. * in the collection.
  368. *
  369. * @param {Number} index The zero-based index of the point.
  370. * @returns {PointPrimitive} The point at the specified index.
  371. *
  372. * @performance Expected constant time. If points were removed from the collection and
  373. * {@link PointPrimitiveCollection#update} was not called, an implicit <code>O(n)</code>
  374. * operation is performed.
  375. *
  376. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  377. *
  378. *
  379. * @example
  380. * // Toggle the show property of every point in the collection
  381. * var len = pointPrimitives.length;
  382. * for (var i = 0; i < len; ++i) {
  383. * var p = pointPrimitives.get(i);
  384. * p.show = !p.show;
  385. * }
  386. *
  387. * @see PointPrimitiveCollection#length
  388. */
  389. PointPrimitiveCollection.prototype.get = function (index) {
  390. //>>includeStart('debug', pragmas.debug);
  391. if (!defined(index)) {
  392. throw new DeveloperError("index is required.");
  393. }
  394. //>>includeEnd('debug');
  395. removePointPrimitives(this);
  396. return this._pointPrimitives[index];
  397. };
  398. PointPrimitiveCollection.prototype.computeNewBuffersUsage = function () {
  399. var buffersUsage = this._buffersUsage;
  400. var usageChanged = false;
  401. var properties = this._propertiesChanged;
  402. for (var k = 0; k < NUMBER_OF_PROPERTIES; ++k) {
  403. var newUsage =
  404. properties[k] === 0 ? BufferUsage.STATIC_DRAW : BufferUsage.STREAM_DRAW;
  405. usageChanged = usageChanged || buffersUsage[k] !== newUsage;
  406. buffersUsage[k] = newUsage;
  407. }
  408. return usageChanged;
  409. };
  410. function createVAF(context, numberOfPointPrimitives, buffersUsage) {
  411. return new VertexArrayFacade(
  412. context,
  413. [
  414. {
  415. index: attributeLocations.positionHighAndSize,
  416. componentsPerAttribute: 4,
  417. componentDatatype: ComponentDatatype.FLOAT,
  418. usage: buffersUsage[POSITION_INDEX],
  419. },
  420. {
  421. index: attributeLocations.positionLowAndShow,
  422. componentsPerAttribute: 4,
  423. componentDatatype: ComponentDatatype.FLOAT,
  424. usage: buffersUsage[POSITION_INDEX],
  425. },
  426. {
  427. index: attributeLocations.compressedAttribute0,
  428. componentsPerAttribute: 4,
  429. componentDatatype: ComponentDatatype.FLOAT,
  430. usage: buffersUsage[COLOR_INDEX],
  431. },
  432. {
  433. index: attributeLocations.compressedAttribute1,
  434. componentsPerAttribute: 4,
  435. componentDatatype: ComponentDatatype.FLOAT,
  436. usage: buffersUsage[TRANSLUCENCY_BY_DISTANCE_INDEX],
  437. },
  438. {
  439. index: attributeLocations.scaleByDistance,
  440. componentsPerAttribute: 4,
  441. componentDatatype: ComponentDatatype.FLOAT,
  442. usage: buffersUsage[SCALE_BY_DISTANCE_INDEX],
  443. },
  444. {
  445. index: attributeLocations.distanceDisplayConditionAndDisableDepth,
  446. componentsPerAttribute: 3,
  447. componentDatatype: ComponentDatatype.FLOAT,
  448. usage: buffersUsage[DISTANCE_DISPLAY_CONDITION_INDEX],
  449. },
  450. ],
  451. numberOfPointPrimitives
  452. ); // 1 vertex per pointPrimitive
  453. }
  454. ///////////////////////////////////////////////////////////////////////////
  455. // PERFORMANCE_IDEA: Save memory if a property is the same for all pointPrimitives, use a latched attribute state,
  456. // instead of storing it in a vertex buffer.
  457. var writePositionScratch = new EncodedCartesian3();
  458. function writePositionSizeAndOutline(
  459. pointPrimitiveCollection,
  460. context,
  461. vafWriters,
  462. pointPrimitive
  463. ) {
  464. var i = pointPrimitive._index;
  465. var position = pointPrimitive._getActualPosition();
  466. if (pointPrimitiveCollection._mode === SceneMode.SCENE3D) {
  467. BoundingSphere.expand(
  468. pointPrimitiveCollection._baseVolume,
  469. position,
  470. pointPrimitiveCollection._baseVolume
  471. );
  472. pointPrimitiveCollection._boundingVolumeDirty = true;
  473. }
  474. EncodedCartesian3.fromCartesian(position, writePositionScratch);
  475. var pixelSize = pointPrimitive.pixelSize;
  476. var outlineWidth = pointPrimitive.outlineWidth;
  477. pointPrimitiveCollection._maxPixelSize = Math.max(
  478. pointPrimitiveCollection._maxPixelSize,
  479. pixelSize + outlineWidth
  480. );
  481. var positionHighWriter = vafWriters[attributeLocations.positionHighAndSize];
  482. var high = writePositionScratch.high;
  483. positionHighWriter(i, high.x, high.y, high.z, pixelSize);
  484. var positionLowWriter = vafWriters[attributeLocations.positionLowAndOutline];
  485. var low = writePositionScratch.low;
  486. positionLowWriter(i, low.x, low.y, low.z, outlineWidth);
  487. }
  488. var LEFT_SHIFT16 = 65536.0; // 2^16
  489. var LEFT_SHIFT8 = 256.0; // 2^8
  490. function writeCompressedAttrib0(
  491. pointPrimitiveCollection,
  492. context,
  493. vafWriters,
  494. pointPrimitive
  495. ) {
  496. var i = pointPrimitive._index;
  497. var color = pointPrimitive.color;
  498. var pickColor = pointPrimitive.getPickId(context).color;
  499. var outlineColor = pointPrimitive.outlineColor;
  500. var red = Color.floatToByte(color.red);
  501. var green = Color.floatToByte(color.green);
  502. var blue = Color.floatToByte(color.blue);
  503. var compressed0 = red * LEFT_SHIFT16 + green * LEFT_SHIFT8 + blue;
  504. red = Color.floatToByte(outlineColor.red);
  505. green = Color.floatToByte(outlineColor.green);
  506. blue = Color.floatToByte(outlineColor.blue);
  507. var compressed1 = red * LEFT_SHIFT16 + green * LEFT_SHIFT8 + blue;
  508. red = Color.floatToByte(pickColor.red);
  509. green = Color.floatToByte(pickColor.green);
  510. blue = Color.floatToByte(pickColor.blue);
  511. var compressed2 = red * LEFT_SHIFT16 + green * LEFT_SHIFT8 + blue;
  512. var compressed3 =
  513. Color.floatToByte(color.alpha) * LEFT_SHIFT16 +
  514. Color.floatToByte(outlineColor.alpha) * LEFT_SHIFT8 +
  515. Color.floatToByte(pickColor.alpha);
  516. var writer = vafWriters[attributeLocations.compressedAttribute0];
  517. writer(i, compressed0, compressed1, compressed2, compressed3);
  518. }
  519. function writeCompressedAttrib1(
  520. pointPrimitiveCollection,
  521. context,
  522. vafWriters,
  523. pointPrimitive
  524. ) {
  525. var i = pointPrimitive._index;
  526. var near = 0.0;
  527. var nearValue = 1.0;
  528. var far = 1.0;
  529. var farValue = 1.0;
  530. var translucency = pointPrimitive.translucencyByDistance;
  531. if (defined(translucency)) {
  532. near = translucency.near;
  533. nearValue = translucency.nearValue;
  534. far = translucency.far;
  535. farValue = translucency.farValue;
  536. if (nearValue !== 1.0 || farValue !== 1.0) {
  537. // translucency by distance calculation in shader need not be enabled
  538. // until a pointPrimitive with near and far !== 1.0 is found
  539. pointPrimitiveCollection._shaderTranslucencyByDistance = true;
  540. }
  541. }
  542. var show = pointPrimitive.show && pointPrimitive.clusterShow;
  543. // If the color alphas are zero, do not show this pointPrimitive. This lets us avoid providing
  544. // color during the pick pass and also eliminates a discard in the fragment shader.
  545. if (
  546. pointPrimitive.color.alpha === 0.0 &&
  547. pointPrimitive.outlineColor.alpha === 0.0
  548. ) {
  549. show = false;
  550. }
  551. nearValue = CesiumMath.clamp(nearValue, 0.0, 1.0);
  552. nearValue = nearValue === 1.0 ? 255.0 : (nearValue * 255.0) | 0;
  553. var compressed0 = (show ? 1.0 : 0.0) * LEFT_SHIFT8 + nearValue;
  554. farValue = CesiumMath.clamp(farValue, 0.0, 1.0);
  555. farValue = farValue === 1.0 ? 255.0 : (farValue * 255.0) | 0;
  556. var compressed1 = farValue;
  557. var writer = vafWriters[attributeLocations.compressedAttribute1];
  558. writer(i, compressed0, compressed1, near, far);
  559. }
  560. function writeScaleByDistance(
  561. pointPrimitiveCollection,
  562. context,
  563. vafWriters,
  564. pointPrimitive
  565. ) {
  566. var i = pointPrimitive._index;
  567. var writer = vafWriters[attributeLocations.scaleByDistance];
  568. var near = 0.0;
  569. var nearValue = 1.0;
  570. var far = 1.0;
  571. var farValue = 1.0;
  572. var scale = pointPrimitive.scaleByDistance;
  573. if (defined(scale)) {
  574. near = scale.near;
  575. nearValue = scale.nearValue;
  576. far = scale.far;
  577. farValue = scale.farValue;
  578. if (nearValue !== 1.0 || farValue !== 1.0) {
  579. // scale by distance calculation in shader need not be enabled
  580. // until a pointPrimitive with near and far !== 1.0 is found
  581. pointPrimitiveCollection._shaderScaleByDistance = true;
  582. }
  583. }
  584. writer(i, near, nearValue, far, farValue);
  585. }
  586. function writeDistanceDisplayConditionAndDepthDisable(
  587. pointPrimitiveCollection,
  588. context,
  589. vafWriters,
  590. pointPrimitive
  591. ) {
  592. var i = pointPrimitive._index;
  593. var writer =
  594. vafWriters[attributeLocations.distanceDisplayConditionAndDisableDepth];
  595. var near = 0.0;
  596. var far = Number.MAX_VALUE;
  597. var distanceDisplayCondition = pointPrimitive.distanceDisplayCondition;
  598. if (defined(distanceDisplayCondition)) {
  599. near = distanceDisplayCondition.near;
  600. far = distanceDisplayCondition.far;
  601. near *= near;
  602. far *= far;
  603. pointPrimitiveCollection._shaderDistanceDisplayCondition = true;
  604. }
  605. var disableDepthTestDistance = pointPrimitive.disableDepthTestDistance;
  606. disableDepthTestDistance *= disableDepthTestDistance;
  607. if (disableDepthTestDistance > 0.0) {
  608. pointPrimitiveCollection._shaderDisableDepthDistance = true;
  609. if (disableDepthTestDistance === Number.POSITIVE_INFINITY) {
  610. disableDepthTestDistance = -1.0;
  611. }
  612. }
  613. writer(i, near, far, disableDepthTestDistance);
  614. }
  615. function writePointPrimitive(
  616. pointPrimitiveCollection,
  617. context,
  618. vafWriters,
  619. pointPrimitive
  620. ) {
  621. writePositionSizeAndOutline(
  622. pointPrimitiveCollection,
  623. context,
  624. vafWriters,
  625. pointPrimitive
  626. );
  627. writeCompressedAttrib0(
  628. pointPrimitiveCollection,
  629. context,
  630. vafWriters,
  631. pointPrimitive
  632. );
  633. writeCompressedAttrib1(
  634. pointPrimitiveCollection,
  635. context,
  636. vafWriters,
  637. pointPrimitive
  638. );
  639. writeScaleByDistance(
  640. pointPrimitiveCollection,
  641. context,
  642. vafWriters,
  643. pointPrimitive
  644. );
  645. writeDistanceDisplayConditionAndDepthDisable(
  646. pointPrimitiveCollection,
  647. context,
  648. vafWriters,
  649. pointPrimitive
  650. );
  651. }
  652. function recomputeActualPositions(
  653. pointPrimitiveCollection,
  654. pointPrimitives,
  655. length,
  656. frameState,
  657. modelMatrix,
  658. recomputeBoundingVolume
  659. ) {
  660. var boundingVolume;
  661. if (frameState.mode === SceneMode.SCENE3D) {
  662. boundingVolume = pointPrimitiveCollection._baseVolume;
  663. pointPrimitiveCollection._boundingVolumeDirty = true;
  664. } else {
  665. boundingVolume = pointPrimitiveCollection._baseVolume2D;
  666. }
  667. var positions = [];
  668. for (var i = 0; i < length; ++i) {
  669. var pointPrimitive = pointPrimitives[i];
  670. var position = pointPrimitive.position;
  671. var actualPosition = PointPrimitive._computeActualPosition(
  672. position,
  673. frameState,
  674. modelMatrix
  675. );
  676. if (defined(actualPosition)) {
  677. pointPrimitive._setActualPosition(actualPosition);
  678. if (recomputeBoundingVolume) {
  679. positions.push(actualPosition);
  680. } else {
  681. BoundingSphere.expand(boundingVolume, actualPosition, boundingVolume);
  682. }
  683. }
  684. }
  685. if (recomputeBoundingVolume) {
  686. BoundingSphere.fromPoints(positions, boundingVolume);
  687. }
  688. }
  689. function updateMode(pointPrimitiveCollection, frameState) {
  690. var mode = frameState.mode;
  691. var pointPrimitives = pointPrimitiveCollection._pointPrimitives;
  692. var pointPrimitivesToUpdate =
  693. pointPrimitiveCollection._pointPrimitivesToUpdate;
  694. var modelMatrix = pointPrimitiveCollection._modelMatrix;
  695. if (
  696. pointPrimitiveCollection._createVertexArray ||
  697. pointPrimitiveCollection._mode !== mode ||
  698. (mode !== SceneMode.SCENE3D &&
  699. !Matrix4.equals(modelMatrix, pointPrimitiveCollection.modelMatrix))
  700. ) {
  701. pointPrimitiveCollection._mode = mode;
  702. Matrix4.clone(pointPrimitiveCollection.modelMatrix, modelMatrix);
  703. pointPrimitiveCollection._createVertexArray = true;
  704. if (
  705. mode === SceneMode.SCENE3D ||
  706. mode === SceneMode.SCENE2D ||
  707. mode === SceneMode.COLUMBUS_VIEW
  708. ) {
  709. recomputeActualPositions(
  710. pointPrimitiveCollection,
  711. pointPrimitives,
  712. pointPrimitives.length,
  713. frameState,
  714. modelMatrix,
  715. true
  716. );
  717. }
  718. } else if (mode === SceneMode.MORPHING) {
  719. recomputeActualPositions(
  720. pointPrimitiveCollection,
  721. pointPrimitives,
  722. pointPrimitives.length,
  723. frameState,
  724. modelMatrix,
  725. true
  726. );
  727. } else if (mode === SceneMode.SCENE2D || mode === SceneMode.COLUMBUS_VIEW) {
  728. recomputeActualPositions(
  729. pointPrimitiveCollection,
  730. pointPrimitivesToUpdate,
  731. pointPrimitiveCollection._pointPrimitivesToUpdateIndex,
  732. frameState,
  733. modelMatrix,
  734. false
  735. );
  736. }
  737. }
  738. function updateBoundingVolume(collection, frameState, boundingVolume) {
  739. var pixelSize = frameState.camera.getPixelSize(
  740. boundingVolume,
  741. frameState.context.drawingBufferWidth,
  742. frameState.context.drawingBufferHeight
  743. );
  744. var size = pixelSize * collection._maxPixelSize;
  745. boundingVolume.radius += size;
  746. }
  747. var scratchWriterArray = [];
  748. /**
  749. * @private
  750. */
  751. PointPrimitiveCollection.prototype.update = function (frameState) {
  752. removePointPrimitives(this);
  753. this._maxTotalPointSize = ContextLimits.maximumAliasedPointSize;
  754. updateMode(this, frameState);
  755. var pointPrimitives = this._pointPrimitives;
  756. var pointPrimitivesLength = pointPrimitives.length;
  757. var pointPrimitivesToUpdate = this._pointPrimitivesToUpdate;
  758. var pointPrimitivesToUpdateLength = this._pointPrimitivesToUpdateIndex;
  759. var properties = this._propertiesChanged;
  760. var createVertexArray = this._createVertexArray;
  761. var vafWriters;
  762. var context = frameState.context;
  763. var pass = frameState.passes;
  764. var picking = pass.pick;
  765. // PERFORMANCE_IDEA: Round robin multiple buffers.
  766. if (createVertexArray || (!picking && this.computeNewBuffersUsage())) {
  767. this._createVertexArray = false;
  768. for (var k = 0; k < NUMBER_OF_PROPERTIES; ++k) {
  769. properties[k] = 0;
  770. }
  771. this._vaf = this._vaf && this._vaf.destroy();
  772. if (pointPrimitivesLength > 0) {
  773. // PERFORMANCE_IDEA: Instead of creating a new one, resize like std::vector.
  774. this._vaf = createVAF(context, pointPrimitivesLength, this._buffersUsage);
  775. vafWriters = this._vaf.writers;
  776. // Rewrite entire buffer if pointPrimitives were added or removed.
  777. for (var i = 0; i < pointPrimitivesLength; ++i) {
  778. var pointPrimitive = this._pointPrimitives[i];
  779. pointPrimitive._dirty = false; // In case it needed an update.
  780. writePointPrimitive(this, context, vafWriters, pointPrimitive);
  781. }
  782. this._vaf.commit();
  783. }
  784. this._pointPrimitivesToUpdateIndex = 0;
  785. } else if (pointPrimitivesToUpdateLength > 0) {
  786. // PointPrimitives were modified, but none were added or removed.
  787. var writers = scratchWriterArray;
  788. writers.length = 0;
  789. if (
  790. properties[POSITION_INDEX] ||
  791. properties[OUTLINE_WIDTH_INDEX] ||
  792. properties[PIXEL_SIZE_INDEX]
  793. ) {
  794. writers.push(writePositionSizeAndOutline);
  795. }
  796. if (properties[COLOR_INDEX] || properties[OUTLINE_COLOR_INDEX]) {
  797. writers.push(writeCompressedAttrib0);
  798. }
  799. if (properties[SHOW_INDEX] || properties[TRANSLUCENCY_BY_DISTANCE_INDEX]) {
  800. writers.push(writeCompressedAttrib1);
  801. }
  802. if (properties[SCALE_BY_DISTANCE_INDEX]) {
  803. writers.push(writeScaleByDistance);
  804. }
  805. if (
  806. properties[DISTANCE_DISPLAY_CONDITION_INDEX] ||
  807. properties[DISABLE_DEPTH_DISTANCE_INDEX]
  808. ) {
  809. writers.push(writeDistanceDisplayConditionAndDepthDisable);
  810. }
  811. var numWriters = writers.length;
  812. vafWriters = this._vaf.writers;
  813. if (pointPrimitivesToUpdateLength / pointPrimitivesLength > 0.1) {
  814. // If more than 10% of pointPrimitive change, rewrite the entire buffer.
  815. // PERFORMANCE_IDEA: I totally made up 10% :).
  816. for (var m = 0; m < pointPrimitivesToUpdateLength; ++m) {
  817. var b = pointPrimitivesToUpdate[m];
  818. b._dirty = false;
  819. for (var n = 0; n < numWriters; ++n) {
  820. writers[n](this, context, vafWriters, b);
  821. }
  822. }
  823. this._vaf.commit();
  824. } else {
  825. for (var h = 0; h < pointPrimitivesToUpdateLength; ++h) {
  826. var bb = pointPrimitivesToUpdate[h];
  827. bb._dirty = false;
  828. for (var o = 0; o < numWriters; ++o) {
  829. writers[o](this, context, vafWriters, bb);
  830. }
  831. this._vaf.subCommit(bb._index, 1);
  832. }
  833. this._vaf.endSubCommits();
  834. }
  835. this._pointPrimitivesToUpdateIndex = 0;
  836. }
  837. // If the number of total pointPrimitives ever shrinks considerably
  838. // Truncate pointPrimitivesToUpdate so that we free memory that we're
  839. // not going to be using.
  840. if (pointPrimitivesToUpdateLength > pointPrimitivesLength * 1.5) {
  841. pointPrimitivesToUpdate.length = pointPrimitivesLength;
  842. }
  843. if (!defined(this._vaf) || !defined(this._vaf.va)) {
  844. return;
  845. }
  846. if (this._boundingVolumeDirty) {
  847. this._boundingVolumeDirty = false;
  848. BoundingSphere.transform(
  849. this._baseVolume,
  850. this.modelMatrix,
  851. this._baseVolumeWC
  852. );
  853. }
  854. var boundingVolume;
  855. var modelMatrix = Matrix4.IDENTITY;
  856. if (frameState.mode === SceneMode.SCENE3D) {
  857. modelMatrix = this.modelMatrix;
  858. boundingVolume = BoundingSphere.clone(
  859. this._baseVolumeWC,
  860. this._boundingVolume
  861. );
  862. } else {
  863. boundingVolume = BoundingSphere.clone(
  864. this._baseVolume2D,
  865. this._boundingVolume
  866. );
  867. }
  868. updateBoundingVolume(this, frameState, boundingVolume);
  869. var blendOptionChanged = this._blendOption !== this.blendOption;
  870. this._blendOption = this.blendOption;
  871. if (blendOptionChanged) {
  872. if (
  873. this._blendOption === BlendOption.OPAQUE ||
  874. this._blendOption === BlendOption.OPAQUE_AND_TRANSLUCENT
  875. ) {
  876. this._rsOpaque = RenderState.fromCache({
  877. depthTest: {
  878. enabled: true,
  879. func: WebGLConstants.LEQUAL,
  880. },
  881. depthMask: true,
  882. });
  883. } else {
  884. this._rsOpaque = undefined;
  885. }
  886. if (
  887. this._blendOption === BlendOption.TRANSLUCENT ||
  888. this._blendOption === BlendOption.OPAQUE_AND_TRANSLUCENT
  889. ) {
  890. this._rsTranslucent = RenderState.fromCache({
  891. depthTest: {
  892. enabled: true,
  893. func: WebGLConstants.LEQUAL,
  894. },
  895. depthMask: false,
  896. blending: BlendingState.ALPHA_BLEND,
  897. });
  898. } else {
  899. this._rsTranslucent = undefined;
  900. }
  901. }
  902. this._shaderDisableDepthDistance =
  903. this._shaderDisableDepthDistance ||
  904. frameState.minimumDisableDepthTestDistance !== 0.0;
  905. var vs;
  906. var fs;
  907. if (
  908. blendOptionChanged ||
  909. (this._shaderScaleByDistance && !this._compiledShaderScaleByDistance) ||
  910. (this._shaderTranslucencyByDistance &&
  911. !this._compiledShaderTranslucencyByDistance) ||
  912. (this._shaderDistanceDisplayCondition &&
  913. !this._compiledShaderDistanceDisplayCondition) ||
  914. this._shaderDisableDepthDistance !==
  915. this._compiledShaderDisableDepthDistance
  916. ) {
  917. vs = new ShaderSource({
  918. sources: [PointPrimitiveCollectionVS],
  919. });
  920. if (this._shaderScaleByDistance) {
  921. vs.defines.push("EYE_DISTANCE_SCALING");
  922. }
  923. if (this._shaderTranslucencyByDistance) {
  924. vs.defines.push("EYE_DISTANCE_TRANSLUCENCY");
  925. }
  926. if (this._shaderDistanceDisplayCondition) {
  927. vs.defines.push("DISTANCE_DISPLAY_CONDITION");
  928. }
  929. if (this._shaderDisableDepthDistance) {
  930. vs.defines.push("DISABLE_DEPTH_DISTANCE");
  931. }
  932. if (this._blendOption === BlendOption.OPAQUE_AND_TRANSLUCENT) {
  933. fs = new ShaderSource({
  934. defines: ["OPAQUE"],
  935. sources: [PointPrimitiveCollectionFS],
  936. });
  937. this._sp = ShaderProgram.replaceCache({
  938. context: context,
  939. shaderProgram: this._sp,
  940. vertexShaderSource: vs,
  941. fragmentShaderSource: fs,
  942. attributeLocations: attributeLocations,
  943. });
  944. fs = new ShaderSource({
  945. defines: ["TRANSLUCENT"],
  946. sources: [PointPrimitiveCollectionFS],
  947. });
  948. this._spTranslucent = ShaderProgram.replaceCache({
  949. context: context,
  950. shaderProgram: this._spTranslucent,
  951. vertexShaderSource: vs,
  952. fragmentShaderSource: fs,
  953. attributeLocations: attributeLocations,
  954. });
  955. }
  956. if (this._blendOption === BlendOption.OPAQUE) {
  957. fs = new ShaderSource({
  958. sources: [PointPrimitiveCollectionFS],
  959. });
  960. this._sp = ShaderProgram.replaceCache({
  961. context: context,
  962. shaderProgram: this._sp,
  963. vertexShaderSource: vs,
  964. fragmentShaderSource: fs,
  965. attributeLocations: attributeLocations,
  966. });
  967. }
  968. if (this._blendOption === BlendOption.TRANSLUCENT) {
  969. fs = new ShaderSource({
  970. sources: [PointPrimitiveCollectionFS],
  971. });
  972. this._spTranslucent = ShaderProgram.replaceCache({
  973. context: context,
  974. shaderProgram: this._spTranslucent,
  975. vertexShaderSource: vs,
  976. fragmentShaderSource: fs,
  977. attributeLocations: attributeLocations,
  978. });
  979. }
  980. this._compiledShaderScaleByDistance = this._shaderScaleByDistance;
  981. this._compiledShaderTranslucencyByDistance = this._shaderTranslucencyByDistance;
  982. this._compiledShaderDistanceDisplayCondition = this._shaderDistanceDisplayCondition;
  983. this._compiledShaderDisableDepthDistance = this._shaderDisableDepthDistance;
  984. }
  985. var va;
  986. var vaLength;
  987. var command;
  988. var j;
  989. var commandList = frameState.commandList;
  990. if (pass.render || picking) {
  991. var colorList = this._colorCommands;
  992. var opaque = this._blendOption === BlendOption.OPAQUE;
  993. var opaqueAndTranslucent =
  994. this._blendOption === BlendOption.OPAQUE_AND_TRANSLUCENT;
  995. va = this._vaf.va;
  996. vaLength = va.length;
  997. colorList.length = vaLength;
  998. var totalLength = opaqueAndTranslucent ? vaLength * 2 : vaLength;
  999. for (j = 0; j < totalLength; ++j) {
  1000. var opaqueCommand = opaque || (opaqueAndTranslucent && j % 2 === 0);
  1001. command = colorList[j];
  1002. if (!defined(command)) {
  1003. command = colorList[j] = new DrawCommand();
  1004. }
  1005. command.primitiveType = PrimitiveType.POINTS;
  1006. command.pass =
  1007. opaqueCommand || !opaqueAndTranslucent ? Pass.OPAQUE : Pass.TRANSLUCENT;
  1008. command.owner = this;
  1009. var index = opaqueAndTranslucent ? Math.floor(j / 2.0) : j;
  1010. command.boundingVolume = boundingVolume;
  1011. command.modelMatrix = modelMatrix;
  1012. command.shaderProgram = opaqueCommand ? this._sp : this._spTranslucent;
  1013. command.uniformMap = this._uniforms;
  1014. command.vertexArray = va[index].va;
  1015. command.renderState = opaqueCommand
  1016. ? this._rsOpaque
  1017. : this._rsTranslucent;
  1018. command.debugShowBoundingVolume = this.debugShowBoundingVolume;
  1019. command.pickId = "v_pickColor";
  1020. commandList.push(command);
  1021. }
  1022. }
  1023. };
  1024. /**
  1025. * Returns true if this object was destroyed; otherwise, false.
  1026. * <br /><br />
  1027. * If this object was destroyed, it should not be used; calling any function other than
  1028. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  1029. *
  1030. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  1031. *
  1032. * @see PointPrimitiveCollection#destroy
  1033. */
  1034. PointPrimitiveCollection.prototype.isDestroyed = function () {
  1035. return false;
  1036. };
  1037. /**
  1038. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  1039. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  1040. * <br /><br />
  1041. * Once an object is destroyed, it should not be used; calling any function other than
  1042. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  1043. * assign the return value (<code>undefined</code>) to the object as done in the example.
  1044. *
  1045. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  1046. *
  1047. *
  1048. * @example
  1049. * pointPrimitives = pointPrimitives && pointPrimitives.destroy();
  1050. *
  1051. * @see PointPrimitiveCollection#isDestroyed
  1052. */
  1053. PointPrimitiveCollection.prototype.destroy = function () {
  1054. this._sp = this._sp && this._sp.destroy();
  1055. this._spTranslucent = this._spTranslucent && this._spTranslucent.destroy();
  1056. this._spPick = this._spPick && this._spPick.destroy();
  1057. this._vaf = this._vaf && this._vaf.destroy();
  1058. destroyPointPrimitives(this._pointPrimitives);
  1059. return destroyObject(this);
  1060. };
  1061. export default PointPrimitiveCollection;