element-sphere.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. * @author David Sehnal <david.sehnal@gmail.com>
  6. */
  7. import { ValueCell } from 'mol-util/value-cell'
  8. import { createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'
  9. import { Unit } from 'mol-model/structure';
  10. import { DefaultStructureProps, UnitsVisual } from '../index';
  11. import { RuntimeContext } from 'mol-task'
  12. import { createTransforms, createColors } from './util/common';
  13. import { createElementSphereMesh, markElement, getElementRadius, getElementLoci } from './util/element';
  14. import { deepEqual } from 'mol-util';
  15. import { MeshValues } from 'mol-gl/renderable';
  16. import { getMeshData } from '../../../util/mesh-data';
  17. import { Mesh } from '../../../shape/mesh';
  18. import { PickingId } from '../../../util/picking';
  19. import { createMarkers, MarkerAction } from '../../../util/marker-data';
  20. import { Loci } from 'mol-model/loci';
  21. import { SizeTheme } from '../../../theme';
  22. import { createMeshValues, updateMeshValues, updateRenderableState, createRenderableState, DefaultMeshProps } from '../../util';
  23. export const DefaultElementSphereProps = {
  24. ...DefaultMeshProps,
  25. ...DefaultStructureProps,
  26. sizeTheme: { name: 'physical', factor: 1 } as SizeTheme,
  27. detail: 0,
  28. unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[]
  29. }
  30. export type ElementSphereProps = Partial<typeof DefaultElementSphereProps>
  31. export function ElementSphereVisual(): UnitsVisual<ElementSphereProps> {
  32. let renderObject: MeshRenderObject
  33. let currentProps: typeof DefaultElementSphereProps
  34. let mesh: Mesh
  35. let currentGroup: Unit.SymmetryGroup
  36. return {
  37. get renderObject () { return renderObject },
  38. async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: ElementSphereProps = {}) {
  39. currentProps = Object.assign({}, DefaultElementSphereProps, props)
  40. currentGroup = group
  41. const { detail, colorTheme, sizeTheme, unitKinds } = { ...DefaultElementSphereProps, ...props }
  42. const instanceCount = group.units.length
  43. const elementCount = group.elements.length
  44. const unit = group.units[0]
  45. const radius = getElementRadius(unit, sizeTheme)
  46. mesh = unitKinds.includes(unit.kind)
  47. ? await createElementSphereMesh(ctx, unit, radius, detail, mesh)
  48. : Mesh.createEmpty(mesh)
  49. const transforms = createTransforms(group)
  50. const color = createColors(group, elementCount, colorTheme)
  51. const marker = createMarkers(instanceCount * elementCount)
  52. const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount }
  53. const values: MeshValues = {
  54. ...getMeshData(mesh),
  55. ...color,
  56. ...marker,
  57. aTransform: transforms,
  58. elements: mesh.indexBuffer,
  59. ...createMeshValues(currentProps, counts),
  60. }
  61. const state = createRenderableState(currentProps)
  62. renderObject = createMeshRenderObject(values, state)
  63. },
  64. async update(ctx: RuntimeContext, props: ElementSphereProps) {
  65. const newProps = Object.assign({}, currentProps, props)
  66. if (!renderObject) return false
  67. let updateColor = false
  68. if (newProps.detail !== currentProps.detail) {
  69. const unit = currentGroup.units[0]
  70. const radius = getElementRadius(unit, newProps.sizeTheme)
  71. mesh = await createElementSphereMesh(ctx, unit, radius, newProps.detail, mesh)
  72. ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3)
  73. updateColor = true
  74. }
  75. if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) {
  76. updateColor = true
  77. }
  78. if (updateColor) {
  79. const elementCount = currentGroup.elements.length
  80. if (ctx.shouldUpdate) await ctx.update('Computing sphere colors');
  81. createColors(currentGroup, elementCount, newProps.colorTheme, renderObject.values)
  82. }
  83. updateMeshValues(renderObject.values, newProps)
  84. updateRenderableState(renderObject.state, newProps)
  85. currentProps = newProps
  86. return true
  87. },
  88. getLoci(pickingId: PickingId) {
  89. return getElementLoci(renderObject.id, currentGroup, pickingId)
  90. },
  91. mark(loci: Loci, action: MarkerAction) {
  92. markElement(renderObject.values.tMarker, currentGroup, loci, action)
  93. },
  94. destroy() {
  95. // TODO
  96. }
  97. }
  98. }