size-data.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /**
  2. * Copyright (c) 2018 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 { getGranularity } from './geometry';
  13. import { encodeFloatLog } 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 (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. export type LocationSize = (location: Location) => number
  30. const emptySizeTexture = { array: new Uint8Array(1), width: 1, height: 1 }
  31. function createEmptySizeTexture() {
  32. return {
  33. tSize: ValueCell.create(emptySizeTexture),
  34. uSizeTexDim: ValueCell.create(Vec2.create(1, 1))
  35. }
  36. }
  37. export function createValueSize(value: number, sizeData?: SizeData): SizeData {
  38. if (sizeData) {
  39. ValueCell.update(sizeData.uSize, value)
  40. if (sizeData.dSizeType.ref.value !== 'uniform') {
  41. ValueCell.update(sizeData.dSizeType, 'uniform')
  42. }
  43. return sizeData
  44. } else {
  45. return {
  46. uSize: ValueCell.create(value),
  47. ...createEmptySizeTexture(),
  48. dSizeType: ValueCell.create('uniform'),
  49. }
  50. }
  51. }
  52. /** Creates size uniform */
  53. export function createUniformSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData {
  54. return createValueSize(sizeFn(NullLocation), sizeData)
  55. }
  56. export function createTextureSize(sizes: TextureImage<Uint8Array>, type: SizeType, sizeData?: SizeData): SizeData {
  57. if (sizeData) {
  58. ValueCell.update(sizeData.tSize, sizes)
  59. ValueCell.update(sizeData.uSizeTexDim, Vec2.create(sizes.width, sizes.height))
  60. if (sizeData.dSizeType.ref.value !== type) {
  61. ValueCell.update(sizeData.dSizeType, type)
  62. }
  63. return sizeData
  64. } else {
  65. return {
  66. uSize: ValueCell.create(0),
  67. tSize: ValueCell.create(sizes),
  68. uSizeTexDim: ValueCell.create(Vec2.create(sizes.width, sizes.height)),
  69. dSizeType: ValueCell.create(type),
  70. }
  71. }
  72. }
  73. /** Creates size texture with size for each instance/unit */
  74. export function createInstanceSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData {
  75. const { instanceCount} = locationIt
  76. const sizes = sizeData && sizeData.tSize.ref.value.array.length >= instanceCount ? sizeData.tSize.ref.value : createTextureImage(instanceCount, 1)
  77. locationIt.reset()
  78. while (locationIt.hasNext && !locationIt.isNextNewInstance) {
  79. const v = locationIt.move()
  80. sizes.array[v.instanceIndex] = encodeFloatLog(sizeFn(v.location)) * 255
  81. locationIt.skipInstance()
  82. }
  83. return createTextureSize(sizes, 'instance', sizeData)
  84. }
  85. /** Creates size texture with size for each group (i.e. shared across instances/units) */
  86. export function createGroupSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData {
  87. const { groupCount } = locationIt
  88. const sizes = sizeData && sizeData.tSize.ref.value.array.length >= groupCount ? sizeData.tSize.ref.value : createTextureImage(groupCount, 1)
  89. locationIt.reset()
  90. while (locationIt.hasNext && !locationIt.isNextNewInstance) {
  91. const v = locationIt.move()
  92. sizes.array[v.groupIndex] = encodeFloatLog(sizeFn(v.location)) * 255
  93. }
  94. return createTextureSize(sizes, 'group', sizeData)
  95. }
  96. /** Creates size texture with size for each group in each instance (i.e. for each unit) */
  97. export function createGroupInstanceSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData {
  98. const { groupCount, instanceCount } = locationIt
  99. const count = instanceCount * groupCount
  100. const sizes = sizeData && sizeData.tSize.ref.value.array.length >= count ? sizeData.tSize.ref.value : createTextureImage(count, 1)
  101. locationIt.reset()
  102. while (locationIt.hasNext && !locationIt.isNextNewInstance) {
  103. const v = locationIt.move()
  104. sizes.array[v.index] = encodeFloatLog(sizeFn(v.location)) * 255
  105. }
  106. return createTextureSize(sizes, 'groupInstance', sizeData)
  107. }