color-data.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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 { TextureImage, createTextureImage } from 'mol-gl/renderable/util';
  8. import { Color, ColorMap } from 'mol-util/color';
  9. import { Vec2, Vec3 } from 'mol-math/linear-algebra';
  10. import { LocationIterator } from '../util/location-iterator';
  11. import { NullLocation } from 'mol-model/location';
  12. import { LocationColor, ColorThemeProps, ColorTheme, ColorThemeName, ScaleLegend, TableLegend, ColorScaleName, getColorScaleFromName } from 'mol-theme/color';
  13. import { RuntimeContext } from 'mol-task';
  14. import { getGranularity } from './geometry';
  15. import { Structure } from 'mol-model/structure';
  16. export type ColorType = 'uniform' | 'instance' | 'group' | 'groupInstance'
  17. export type ColorData = {
  18. uColor: ValueCell<Vec3>,
  19. aColor: ValueCell<Float32Array>,
  20. tColor: ValueCell<TextureImage<Uint8Array>>,
  21. uColorTexDim: ValueCell<Vec2>,
  22. dColorType: ValueCell<string>,
  23. }
  24. export interface ColorProps {
  25. colorTheme: ColorThemeName
  26. colorList?: Color[] | ColorScaleName
  27. colorMap?: ColorMap<any>
  28. colorDomain?: [number, number]
  29. colorValue?: Color
  30. colorFunction?: LocationColor,
  31. colorGranularity?: ColorType,
  32. colorDescription?: string,
  33. colorLegend?: ScaleLegend | TableLegend
  34. structure?: Structure
  35. }
  36. export function getColorThemeProps(props: ColorProps): ColorThemeProps {
  37. const p: ColorThemeProps = {
  38. name: props.colorTheme
  39. }
  40. if (props.colorDomain !== undefined) p.domain = props.colorDomain
  41. if (props.colorList !== undefined) {
  42. p.list = typeof props.colorList === 'string' ? getColorScaleFromName(props.colorList) : props.colorList
  43. }
  44. if (props.colorMap !== undefined) p.map = props.colorMap
  45. if (props.colorValue !== undefined) p.value = props.colorValue
  46. if (props.structure !== undefined) p.structure = props.structure
  47. if (props.colorFunction !== undefined) p.color = props.colorFunction
  48. if (props.colorGranularity !== undefined) p.granularity = props.colorGranularity
  49. if (props.colorDescription !== undefined) p.description = props.colorDescription
  50. if (props.colorLegend !== undefined) p.legend = props.colorLegend
  51. return p
  52. }
  53. export function createColors(ctx: RuntimeContext, locationIt: LocationIterator, colorTheme: ColorTheme, colorData?: ColorData): Promise<ColorData> {
  54. switch (getGranularity(locationIt, colorTheme.granularity)) {
  55. case 'uniform': return createUniformColor(ctx, locationIt, colorTheme.color, colorData)
  56. case 'group': return createGroupColor(ctx, locationIt, colorTheme.color, colorData)
  57. case 'groupInstance': return createGroupInstanceColor(ctx, locationIt, colorTheme.color, colorData)
  58. case 'instance': return createInstanceColor(ctx, locationIt, colorTheme.color, colorData)
  59. }
  60. }
  61. export function createValueColor(value: Color, colorData?: ColorData): ColorData {
  62. if (colorData) {
  63. ValueCell.update(colorData.uColor, Color.toRgbNormalized(value) as Vec3)
  64. if (colorData.dColorType.ref.value !== 'uniform') {
  65. ValueCell.update(colorData.dColorType, 'uniform')
  66. }
  67. return colorData
  68. } else {
  69. return {
  70. uColor: ValueCell.create(Color.toRgbNormalized(value) as Vec3),
  71. aColor: ValueCell.create(new Float32Array(0)),
  72. tColor: ValueCell.create({ array: new Uint8Array(3), width: 1, height: 1 }),
  73. uColorTexDim: ValueCell.create(Vec2.create(1, 1)),
  74. dColorType: ValueCell.create('uniform'),
  75. }
  76. }
  77. }
  78. /** Creates color uniform */
  79. export async function createUniformColor(ctx: RuntimeContext, locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): Promise<ColorData> {
  80. return createValueColor(color(NullLocation, false), colorData)
  81. }
  82. export function createTextureColor(colors: TextureImage<Uint8Array>, type: ColorType, colorData?: ColorData): ColorData {
  83. if (colorData) {
  84. ValueCell.update(colorData.tColor, colors)
  85. ValueCell.update(colorData.uColorTexDim, Vec2.create(colors.width, colors.height))
  86. if (colorData.dColorType.ref.value !== type) {
  87. ValueCell.update(colorData.dColorType, type)
  88. }
  89. return colorData
  90. } else {
  91. return {
  92. uColor: ValueCell.create(Vec3.zero()),
  93. aColor: ValueCell.create(new Float32Array(0)),
  94. tColor: ValueCell.create(colors),
  95. uColorTexDim: ValueCell.create(Vec2.create(colors.width, colors.height)),
  96. dColorType: ValueCell.create(type),
  97. }
  98. }
  99. }
  100. /** Creates color texture with color for each instance/unit */
  101. export async function createInstanceColor(ctx: RuntimeContext, locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): Promise<ColorData> {
  102. const { instanceCount } = locationIt
  103. const colors = colorData && colorData.tColor.ref.value.array.length >= instanceCount * 3 ? colorData.tColor.ref.value : createTextureImage(instanceCount, 3)
  104. let i = 0
  105. while (locationIt.hasNext) {
  106. const { location, isSecondary, instanceIndex } = locationIt.move()
  107. Color.toArray(color(location, isSecondary), colors.array, instanceIndex * 3)
  108. locationIt.skipInstance()
  109. if (i % 10000 === 0 && ctx.shouldUpdate) {
  110. await ctx.update({ message: 'Creating instance colors', current: i, max: instanceCount });
  111. }
  112. ++i
  113. }
  114. return createTextureColor(colors, 'instance', colorData)
  115. }
  116. /** Creates color texture with color for each group (i.e. shared across instances/units) */
  117. export async function createGroupColor(ctx: RuntimeContext, locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): Promise<ColorData> {
  118. const { groupCount } = locationIt
  119. const colors = colorData && colorData.tColor.ref.value.array.length >= groupCount * 3 ? colorData.tColor.ref.value : createTextureImage(groupCount, 3)
  120. let i = 0
  121. while (locationIt.hasNext && !locationIt.isNextNewInstance) {
  122. const { location, isSecondary, groupIndex } = locationIt.move()
  123. Color.toArray(color(location, isSecondary), colors.array, groupIndex * 3)
  124. if (i % 10000 === 0 && ctx.shouldUpdate) {
  125. await ctx.update({ message: 'Creating group colors', current: i, max: groupCount });
  126. }
  127. ++i
  128. }
  129. return createTextureColor(colors, 'group', colorData)
  130. }
  131. /** Creates color texture with color for each group in each instance (i.e. for each unit) */
  132. export async function createGroupInstanceColor(ctx: RuntimeContext, locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): Promise<ColorData> {
  133. const { groupCount, instanceCount } = locationIt
  134. const count = instanceCount * groupCount
  135. const colors = colorData && colorData.tColor.ref.value.array.length >= count * 3 ? colorData.tColor.ref.value : createTextureImage(count, 3)
  136. let i = 0
  137. while (locationIt.hasNext) {
  138. const { location, isSecondary, index } = locationIt.move()
  139. Color.toArray(color(location, isSecondary), colors.array, index * 3)
  140. if (i % 10000 === 0 && ctx.shouldUpdate) {
  141. await ctx.update({ message: 'Creating group instance colors', current: i, max: count });
  142. }
  143. ++i
  144. }
  145. return createTextureColor(colors, 'groupInstance', colorData)
  146. }