PolylineCollection.js 69 KB

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