size-data.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /**
  2. * Copyright (c) 2018-2020 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';
  7. import { Vec2 } from '../../mol-math/linear-algebra';
  8. import { TextureImage, createTextureImage } from '../../mol-gl/renderable/util';
  9. import { LocationIterator } from '../util/location-iterator';
  10. import { Location, NullLocation } from '../../mol-model/location';
  11. import { SizeTheme } from '../../mol-theme/size';
  12. import { Geometry } from './geometry';
  13. import { decodeFloatRGB, encodeFloatRGBtoArray } from '../../mol-util/float-packing';
  14. export type SizeType = 'uniform' | 'instance' | 'group' | 'groupInstance'
  15. export type SizeData = {
  16. uSize: ValueCell<number>,
  17. tSize: ValueCell<TextureImage<Uint8Array>>,
  18. uSizeTexDim: ValueCell<Vec2>,
  19. dSizeType: ValueCell<string>,
  20. }
  21. export function createSizes(locationIt: LocationIterator, sizeTheme: SizeTheme<any>, sizeData?: SizeData): SizeData {
  22. switch (Geometry.getGranularity(locationIt, sizeTheme.granularity)) {
  23. case 'uniform': return createUniformSize(locationIt, sizeTheme.size, sizeData);
  24. case 'group': return createGroupSize(locationIt, sizeTheme.size, sizeData);
  25. case 'groupInstance': return createGroupInstanceSize(locationIt, sizeTheme.size, sizeData);
  26. case 'instance': return createInstanceSize(locationIt, sizeTheme.size, sizeData);
  27. }
  28. }
  29. const sizeFactor = 100; // NOTE same factor is set in shaders
  30. export function getMaxSize(sizeData: SizeData): number {
  31. const type = sizeData.dSizeType.ref.value as SizeType;
  32. switch (type) {
  33. case 'uniform':
  34. return sizeData.uSize.ref.value;
  35. case 'instance':
  36. case 'group':
  37. case 'groupInstance':
  38. let maxSize = 0;
  39. const array = sizeData.tSize.ref.value.array;
  40. for (let i = 0, il = array.length; i < il; i += 3) {
  41. const value = decodeFloatRGB(array[i], array[i + 1], array[i + 2]);
  42. if (maxSize < value) maxSize = value;
  43. }
  44. return maxSize / sizeFactor;
  45. }
  46. }
  47. export type LocationSize = (location: Location) => number
  48. const emptySizeTexture = { array: new Uint8Array(3), width: 1, height: 1 };
  49. function createEmptySizeTexture() {
  50. return {
  51. tSize: ValueCell.create(emptySizeTexture),
  52. uSizeTexDim: ValueCell.create(Vec2.create(1, 1))
  53. };
  54. }
  55. export function createValueSize(value: number, sizeData?: SizeData): SizeData {
  56. if (sizeData) {
  57. ValueCell.update(sizeData.uSize, value);
  58. if (sizeData.dSizeType.ref.value !== 'uniform') {
  59. ValueCell.update(sizeData.dSizeType, 'uniform');
  60. }
  61. return sizeData;
  62. } else {
  63. return {
  64. uSize: ValueCell.create(value),
  65. ...createEmptySizeTexture(),
  66. dSizeType: ValueCell.create('uniform'),
  67. };
  68. }
  69. }
  70. /** Creates size uniform */
  71. export function createUniformSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData {
  72. return createValueSize(sizeFn(NullLocation), sizeData);
  73. }
  74. export function createTextureSize(sizes: TextureImage<Uint8Array>, type: SizeType, sizeData?: SizeData): SizeData {
  75. if (sizeData) {
  76. ValueCell.update(sizeData.tSize, sizes);
  77. ValueCell.update(sizeData.uSizeTexDim, Vec2.create(sizes.width, sizes.height));
  78. if (sizeData.dSizeType.ref.value !== type) {
  79. ValueCell.update(sizeData.dSizeType, type);
  80. }
  81. return sizeData;
  82. } else {
  83. return {
  84. uSize: ValueCell.create(0),
  85. tSize: ValueCell.create(sizes),
  86. uSizeTexDim: ValueCell.create(Vec2.create(sizes.width, sizes.height)),
  87. dSizeType: ValueCell.create(type),
  88. };
  89. }
  90. }
  91. /** Creates size texture with size for each instance/unit */
  92. export function createInstanceSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData {
  93. const { instanceCount} = locationIt;
  94. const sizes = createTextureImage(Math.max(1, instanceCount), 3, Uint8Array, sizeData && sizeData.tSize.ref.value.array);
  95. locationIt.reset();
  96. while (locationIt.hasNext && !locationIt.isNextNewInstance) {
  97. const v = locationIt.move();
  98. encodeFloatRGBtoArray(sizeFn(v.location) * sizeFactor, sizes.array, v.instanceIndex * 3);
  99. locationIt.skipInstance();
  100. }
  101. return createTextureSize(sizes, 'instance', sizeData);
  102. }
  103. /** Creates size texture with size for each group (i.e. shared across instances/units) */
  104. export function createGroupSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData {
  105. const { groupCount } = locationIt;
  106. const sizes = createTextureImage(Math.max(1, groupCount), 3, Uint8Array, sizeData && sizeData.tSize.ref.value.array);
  107. locationIt.reset();
  108. while (locationIt.hasNext && !locationIt.isNextNewInstance) {
  109. const v = locationIt.move();
  110. encodeFloatRGBtoArray(sizeFn(v.location) * sizeFactor, sizes.array, v.groupIndex * 3);
  111. }
  112. return createTextureSize(sizes, 'group', sizeData);
  113. }
  114. /** Creates size texture with size for each group in each instance (i.e. for each unit) */
  115. export function createGroupInstanceSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData {
  116. const { groupCount, instanceCount } = locationIt;
  117. const count = instanceCount * groupCount;
  118. const sizes = createTextureImage(Math.max(1, count), 3, Uint8Array, sizeData && sizeData.tSize.ref.value.array);
  119. locationIt.reset();
  120. while (locationIt.hasNext) {
  121. const v = locationIt.move();
  122. encodeFloatRGBtoArray(sizeFn(v.location) * sizeFactor, sizes.array, v.index * 3);
  123. }
  124. return createTextureSize(sizes, 'groupInstance', sizeData);
  125. }