diff --git a/src/mol-data/util/chunked-array.ts b/src/mol-data/util/chunked-array.ts index b2c344b4e23a58684b05dab0036dd0a238f4af77..a049472100efb26c1a1f536878687ffe7fc9df64 100644 --- a/src/mol-data/util/chunked-array.ts +++ b/src/mol-data/util/chunked-array.ts @@ -135,11 +135,10 @@ namespace ChunkedArray { return ret; } - export function create<T, C extends Sizes = 1>(ctor: { new (size: number): ArrayLike<T> }, elementSize: C, chunkSize: number): ChunkedArray<T, C> - /** The size of the initial chunk is elementSize * initialCount */ - export function create<T, C extends Sizes = 1>(ctor: { new (size: number): ArrayLike<T> }, elementSize: C, chunkSize: number, initialCount: number): ChunkedArray<T, C> - /** Use the provided array as the initial chunk. The size of the array must be divisible by the elementSize */ - export function create<T, C extends Sizes = 1>(ctor: { new (size: number): ArrayLike<T> }, elementSize: C, chunkSize: number, initialChunk?: ArrayLike<T>): ChunkedArray<T, C> + /** + * The size of the initial chunk is elementSize * initialCount. + * Use the provided array as the initial chunk. The size of the array must be divisible by the elementSize. + */ export function create<T, C extends Sizes = 1>(ctor: { new (size: number): ArrayLike<T> }, elementSize: C, chunkSize: number, initialChunkOrCount?: number | ArrayLike<T>): ChunkedArray<T, C> { const ret: ChunkedArray<T, C> = { ctor, diff --git a/src/mol-geo/representation/structure/point.ts b/src/mol-geo/representation/structure/point.ts index 4e0e1573cc0439fb7a2a21cab9a4cad8145390da..0984717e021af677117293dd5041214062260233 100644 --- a/src/mol-geo/representation/structure/point.ts +++ b/src/mol-geo/representation/structure/point.ts @@ -92,7 +92,7 @@ export default function Point(): UnitsRepresentation<PointProps> { const values: PointValues = { aPosition: ValueCell.create(vertices), aElementId: ValueCell.create(fillSerial(new Float32Array(elementCount))), - aTransform: ValueCell.create(transforms), + aTransform: transforms, aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), ...color, ...size, diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts index 87ebb47dc50d0b661e30b6e49601d91e41b4c89c..71e8b31e256e6de13f6468f2b6ce9e747d68c9f9 100644 --- a/src/mol-geo/representation/structure/spacefill.ts +++ b/src/mol-geo/representation/structure/spacefill.ts @@ -21,6 +21,7 @@ import { deepEqual, defaults } from 'mol-util'; import { fillSerial } from 'mol-gl/renderable/util'; import { RenderableState, MeshValues } from 'mol-gl/renderable'; import { getMeshData } from '../../util/mesh-data'; +import { Mesh } from '../../shape/mesh'; export const DefaultSpacefillProps = { ...DefaultStructureProps, @@ -75,6 +76,8 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> { const renderObjects: RenderObject[] = [] let spheres: MeshRenderObject let currentProps: typeof DefaultSpacefillProps + let mesh: Mesh + let currentGroup: Unit.SymmetryGroup return { renderObjects, @@ -83,10 +86,11 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> { return Task.create('Spacefill.create', async ctx => { renderObjects.length = 0 // clear + currentGroup = group const { detail, colorTheme } = { ...DefaultSpacefillProps, ...props } - const mesh = await createSpacefillMesh(group.units[0], detail).runAsChild(ctx, 'Computing spacefill mesh') + mesh = await createSpacefillMesh(group.units[0], detail).runAsChild(ctx, 'Computing spacefill mesh') // console.log(mesh) const vertexMap = VertexMap.fromMesh(mesh) @@ -101,7 +105,7 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> { const values: MeshValues = { ...getMeshData(mesh), - aTransform: ValueCell.create(transforms), + aTransform: transforms, aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), ...color, @@ -133,9 +137,20 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> { return Task.create('Spacefill.update', async ctx => { if (!spheres) return false - if (newProps.detail !== currentProps.detail) return false + // if (newProps.detail !== currentProps.detail) return false if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) return false + if (newProps.detail !== currentProps.detail) { + await createSpacefillMesh(currentGroup.units[0], newProps.detail).runAsChild(ctx, 'Computing spacefill mesh') + const vertexMap = VertexMap.fromMesh(mesh) + + await ctx.update('Computing spacefill transforms'); + createTransforms(currentGroup) + + await ctx.update('Computing spacefill colors'); + createColors(currentGroup, vertexMap, newProps.colorTheme) + } + ValueCell.update(spheres.values.uAlpha, newProps.alpha) ValueCell.update(spheres.values.dDoubleSided, newProps.doubleSided) spheres.state.visible = newProps.visible diff --git a/src/mol-geo/representation/structure/utils.ts b/src/mol-geo/representation/structure/utils.ts index c7cd81d17c60d684d5c7bb485dc91d25825c6bba..a242839edcee47cdf8b2ec8b3eaaea48d444fd2c 100644 --- a/src/mol-geo/representation/structure/utils.ts +++ b/src/mol-geo/representation/structure/utils.ts @@ -8,34 +8,36 @@ import { Unit } from 'mol-model/structure'; import { Mat4 } from 'mol-math/linear-algebra' -import { createUniformColor } from '../../util/color-data'; +import { createUniformColor, ColorData } from '../../util/color-data'; import { createUniformSize } from '../../util/size-data'; import { elementSizeData } from '../../theme/structure/size/element'; import VertexMap from '../../shape/vertex-map'; import { ColorTheme, SizeTheme } from '../../theme'; import { elementIndexColorData, elementSymbolColorData, instanceIndexColorData, chainIdColorData } from '../../theme/structure/color'; +import { ValueCell } from 'mol-util'; -export function createTransforms({ units }: Unit.SymmetryGroup) { +export function createTransforms({ units }: Unit.SymmetryGroup, transforms?: ValueCell<Float32Array>) { const unitCount = units.length - const transforms = new Float32Array(unitCount * 16) + const n = unitCount * 16 + const array = transforms && transforms.ref.value.length >= n ? transforms.ref.value : new Float32Array(n) for (let i = 0; i < unitCount; i++) { - Mat4.toArray(units[i].conformation.operator.matrix, transforms, i * 16) + Mat4.toArray(units[i].conformation.operator.matrix, array, i * 16) } - return transforms + return transforms ? ValueCell.update(transforms, array) : ValueCell.create(array) } -export function createColors(group: Unit.SymmetryGroup, vertexMap: VertexMap, props: ColorTheme) { +export function createColors(group: Unit.SymmetryGroup, vertexMap: VertexMap, props: ColorTheme, colorData?: ColorData) { switch (props.name) { case 'atom-index': - return elementIndexColorData({ group, vertexMap }) + return elementIndexColorData({ group, vertexMap }, colorData) case 'chain-id': - return chainIdColorData({ group, vertexMap }) + return chainIdColorData({ group, vertexMap }, colorData) case 'element-symbol': - return elementSymbolColorData({ group, vertexMap }) + return elementSymbolColorData({ group, vertexMap }, colorData) case 'instance-index': - return instanceIndexColorData({ group, vertexMap }) + return instanceIndexColorData({ group, vertexMap }, colorData) case 'uniform': - return createUniformColor(props) + return createUniformColor(props, colorData) } } diff --git a/src/mol-geo/shape/mesh-builder.ts b/src/mol-geo/shape/mesh-builder.ts index 7bf4cf995851893c66f66fc874389670b5033707..d628ce4aa94690f86daac3dd1fccd30887c8f83f 100644 --- a/src/mol-geo/shape/mesh-builder.ts +++ b/src/mol-geo/shape/mesh-builder.ts @@ -33,13 +33,13 @@ const tmpV = Vec3.zero() // TODO cache primitives based on props export namespace MeshBuilder { - export function create(initialCount = 2048, chunkSize = 1024): MeshBuilder { - const vertices = ChunkedArray.create(Float32Array, 3, chunkSize, initialCount); - const normals = ChunkedArray.create(Float32Array, 3, chunkSize, initialCount); - const indices = ChunkedArray.create(Uint32Array, 3, chunkSize * 3, initialCount * 3); + export function create(initialCount = 2048, chunkSize = 1024, mesh?: Mesh): MeshBuilder { + const vertices = ChunkedArray.create(Float32Array, 3, chunkSize, mesh ? mesh.vertexBuffer.ref.value : initialCount); + const normals = ChunkedArray.create(Float32Array, 3, chunkSize, mesh ? mesh.normalBuffer.ref.value : initialCount); + const indices = ChunkedArray.create(Uint32Array, 3, chunkSize * 3, mesh ? mesh.indexBuffer.ref.value : initialCount * 3); - const ids = ChunkedArray.create(Float32Array, 1, chunkSize, initialCount); - const offsets = ChunkedArray.create(Uint32Array, 1, chunkSize, initialCount); + const ids = ChunkedArray.create(Float32Array, 1, chunkSize, mesh ? mesh.idBuffer.ref.value : initialCount); + const offsets = ChunkedArray.create(Uint32Array, 1, chunkSize, mesh ? mesh.offsetBuffer.ref.value : initialCount); let currentId = -1 @@ -102,6 +102,7 @@ export namespace MeshBuilder { idBuffer: ValueCell.create(ChunkedArray.compact(ids, true) as Float32Array), offsetBuffer: ValueCell.create(ChunkedArray.compact(offsets, true) as Uint32Array), normalsComputed: true, + offsetsComputed: true, } return mesh } diff --git a/src/mol-geo/shape/mesh.ts b/src/mol-geo/shape/mesh.ts index 88152c0fb4b4e7f39399e8f02202c5de690860f4..6d63fd851e2236521a0be698e734e1735a2cb5c3 100644 --- a/src/mol-geo/shape/mesh.ts +++ b/src/mol-geo/shape/mesh.ts @@ -24,9 +24,13 @@ export interface Mesh { normalBuffer: ValueCell<Float32Array>, /** Id buffer as array of ids for each vertex wrapped in a value cell */ idBuffer: ValueCell<Float32Array>, + /** Offset buffer as array of offsets for id ranges wrapped in a value cell */ + offsetBuffer: ValueCell<Uint32Array>, /** Flag indicating if normals are computed for the current set of vertices */ normalsComputed: boolean, + /** Flag indicating if offsets are computed for the current set of ids */ + offsetsComputed: boolean, /** Bounding sphere of the mesh */ boundingSphere?: Sphere3D diff --git a/src/mol-geo/theme/structure/color/chain-id.ts b/src/mol-geo/theme/structure/color/chain-id.ts index d521d6036c9f12edaa560e8ba87be14b9bc76fb6..b6de2bc0541fe860f8ab23e1bf167ea99c5cffbb 100644 --- a/src/mol-geo/theme/structure/color/chain-id.ts +++ b/src/mol-geo/theme/structure/color/chain-id.ts @@ -7,7 +7,7 @@ import { Unit, Queries, Element } from 'mol-model/structure'; import { StructureColorDataProps } from '.'; -import { createAttributeOrElementColor } from '../../../util/color-data'; +import { createAttributeOrElementColor, ColorData } from '../../../util/color-data'; import { ColorScale } from 'mol-util/color'; import { Column } from 'mol-data/db'; @@ -38,7 +38,7 @@ function createChainIdMap(unit: Unit) { return { map, count: index } } -export function chainIdColorData(props: StructureColorDataProps) { +export function chainIdColorData(props: StructureColorDataProps, colorData?: ColorData) { const { group: { units, elements }, vertexMap } = props const unit = units[0] @@ -63,5 +63,5 @@ export function chainIdColorData(props: StructureColorDataProps) { return scale.color(map.get(asym_id(l)) || 0) }, vertexMap - }) + }, colorData) } \ No newline at end of file diff --git a/src/mol-geo/theme/structure/color/element-index.ts b/src/mol-geo/theme/structure/color/element-index.ts index f6540f95e3fff159b13f9f20908bba27152d83ec..7b5de65a485aafec0c56937271d683d8877e2720 100644 --- a/src/mol-geo/theme/structure/color/element-index.ts +++ b/src/mol-geo/theme/structure/color/element-index.ts @@ -6,9 +6,9 @@ import { ColorScale } from 'mol-util/color'; import { StructureColorDataProps } from '.'; -import { createElementInstanceColor } from '../../../util/color-data'; +import { createElementInstanceColor, ColorData } from '../../../util/color-data'; -export function elementIndexColorData(props: StructureColorDataProps) { +export function elementIndexColorData(props: StructureColorDataProps, colorData?: ColorData) { const { group: { units, elements }, vertexMap } = props const instanceCount = units.length const elementCount = elements.length @@ -19,5 +19,5 @@ export function elementIndexColorData(props: StructureColorDataProps) { colorFn: (instanceIdx, elementIdx) => scale.color(instanceIdx * elementCount + elementIdx), instanceCount, vertexMap - }) + }, colorData) } \ No newline at end of file diff --git a/src/mol-geo/theme/structure/color/element-symbol.ts b/src/mol-geo/theme/structure/color/element-symbol.ts index affedfac08a2ca695894d76ff1177370a827b2e8..b9a493a4147c6c0e59b6e773b7d99678832bfc35 100644 --- a/src/mol-geo/theme/structure/color/element-symbol.ts +++ b/src/mol-geo/theme/structure/color/element-symbol.ts @@ -7,7 +7,7 @@ import { ElementSymbol } from 'mol-model/structure/model/types'; import { Color } from 'mol-util/color'; import { StructureColorDataProps } from '.'; -import { createAttributeOrElementColor } from '../../../util/color-data'; +import { createAttributeOrElementColor, ColorData } from '../../../util/color-data'; // from Jmol http://jmol.sourceforge.net/jscolors/ (or 0xFFFFFF) export const ElementSymbolColors: { [k: string]: Color } = { @@ -21,7 +21,7 @@ export function elementSymbolColor(element: ElementSymbol): Color { return c === void 0 ? DefaultElementSymbolColor : c } -export function elementSymbolColorData(props: StructureColorDataProps) { +export function elementSymbolColorData(props: StructureColorDataProps, colorData?: ColorData) { const { group: { units, elements }, vertexMap } = props const { type_symbol } = units[0].model.atomicHierarchy.atoms return createAttributeOrElementColor(vertexMap, { @@ -30,5 +30,5 @@ export function elementSymbolColorData(props: StructureColorDataProps) { return elementSymbolColor(type_symbol.value(e)) }, vertexMap - }) + }, colorData) } \ No newline at end of file diff --git a/src/mol-geo/theme/structure/color/instance-index.ts b/src/mol-geo/theme/structure/color/instance-index.ts index ffae3b0861016c0901dac0e591150e26f114ae4f..bc79c2c22fc4dbab17f7932ef48d38f5fc884548 100644 --- a/src/mol-geo/theme/structure/color/instance-index.ts +++ b/src/mol-geo/theme/structure/color/instance-index.ts @@ -6,9 +6,9 @@ import { ColorScale } from 'mol-util/color'; import { StructureColorDataProps } from '.'; -import { createInstanceColor } from '../../../util/color-data'; +import { createInstanceColor, ColorData } from '../../../util/color-data'; -export function instanceIndexColorData(props: StructureColorDataProps) { +export function instanceIndexColorData(props: StructureColorDataProps, colorData?: ColorData) { const { group: { units } } = props const instanceCount = units.length @@ -17,5 +17,5 @@ export function instanceIndexColorData(props: StructureColorDataProps) { return createInstanceColor({ colorFn: scale.color, instanceCount - }) + }, colorData) } \ No newline at end of file diff --git a/src/mol-geo/util/color-data.ts b/src/mol-geo/util/color-data.ts index 562ac7469a39d6e502cdc6e8d776250533584c90..f36dfe7305cdd9b1a5692aeb8710da760c3664c3 100644 --- a/src/mol-geo/util/color-data.ts +++ b/src/mol-geo/util/color-data.ts @@ -25,13 +25,19 @@ export interface UniformColorProps { } /** Creates color uniform */ -export function createUniformColor(props: UniformColorProps): ColorData { - return { - uColor: ValueCell.create(Color.toRgbNormalized(props.value) as Vec3), - aColor: ValueCell.create(new Float32Array(0)), - tColor: ValueCell.create(emptyTexture), - uColorTexSize: ValueCell.create(Vec2.zero()), - dColorType: ValueCell.create('uniform'), +export function createUniformColor(props: UniformColorProps, colorData?: ColorData): ColorData { + if (colorData) { + ValueCell.update(colorData.uColor, Color.toRgbNormalized(props.value) as Vec3) + ValueCell.update(colorData.dColorType, 'uniform') + return colorData + } else { + return { + uColor: ValueCell.create(Color.toRgbNormalized(props.value) as Vec3), + aColor: ValueCell.create(new Float32Array(0)), + tColor: ValueCell.create(emptyTexture), + uColorTexSize: ValueCell.create(Vec2.zero()), + dColorType: ValueCell.create('uniform'), + } } } @@ -41,7 +47,7 @@ export interface AttributeColorProps { } /** Creates color attribute with color for each element (i.e. shared across instances/units) */ -export function createAttributeColor(props: AttributeColorProps): ColorData { +export function createAttributeColor(props: AttributeColorProps, colorData?: ColorData): ColorData { const { colorFn, vertexMap } = props const { idCount, offsetCount, offsets } = vertexMap const colors = new Float32Array(idCount * 3); @@ -53,22 +59,35 @@ export function createAttributeColor(props: AttributeColorProps): ColorData { Color.toArrayNormalized(hexColor, colors, i * 3) } } - return { - uColor: ValueCell.create(Vec3.zero()), - aColor: ValueCell.create(colors), - tColor: ValueCell.create(emptyTexture), - uColorTexSize: ValueCell.create(Vec2.zero()), - dColorType: ValueCell.create('attribute'), + if (colorData) { + ValueCell.update(colorData.aColor, colors) + ValueCell.update(colorData.dColorType, 'attribute') + return colorData + } else { + return { + uColor: ValueCell.create(Vec3.zero()), + aColor: ValueCell.create(colors), + tColor: ValueCell.create(emptyTexture), + uColorTexSize: ValueCell.create(Vec2.zero()), + dColorType: ValueCell.create('attribute'), + } } } -export function createTextureColor(colors: TextureImage, type: ColorType): ColorData { - return { - uColor: ValueCell.create(Vec3.zero()), - aColor: ValueCell.create(new Float32Array(0)), - tColor: ValueCell.create(colors), - uColorTexSize: ValueCell.create(Vec2.create(colors.width, colors.height)), - dColorType: ValueCell.create(type), +export function createTextureColor(colors: TextureImage, type: ColorType, colorData?: ColorData): ColorData { + if (colorData) { + ValueCell.update(colorData.tColor, colors) + ValueCell.update(colorData.uColorTexSize, Vec2.create(colors.width, colors.height)) + ValueCell.update(colorData.dColorType, type) + return colorData + } else { + return { + uColor: ValueCell.create(Vec3.zero()), + aColor: ValueCell.create(new Float32Array(0)), + tColor: ValueCell.create(colors), + uColorTexSize: ValueCell.create(Vec2.create(colors.width, colors.height)), + dColorType: ValueCell.create(type), + } } } @@ -78,9 +97,9 @@ export interface InstanceColorProps { } /** Creates color texture with color for each instance/unit */ -export function createInstanceColor(props: InstanceColorProps): ColorData { +export function createInstanceColor(props: InstanceColorProps, colorData?: ColorData): ColorData { const { colorFn, instanceCount} = props - const colors = createColorTexture(instanceCount) + const colors = colorData && colorData.tColor.ref.value.array.length >= instanceCount * 3 ? colorData.tColor.ref.value : createColorTexture(instanceCount) for (let i = 0; i < instanceCount; i++) { Color.toArray(colorFn(i), colors.array, i * 3) } @@ -93,10 +112,10 @@ export interface ElementColorProps { } /** Creates color texture with color for each element (i.e. shared across instances/units) */ -export function createElementColor(props: ElementColorProps): ColorData { +export function createElementColor(props: ElementColorProps, colorData?: ColorData): ColorData { const { colorFn, vertexMap } = props const elementCount = vertexMap.offsetCount - 1 - const colors = createColorTexture(elementCount) + const colors = colorData && colorData.tColor.ref.value.array.length >= elementCount * 3 ? colorData.tColor.ref.value : createColorTexture(elementCount) for (let i = 0, il = elementCount; i < il; ++i) { Color.toArray(colorFn(i), colors.array, i * 3) } @@ -110,11 +129,11 @@ export interface ElementInstanceColorProps { } /** Creates color texture with color for each element instance (i.e. for each unit) */ -export function createElementInstanceColor(props: ElementInstanceColorProps): ColorData { +export function createElementInstanceColor(props: ElementInstanceColorProps, colorData?: ColorData): ColorData { const { colorFn, instanceCount, vertexMap } = props const elementCount = vertexMap.offsetCount - 1 const count = instanceCount * elementCount - const colors = createColorTexture(count) + const colors = colorData && colorData.tColor.ref.value.array.length >= count * 3 ? colorData.tColor.ref.value : createColorTexture(count) let colorOffset = 0 for (let i = 0; i < instanceCount; i++) { for (let j = 0, jl = elementCount; j < jl; ++j) { @@ -126,6 +145,6 @@ export function createElementInstanceColor(props: ElementInstanceColorProps): Co } /** Create color attribute or texture, depending on the vertexMap */ -export function createAttributeOrElementColor(vertexMap: VertexMap, props: AttributeColorProps) { - return vertexMap.idCount < 4 * vertexMap.offsetCount ? createAttributeColor(props) : createElementColor(props) +export function createAttributeOrElementColor(vertexMap: VertexMap, props: AttributeColorProps, colorData?: ColorData) { + return vertexMap.idCount < 4 * vertexMap.offsetCount ? createAttributeColor(props, colorData) : createElementColor(props, colorData) } \ No newline at end of file diff --git a/src/mol-geo/util/marching-cubes/algorithm.ts b/src/mol-geo/util/marching-cubes/algorithm.ts index da88ea4cd7cea5565d1753da2d0bf20f59a32c5c..248f05397889b7a43773a7b78341d1df4aec659e 100644 --- a/src/mol-geo/util/marching-cubes/algorithm.ts +++ b/src/mol-geo/util/marching-cubes/algorithm.ts @@ -84,7 +84,9 @@ class MarchingCubesComputation { ? ValueCell.update(os.idBuffer, ChunkedArray.compact(this.state.idBuffer) as Float32Array) : ValueCell.create(ChunkedArray.compact(this.state.idBuffer) as Float32Array) : ValueCell.create(new Float32Array(0)), - normalsComputed: false + offsetBuffer: os ? os.offsetBuffer : ValueCell.create(new Uint32Array(0)), + normalsComputed: false, + offsetsComputed: false } return ret; diff --git a/src/mol-view/stage.ts b/src/mol-view/stage.ts index a32f0b114fa627cc0c4fa0931339055f6f9f2a0c..df5a3f8629845ce43ec9f6d8046e44dc71cce738 100644 --- a/src/mol-view/stage.ts +++ b/src/mol-view/stage.ts @@ -22,8 +22,8 @@ import { SpacefillProps } from 'mol-geo/representation/structure/spacefill'; const spacefillProps: SpacefillProps = { doubleSided: true, - detail: 2, - colorTheme: { name: 'instance-index' } + detail: 0, + colorTheme: { name: 'atom-index' } } export class Stage {