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

renderBufferPolylineCollection.js 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. // @ts-check
  2. import defined from "../Core/defined.js";
  3. import Cartesian3 from "../Core/Cartesian3.js";
  4. import Color from "../Core/Color.js";
  5. import BufferPolyline from "./BufferPolyline.js";
  6. import Buffer from "../Renderer/Buffer.js";
  7. import BufferUsage from "../Renderer/BufferUsage.js";
  8. import VertexArray from "../Renderer/VertexArray.js";
  9. import ComponentDatatype from "../Core/ComponentDatatype.js";
  10. import RenderState from "../Renderer/RenderState.js";
  11. import BlendingState from "./BlendingState.js";
  12. import ShaderSource from "../Renderer/ShaderSource.js";
  13. import ShaderProgram from "../Renderer/ShaderProgram.js";
  14. import DrawCommand from "../Renderer/DrawCommand.js";
  15. import Pass from "../Renderer/Pass.js";
  16. import PrimitiveType from "../Core/PrimitiveType.js";
  17. import BufferPolylineMaterialVS from "../Shaders/BufferPolylineMaterialVS.js";
  18. import BufferPolylineMaterialFS from "../Shaders/BufferPolylineMaterialFS.js";
  19. import EncodedCartesian3 from "../Core/EncodedCartesian3.js";
  20. import AttributeCompression from "../Core/AttributeCompression.js";
  21. import IndexDatatype from "../Core/IndexDatatype.js";
  22. import PolylineCommon from "../Shaders/PolylineCommon.js";
  23. import BufferPolylineMaterial from "./BufferPolylineMaterial.js";
  24. import BlendOption from "./BlendOption.js";
  25. /** @import FrameState from "./FrameState.js"; */
  26. /** @import BufferPolylineCollection from "./BufferPolylineCollection.js"; */
  27. /** @import {TypedArray} from "../Core/globalTypes.js"; */
  28. /**
  29. * TODO(PR#13211): Need 'keyof' syntax to avoid duplicating attribute names.
  30. * @typedef {'positionHigh' | 'positionLow' | 'prevPositionHigh' | 'prevPositionLow' | 'nextPositionHigh' | 'nextPositionLow' | 'pickColor' | 'showColorWidthAndTexCoord' | 'alpha'} BufferPolylineAttribute
  31. * @ignore
  32. */
  33. /**
  34. * Attribute locations when using 64-bit position precision.
  35. * @type {Record<BufferPolylineAttribute, number>}
  36. * @ignore
  37. */
  38. const BufferPolylineAttributeLocationsFloat64 = {
  39. positionHigh: 0,
  40. positionLow: 1,
  41. prevPositionHigh: 2,
  42. prevPositionLow: 3,
  43. nextPositionHigh: 4,
  44. nextPositionLow: 5,
  45. pickColor: 6,
  46. showColorWidthAndTexCoord: 7,
  47. alpha: 8,
  48. };
  49. /**
  50. * Attribute locations when using <= 32-bit position precision.
  51. * @type {Record<string, number>}
  52. * @ignore
  53. */
  54. const BufferPolylineAttributeLocations = {
  55. position: 0,
  56. prevPosition: 1,
  57. nextPosition: 2,
  58. pickColor: 3,
  59. showColorWidthAndTexCoord: 4,
  60. alpha: 5,
  61. };
  62. /**
  63. * @typedef {object} BufferPolylineRenderContext
  64. * @property {VertexArray} [vertexArray]
  65. * @property {Record<string, TypedArray>} [attributeArrays]
  66. * @property {TypedArray} [indexArray]
  67. * @property {RenderState} [renderState]
  68. * @property {ShaderProgram} [shaderProgram]
  69. * @property {DrawCommand} [command]
  70. * @property {Function} destroy
  71. * @ignore
  72. */
  73. // Scratch variables.
  74. const polyline = new BufferPolyline();
  75. const material = new BufferPolylineMaterial();
  76. const pickColor = new Color();
  77. const cartesian = new Cartesian3();
  78. const prevCartesian = new Cartesian3();
  79. const nextCartesian = new Cartesian3();
  80. const cartesianEnc = new EncodedCartesian3();
  81. const prevCartesianEnc = new EncodedCartesian3();
  82. const nextCartesianEnc = new EncodedCartesian3();
  83. /**
  84. * Renders line segments as quads, each composed of two triangles. Writes each
  85. * vertex twice, extruding the pairs in opposing directions outward.
  86. *
  87. * Tips:
  88. * - # segments in polyline primitive = vertexCount - 1
  89. * - # segments in collection = vertexCount - primitiveCount
  90. * - # vertices rendered = vertexCount * 2
  91. * - # indices = segmentCount * 6
  92. *
  93. * 0 - 2 - 4 - 6 - 8
  94. * | \ | \ | \ | \ | ...
  95. * 1 - 3 - 5 - 7 - 9
  96. *
  97. * @param {BufferPolylineCollection} collection
  98. * @param {FrameState} frameState
  99. * @param {BufferPolylineRenderContext} [renderContext]
  100. * @returns {BufferPolylineRenderContext}
  101. * @ignore
  102. */
  103. function renderBufferPolylineCollection(collection, frameState, renderContext) {
  104. const context = frameState.context;
  105. renderContext = renderContext || { destroy: destroyRenderContext };
  106. const useFloat64 = collection._positionDatatype === ComponentDatatype.DOUBLE;
  107. const attributeLocations = useFloat64
  108. ? BufferPolylineAttributeLocationsFloat64
  109. : BufferPolylineAttributeLocations;
  110. if (
  111. !defined(renderContext.attributeArrays) ||
  112. !defined(renderContext.indexArray)
  113. ) {
  114. // Number of primitives can only increase, which _decreases_ remaining
  115. // segment capacity: use `primitiveCount` here, not `primitiveCountMax`.
  116. const segmentCountMax =
  117. collection.vertexCountMax - collection.primitiveCount;
  118. const vertexCountMax = collection.vertexCountMax * 2;
  119. // @ts-expect-error https://github.com/CesiumGS/cesium/issues/13420
  120. renderContext.indexArray = IndexDatatype.createTypedArray(
  121. vertexCountMax,
  122. segmentCountMax * 6,
  123. );
  124. renderContext.attributeArrays = {
  125. ...(!useFloat64
  126. ? {
  127. // @ts-expect-error https://github.com/CesiumGS/cesium/issues/13420
  128. position: ComponentDatatype.createTypedArray(
  129. collection._positionDatatype,
  130. vertexCountMax * 3,
  131. ),
  132. // @ts-expect-error https://github.com/CesiumGS/cesium/issues/13420
  133. prevPosition: ComponentDatatype.createTypedArray(
  134. collection._positionDatatype,
  135. vertexCountMax * 3,
  136. ),
  137. // @ts-expect-error https://github.com/CesiumGS/cesium/issues/13420
  138. nextPosition: ComponentDatatype.createTypedArray(
  139. collection._positionDatatype,
  140. vertexCountMax * 3,
  141. ),
  142. }
  143. : {
  144. positionHigh: new Float32Array(vertexCountMax * 3),
  145. positionLow: new Float32Array(vertexCountMax * 3),
  146. prevPositionHigh: new Float32Array(vertexCountMax * 3),
  147. prevPositionLow: new Float32Array(vertexCountMax * 3),
  148. nextPositionHigh: new Float32Array(vertexCountMax * 3),
  149. nextPositionLow: new Float32Array(vertexCountMax * 3),
  150. }),
  151. pickColor: new Uint8Array(vertexCountMax * 4),
  152. showColorWidthAndTexCoord: new Float32Array(vertexCountMax * 4),
  153. alpha: new Uint8Array(vertexCountMax),
  154. };
  155. }
  156. if (collection._dirtyCount > 0) {
  157. const { _dirtyOffset, _dirtyCount } = collection;
  158. const { attributeArrays } = renderContext;
  159. const indexArray = renderContext.indexArray;
  160. const pickColorArray = attributeArrays.pickColor;
  161. const showColorWidthAndTexCoordArray =
  162. attributeArrays.showColorWidthAndTexCoord;
  163. const alphaArray = attributeArrays.alpha;
  164. for (let i = _dirtyOffset, il = _dirtyOffset + _dirtyCount; i < il; i++) {
  165. collection.get(i, polyline);
  166. if (!polyline._dirty) {
  167. continue;
  168. }
  169. polyline.getMaterial(material);
  170. const encodedColor = AttributeCompression.encodeRGB8(material.color);
  171. const colorAlpha = material.color.alpha;
  172. Color.fromRgba(polyline._pickId, pickColor);
  173. const show = polyline.show;
  174. let vOffset = polyline.vertexOffset * 2; // vertex offset
  175. let iOffset = (polyline.vertexOffset - i) * 6; // index offset
  176. const jl = polyline.vertexCount;
  177. if (!useFloat64) {
  178. const posView = collection._positionView;
  179. const posStart = polyline.vertexOffset * 3;
  180. const posArray = attributeArrays.position;
  181. const prevPosArray = attributeArrays.prevPosition;
  182. const nextPosArray = attributeArrays.nextPosition;
  183. for (let j = 0; j < jl; j++) {
  184. const isFirstSegment = j === 0;
  185. const isLastSegment = j === jl - 1;
  186. const cx = posView[posStart + j * 3];
  187. const cy = posView[posStart + j * 3 + 1];
  188. const cz = posView[posStart + j * 3 + 2];
  189. let px, py, pz, nx, ny, nz;
  190. if (isFirstSegment) {
  191. nx = posView[posStart + 1 * 3];
  192. ny = posView[posStart + 1 * 3 + 1];
  193. nz = posView[posStart + 1 * 3 + 2];
  194. // Mirror current over next to get synthetic prev.
  195. px = 2 * cx - nx;
  196. py = 2 * cy - ny;
  197. pz = 2 * cz - nz;
  198. } else if (isLastSegment) {
  199. px = posView[posStart + (j - 1) * 3];
  200. py = posView[posStart + (j - 1) * 3 + 1];
  201. pz = posView[posStart + (j - 1) * 3 + 2];
  202. // Mirror current over prev to get synthetic next.
  203. nx = 2 * cx - px;
  204. ny = 2 * cy - py;
  205. nz = 2 * cz - pz;
  206. } else {
  207. px = posView[posStart + (j - 1) * 3];
  208. py = posView[posStart + (j - 1) * 3 + 1];
  209. pz = posView[posStart + (j - 1) * 3 + 2];
  210. nx = posView[posStart + (j + 1) * 3];
  211. ny = posView[posStart + (j + 1) * 3 + 1];
  212. nz = posView[posStart + (j + 1) * 3 + 2];
  213. }
  214. if (!isLastSegment) {
  215. indexArray[iOffset] = vOffset;
  216. indexArray[iOffset + 1] = vOffset + 1;
  217. indexArray[iOffset + 2] = vOffset + 2;
  218. indexArray[iOffset + 3] = vOffset + 2;
  219. indexArray[iOffset + 4] = vOffset + 1;
  220. indexArray[iOffset + 5] = vOffset + 3;
  221. iOffset += 6;
  222. }
  223. // Write each vertex twice for the quad.
  224. for (let k = 0; k < 2; k++) {
  225. posArray[vOffset * 3] = cx;
  226. posArray[vOffset * 3 + 1] = cy;
  227. posArray[vOffset * 3 + 2] = cz;
  228. prevPosArray[vOffset * 3] = px;
  229. prevPosArray[vOffset * 3 + 1] = py;
  230. prevPosArray[vOffset * 3 + 2] = pz;
  231. nextPosArray[vOffset * 3] = nx;
  232. nextPosArray[vOffset * 3 + 1] = ny;
  233. nextPosArray[vOffset * 3 + 2] = nz;
  234. pickColorArray[vOffset * 4] = Color.floatToByte(pickColor.red);
  235. pickColorArray[vOffset * 4 + 1] = Color.floatToByte(
  236. pickColor.green,
  237. );
  238. pickColorArray[vOffset * 4 + 2] = Color.floatToByte(pickColor.blue);
  239. pickColorArray[vOffset * 4 + 3] = Color.floatToByte(
  240. pickColor.alpha,
  241. );
  242. showColorWidthAndTexCoordArray[vOffset * 4] = show ? 1 : 0;
  243. showColorWidthAndTexCoordArray[vOffset * 4 + 1] = encodedColor;
  244. showColorWidthAndTexCoordArray[vOffset * 4 + 2] = material.width;
  245. showColorWidthAndTexCoordArray[vOffset * 4 + 3] = j / (jl - 1);
  246. alphaArray[vOffset] = colorAlpha * 255.0;
  247. vOffset++;
  248. }
  249. }
  250. } else {
  251. const cartesianArray = polyline.getPositions();
  252. for (let j = 0; j < jl; j++) {
  253. const isFirstSegment = j === 0;
  254. const isLastSegment = j === jl - 1;
  255. // For first/last vertices, infer missing vertices by mirroring the segment.
  256. // @ts-expect-error TODO(tsd-jsdoc): See https://github.com/CesiumGS/cesium/pull/13302.
  257. Cartesian3.fromArray(cartesianArray, j * 3, cartesian);
  258. if (isFirstSegment) {
  259. // @ts-expect-error TODO(tsd-jsdoc): See https://github.com/CesiumGS/cesium/pull/13302.
  260. Cartesian3.fromArray(cartesianArray, (j + 1) * 3, nextCartesian);
  261. Cartesian3.subtract(cartesian, nextCartesian, prevCartesian);
  262. Cartesian3.add(cartesian, prevCartesian, prevCartesian);
  263. } else if (isLastSegment) {
  264. // @ts-expect-error TODO(tsd-jsdoc): See https://github.com/CesiumGS/cesium/pull/13302.
  265. Cartesian3.fromArray(cartesianArray, (j - 1) * 3, prevCartesian);
  266. Cartesian3.subtract(cartesian, prevCartesian, nextCartesian);
  267. Cartesian3.add(cartesian, nextCartesian, nextCartesian);
  268. } else {
  269. // @ts-expect-error TODO(tsd-jsdoc): See https://github.com/CesiumGS/cesium/pull/13302.
  270. Cartesian3.fromArray(cartesianArray, (j - 1) * 3, prevCartesian);
  271. // @ts-expect-error TODO(tsd-jsdoc): See https://github.com/CesiumGS/cesium/pull/13302.
  272. Cartesian3.fromArray(cartesianArray, (j + 1) * 3, nextCartesian);
  273. }
  274. // For each segment, draw two triangles.
  275. if (!isLastSegment) {
  276. indexArray[iOffset] = vOffset;
  277. indexArray[iOffset + 1] = vOffset + 1;
  278. indexArray[iOffset + 2] = vOffset + 2;
  279. indexArray[iOffset + 3] = vOffset + 2;
  280. indexArray[iOffset + 4] = vOffset + 1;
  281. indexArray[iOffset + 5] = vOffset + 3;
  282. iOffset += 6;
  283. }
  284. EncodedCartesian3.fromCartesian(cartesian, cartesianEnc);
  285. EncodedCartesian3.fromCartesian(prevCartesian, prevCartesianEnc);
  286. EncodedCartesian3.fromCartesian(nextCartesian, nextCartesianEnc);
  287. // TODO(donmccurdy): Diverging from PolylineCollection.js, which writes
  288. // internal vertices to buffer 4x, not 2x. Not sure that's needed?
  289. for (let k = 0; k < 2; k++) {
  290. // Position.
  291. attributeArrays.positionHigh[vOffset * 3] = cartesianEnc.high.x;
  292. attributeArrays.positionHigh[vOffset * 3 + 1] = cartesianEnc.high.y;
  293. attributeArrays.positionHigh[vOffset * 3 + 2] = cartesianEnc.high.z;
  294. attributeArrays.positionLow[vOffset * 3] = cartesianEnc.low.x;
  295. attributeArrays.positionLow[vOffset * 3 + 1] = cartesianEnc.low.y;
  296. attributeArrays.positionLow[vOffset * 3 + 2] = cartesianEnc.low.z;
  297. // Previous position.
  298. attributeArrays.prevPositionHigh[vOffset * 3] =
  299. prevCartesianEnc.high.x;
  300. attributeArrays.prevPositionHigh[vOffset * 3 + 1] =
  301. prevCartesianEnc.high.y;
  302. attributeArrays.prevPositionHigh[vOffset * 3 + 2] =
  303. prevCartesianEnc.high.z;
  304. attributeArrays.prevPositionLow[vOffset * 3] =
  305. prevCartesianEnc.low.x;
  306. attributeArrays.prevPositionLow[vOffset * 3 + 1] =
  307. prevCartesianEnc.low.y;
  308. attributeArrays.prevPositionLow[vOffset * 3 + 2] =
  309. prevCartesianEnc.low.z;
  310. // Next position.
  311. attributeArrays.nextPositionHigh[vOffset * 3] =
  312. nextCartesianEnc.high.x;
  313. attributeArrays.nextPositionHigh[vOffset * 3 + 1] =
  314. nextCartesianEnc.high.y;
  315. attributeArrays.nextPositionHigh[vOffset * 3 + 2] =
  316. nextCartesianEnc.high.z;
  317. attributeArrays.nextPositionLow[vOffset * 3] =
  318. nextCartesianEnc.low.x;
  319. attributeArrays.nextPositionLow[vOffset * 3 + 1] =
  320. nextCartesianEnc.low.y;
  321. attributeArrays.nextPositionLow[vOffset * 3 + 2] =
  322. nextCartesianEnc.low.z;
  323. // Pick ID.
  324. pickColorArray[vOffset * 4] = Color.floatToByte(pickColor.red);
  325. pickColorArray[vOffset * 4 + 1] = Color.floatToByte(
  326. pickColor.green,
  327. );
  328. pickColorArray[vOffset * 4 + 2] = Color.floatToByte(pickColor.blue);
  329. pickColorArray[vOffset * 4 + 3] = Color.floatToByte(
  330. pickColor.alpha,
  331. );
  332. // Properties.
  333. showColorWidthAndTexCoordArray[vOffset * 4] = show ? 1 : 0;
  334. showColorWidthAndTexCoordArray[vOffset * 4 + 1] = encodedColor;
  335. showColorWidthAndTexCoordArray[vOffset * 4 + 2] = material.width;
  336. showColorWidthAndTexCoordArray[vOffset * 4 + 3] = j / (jl - 1); // texcoord.s
  337. alphaArray[vOffset] = colorAlpha * 255.0;
  338. vOffset++;
  339. }
  340. }
  341. }
  342. polyline._dirty = false;
  343. }
  344. }
  345. if (!defined(renderContext.vertexArray)) {
  346. const attributeArrays = renderContext.attributeArrays;
  347. renderContext.vertexArray = new VertexArray({
  348. context,
  349. indexBuffer: Buffer.createIndexBuffer({
  350. context,
  351. typedArray: renderContext.indexArray,
  352. usage: BufferUsage.STATIC_DRAW,
  353. // @ts-expect-error https://github.com/CesiumGS/cesium/issues/13420
  354. indexDatatype: IndexDatatype.fromTypedArray(renderContext.indexArray),
  355. }),
  356. attributes: [
  357. ...(!useFloat64
  358. ? [
  359. {
  360. index: BufferPolylineAttributeLocations.position,
  361. componentDatatype: collection._positionDatatype,
  362. componentsPerAttribute: 3,
  363. normalize: collection._positionNormalized,
  364. vertexBuffer: Buffer.createVertexBuffer({
  365. typedArray: attributeArrays.position,
  366. context,
  367. usage: BufferUsage.STATIC_DRAW,
  368. }),
  369. },
  370. {
  371. index: BufferPolylineAttributeLocations.prevPosition,
  372. componentDatatype: collection._positionDatatype,
  373. componentsPerAttribute: 3,
  374. normalize: collection._positionNormalized,
  375. vertexBuffer: Buffer.createVertexBuffer({
  376. typedArray: attributeArrays.prevPosition,
  377. context,
  378. usage: BufferUsage.STATIC_DRAW,
  379. }),
  380. },
  381. {
  382. index: BufferPolylineAttributeLocations.nextPosition,
  383. componentDatatype: collection._positionDatatype,
  384. componentsPerAttribute: 3,
  385. normalize: collection._positionNormalized,
  386. vertexBuffer: Buffer.createVertexBuffer({
  387. typedArray: attributeArrays.nextPosition,
  388. context,
  389. usage: BufferUsage.STATIC_DRAW,
  390. }),
  391. },
  392. ]
  393. : [
  394. {
  395. index: BufferPolylineAttributeLocationsFloat64.positionHigh,
  396. componentDatatype: ComponentDatatype.FLOAT,
  397. componentsPerAttribute: 3,
  398. vertexBuffer: Buffer.createVertexBuffer({
  399. typedArray: attributeArrays.positionHigh,
  400. context,
  401. usage: BufferUsage.STATIC_DRAW,
  402. }),
  403. },
  404. {
  405. index: BufferPolylineAttributeLocationsFloat64.positionLow,
  406. componentDatatype: ComponentDatatype.FLOAT,
  407. componentsPerAttribute: 3,
  408. vertexBuffer: Buffer.createVertexBuffer({
  409. typedArray: attributeArrays.positionLow,
  410. context,
  411. usage: BufferUsage.STATIC_DRAW,
  412. }),
  413. },
  414. {
  415. index: BufferPolylineAttributeLocationsFloat64.prevPositionHigh,
  416. componentDatatype: ComponentDatatype.FLOAT,
  417. componentsPerAttribute: 3,
  418. vertexBuffer: Buffer.createVertexBuffer({
  419. typedArray: attributeArrays.prevPositionHigh,
  420. context,
  421. usage: BufferUsage.STATIC_DRAW,
  422. }),
  423. },
  424. {
  425. index: BufferPolylineAttributeLocationsFloat64.prevPositionLow,
  426. componentDatatype: ComponentDatatype.FLOAT,
  427. componentsPerAttribute: 3,
  428. vertexBuffer: Buffer.createVertexBuffer({
  429. typedArray: attributeArrays.prevPositionLow,
  430. context,
  431. usage: BufferUsage.STATIC_DRAW,
  432. }),
  433. },
  434. {
  435. index: BufferPolylineAttributeLocationsFloat64.nextPositionHigh,
  436. componentDatatype: ComponentDatatype.FLOAT,
  437. componentsPerAttribute: 3,
  438. vertexBuffer: Buffer.createVertexBuffer({
  439. typedArray: attributeArrays.nextPositionHigh,
  440. context,
  441. usage: BufferUsage.STATIC_DRAW,
  442. }),
  443. },
  444. {
  445. index: BufferPolylineAttributeLocationsFloat64.nextPositionLow,
  446. componentDatatype: ComponentDatatype.FLOAT,
  447. componentsPerAttribute: 3,
  448. vertexBuffer: Buffer.createVertexBuffer({
  449. typedArray: attributeArrays.nextPositionLow,
  450. context,
  451. usage: BufferUsage.STATIC_DRAW,
  452. }),
  453. },
  454. ]),
  455. {
  456. index: attributeLocations.pickColor,
  457. componentDatatype: ComponentDatatype.UNSIGNED_BYTE,
  458. componentsPerAttribute: 4,
  459. vertexBuffer: Buffer.createVertexBuffer({
  460. typedArray: attributeArrays.pickColor,
  461. context,
  462. usage: BufferUsage.STATIC_DRAW,
  463. }),
  464. },
  465. {
  466. index: attributeLocations.showColorWidthAndTexCoord,
  467. componentDatatype: ComponentDatatype.FLOAT,
  468. componentsPerAttribute: 4,
  469. vertexBuffer: Buffer.createVertexBuffer({
  470. typedArray: attributeArrays.showColorWidthAndTexCoord,
  471. context,
  472. usage: BufferUsage.STATIC_DRAW,
  473. }),
  474. },
  475. {
  476. index: attributeLocations.alpha,
  477. componentDatatype: ComponentDatatype.UNSIGNED_BYTE,
  478. componentsPerAttribute: 1,
  479. vertexBuffer: Buffer.createVertexBuffer({
  480. typedArray: attributeArrays.alpha,
  481. context,
  482. usage: BufferUsage.STATIC_DRAW,
  483. }),
  484. },
  485. ],
  486. });
  487. } else if (collection._dirtyCount > 0) {
  488. const { indexOffset, indexCount, vertexOffset, vertexCount } =
  489. getPolylineDirtyRanges(collection);
  490. renderContext.vertexArray.copyIndexFromRange(
  491. renderContext.indexArray,
  492. indexOffset,
  493. indexCount,
  494. );
  495. for (const key in attributeLocations) {
  496. if (Object.hasOwn(attributeLocations, key)) {
  497. const attribute = /** @type {BufferPolylineAttribute} */ (key);
  498. renderContext.vertexArray.copyAttributeFromRange(
  499. attributeLocations[attribute],
  500. renderContext.attributeArrays[attribute],
  501. vertexOffset,
  502. vertexCount,
  503. );
  504. }
  505. }
  506. }
  507. if (!defined(renderContext.renderState)) {
  508. renderContext.renderState = RenderState.fromCache({
  509. blending:
  510. collection._blendOption === BlendOption.OPAQUE
  511. ? BlendingState.DISABLED
  512. : BlendingState.ALPHA_BLEND,
  513. depthTest: { enabled: true },
  514. });
  515. }
  516. if (!defined(renderContext.shaderProgram)) {
  517. renderContext.shaderProgram = ShaderProgram.fromCache({
  518. context,
  519. vertexShaderSource: new ShaderSource({
  520. sources: [PolylineCommon, BufferPolylineMaterialVS],
  521. defines: useFloat64 ? ["USE_FLOAT64"] : [],
  522. }),
  523. fragmentShaderSource: new ShaderSource({
  524. sources: [BufferPolylineMaterialFS],
  525. }),
  526. attributeLocations,
  527. });
  528. }
  529. const drawCount = getDrawIndexCount(collection);
  530. if (!defined(renderContext.command)) {
  531. renderContext.command = new DrawCommand({
  532. vertexArray: renderContext.vertexArray,
  533. renderState: renderContext.renderState,
  534. shaderProgram: renderContext.shaderProgram,
  535. primitiveType: PrimitiveType.TRIANGLES,
  536. pass:
  537. collection._blendOption === BlendOption.OPAQUE
  538. ? Pass.OPAQUE
  539. : Pass.TRANSLUCENT,
  540. pickId: collection._allowPicking ? "v_pickColor" : undefined,
  541. owner: collection,
  542. count: drawCount,
  543. modelMatrix: collection.modelMatrix, // shared reference
  544. boundingVolume: collection.boundingVolume, // shared reference
  545. debugShowBoundingVolume: collection.debugShowBoundingVolume,
  546. });
  547. }
  548. const command = renderContext.command;
  549. if (command.count !== drawCount) {
  550. command.count = drawCount;
  551. }
  552. if (command.debugShowBoundingVolume !== collection.debugShowBoundingVolume) {
  553. command.debugShowBoundingVolume = collection.debugShowBoundingVolume;
  554. }
  555. frameState.commandList.push(command);
  556. collection._dirtyCount = 0;
  557. collection._dirtyOffset = 0;
  558. return renderContext;
  559. }
  560. /**
  561. * Returns number of drawn (not allocated) indices for given collection.
  562. * @param {BufferPolylineCollection} collection
  563. * @ignore
  564. */
  565. function getDrawIndexCount(collection) {
  566. return (collection.vertexCount - collection.primitiveCount) * 6;
  567. }
  568. /**
  569. * Computes dirty ranges for attribute and index buffers in a collection.
  570. * @param {BufferPolylineCollection} collection
  571. * @ignore
  572. */
  573. function getPolylineDirtyRanges(collection) {
  574. const { _dirtyOffset, _dirtyCount } = collection;
  575. collection.get(_dirtyOffset, polyline);
  576. const vertexOffset = polyline.vertexOffset * 2;
  577. const segmentOffset = polyline.vertexOffset - _dirtyOffset;
  578. const indexOffset = segmentOffset * 6;
  579. collection.get(_dirtyOffset + _dirtyCount - 1, polyline);
  580. const vertexCount =
  581. (polyline.vertexOffset + polyline.vertexCount) * 2 - vertexOffset;
  582. const segmentCount = vertexCount / 2 - _dirtyCount;
  583. const indexCount = segmentCount * 6;
  584. return { indexOffset, indexCount, vertexOffset, vertexCount };
  585. }
  586. /**
  587. * Destroys render context resources. Deleting properties from the context
  588. * object isn't necessary, as collection.destroy() will discard the object.
  589. * @ignore
  590. */
  591. function destroyRenderContext() {
  592. const context = /** @type {BufferPolylineRenderContext} */ (this);
  593. if (defined(context.vertexArray)) {
  594. context.vertexArray.destroy();
  595. }
  596. if (defined(context.shaderProgram)) {
  597. context.shaderProgram.destroy();
  598. }
  599. if (defined(context.renderState)) {
  600. RenderState.removeFromCache(context.renderState);
  601. }
  602. }
  603. export default renderBufferPolylineCollection;