marker-data.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /**
  2. * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { ValueCell } from '../../mol-util/value-cell';
  7. import { Vec2 } from '../../mol-math/linear-algebra';
  8. import { TextureImage, createTextureImage } from '../../mol-gl/renderable/util';
  9. export type MarkerType = 'instance' | 'groupInstance';
  10. export type MarkerData = {
  11. uMarker: ValueCell<number>
  12. tMarker: ValueCell<TextureImage<Uint8Array>>
  13. uMarkerTexDim: ValueCell<Vec2>
  14. markerAverage: ValueCell<number>
  15. markerStatus: ValueCell<number>
  16. dMarkerType: ValueCell<string>
  17. }
  18. const MarkerCountLut = new Uint8Array(0x0303 + 1);
  19. MarkerCountLut[0x0001] = 1;
  20. MarkerCountLut[0x0002] = 1;
  21. MarkerCountLut[0x0003] = 1;
  22. MarkerCountLut[0x0100] = 1;
  23. MarkerCountLut[0x0200] = 1;
  24. MarkerCountLut[0x0300] = 1;
  25. MarkerCountLut[0x0101] = 2;
  26. MarkerCountLut[0x0201] = 2;
  27. MarkerCountLut[0x0301] = 2;
  28. MarkerCountLut[0x0102] = 2;
  29. MarkerCountLut[0x0202] = 2;
  30. MarkerCountLut[0x0302] = 2;
  31. MarkerCountLut[0x0103] = 2;
  32. MarkerCountLut[0x0203] = 2;
  33. MarkerCountLut[0x0303] = 2;
  34. /**
  35. * Calculates the average number of entries that have any marker flag set.
  36. *
  37. * For alternative implementations and performance tests see
  38. * `src\perf-tests\markers-average.ts`.
  39. */
  40. export function getMarkersAverage(array: Uint8Array, count: number): number {
  41. if (count === 0) return 0;
  42. const view = new Uint32Array(array.buffer, 0, array.buffer.byteLength >> 2);
  43. const viewEnd = (count - 4) >> 2;
  44. const backStart = 4 * viewEnd;
  45. let sum = 0;
  46. if (viewEnd < 0) {
  47. // avoid edge cases with small arrays
  48. for (let i = 0; i < count; ++i) {
  49. sum += array[i] && 1;
  50. }
  51. } else {
  52. for (let i = 0; i < viewEnd; ++i) {
  53. const v = view[i];
  54. sum += MarkerCountLut[v & 0xFFFF] + MarkerCountLut[v >> 16];
  55. }
  56. for (let i = backStart; i < count; ++i) {
  57. sum += array[i] && 1;
  58. }
  59. }
  60. return sum / count;
  61. }
  62. export function createMarkers(count: number, type: MarkerType, markerData?: MarkerData): MarkerData {
  63. const markers = createTextureImage(Math.max(1, count), 1, Uint8Array, markerData && markerData.tMarker.ref.value.array);
  64. const average = getMarkersAverage(markers.array, count);
  65. const status = average === 0 ? 0 : -1;
  66. if (markerData) {
  67. ValueCell.updateIfChanged(markerData.uMarker, 0);
  68. ValueCell.update(markerData.tMarker, markers);
  69. ValueCell.update(markerData.uMarkerTexDim, Vec2.create(markers.width, markers.height));
  70. ValueCell.updateIfChanged(markerData.markerAverage, average);
  71. ValueCell.updateIfChanged(markerData.markerStatus, status);
  72. ValueCell.updateIfChanged(markerData.dMarkerType, type);
  73. return markerData;
  74. } else {
  75. return {
  76. uMarker: ValueCell.create(0),
  77. tMarker: ValueCell.create(markers),
  78. uMarkerTexDim: ValueCell.create(Vec2.create(markers.width, markers.height)),
  79. markerAverage: ValueCell.create(average),
  80. markerStatus: ValueCell.create(status),
  81. dMarkerType: ValueCell.create(type),
  82. };
  83. }
  84. }
  85. const emptyMarkerTexture = { array: new Uint8Array(1), width: 1, height: 1 };
  86. export function createEmptyMarkers(markerData?: MarkerData): MarkerData {
  87. if (markerData) {
  88. ValueCell.updateIfChanged(markerData.uMarker, 0);
  89. ValueCell.update(markerData.tMarker, emptyMarkerTexture);
  90. ValueCell.update(markerData.uMarkerTexDim, Vec2.create(1, 1));
  91. ValueCell.updateIfChanged(markerData.markerAverage, 0);
  92. ValueCell.updateIfChanged(markerData.markerStatus, 0);
  93. return markerData;
  94. } else {
  95. return {
  96. uMarker: ValueCell.create(0),
  97. tMarker: ValueCell.create(emptyMarkerTexture),
  98. uMarkerTexDim: ValueCell.create(Vec2.create(1, 1)),
  99. markerAverage: ValueCell.create(0),
  100. markerStatus: ValueCell.create(0),
  101. dMarkerType: ValueCell.create('groupInstance'),
  102. };
  103. }
  104. }