智慧水务管理系统 - 精河县供水工程综合管理平台

PointPrimitiveCollection.js 38KB

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