size-data.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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 { RuntimeContext } from 'mol-task';
  12. import { SizeThemeProps, SizeTheme, SizeThemeName } from 'mol-view/theme/size';
  13. import { getGranularity } from './geometry';
  14. import { Structure } from 'mol-model/structure';
  15. export type SizeType = 'uniform' | 'instance' | 'group' | 'groupInstance'
  16. export type SizeData = {
  17. uSize: ValueCell<number>,
  18. aSize: ValueCell<Float32Array>,
  19. tSize: ValueCell<TextureImage<Uint8Array>>,
  20. uSizeTexDim: ValueCell<Vec2>,
  21. dSizeType: ValueCell<string>,
  22. }
  23. export interface SizeProps {
  24. sizeTheme: SizeThemeName
  25. sizeValue?: number
  26. sizeFactor?: number
  27. structure?: Structure
  28. }
  29. export function getSizeThemeProps(props: SizeProps): SizeThemeProps {
  30. return {
  31. name: props.sizeTheme,
  32. value: props.sizeValue,
  33. factor: props.sizeFactor,
  34. structure: props.structure,
  35. }
  36. }
  37. export async function createSizes(ctx: RuntimeContext, locationIt: LocationIterator, props: SizeProps, sizeData?: SizeData): Promise<SizeData> {
  38. const sizeTheme = SizeTheme(getSizeThemeProps(props))
  39. switch (getGranularity(locationIt, sizeTheme.granularity)) {
  40. case 'uniform': return createUniformSize(ctx, locationIt, sizeTheme.size, sizeData)
  41. case 'group': return createGroupSize(ctx, locationIt, sizeTheme.size, sizeData)
  42. case 'groupInstance': return createGroupInstanceSize(ctx, locationIt, sizeTheme.size, sizeData)
  43. case 'instance': return createInstanceSize(ctx, locationIt, sizeTheme.size, sizeData)
  44. }
  45. }
  46. export type LocationSize = (location: Location) => number
  47. const emptySizeTexture = { array: new Uint8Array(1), width: 1, height: 1 }
  48. function createEmptySizeTexture() {
  49. return {
  50. tSize: ValueCell.create(emptySizeTexture),
  51. uSizeTexDim: ValueCell.create(Vec2.create(1, 1))
  52. }
  53. }
  54. export function createValueSize(value: number, sizeData?: SizeData): SizeData {
  55. if (sizeData) {
  56. ValueCell.update(sizeData.uSize, value)
  57. if (sizeData.dSizeType.ref.value !== 'uniform') {
  58. ValueCell.update(sizeData.dSizeType, 'uniform')
  59. }
  60. return sizeData
  61. } else {
  62. return {
  63. uSize: ValueCell.create(value),
  64. aSize: ValueCell.create(new Float32Array(0)),
  65. ...createEmptySizeTexture(),
  66. dSizeType: ValueCell.create('uniform'),
  67. }
  68. }
  69. }
  70. /** Creates size uniform */
  71. export async function createUniformSize(ctx: RuntimeContext, locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): Promise<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. aSize: ValueCell.create(new Float32Array(0)),
  86. tSize: ValueCell.create(sizes),
  87. uSizeTexDim: ValueCell.create(Vec2.create(sizes.width, sizes.height)),
  88. dSizeType: ValueCell.create(type),
  89. }
  90. }
  91. }
  92. /** Creates size texture with size for each instance/unit */
  93. export async function createInstanceSize(ctx: RuntimeContext, locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): Promise<SizeData> {
  94. const { instanceCount} = locationIt
  95. const sizes = sizeData && sizeData.tSize.ref.value.array.length >= instanceCount ? sizeData.tSize.ref.value : createTextureImage(instanceCount, 1)
  96. let i = 0
  97. while (locationIt.hasNext && !locationIt.isNextNewInstance) {
  98. const v = locationIt.move()
  99. sizes.array[v.instanceIndex] = sizeFn(v.location)
  100. locationIt.skipInstance()
  101. if (i % 10000 === 0 && ctx.shouldUpdate) {
  102. await ctx.update({ message: 'Creating instance sizes', current: i, max: instanceCount });
  103. }
  104. ++i
  105. }
  106. return createTextureSize(sizes, 'instance', sizeData)
  107. }
  108. /** Creates size texture with size for each group (i.e. shared across instances/units) */
  109. export async function createGroupSize(ctx: RuntimeContext, locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): Promise<SizeData> {
  110. const { groupCount } = locationIt
  111. const sizes = sizeData && sizeData.tSize.ref.value.array.length >= groupCount ? sizeData.tSize.ref.value : createTextureImage(groupCount, 1)
  112. let i = 0
  113. while (locationIt.hasNext && !locationIt.isNextNewInstance) {
  114. const v = locationIt.move()
  115. sizes.array[v.groupIndex] = sizeFn(v.location)
  116. if (i % 10000 === 0 && ctx.shouldUpdate) {
  117. await ctx.update({ message: 'Creating group sizes', current: i, max: groupCount });
  118. }
  119. ++i
  120. }
  121. return createTextureSize(sizes, 'group', sizeData)
  122. }
  123. /** Creates size texture with size for each group in each instance (i.e. for each unit) */
  124. export async function createGroupInstanceSize(ctx: RuntimeContext, locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): Promise<SizeData> {
  125. const { groupCount, instanceCount } = locationIt
  126. const count = instanceCount * groupCount
  127. const sizes = sizeData && sizeData.tSize.ref.value.array.length >= count ? sizeData.tSize.ref.value : createTextureImage(count, 1)
  128. let i = 0
  129. while (locationIt.hasNext && !locationIt.isNextNewInstance) {
  130. const v = locationIt.move()
  131. sizes.array[v.index] = sizeFn(v.location)
  132. if (i % 10000 === 0 && ctx.shouldUpdate) {
  133. await ctx.update({ message: 'Creating group instance sizes', current: i, max: count });
  134. }
  135. ++i
  136. }
  137. return createTextureSize(sizes, 'groupInstance', sizeData)
  138. }