PolylineCollection.js 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498
  1. /*global define*/
  2. define([
  3. '../Core/BoundingSphere',
  4. '../Core/Cartesian3',
  5. '../Core/Cartesian4',
  6. '../Core/Cartographic',
  7. '../Core/Color',
  8. '../Core/ComponentDatatype',
  9. '../Core/defaultValue',
  10. '../Core/defined',
  11. '../Core/defineProperties',
  12. '../Core/destroyObject',
  13. '../Core/DeveloperError',
  14. '../Core/EncodedCartesian3',
  15. '../Core/IndexDatatype',
  16. '../Core/Intersect',
  17. '../Core/Math',
  18. '../Core/Matrix4',
  19. '../Renderer/BufferUsage',
  20. '../Renderer/DrawCommand',
  21. '../Renderer/ShaderSource',
  22. '../Shaders/PolylineCommon',
  23. '../Shaders/PolylineFS',
  24. '../Shaders/PolylineVS',
  25. './BlendingState',
  26. './Material',
  27. './Pass',
  28. './Polyline',
  29. './SceneMode'
  30. ], function(
  31. BoundingSphere,
  32. Cartesian3,
  33. Cartesian4,
  34. Cartographic,
  35. Color,
  36. ComponentDatatype,
  37. defaultValue,
  38. defined,
  39. defineProperties,
  40. destroyObject,
  41. DeveloperError,
  42. EncodedCartesian3,
  43. IndexDatatype,
  44. Intersect,
  45. CesiumMath,
  46. Matrix4,
  47. BufferUsage,
  48. DrawCommand,
  49. ShaderSource,
  50. PolylineCommon,
  51. PolylineFS,
  52. PolylineVS,
  53. BlendingState,
  54. Material,
  55. Pass,
  56. Polyline,
  57. SceneMode) {
  58. "use strict";
  59. var SHOW_INDEX = Polyline.SHOW_INDEX;
  60. var WIDTH_INDEX = Polyline.WIDTH_INDEX;
  61. var POSITION_INDEX = Polyline.POSITION_INDEX;
  62. var MATERIAL_INDEX = Polyline.MATERIAL_INDEX;
  63. //POSITION_SIZE_INDEX is needed for when the polyline's position array changes size.
  64. //When it does, we need to recreate the indicesBuffer.
  65. var POSITION_SIZE_INDEX = Polyline.POSITION_SIZE_INDEX;
  66. var NUMBER_OF_PROPERTIES = Polyline.NUMBER_OF_PROPERTIES;
  67. var attributeLocations = {
  68. texCoordExpandWidthAndShow : 0,
  69. position3DHigh : 1,
  70. position3DLow : 2,
  71. position2DHigh : 3,
  72. position2DLow : 4,
  73. prevPosition3DHigh : 5,
  74. prevPosition3DLow : 6,
  75. prevPosition2DHigh : 7,
  76. prevPosition2DLow : 8,
  77. nextPosition3DHigh : 9,
  78. nextPosition3DLow : 10,
  79. nextPosition2DHigh : 11,
  80. nextPosition2DLow : 12,
  81. pickColor : 13
  82. };
  83. /**
  84. * A renderable collection of polylines.
  85. * <br /><br />
  86. * <div align="center">
  87. * <img src="images/Polyline.png" width="400" height="300" /><br />
  88. * Example polylines
  89. * </div>
  90. * <br /><br />
  91. * Polylines are added and removed from the collection using {@link PolylineCollection#add}
  92. * and {@link PolylineCollection#remove}.
  93. *
  94. * @alias PolylineCollection
  95. * @constructor
  96. *
  97. * @param {Object} [options] Object with the following properties:
  98. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each polyline from model to world coordinates.
  99. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  100. *
  101. * @performance For best performance, prefer a few collections, each with many polylines, to
  102. * many collections with only a few polylines each. Organize collections so that polylines
  103. * with the same update frequency are in the same collection, i.e., polylines that do not
  104. * change should be in one collection; polylines that change every frame should be in another
  105. * collection; and so on.
  106. *
  107. * @see PolylineCollection#add
  108. * @see PolylineCollection#remove
  109. * @see Polyline
  110. * @see LabelCollection
  111. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Polylines.html|Cesium Sandcastle Polyline Demo}
  112. *
  113. * @example
  114. * // Create a polyline collection with two polylines
  115. * var polylines = new Cesium.PolylineCollection();
  116. * polylines.add({
  117. * position : Cesium.Cartesian3.fromDegreesArray([
  118. * -75.10, 39.57,
  119. * -77.02, 38.53,
  120. * -80.50, 35.14,
  121. * -80.12, 25.46]),
  122. * width : 2
  123. * });
  124. *
  125. * polylines.add({
  126. * positions : Cesium.Cartesian3.fromDegreesArray([
  127. * -73.10, 37.57,
  128. * -75.02, 36.53,
  129. * -78.50, 33.14,
  130. * -78.12, 23.46]),
  131. * width : 4
  132. * });
  133. */
  134. var PolylineCollection = function(options) {
  135. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  136. /**
  137. * The 4x4 transformation matrix that transforms each polyline in this collection from model to world coordinates.
  138. * When this is the identity matrix, the polylines are drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  139. * Local reference frames can be used by providing a different transformation matrix, like that returned
  140. * by {@link Transforms.eastNorthUpToFixedFrame}.
  141. *
  142. * @type {Matrix4}
  143. * @default {@link Matrix4.IDENTITY}
  144. */
  145. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  146. this._modelMatrix = Matrix4.clone(Matrix4.IDENTITY);
  147. /**
  148. * This property is for debugging only; it is not for production use nor is it optimized.
  149. * <p>
  150. * Draws the bounding sphere for each draw command in the primitive.
  151. * </p>
  152. *
  153. * @type {Boolean}
  154. *
  155. * @default false
  156. */
  157. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  158. this._opaqueRS = undefined;
  159. this._translucentRS = undefined;
  160. this._colorCommands = [];
  161. this._pickCommands = [];
  162. this._polylinesUpdated = false;
  163. this._polylinesRemoved = false;
  164. this._createVertexArray = false;
  165. this._propertiesChanged = new Uint32Array(NUMBER_OF_PROPERTIES);
  166. this._polylines = [];
  167. this._polylineBuckets = {};
  168. // The buffer usage for each attribute is determined based on the usage of the attribute over time.
  169. this._buffersUsage = [
  170. {bufferUsage: BufferUsage.STATIC_DRAW, frameCount:0}, // SHOW_INDEX
  171. {bufferUsage: BufferUsage.STATIC_DRAW, frameCount:0}, // WIDTH_INDEX
  172. {bufferUsage: BufferUsage.STATIC_DRAW, frameCount:0} // POSITION_INDEX
  173. ];
  174. this._mode = undefined;
  175. this._polylinesToUpdate = [];
  176. this._vertexArrays = [];
  177. this._positionBuffer = undefined;
  178. this._pickColorBuffer = undefined;
  179. this._texCoordExpandWidthAndShowBuffer = undefined;
  180. };
  181. defineProperties(PolylineCollection.prototype, {
  182. /**
  183. * Returns the number of polylines in this collection. This is commonly used with
  184. * {@link PolylineCollection#get} to iterate over all the polylines
  185. * in the collection.
  186. * @memberof PolylineCollection.prototype
  187. * @type {Number}
  188. */
  189. length : {
  190. get : function() {
  191. removePolylines(this);
  192. return this._polylines.length;
  193. }
  194. }
  195. });
  196. /**
  197. * Creates and adds a polyline with the specified initial properties to the collection.
  198. * The added polyline is returned so it can be modified or removed from the collection later.
  199. *
  200. * @param {Object}[polyline] A template describing the polyline's properties as shown in Example 1.
  201. * @returns {Polyline} The polyline that was added to the collection.
  202. *
  203. * @performance After calling <code>add</code>, {@link PolylineCollection#update} is called and
  204. * the collection's vertex buffer is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead.
  205. * For best performance, add as many polylines as possible before calling <code>update</code>.
  206. *
  207. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  208. *
  209. * @see PolylineCollection#remove
  210. * @see PolylineCollection#removeAll
  211. * @see PolylineCollection#update
  212. *
  213. * @example
  214. * // Example 1: Add a polyline, specifying all the default values.
  215. * var p = polylines.add({
  216. * show : true,
  217. * positions : ellipsoid.cartographicDegreesToCartesians([
  218. * new Cesium.Cartographic2(-75.10, 39.57),
  219. * new Cesium.Cartographic2(-77.02, 38.53)]),
  220. * width : 1
  221. * });
  222. */
  223. PolylineCollection.prototype.add = function(polyline) {
  224. var p = new Polyline(polyline, this);
  225. p._index = this._polylines.length;
  226. this._polylines.push(p);
  227. this._createVertexArray = true;
  228. return p;
  229. };
  230. /**
  231. * Removes a polyline from the collection.
  232. *
  233. * @param {Polyline} polyline The polyline to remove.
  234. * @returns {Boolean} <code>true</code> if the polyline was removed; <code>false</code> if the polyline was not found in the collection.
  235. *
  236. * @performance After calling <code>remove</code>, {@link PolylineCollection#update} is called and
  237. * the collection's vertex buffer is rewritten - an <code>O(n)</code> operation that also incurs CPU to GPU overhead.
  238. * For best performance, remove as many polylines as possible before calling <code>update</code>.
  239. * If you intend to temporarily hide a polyline, it is usually more efficient to call
  240. * {@link Polyline#show} instead of removing and re-adding the polyline.
  241. *
  242. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  243. *
  244. * @see PolylineCollection#add
  245. * @see PolylineCollection#removeAll
  246. * @see PolylineCollection#update
  247. * @see Polyline#show
  248. *
  249. * @example
  250. * var p = polylines.add(...);
  251. * polylines.remove(p); // Returns true
  252. */
  253. PolylineCollection.prototype.remove = function(polyline) {
  254. if (this.contains(polyline)) {
  255. this._polylines[polyline._index] = undefined; // Removed later
  256. this._polylinesRemoved = true;
  257. this._createVertexArray = true;
  258. if (defined(polyline._bucket)) {
  259. var bucket = polyline._bucket;
  260. bucket.shaderProgram = bucket.shaderProgram && bucket.shaderProgram.destroy();
  261. bucket.pickShaderProgram = bucket.pickShaderProgram && bucket.pickShaderProgram.destroy();
  262. }
  263. polyline._destroy();
  264. return true;
  265. }
  266. return false;
  267. };
  268. /**
  269. * Removes all polylines from the collection.
  270. *
  271. * @performance <code>O(n)</code>. It is more efficient to remove all the polylines
  272. * from a collection and then add new ones than to create a new collection entirely.
  273. *
  274. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  275. *
  276. * @see PolylineCollection#add
  277. * @see PolylineCollection#remove
  278. * @see PolylineCollection#update
  279. *
  280. * @example
  281. * polylines.add(...);
  282. * polylines.add(...);
  283. * polylines.removeAll();
  284. */
  285. PolylineCollection.prototype.removeAll = function() {
  286. releaseShaders(this);
  287. destroyPolylines(this);
  288. this._polylineBuckets = {};
  289. this._polylinesRemoved = false;
  290. this._polylines.length = 0;
  291. this._polylinesToUpdate.length = 0;
  292. this._createVertexArray = true;
  293. };
  294. /**
  295. * Determines if this collection contains the specified polyline.
  296. *
  297. * @param {Polyline} polyline The polyline to check for.
  298. * @returns {Boolean} true if this collection contains the billboard, false otherwise.
  299. *
  300. * @see PolylineCollection#get
  301. */
  302. PolylineCollection.prototype.contains = function(polyline) {
  303. return defined(polyline) && polyline._polylineCollection === this;
  304. };
  305. /**
  306. * Returns the polyline in the collection at the specified index. Indices are zero-based
  307. * and increase as polylines are added. Removing a polyline shifts all polylines after
  308. * it to the left, changing their indices. This function is commonly used with
  309. * {@link PolylineCollection#length} to iterate over all the polylines
  310. * in the collection.
  311. *
  312. * @param {Number} index The zero-based index of the polyline.
  313. * @returns {Polyline} The polyline at the specified index.
  314. *
  315. * @performance If polylines were removed from the collection and
  316. * {@link PolylineCollection#update} was not called, an implicit <code>O(n)</code>
  317. * operation is performed.
  318. *
  319. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  320. *
  321. * @example
  322. * // Toggle the show property of every polyline in the collection
  323. * var len = polylines.length;
  324. * for (var i = 0; i < len; ++i) {
  325. * var p = polylines.get(i);
  326. * p.show = !p.show;
  327. * }
  328. *
  329. * @see PolylineCollection#length
  330. */
  331. PolylineCollection.prototype.get = function(index) {
  332. //>>includeStart('debug', pragmas.debug);
  333. if (!defined(index)) {
  334. throw new DeveloperError('index is required.');
  335. }
  336. //>>includeEnd('debug');
  337. removePolylines(this);
  338. return this._polylines[index];
  339. };
  340. /**
  341. * @private
  342. */
  343. PolylineCollection.prototype.update = function(context, frameState, commandList) {
  344. removePolylines(this);
  345. if (this._polylines.length === 0) {
  346. return;
  347. }
  348. updateMode(this, frameState);
  349. var projection = frameState.mapProjection;
  350. var polyline;
  351. var properties = this._propertiesChanged;
  352. if (this._createVertexArray || computeNewBuffersUsage(this)) {
  353. createVertexArrays(this, context, projection);
  354. } else if (this._polylinesUpdated) {
  355. // Polylines were modified, but no polylines were added or removed.
  356. var polylinesToUpdate = this._polylinesToUpdate;
  357. if (this._mode !== SceneMode.SCENE3D) {
  358. var updateLength = polylinesToUpdate.length;
  359. for ( var i = 0; i < updateLength; ++i) {
  360. polyline = polylinesToUpdate[i];
  361. polyline.update();
  362. }
  363. }
  364. // if a polyline's positions size changes, we need to recreate the vertex arrays and vertex buffers because the indices will be different.
  365. // if a polyline's material changes, we need to recreate the VAOs and VBOs because they will be batched differenty.
  366. if (properties[POSITION_SIZE_INDEX] || properties[MATERIAL_INDEX]) {
  367. createVertexArrays(this, context, projection);
  368. } else {
  369. var length = polylinesToUpdate.length;
  370. var polylineBuckets = this._polylineBuckets;
  371. for ( var ii = 0; ii < length; ++ii) {
  372. polyline = polylinesToUpdate[ii];
  373. properties = polyline._propertiesChanged;
  374. var bucket = polyline._bucket;
  375. var index = 0;
  376. for ( var x in polylineBuckets) {
  377. if (polylineBuckets.hasOwnProperty(x)) {
  378. if (polylineBuckets[x] === bucket) {
  379. if (properties[POSITION_INDEX] || properties[SHOW_INDEX] || properties[WIDTH_INDEX]) {
  380. bucket.writeUpdate(index, polyline, this._positionBuffer, this._texCoordExpandWidthAndShowBuffer, projection);
  381. }
  382. break;
  383. }
  384. index += polylineBuckets[x].lengthOfPositions;
  385. }
  386. }
  387. polyline._clean();
  388. }
  389. }
  390. polylinesToUpdate.length = 0;
  391. this._polylinesUpdated = false;
  392. }
  393. properties = this._propertiesChanged;
  394. for ( var k = 0; k < NUMBER_OF_PROPERTIES; ++k) {
  395. properties[k] = 0;
  396. }
  397. var modelMatrix = Matrix4.IDENTITY;
  398. if (frameState.mode === SceneMode.SCENE3D) {
  399. modelMatrix = this.modelMatrix;
  400. }
  401. var pass = frameState.passes;
  402. var useDepthTest = (frameState.morphTime !== 0.0);
  403. if (!defined(this._opaqueRS) || this._opaqueRS.depthTest.enabled !== useDepthTest) {
  404. this._opaqueRS = context.createRenderState({
  405. depthMask : useDepthTest,
  406. depthTest : {
  407. enabled : useDepthTest
  408. }
  409. });
  410. }
  411. if (!defined(this._translucentRS) || this._translucentRS.depthTest.enabled !== useDepthTest) {
  412. this._translucentRS = context.createRenderState({
  413. blending : BlendingState.ALPHA_BLEND,
  414. depthMask : !useDepthTest,
  415. depthTest : {
  416. enabled : useDepthTest
  417. }
  418. });
  419. }
  420. if (pass.render) {
  421. var colorList = this._colorCommands;
  422. createCommandLists(this, context, frameState, colorList, commandList, modelMatrix, true);
  423. }
  424. if (pass.pick) {
  425. var pickList = this._pickCommands;
  426. createCommandLists(this, context, frameState, pickList, commandList, modelMatrix, false);
  427. }
  428. };
  429. var boundingSphereScratch = new BoundingSphere();
  430. var boundingSphereScratch2 = new BoundingSphere();
  431. function createCommandLists(polylineCollection, context, frameState, commands, commandList, modelMatrix, renderPass) {
  432. var commandsLength = commands.length;
  433. var commandIndex = 0;
  434. var cloneBoundingSphere = true;
  435. var vertexArrays = polylineCollection._vertexArrays;
  436. var debugShowBoundingVolume = polylineCollection.debugShowBoundingVolume;
  437. var length = vertexArrays.length;
  438. for ( var m = 0; m < length; ++m) {
  439. var va = vertexArrays[m];
  440. var buckets = va.buckets;
  441. var bucketLength = buckets.length;
  442. for ( var n = 0; n < bucketLength; ++n) {
  443. var bucketLocator = buckets[n];
  444. var offset = bucketLocator.offset;
  445. var sp = renderPass ? bucketLocator.bucket.shaderProgram : bucketLocator.bucket.pickShaderProgram;
  446. var polylines = bucketLocator.bucket.polylines;
  447. var polylineLength = polylines.length;
  448. var currentId;
  449. var currentMaterial;
  450. var count = 0;
  451. var command;
  452. for (var s = 0; s < polylineLength; ++s) {
  453. var polyline = polylines[s];
  454. var mId = createMaterialId(polyline._material);
  455. if (mId !== currentId) {
  456. if (defined(currentId) && count > 0) {
  457. var translucent = currentMaterial.isTranslucent();
  458. if (commandIndex >= commandsLength) {
  459. command = new DrawCommand({
  460. owner : polylineCollection
  461. });
  462. commands.push(command);
  463. } else {
  464. command = commands[commandIndex];
  465. }
  466. ++commandIndex;
  467. command.boundingVolume = BoundingSphere.clone(boundingSphereScratch, command.boundingVolume);
  468. command.modelMatrix = modelMatrix;
  469. command.shaderProgram = sp;
  470. command.vertexArray = va.va;
  471. command.renderState = translucent ? polylineCollection._translucentRS : polylineCollection._opaqueRS;
  472. command.pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
  473. command.debugShowBoundingVolume = renderPass ? debugShowBoundingVolume : false;
  474. command.uniformMap = currentMaterial._uniforms;
  475. command.count = count;
  476. command.offset = offset;
  477. offset += count;
  478. count = 0;
  479. cloneBoundingSphere = true;
  480. commandList.push(command);
  481. }
  482. currentMaterial = polyline._material;
  483. currentMaterial.update(context);
  484. currentId = mId;
  485. }
  486. var locators = polyline._locatorBuckets;
  487. var locatorLength = locators.length;
  488. for (var t = 0; t < locatorLength; ++t) {
  489. var locator = locators[t];
  490. if (locator.locator === bucketLocator) {
  491. count += locator.count;
  492. }
  493. }
  494. var boundingVolume;
  495. if (frameState.mode === SceneMode.SCENE3D) {
  496. boundingVolume = polyline._boundingVolumeWC;
  497. } else if (frameState.mode === SceneMode.COLUMBUS_VIEW) {
  498. boundingVolume = polyline._boundingVolume2D;
  499. } else if (frameState.mode === SceneMode.SCENE2D) {
  500. if (defined(polyline._boundingVolume2D)) {
  501. boundingVolume = BoundingSphere.clone(polyline._boundingVolume2D, boundingSphereScratch2);
  502. boundingVolume.center.x = 0.0;
  503. }
  504. } else if (defined(polyline._boundingVolumeWC) && defined(polyline._boundingVolume2D)) {
  505. boundingVolume = BoundingSphere.union(polyline._boundingVolumeWC, polyline._boundingVolume2D, boundingSphereScratch2);
  506. }
  507. if (cloneBoundingSphere) {
  508. cloneBoundingSphere = false;
  509. BoundingSphere.clone(boundingVolume, boundingSphereScratch);
  510. } else {
  511. BoundingSphere.union(boundingVolume, boundingSphereScratch, boundingSphereScratch);
  512. }
  513. }
  514. if (defined(currentId) && count > 0) {
  515. if (commandIndex >= commandsLength) {
  516. command = new DrawCommand({
  517. owner : polylineCollection
  518. });
  519. commands.push(command);
  520. } else {
  521. command = commands[commandIndex];
  522. }
  523. ++commandIndex;
  524. command.boundingVolume = BoundingSphere.clone(boundingSphereScratch, command.boundingVolume);
  525. command.modelMatrix = modelMatrix;
  526. command.shaderProgram = sp;
  527. command.vertexArray = va.va;
  528. command.renderState = currentMaterial.isTranslucent() ? polylineCollection._translucentRS : polylineCollection._opaqueRS;
  529. command.pass = currentMaterial.isTranslucent() ? Pass.TRANSLUCENT : Pass.OPAQUE;
  530. command.debugShowBoundingVolume = renderPass ? debugShowBoundingVolume : false;
  531. command.uniformMap = currentMaterial._uniforms;
  532. command.count = count;
  533. command.offset = offset;
  534. cloneBoundingSphere = true;
  535. commandList.push(command);
  536. }
  537. currentId = undefined;
  538. }
  539. }
  540. commands.length = commandIndex;
  541. }
  542. /**
  543. * Returns true if this object was destroyed; otherwise, false.
  544. * <br /><br />
  545. * If this object was destroyed, it should not be used; calling any function other than
  546. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  547. *
  548. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  549. *
  550. * @see PolylineCollection#destroy
  551. */
  552. PolylineCollection.prototype.isDestroyed = function() {
  553. return false;
  554. };
  555. /**
  556. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  557. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  558. * <br /><br />
  559. * Once an object is destroyed, it should not be used; calling any function other than
  560. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  561. * assign the return value (<code>undefined</code>) to the object as done in the example.
  562. *
  563. * @returns {undefined}
  564. *
  565. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  566. *
  567. * @see PolylineCollection#isDestroyed
  568. *
  569. * @example
  570. * polylines = polylines && polylines.destroy();
  571. */
  572. PolylineCollection.prototype.destroy = function() {
  573. destroyVertexArrays(this);
  574. releaseShaders(this);
  575. destroyPolylines(this);
  576. return destroyObject(this);
  577. };
  578. function computeNewBuffersUsage(collection) {
  579. var buffersUsage = collection._buffersUsage;
  580. var usageChanged = false;
  581. var properties = collection._propertiesChanged;
  582. //subtract 2 from NUMBER_OF_PROPERTIES because we don't care about POSITION_SIZE_INDEX or MATERIAL_INDEX property change.
  583. for ( var k = 0; k < NUMBER_OF_PROPERTIES - 2; ++k) {
  584. var bufferUsage = buffersUsage[k];
  585. if (properties[k]) {
  586. if (bufferUsage.bufferUsage !== BufferUsage.STREAM_DRAW) {
  587. usageChanged = true;
  588. bufferUsage.bufferUsage = BufferUsage.STREAM_DRAW;
  589. bufferUsage.frameCount = 100;
  590. } else {
  591. bufferUsage.frameCount = 100;
  592. }
  593. } else {
  594. if (bufferUsage.bufferUsage !== BufferUsage.STATIC_DRAW) {
  595. if (bufferUsage.frameCount === 0) {
  596. usageChanged = true;
  597. bufferUsage.bufferUsage = BufferUsage.STATIC_DRAW;
  598. } else {
  599. bufferUsage.frameCount--;
  600. }
  601. }
  602. }
  603. }
  604. return usageChanged;
  605. }
  606. var emptyVertexBuffer = [0.0, 0.0, 0.0];
  607. function createVertexArrays(collection, context, projection) {
  608. collection._createVertexArray = false;
  609. releaseShaders(collection);
  610. destroyVertexArrays(collection);
  611. sortPolylinesIntoBuckets(collection);
  612. //stores all of the individual indices arrays.
  613. var totalIndices = [[]];
  614. var indices = totalIndices[0];
  615. //used to determine the vertexBuffer offset if the indicesArray goes over 64k.
  616. //if it's the same polyline while it goes over 64k, the offset needs to backtrack componentsPerAttribute * componentDatatype bytes
  617. //so that the polyline looks contiguous.
  618. //if the polyline ends at the 64k mark, then the offset is just 64k * componentsPerAttribute * componentDatatype
  619. var vertexBufferOffset = [0];
  620. var offset = 0;
  621. var vertexArrayBuckets = [[]];
  622. var totalLength = 0;
  623. var polylineBuckets = collection._polylineBuckets;
  624. var x;
  625. var bucket;
  626. for (x in polylineBuckets) {
  627. if (polylineBuckets.hasOwnProperty(x)) {
  628. bucket = polylineBuckets[x];
  629. bucket.updateShader(context);
  630. totalLength += bucket.lengthOfPositions;
  631. }
  632. }
  633. if (totalLength > 0) {
  634. var mode = collection._mode;
  635. var positionArray = new Float32Array(6 * totalLength * 3);
  636. var pickColorArray = new Uint8Array(totalLength * 4);
  637. var texCoordExpandWidthAndShowArray = new Float32Array(totalLength * 4);
  638. var position3DArray;
  639. var positionIndex = 0;
  640. var colorIndex = 0;
  641. var texCoordExpandWidthAndShowIndex = 0;
  642. for (x in polylineBuckets) {
  643. if (polylineBuckets.hasOwnProperty(x)) {
  644. bucket = polylineBuckets[x];
  645. bucket.write(positionArray, pickColorArray, texCoordExpandWidthAndShowArray, positionIndex, colorIndex, texCoordExpandWidthAndShowIndex, context, projection);
  646. if (mode === SceneMode.MORPHING) {
  647. if (!defined(position3DArray)) {
  648. position3DArray = new Float32Array(6 * totalLength * 3);
  649. }
  650. bucket.writeForMorph(position3DArray, positionIndex);
  651. }
  652. var bucketLength = bucket.lengthOfPositions;
  653. positionIndex += 6 * bucketLength * 3;
  654. colorIndex += bucketLength * 4;
  655. texCoordExpandWidthAndShowIndex += bucketLength * 4;
  656. offset = bucket.updateIndices(totalIndices, vertexBufferOffset, vertexArrayBuckets, offset);
  657. }
  658. }
  659. var positionBufferUsage = collection._buffersUsage[POSITION_INDEX].bufferUsage;
  660. var showBufferUsage = collection._buffersUsage[SHOW_INDEX].bufferUsage;
  661. var widthBufferUsage = collection._buffersUsage[WIDTH_INDEX].bufferUsage;
  662. var texCoordExpandWidthAndShowBufferUsage = (showBufferUsage === BufferUsage.STREAM_DRAW || widthBufferUsage === BufferUsage.STREAM_DRAW) ? BufferUsage.STREAM_DRAW : BufferUsage.STATIC_DRAW;
  663. collection._positionBuffer = context.createVertexBuffer(positionArray, positionBufferUsage);
  664. var position3DBuffer;
  665. if (defined(position3DArray)) {
  666. position3DBuffer = context.createVertexBuffer(position3DArray, positionBufferUsage);
  667. }
  668. collection._pickColorBuffer = context.createVertexBuffer(pickColorArray, BufferUsage.STATIC_DRAW);
  669. collection._texCoordExpandWidthAndShowBuffer = context.createVertexBuffer(texCoordExpandWidthAndShowArray, texCoordExpandWidthAndShowBufferUsage);
  670. var pickColorSizeInBytes = 4 * Uint8Array.BYTES_PER_ELEMENT;
  671. var positionSizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT;
  672. var texCoordExpandWidthAndShowSizeInBytes = 4 * Float32Array.BYTES_PER_ELEMENT;
  673. var vbo = 0;
  674. var numberOfIndicesArrays = totalIndices.length;
  675. for ( var k = 0; k < numberOfIndicesArrays; ++k) {
  676. indices = totalIndices[k];
  677. if (indices.length > 0) {
  678. var indicesArray = new Uint16Array(indices);
  679. var indexBuffer = context.createIndexBuffer(indicesArray, BufferUsage.STATIC_DRAW, IndexDatatype.UNSIGNED_SHORT);
  680. vbo += vertexBufferOffset[k];
  681. var positionHighOffset = 6 * (k * (positionSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * positionSizeInBytes);//componentsPerAttribute(3) * componentDatatype(4)
  682. var positionLowOffset = positionSizeInBytes + positionHighOffset;
  683. var prevPositionHighOffset = positionSizeInBytes + positionLowOffset;
  684. var prevPositionLowOffset = positionSizeInBytes + prevPositionHighOffset;
  685. var nextPositionHighOffset = positionSizeInBytes + prevPositionLowOffset;
  686. var nextPositionLowOffset = positionSizeInBytes + nextPositionHighOffset;
  687. var vertexPickColorBufferOffset = k * (pickColorSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * pickColorSizeInBytes;
  688. var vertexTexCoordExpandWidthAndShowBufferOffset = k * (texCoordExpandWidthAndShowSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * texCoordExpandWidthAndShowSizeInBytes;
  689. var attributes = [{
  690. index : attributeLocations.position3DHigh,
  691. componentsPerAttribute : 3,
  692. componentDatatype : ComponentDatatype.FLOAT,
  693. offsetInBytes : positionHighOffset,
  694. strideInBytes : 6 * positionSizeInBytes
  695. }, {
  696. index : attributeLocations.position3DLow,
  697. componentsPerAttribute : 3,
  698. componentDatatype : ComponentDatatype.FLOAT,
  699. offsetInBytes : positionLowOffset,
  700. strideInBytes : 6 * positionSizeInBytes
  701. }, {
  702. index : attributeLocations.position2DHigh,
  703. componentsPerAttribute : 3,
  704. componentDatatype : ComponentDatatype.FLOAT,
  705. offsetInBytes : positionHighOffset,
  706. strideInBytes : 6 * positionSizeInBytes
  707. }, {
  708. index : attributeLocations.position2DLow,
  709. componentsPerAttribute : 3,
  710. componentDatatype : ComponentDatatype.FLOAT,
  711. offsetInBytes : positionLowOffset,
  712. strideInBytes : 6 * positionSizeInBytes
  713. }, {
  714. index : attributeLocations.prevPosition3DHigh,
  715. componentsPerAttribute : 3,
  716. componentDatatype : ComponentDatatype.FLOAT,
  717. offsetInBytes : prevPositionHighOffset,
  718. strideInBytes : 6 * positionSizeInBytes
  719. }, {
  720. index : attributeLocations.prevPosition3DLow,
  721. componentsPerAttribute : 3,
  722. componentDatatype : ComponentDatatype.FLOAT,
  723. offsetInBytes : prevPositionLowOffset,
  724. strideInBytes : 6 * positionSizeInBytes
  725. }, {
  726. index : attributeLocations.prevPosition2DHigh,
  727. componentsPerAttribute : 3,
  728. componentDatatype : ComponentDatatype.FLOAT,
  729. offsetInBytes : prevPositionHighOffset,
  730. strideInBytes : 6 * positionSizeInBytes
  731. }, {
  732. index : attributeLocations.prevPosition2DLow,
  733. componentsPerAttribute : 3,
  734. componentDatatype : ComponentDatatype.FLOAT,
  735. offsetInBytes : prevPositionLowOffset,
  736. strideInBytes : 6 * positionSizeInBytes
  737. }, {
  738. index : attributeLocations.nextPosition3DHigh,
  739. componentsPerAttribute : 3,
  740. componentDatatype : ComponentDatatype.FLOAT,
  741. offsetInBytes : nextPositionHighOffset,
  742. strideInBytes : 6 * positionSizeInBytes
  743. }, {
  744. index : attributeLocations.nextPosition3DLow,
  745. componentsPerAttribute : 3,
  746. componentDatatype : ComponentDatatype.FLOAT,
  747. offsetInBytes : nextPositionLowOffset,
  748. strideInBytes : 6 * positionSizeInBytes
  749. }, {
  750. index : attributeLocations.nextPosition2DHigh,
  751. componentsPerAttribute : 3,
  752. componentDatatype : ComponentDatatype.FLOAT,
  753. offsetInBytes : nextPositionHighOffset,
  754. strideInBytes : 6 * positionSizeInBytes
  755. }, {
  756. index : attributeLocations.nextPosition2DLow,
  757. componentsPerAttribute : 3,
  758. componentDatatype : ComponentDatatype.FLOAT,
  759. offsetInBytes : nextPositionLowOffset,
  760. strideInBytes : 6 * positionSizeInBytes
  761. }, {
  762. index : attributeLocations.texCoordExpandWidthAndShow,
  763. componentsPerAttribute : 4,
  764. componentDatatype : ComponentDatatype.FLOAT,
  765. vertexBuffer : collection._texCoordExpandWidthAndShowBuffer,
  766. offsetInBytes : vertexTexCoordExpandWidthAndShowBufferOffset
  767. }, {
  768. index : attributeLocations.pickColor,
  769. componentsPerAttribute : 4,
  770. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  771. vertexBuffer : collection._pickColorBuffer,
  772. offsetInBytes : vertexPickColorBufferOffset,
  773. normalize : true
  774. }];
  775. var buffer3D;
  776. var bufferProperty3D;
  777. var buffer2D;
  778. var bufferProperty2D;
  779. if (mode === SceneMode.SCENE3D) {
  780. buffer3D = collection._positionBuffer;
  781. bufferProperty3D = 'vertexBuffer';
  782. buffer2D = emptyVertexBuffer;
  783. bufferProperty2D = 'value';
  784. } else if (mode === SceneMode.SCENE2D || mode === SceneMode.COLUMBUS_VIEW) {
  785. buffer3D = emptyVertexBuffer;
  786. bufferProperty3D = 'value';
  787. buffer2D = collection._positionBuffer;
  788. bufferProperty2D = 'vertexBuffer';
  789. } else {
  790. buffer3D = position3DBuffer;
  791. bufferProperty3D = 'vertexBuffer';
  792. buffer2D = collection._positionBuffer;
  793. bufferProperty2D = 'vertexBuffer';
  794. }
  795. attributes[0][bufferProperty3D] = buffer3D;
  796. attributes[1][bufferProperty3D] = buffer3D;
  797. attributes[2][bufferProperty2D] = buffer2D;
  798. attributes[3][bufferProperty2D] = buffer2D;
  799. attributes[4][bufferProperty3D] = buffer3D;
  800. attributes[5][bufferProperty3D] = buffer3D;
  801. attributes[6][bufferProperty2D] = buffer2D;
  802. attributes[7][bufferProperty2D] = buffer2D;
  803. attributes[8][bufferProperty3D] = buffer3D;
  804. attributes[9][bufferProperty3D] = buffer3D;
  805. attributes[10][bufferProperty2D] = buffer2D;
  806. attributes[11][bufferProperty2D] = buffer2D;
  807. var va = context.createVertexArray(attributes, indexBuffer);
  808. collection._vertexArrays.push({
  809. va : va,
  810. buckets : vertexArrayBuckets[k]
  811. });
  812. }
  813. }
  814. }
  815. }
  816. var scratchUniformArray = [];
  817. function createMaterialId(material) {
  818. var uniforms = Material._uniformList[material.type];
  819. var length = uniforms.length;
  820. scratchUniformArray.length = 2.0 * length;
  821. var index = 0;
  822. for (var i = 0; i < length; ++i) {
  823. var uniform = uniforms[i];
  824. scratchUniformArray[index] = uniform;
  825. scratchUniformArray[index + 1] = material._uniforms[uniform]();
  826. index += 2;
  827. }
  828. return material.type + ':' + JSON.stringify(scratchUniformArray);
  829. }
  830. function sortPolylinesIntoBuckets(collection) {
  831. var mode = collection._mode;
  832. var modelMatrix = collection._modelMatrix;
  833. var polylineBuckets = collection._polylineBuckets = {};
  834. var polylines = collection._polylines;
  835. var length = polylines.length;
  836. for ( var i = 0; i < length; ++i) {
  837. var p = polylines[i];
  838. if (p._actualPositions.length > 1) {
  839. p.update();
  840. var material = p.material;
  841. var value = polylineBuckets[material.type];
  842. if (!defined(value)) {
  843. value = polylineBuckets[material.type] = new PolylineBucket(material, mode, modelMatrix);
  844. }
  845. value.addPolyline(p);
  846. }
  847. }
  848. }
  849. function updateMode(collection, frameState) {
  850. var mode = frameState.mode;
  851. if (collection._mode !== mode || (!Matrix4.equals(collection._modelMatrix, collection.modelMatrix))) {
  852. collection._mode = mode;
  853. collection._modelMatrix = Matrix4.clone(collection.modelMatrix);
  854. collection._createVertexArray = true;
  855. }
  856. }
  857. function removePolylines(collection) {
  858. if (collection._polylinesRemoved) {
  859. collection._polylinesRemoved = false;
  860. var polylines = [];
  861. var length = collection._polylines.length;
  862. for ( var i = 0, j = 0; i < length; ++i) {
  863. var polyline = collection._polylines[i];
  864. if (defined(polyline)) {
  865. polyline._index = j++;
  866. polylines.push(polyline);
  867. }
  868. }
  869. collection._polylines = polylines;
  870. }
  871. }
  872. function releaseShaders(collection) {
  873. var polylines = collection._polylines;
  874. var length = polylines.length;
  875. for ( var i = 0; i < length; ++i) {
  876. if (defined(polylines[i])) {
  877. var bucket = polylines[i]._bucket;
  878. if (defined(bucket)) {
  879. bucket.shaderProgram = bucket.shaderProgram && bucket.shaderProgram.destroy();
  880. }
  881. }
  882. }
  883. }
  884. function destroyVertexArrays(collection) {
  885. var length = collection._vertexArrays.length;
  886. for ( var t = 0; t < length; ++t) {
  887. collection._vertexArrays[t].va.destroy();
  888. }
  889. collection._vertexArrays.length = 0;
  890. }
  891. PolylineCollection.prototype._updatePolyline = function(polyline, propertyChanged) {
  892. this._polylinesUpdated = true;
  893. this._polylinesToUpdate.push(polyline);
  894. ++this._propertiesChanged[propertyChanged];
  895. };
  896. function destroyPolylines(collection) {
  897. var polylines = collection._polylines;
  898. var length = polylines.length;
  899. for ( var i = 0; i < length; ++i) {
  900. if (defined(polylines[i])) {
  901. polylines[i]._destroy();
  902. }
  903. }
  904. }
  905. function VertexArrayBucketLocator(count, offset, bucket) {
  906. this.count = count;
  907. this.offset = offset;
  908. this.bucket = bucket;
  909. }
  910. var PolylineBucket = function(material, mode, modelMatrix) {
  911. this.polylines = [];
  912. this.lengthOfPositions = 0;
  913. this.material = material;
  914. this.shaderProgram = undefined;
  915. this.pickShaderProgram = undefined;
  916. this.mode = mode;
  917. this.modelMatrix = modelMatrix;
  918. };
  919. PolylineBucket.prototype.addPolyline = function(p) {
  920. var polylines = this.polylines;
  921. polylines.push(p);
  922. p._actualLength = this.getPolylinePositionsLength(p);
  923. this.lengthOfPositions += p._actualLength;
  924. p._bucket = this;
  925. };
  926. PolylineBucket.prototype.updateShader = function(context) {
  927. if (defined(this.shaderProgram)) {
  928. return;
  929. }
  930. var vs = new ShaderSource({
  931. sources : [PolylineCommon, PolylineVS]
  932. });
  933. var fs = new ShaderSource({
  934. sources : [this.material.shaderSource, PolylineFS]
  935. });
  936. var fsPick = new ShaderSource({
  937. sources : fs.sources,
  938. pickColorQualifier : 'varying'
  939. });
  940. this.shaderProgram = context.createShaderProgram(vs, fs, attributeLocations);
  941. this.pickShaderProgram = context.createShaderProgram(vs, fsPick, attributeLocations);
  942. };
  943. function intersectsIDL(polyline) {
  944. return Cartesian3.dot(Cartesian3.UNIT_X, polyline._boundingVolume.center) < 0 ||
  945. polyline._boundingVolume.intersect(Cartesian4.UNIT_Y) === Intersect.INTERSECTING;
  946. }
  947. PolylineBucket.prototype.getPolylinePositionsLength = function(polyline) {
  948. var length;
  949. if (this.mode === SceneMode.SCENE3D || !intersectsIDL(polyline)) {
  950. length = polyline._actualPositions.length;
  951. return length * 4.0 - 4.0;
  952. }
  953. var count = 0;
  954. var segmentLengths = polyline._segments.lengths;
  955. length = segmentLengths.length;
  956. for (var i = 0; i < length; ++i) {
  957. count += segmentLengths[i] * 4.0 - 4.0;
  958. }
  959. return count;
  960. };
  961. var scratchWritePosition = new Cartesian3();
  962. var scratchWritePrevPosition = new Cartesian3();
  963. var scratchWriteNextPosition = new Cartesian3();
  964. var scratchWriteVector = new Cartesian3();
  965. PolylineBucket.prototype.write = function(positionArray, pickColorArray, texCoordExpandWidthAndShowArray, positionIndex, colorIndex, texCoordExpandWidthAndShowIndex, context, projection) {
  966. var mode = this.mode;
  967. var polylines = this.polylines;
  968. var length = polylines.length;
  969. for ( var i = 0; i < length; ++i) {
  970. var polyline = polylines[i];
  971. var width = polyline.width;
  972. var show = polyline.show && width > 0.0;
  973. var segments = this.getSegments(polyline, projection);
  974. var positions = segments.positions;
  975. var lengths = segments.lengths;
  976. var positionsLength = positions.length;
  977. var pickColor = polyline.getPickId(context).color;
  978. var segmentIndex = 0;
  979. var count = 0;
  980. var position;
  981. for ( var j = 0; j < positionsLength; ++j) {
  982. if (j === 0) {
  983. if (polyline._loop) {
  984. position = positions[positionsLength - 2];
  985. } else {
  986. position = scratchWriteVector;
  987. Cartesian3.subtract(positions[0], positions[1], position);
  988. Cartesian3.add(positions[0], position, position);
  989. }
  990. } else {
  991. position = positions[j - 1];
  992. }
  993. scratchWritePrevPosition.x = position.x;
  994. scratchWritePrevPosition.y = position.y;
  995. scratchWritePrevPosition.z = (mode !== SceneMode.SCENE2D) ? position.z : 0.0;
  996. position = positions[j];
  997. scratchWritePosition.x = position.x;
  998. scratchWritePosition.y = position.y;
  999. scratchWritePosition.z = (mode !== SceneMode.SCENE2D) ? position.z : 0.0;
  1000. if (j === positionsLength - 1) {
  1001. if (polyline._loop) {
  1002. position = positions[1];
  1003. } else {
  1004. position = scratchWriteVector;
  1005. Cartesian3.subtract(positions[positionsLength - 1], positions[positionsLength - 2], position);
  1006. Cartesian3.add(positions[positionsLength - 1], position, position);
  1007. }
  1008. } else {
  1009. position = positions[j + 1];
  1010. }
  1011. scratchWriteNextPosition.x = position.x;
  1012. scratchWriteNextPosition.y = position.y;
  1013. scratchWriteNextPosition.z = (mode !== SceneMode.SCENE2D) ? position.z : 0.0;
  1014. var segmentLength = lengths[segmentIndex];
  1015. if (j === count + segmentLength) {
  1016. count += segmentLength;
  1017. ++segmentIndex;
  1018. }
  1019. var segmentStart = j - count === 0;
  1020. var segmentEnd = j === count + lengths[segmentIndex] - 1;
  1021. var startK = (segmentStart) ? 2 : 0;
  1022. var endK = (segmentEnd) ? 2 : 4;
  1023. for (var k = startK; k < endK; ++k) {
  1024. EncodedCartesian3.writeElements(scratchWritePosition, positionArray, positionIndex);
  1025. EncodedCartesian3.writeElements(scratchWritePrevPosition, positionArray, positionIndex + 6);
  1026. EncodedCartesian3.writeElements(scratchWriteNextPosition, positionArray, positionIndex + 12);
  1027. pickColorArray[colorIndex] = Color.floatToByte(pickColor.red);
  1028. pickColorArray[colorIndex + 1] = Color.floatToByte(pickColor.green);
  1029. pickColorArray[colorIndex + 2] = Color.floatToByte(pickColor.blue);
  1030. pickColorArray[colorIndex + 3] = Color.floatToByte(pickColor.alpha);
  1031. var direction = (k - 2 < 0) ? -1.0 : 1.0;
  1032. texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex] = j / (positionsLength - 1); // s tex coord
  1033. texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 1] = 2 * (k % 2) - 1; // expand direction
  1034. texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 2] = direction * width;
  1035. texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 3] = show;
  1036. positionIndex += 6 * 3;
  1037. colorIndex += 4;
  1038. texCoordExpandWidthAndShowIndex += 4;
  1039. }
  1040. }
  1041. }
  1042. };
  1043. var morphPositionScratch = new Cartesian3();
  1044. var morphPrevPositionScratch = new Cartesian3();
  1045. var morphNextPositionScratch = new Cartesian3();
  1046. var morphVectorScratch = new Cartesian3();
  1047. PolylineBucket.prototype.writeForMorph = function(positionArray, positionIndex) {
  1048. var modelMatrix = this.modelMatrix;
  1049. var polylines = this.polylines;
  1050. var length = polylines.length;
  1051. for ( var i = 0; i < length; ++i) {
  1052. var polyline = polylines[i];
  1053. var positions = polyline._segments.positions;
  1054. var lengths = polyline._segments.lengths;
  1055. var positionsLength = positions.length;
  1056. var segmentIndex = 0;
  1057. var count = 0;
  1058. for ( var j = 0; j < positionsLength; ++j) {
  1059. var prevPosition;
  1060. if (j === 0) {
  1061. if (polyline._loop) {
  1062. prevPosition = positions[positionsLength - 2];
  1063. } else {
  1064. prevPosition = morphVectorScratch;
  1065. Cartesian3.subtract(positions[0], positions[1], prevPosition);
  1066. Cartesian3.add(positions[0], prevPosition, prevPosition);
  1067. }
  1068. } else {
  1069. prevPosition = positions[j - 1];
  1070. }
  1071. prevPosition = Matrix4.multiplyByPoint(modelMatrix, prevPosition, morphPrevPositionScratch);
  1072. var position = Matrix4.multiplyByPoint(modelMatrix, positions[j], morphPositionScratch);
  1073. var nextPosition;
  1074. if (j === positionsLength - 1) {
  1075. if (polyline._loop) {
  1076. nextPosition = positions[1];
  1077. } else {
  1078. nextPosition = morphVectorScratch;
  1079. Cartesian3.subtract(positions[positionsLength - 1], positions[positionsLength - 2], nextPosition);
  1080. Cartesian3.add(positions[positionsLength - 1], nextPosition, nextPosition);
  1081. }
  1082. } else {
  1083. nextPosition = positions[j + 1];
  1084. }
  1085. nextPosition = Matrix4.multiplyByPoint(modelMatrix, nextPosition, morphNextPositionScratch);
  1086. var segmentLength = lengths[segmentIndex];
  1087. if (j === count + segmentLength) {
  1088. count += segmentLength;
  1089. ++segmentIndex;
  1090. }
  1091. var segmentStart = j - count === 0;
  1092. var segmentEnd = j === count + lengths[segmentIndex] - 1;
  1093. var startK = (segmentStart) ? 2 : 0;
  1094. var endK = (segmentEnd) ? 2 : 4;
  1095. for (var k = startK; k < endK; ++k) {
  1096. EncodedCartesian3.writeElements(position, positionArray, positionIndex);
  1097. EncodedCartesian3.writeElements(prevPosition, positionArray, positionIndex + 6);
  1098. EncodedCartesian3.writeElements(nextPosition, positionArray, positionIndex + 12);
  1099. positionIndex += 6 * 3;
  1100. }
  1101. }
  1102. }
  1103. };
  1104. var scratchSegmentLengths = new Array(1);
  1105. PolylineBucket.prototype.updateIndices = function(totalIndices, vertexBufferOffset, vertexArrayBuckets, offset) {
  1106. var vaCount = vertexArrayBuckets.length - 1;
  1107. var bucketLocator = new VertexArrayBucketLocator(0, offset, this);
  1108. vertexArrayBuckets[vaCount].push(bucketLocator);
  1109. var count = 0;
  1110. var indices = totalIndices[totalIndices.length - 1];
  1111. var indicesCount = 0;
  1112. if (indices.length > 0) {
  1113. indicesCount = indices[indices.length - 1] + 1;
  1114. }
  1115. var polylines = this.polylines;
  1116. var length = polylines.length;
  1117. for ( var i = 0; i < length; ++i) {
  1118. var polyline = polylines[i];
  1119. polyline._locatorBuckets = [];
  1120. var segments;
  1121. if (this.mode === SceneMode.SCENE3D) {
  1122. segments = scratchSegmentLengths;
  1123. var positionsLength = polyline._actualPositions.length;
  1124. if (positionsLength > 0) {
  1125. segments[0] = positionsLength;
  1126. } else {
  1127. continue;
  1128. }
  1129. } else {
  1130. segments = polyline._segments.lengths;
  1131. }
  1132. var numberOfSegments = segments.length;
  1133. if (numberOfSegments > 0) {
  1134. var segmentIndexCount = 0;
  1135. for ( var j = 0; j < numberOfSegments; ++j) {
  1136. var segmentLength = segments[j] - 1.0;
  1137. for ( var k = 0; k < segmentLength; ++k) {
  1138. if (indicesCount + 4 >= CesiumMath.SIXTY_FOUR_KILOBYTES - 1) {
  1139. polyline._locatorBuckets.push({
  1140. locator : bucketLocator,
  1141. count : segmentIndexCount
  1142. });
  1143. segmentIndexCount = 0;
  1144. vertexBufferOffset.push(4);
  1145. indices = [];
  1146. totalIndices.push(indices);
  1147. indicesCount = 0;
  1148. bucketLocator.count = count;
  1149. count = 0;
  1150. offset = 0;
  1151. bucketLocator = new VertexArrayBucketLocator(0, 0, this);
  1152. vertexArrayBuckets[++vaCount] = [bucketLocator];
  1153. }
  1154. indices.push(indicesCount, indicesCount + 2, indicesCount + 1);
  1155. indices.push(indicesCount + 1, indicesCount + 2, indicesCount + 3);
  1156. segmentIndexCount += 6;
  1157. count += 6;
  1158. offset += 6;
  1159. indicesCount += 4;
  1160. }
  1161. }
  1162. polyline._locatorBuckets.push({
  1163. locator : bucketLocator,
  1164. count : segmentIndexCount
  1165. });
  1166. if (indicesCount + 4 >= CesiumMath.SIXTY_FOUR_KILOBYTES - 1) {
  1167. vertexBufferOffset.push(0);
  1168. indices = [];
  1169. totalIndices.push(indices);
  1170. indicesCount = 0;
  1171. bucketLocator.count = count;
  1172. offset = 0;
  1173. count = 0;
  1174. bucketLocator = new VertexArrayBucketLocator(0, 0, this);
  1175. vertexArrayBuckets[++vaCount] = [bucketLocator];
  1176. }
  1177. }
  1178. polyline._clean();
  1179. }
  1180. bucketLocator.count = count;
  1181. return offset;
  1182. };
  1183. PolylineBucket.prototype.getPolylineStartIndex = function(polyline) {
  1184. var polylines = this.polylines;
  1185. var positionIndex = 0;
  1186. var length = polylines.length;
  1187. for ( var i = 0; i < length; ++i) {
  1188. var p = polylines[i];
  1189. if (p === polyline) {
  1190. break;
  1191. }
  1192. positionIndex += p._actualLength;
  1193. }
  1194. return positionIndex;
  1195. };
  1196. var scratchSegments = {
  1197. positions : undefined,
  1198. lengths : undefined
  1199. };
  1200. var scratchLengths = new Array(1);
  1201. var pscratch = new Cartesian3();
  1202. var scratchCartographic = new Cartographic();
  1203. PolylineBucket.prototype.getSegments = function(polyline, projection) {
  1204. var positions = polyline._actualPositions;
  1205. if (this.mode === SceneMode.SCENE3D) {
  1206. scratchLengths[0] = positions.length;
  1207. scratchSegments.positions = positions;
  1208. scratchSegments.lengths = scratchLengths;
  1209. return scratchSegments;
  1210. }
  1211. if (intersectsIDL(polyline)) {
  1212. positions = polyline._segments.positions;
  1213. }
  1214. var ellipsoid = projection.ellipsoid;
  1215. var newPositions = [];
  1216. var modelMatrix = this.modelMatrix;
  1217. var length = positions.length;
  1218. var position;
  1219. var p = pscratch;
  1220. for ( var n = 0; n < length; ++n) {
  1221. position = positions[n];
  1222. p = Matrix4.multiplyByPoint(modelMatrix, position, p);
  1223. newPositions.push(projection.project(ellipsoid.cartesianToCartographic(p, scratchCartographic)));
  1224. }
  1225. if (newPositions.length > 0) {
  1226. polyline._boundingVolume2D = BoundingSphere.fromPoints(newPositions, polyline._boundingVolume2D);
  1227. var center2D = polyline._boundingVolume2D.center;
  1228. polyline._boundingVolume2D.center = new Cartesian3(center2D.z, center2D.x, center2D.y);
  1229. }
  1230. scratchSegments.positions = newPositions;
  1231. scratchSegments.lengths = polyline._segments.lengths;
  1232. return scratchSegments;
  1233. };
  1234. var scratchPositionsArray;
  1235. var scratchTexCoordArray;
  1236. PolylineBucket.prototype.writeUpdate = function(index, polyline, positionBuffer, texCoordExpandWidthAndShowBuffer, projection) {
  1237. var mode = this.mode;
  1238. var positionsLength = polyline._actualLength;
  1239. if (positionsLength) {
  1240. index += this.getPolylineStartIndex(polyline);
  1241. var positionArray = scratchPositionsArray;
  1242. var texCoordExpandWidthAndShowArray = scratchTexCoordArray;
  1243. var positionsArrayLength = 6 * positionsLength * 3;
  1244. if (!defined(positionArray) || positionArray.length < positionsArrayLength) {
  1245. positionArray = scratchPositionsArray = new Float32Array(positionsArrayLength);
  1246. texCoordExpandWidthAndShowArray = scratchTexCoordArray = new Float32Array(positionsLength * 4);
  1247. } else if (positionArray.length > positionsArrayLength) {
  1248. positionArray = new Float32Array(positionArray.buffer, 0, positionsArrayLength);
  1249. texCoordExpandWidthAndShowArray = new Float32Array(texCoordExpandWidthAndShowArray.buffer, 0, positionsLength * 4);
  1250. }
  1251. var positionIndex = 0;
  1252. var texCoordExpandWidthAndShowIndex = 0;
  1253. var segments = this.getSegments(polyline, projection);
  1254. var positions = segments.positions;
  1255. var lengths = segments.lengths;
  1256. var segmentIndex = 0;
  1257. var count = 0;
  1258. var position;
  1259. var width = polyline.width;
  1260. var show = polyline.show && width > 0.0;
  1261. positionsLength = positions.length;
  1262. for ( var i = 0; i < positionsLength; ++i) {
  1263. if (i === 0) {
  1264. if (polyline._loop) {
  1265. position = positions[positionsLength - 2];
  1266. } else {
  1267. position = scratchWriteVector;
  1268. Cartesian3.subtract(positions[0], positions[1], position);
  1269. Cartesian3.add(positions[0], position, position);
  1270. }
  1271. } else {
  1272. position = positions[i - 1];
  1273. }
  1274. scratchWritePrevPosition.x = position.x;
  1275. scratchWritePrevPosition.y = position.y;
  1276. scratchWritePrevPosition.z = (mode !== SceneMode.SCENE2D) ? position.z : 0.0;
  1277. position = positions[i];
  1278. scratchWritePosition.x = position.x;
  1279. scratchWritePosition.y = position.y;
  1280. scratchWritePosition.z = (mode !== SceneMode.SCENE2D) ? position.z : 0.0;
  1281. if (i === positionsLength - 1) {
  1282. if (polyline._loop) {
  1283. position = positions[1];
  1284. } else {
  1285. position = scratchWriteVector;
  1286. Cartesian3.subtract(positions[positionsLength - 1], positions[positionsLength - 2], position);
  1287. Cartesian3.add(positions[positionsLength - 1], position, position);
  1288. }
  1289. } else {
  1290. position = positions[i + 1];
  1291. }
  1292. scratchWriteNextPosition.x = position.x;
  1293. scratchWriteNextPosition.y = position.y;
  1294. scratchWriteNextPosition.z = (mode !== SceneMode.SCENE2D) ? position.z : 0.0;
  1295. var segmentLength = lengths[segmentIndex];
  1296. if (i === count + segmentLength) {
  1297. count += segmentLength;
  1298. ++segmentIndex;
  1299. }
  1300. var segmentStart = i - count === 0;
  1301. var segmentEnd = i === count + lengths[segmentIndex] - 1;
  1302. var startJ = (segmentStart) ? 2 : 0;
  1303. var endJ = (segmentEnd) ? 2 : 4;
  1304. for (var j = startJ; j < endJ; ++j) {
  1305. EncodedCartesian3.writeElements(scratchWritePosition, positionArray, positionIndex);
  1306. EncodedCartesian3.writeElements(scratchWritePrevPosition, positionArray, positionIndex + 6);
  1307. EncodedCartesian3.writeElements(scratchWriteNextPosition, positionArray, positionIndex + 12);
  1308. var direction = (j - 2 < 0) ? -1.0 : 1.0;
  1309. texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex] = i / (positionsLength - 1); // s tex coord
  1310. texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 1] = 2 * (j % 2) - 1; // expand direction
  1311. texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 2] = direction * width;
  1312. texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 3] = show;
  1313. positionIndex += 6 * 3;
  1314. texCoordExpandWidthAndShowIndex += 4;
  1315. }
  1316. }
  1317. positionBuffer.copyFromArrayView(positionArray, 6 * 3 * Float32Array.BYTES_PER_ELEMENT * index);
  1318. texCoordExpandWidthAndShowBuffer.copyFromArrayView(texCoordExpandWidthAndShowArray, 4 * Float32Array.BYTES_PER_ELEMENT * index);
  1319. }
  1320. };
  1321. return PolylineCollection;
  1322. });