From 762048b76cfac43c4ef16d836dd318c29c7efa77 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alexander.rose@weirdbyte.de> Date: Fri, 15 Jun 2018 22:27:09 +0200 Subject: [PATCH] pass runtime ctx instead of creating new tasks --- src/mol-geo/representation/structure/bond.ts | 190 ++++++++-------- src/mol-geo/representation/structure/index.ts | 24 ++- src/mol-geo/representation/structure/point.ts | 202 +++++++++--------- .../representation/structure/spacefill.ts | 138 ++++++------ src/mol-geo/representation/structure/utils.ts | 44 ++-- src/mol-geo/representation/volume/index.ts | 8 +- src/mol-geo/representation/volume/surface.ts | 94 ++++---- 7 files changed, 345 insertions(+), 355 deletions(-) diff --git a/src/mol-geo/representation/structure/bond.ts b/src/mol-geo/representation/structure/bond.ts index 69ac57911..a29b0a550 100644 --- a/src/mol-geo/representation/structure/bond.ts +++ b/src/mol-geo/representation/structure/bond.ts @@ -10,9 +10,9 @@ import { ValueCell } from 'mol-util/value-cell' import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object' -import { Unit, Element, Link } from 'mol-model/structure'; +import { Unit, Link } from 'mol-model/structure'; import { UnitsRepresentation, DefaultStructureProps } from './index'; -import { Task } from 'mol-task' +import { RuntimeContext } from 'mol-task' import { createTransforms } from './utils'; import { fillSerial } from 'mol-gl/renderable/util'; import { RenderableState, MeshValues } from 'mol-gl/renderable'; @@ -26,51 +26,49 @@ import { defaults } from 'mol-util'; import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci'; import { MarkerAction, applyMarkerAction, createMarkers } from '../../util/marker-data'; -function createBondMesh(unit: Unit, mesh?: Mesh) { - return Task.create('Cylinder mesh', async ctx => { - if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) - - const elements = unit.elements; - const bonds = unit.links - const { edgeCount, a, b } = bonds - - if (!edgeCount) return Mesh.createEmpty(mesh) - - // TODO calculate vertextCount properly - const vertexCount = 32 * edgeCount - const meshBuilder = MeshBuilder.create(vertexCount, vertexCount / 2, mesh) - - const va = Vec3.zero() - const vb = Vec3.zero() - const vt = Vec3.zero() - const m = Mat4.identity() - - const { x, y, z } = unit.conformation - const l = Element.Location() - l.unit = unit - - for (let edgeIndex = 0, _eI = edgeCount * 2; edgeIndex < _eI; ++edgeIndex) { - const aI = elements[a[edgeIndex]], bI = elements[b[edgeIndex]]; - // each edge is included twice because of the "adjacency list" structure - // keep only the 1st occurence. - if (aI >= bI) continue; - va[0] = x(aI); va[1] = y(aI); va[2] = z(aI) - vb[0] = x(bI); vb[1] = y(bI); vb[2] = z(bI) - - Vec3.scale(vt, Vec3.add(vt, va, vb), 0.5) - Vec3.makeRotation(m, Vec3.create(0, 1, 0), Vec3.sub(vb, vb, va)) - Mat4.setTranslation(m, vt) - - meshBuilder.setId(edgeIndex) - meshBuilder.addCylinder(m, { radiusTop: 0.2, radiusBottom: 0.2 }) - - if (edgeIndex % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Cylinder mesh', current: edgeIndex, max: edgeCount }); - } +async function createBondMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { + if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) + + const elements = unit.elements; + const bonds = unit.links + const { edgeCount, a, b } = bonds + + if (!edgeCount) return Mesh.createEmpty(mesh) + + // TODO calculate vertextCount properly + const vertexCount = 32 * edgeCount + const meshBuilder = MeshBuilder.create(vertexCount, vertexCount / 2, mesh) + + const va = Vec3.zero() + const vb = Vec3.zero() + const vt = Vec3.zero() + const m = Mat4.identity() + + const pos = unit.conformation.invariantPosition + // const l = Element.Location() + // l.unit = unit + + for (let edgeIndex = 0, _eI = edgeCount * 2; edgeIndex < _eI; ++edgeIndex) { + const aI = elements[a[edgeIndex]], bI = elements[b[edgeIndex]]; + // each edge is included twice because of the "adjacency list" structure + // keep only the 1st occurence. + if (aI >= bI) continue; + pos(aI, va) + pos(bI, vb) + + Vec3.scale(vt, Vec3.add(vt, va, vb), 0.5) + Vec3.makeRotation(m, Vec3.create(0, 1, 0), Vec3.sub(vb, vb, va)) + Mat4.setTranslation(m, vt) + + meshBuilder.setId(edgeIndex) + meshBuilder.addCylinder(m, { radiusTop: 0.2, radiusBottom: 0.2 }) + + if (edgeIndex % 10000 === 0 && ctx.shouldUpdate) { + await ctx.update({ message: 'Cylinder mesh', current: edgeIndex, max: edgeCount }); } + } - return meshBuilder.getMesh() - }) + return meshBuilder.getMesh() } export const DefaultBondProps = { @@ -80,7 +78,7 @@ export const DefaultBondProps = { } export type BondProps = Partial<typeof DefaultBondProps> -export default function BondUnitsRepresentation(): UnitsRepresentation<BondProps> { +export default function IntraUnitBonds(): UnitsRepresentation<BondProps> { const renderObjects: RenderObject[] = [] let cylinders: MeshRenderObject let currentProps: typeof DefaultBondProps @@ -90,78 +88,74 @@ export default function BondUnitsRepresentation(): UnitsRepresentation<BondProps return { renderObjects, - create(group: Unit.SymmetryGroup, props: BondProps = {}) { + async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: BondProps = {}) { currentProps = Object.assign({}, DefaultBondProps, props) - return Task.create('Bond.create', async ctx => { - renderObjects.length = 0 // clear - currentGroup = group + renderObjects.length = 0 // clear + currentGroup = group - const unit = group.units[0] - const elementCount = Unit.isAtomic(unit) ? unit.links.edgeCount * 2 : 0 - const instanceCount = group.units.length + const unit = group.units[0] + const elementCount = Unit.isAtomic(unit) ? unit.links.edgeCount * 2 : 0 + const instanceCount = group.units.length - mesh = await createBondMesh(unit).runAsChild(ctx, 'Computing bond mesh') + mesh = await createBondMesh(ctx, unit) - // console.log(mesh) - // vertexMap = VertexMap.fromMesh(mesh) + // console.log(mesh) + // vertexMap = VertexMap.fromMesh(mesh) - await ctx.update('Computing bond transforms'); - const transforms = createTransforms(group) + if (ctx.shouldUpdate) await ctx.update('Computing bond transforms'); + const transforms = createTransforms(group) - await ctx.update('Computing bond colors'); - const color = createUniformColor({ value: 0xFF0000 }) + if (ctx.shouldUpdate) await ctx.update('Computing bond colors'); + const color = createUniformColor({ value: 0xFF0000 }) - await ctx.update('Computing bond marks'); - const marker = createMarkers(instanceCount * elementCount) + if (ctx.shouldUpdate) await ctx.update('Computing bond marks'); + const marker = createMarkers(instanceCount * elementCount) - const values: MeshValues = { - ...getMeshData(mesh), - aTransform: transforms, - aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), - ...color, - ...marker, + const values: MeshValues = { + ...getMeshData(mesh), + aTransform: transforms, + aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), + ...color, + ...marker, - uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), - uInstanceCount: ValueCell.create(instanceCount), - uElementCount: ValueCell.create(elementCount), + uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), + uInstanceCount: ValueCell.create(instanceCount), + uElementCount: ValueCell.create(elementCount), - elements: mesh.indexBuffer, + elements: mesh.indexBuffer, - drawCount: ValueCell.create(mesh.triangleCount * 3), - instanceCount: ValueCell.create(instanceCount), + drawCount: ValueCell.create(mesh.triangleCount * 3), + instanceCount: ValueCell.create(instanceCount), - dDoubleSided: ValueCell.create(defaults(props.doubleSided, true)), - dFlatShaded: ValueCell.create(defaults(props.flatShaded, false)), - dFlipSided: ValueCell.create(defaults(props.flipSided, false)), - dUseFog: ValueCell.create(defaults(props.useFog, true)), - } - const state: RenderableState = { - depthMask: defaults(props.depthMask, true), - visible: defaults(props.visible, true) - } + dDoubleSided: ValueCell.create(defaults(props.doubleSided, true)), + dFlatShaded: ValueCell.create(defaults(props.flatShaded, false)), + dFlipSided: ValueCell.create(defaults(props.flipSided, false)), + dUseFog: ValueCell.create(defaults(props.useFog, true)), + } + const state: RenderableState = { + depthMask: defaults(props.depthMask, true), + visible: defaults(props.visible, true) + } - cylinders = createMeshRenderObject(values, state) - renderObjects.push(cylinders) - }) + cylinders = createMeshRenderObject(values, state) + renderObjects.push(cylinders) }, - update(props: BondProps) { + async update(ctx: RuntimeContext, props: BondProps) { const newProps = Object.assign({}, currentProps, props) - return Task.create('Bond.update', async ctx => { - if (!cylinders) return false - // TODO + if (!cylinders) return false + // TODO - ValueCell.updateIfChanged(cylinders.values.uAlpha, newProps.alpha) - ValueCell.updateIfChanged(cylinders.values.dDoubleSided, newProps.doubleSided) - ValueCell.updateIfChanged(cylinders.values.dFlipSided, newProps.flipSided) - ValueCell.updateIfChanged(cylinders.values.dFlatShaded, newProps.flatShaded) + ValueCell.updateIfChanged(cylinders.values.uAlpha, newProps.alpha) + ValueCell.updateIfChanged(cylinders.values.dDoubleSided, newProps.doubleSided) + ValueCell.updateIfChanged(cylinders.values.dFlipSided, newProps.flipSided) + ValueCell.updateIfChanged(cylinders.values.dFlatShaded, newProps.flatShaded) - cylinders.state.visible = newProps.visible - cylinders.state.depthMask = newProps.depthMask + cylinders.state.visible = newProps.visible + cylinders.state.depthMask = newProps.depthMask - return true - }) + return true }, getLoci(pickingId: PickingId) { const { objectId, instanceId, elementId } = pickingId diff --git a/src/mol-geo/representation/structure/index.ts b/src/mol-geo/representation/structure/index.ts index 968950ec9..3ed2ce54a 100644 --- a/src/mol-geo/representation/structure/index.ts +++ b/src/mol-geo/representation/structure/index.ts @@ -6,7 +6,7 @@ */ import { Structure, StructureSymmetry, Unit } from 'mol-model/structure'; -import { Task } from 'mol-task' +import { Task, RuntimeContext } from 'mol-task' import { RenderObject } from 'mol-gl/render-object'; import { Representation, RepresentationProps } from '..'; import { ColorTheme } from '../../theme'; @@ -16,8 +16,8 @@ import { MarkerAction } from '../../util/marker-data'; export interface UnitsRepresentation<P> { renderObjects: ReadonlyArray<RenderObject> - create: (group: Unit.SymmetryGroup, props: P) => Task<void> - update: (props: P) => Task<boolean> + create: (ctx: RuntimeContext, group: Unit.SymmetryGroup, props: P) => Promise<void> + update: (ctx: RuntimeContext, props: P) => Promise<boolean> getLoci: (pickingId: PickingId) => Loci mark: (loci: Loci, action: MarkerAction) => void } @@ -64,10 +64,15 @@ export function StructureRepresentation<P extends StructureProps>(reprCtor: () = const groups = StructureSymmetry.getTransformGroups(structure); for (let i = 0; i < groups.length; i++) { + if(ctx.shouldUpdate) await ctx.update({ + message: 'Building structure unit representations...', + current: i, + max: groups.length + }) const group = groups[i]; const repr = reprCtor() groupReprs.push({ repr, group }) - await repr.create(group, props).runAsChild(ctx, { message: 'Building structure unit representations...', current: i, max: groups.length }); + await repr.create(ctx, group, props) renderObjects.push(...repr.renderObjects) } }); @@ -77,12 +82,17 @@ export function StructureRepresentation<P extends StructureProps>(reprCtor: () = renderObjects.length = 0 // clear for (let i = 0, il = groupReprs.length; i < il; ++i) { + if(ctx.shouldUpdate) await ctx.update({ + message: 'Updating structure unit representations...', + current: i, + max: il + }) const groupRepr = groupReprs[i] const { repr, group } = groupRepr - const state = { message: 'Updating structure unit representations...', current: i, max: il }; - if (!await repr.update(props).runAsChild(ctx, state)) { + + if (!await repr.update(ctx, props)) { console.log('update failed, need to rebuild') - await repr.create(group, props).runAsChild(ctx, state) + repr.create(ctx, group, props) } renderObjects.push(...repr.renderObjects) } diff --git a/src/mol-geo/representation/structure/point.ts b/src/mol-geo/representation/structure/point.ts index 6595224d4..dd0b38ec2 100644 --- a/src/mol-geo/representation/structure/point.ts +++ b/src/mol-geo/representation/structure/point.ts @@ -8,7 +8,7 @@ import { ValueCell } from 'mol-util/value-cell' import { createPointRenderObject, RenderObject, PointRenderObject } from 'mol-gl/render-object' import { Unit, Element } from 'mol-model/structure'; -import { Task } from 'mol-task' +import { RuntimeContext } from 'mol-task' import { fillSerial } from 'mol-gl/renderable/util'; import { UnitsRepresentation, DefaultStructureProps } from './index'; @@ -21,6 +21,7 @@ import { RenderableState, PointValues } from 'mol-gl/renderable'; import { PickingId } from '../../util/picking'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { MarkerAction, createMarkers } from '../../util/marker-data'; +import { Vec3 } from 'mol-math/linear-algebra'; export const DefaultPointProps = { ...DefaultStructureProps, @@ -33,16 +34,15 @@ export function createPointVertices(unit: Unit) { const elementCount = elements.length const vertices = new Float32Array(elementCount * 3) - const { x, y, z } = unit.conformation - const l = Element.Location() - l.unit = unit + const pos = unit.conformation.invariantPosition + const p = Vec3.zero() for (let i = 0; i < elementCount; i++) { - l.element = elements[i]; const i3 = i * 3 - vertices[i3] = x(l.element) - vertices[i3 + 1] = y(l.element) - vertices[i3 + 2] = z(l.element) + pos(elements[i], p) + vertices[i3] = p[0] + vertices[i3 + 1] = p[1] + vertices[i3 + 2] = p[2] } return vertices } @@ -58,104 +58,100 @@ export default function PointUnitsRepresentation(): UnitsRepresentation<PointPro return { renderObjects, - create(group: Unit.SymmetryGroup, props: PointProps = {}) { + async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: PointProps = {}) { currentProps = Object.assign({}, DefaultPointProps, props) - return Task.create('Point.create', async ctx => { - renderObjects.length = 0 // clear - currentGroup = group - - _units = group.units - _elements = group.elements; - - const { colorTheme, sizeTheme } = currentProps - const elementCount = _elements.length - const instanceCount = group.units.length - - const vertexMap = VertexMap.create( - elementCount, - elementCount + 1, - fillSerial(new Uint32Array(elementCount)), - fillSerial(new Uint32Array(elementCount + 1)) - ) - - await ctx.update('Computing point vertices'); - const vertices = createPointVertices(_units[0]) - - await ctx.update('Computing point transforms'); - const transforms = createTransforms(group) - - await ctx.update('Computing point colors'); - const color = createColors(group, vertexMap, colorTheme) - - await ctx.update('Computing point sizes'); - const size = createSizes(group, vertexMap, sizeTheme) - - await ctx.update('Computing spacefill marks'); - const marker = createMarkers(instanceCount * elementCount) - - const values: PointValues = { - aPosition: ValueCell.create(vertices), - aElementId: ValueCell.create(fillSerial(new Float32Array(elementCount))), - aTransform: transforms, - aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), - ...color, - ...marker, - ...size, - - uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), - uInstanceCount: ValueCell.create(instanceCount), - uElementCount: ValueCell.create(group.elements.length), - - drawCount: ValueCell.create(vertices.length / 3), - instanceCount: ValueCell.create(instanceCount), - - dPointSizeAttenuation: ValueCell.create(true), - dUseFog: ValueCell.create(defaults(props.useFog, true)), - } - const state: RenderableState = { - depthMask: defaults(props.depthMask, true), - visible: defaults(props.visible, true) - } - - points = createPointRenderObject(values, state) - renderObjects.push(points) - }) + renderObjects.length = 0 // clear + currentGroup = group + + _units = group.units + _elements = group.elements; + + const { colorTheme, sizeTheme } = currentProps + const elementCount = _elements.length + const instanceCount = group.units.length + + const vertexMap = VertexMap.create( + elementCount, + elementCount + 1, + fillSerial(new Uint32Array(elementCount)), + fillSerial(new Uint32Array(elementCount + 1)) + ) + + if (ctx.shouldUpdate) await ctx.update('Computing point vertices'); + const vertices = createPointVertices(_units[0]) + + if (ctx.shouldUpdate) await ctx.update('Computing point transforms'); + const transforms = createTransforms(group) + + if (ctx.shouldUpdate) await ctx.update('Computing point colors'); + const color = createColors(group, vertexMap, colorTheme) + + if (ctx.shouldUpdate) await ctx.update('Computing point sizes'); + const size = createSizes(group, vertexMap, sizeTheme) + + if (ctx.shouldUpdate) await ctx.update('Computing spacefill marks'); + const marker = createMarkers(instanceCount * elementCount) + + const values: PointValues = { + aPosition: ValueCell.create(vertices), + aElementId: ValueCell.create(fillSerial(new Float32Array(elementCount))), + aTransform: transforms, + aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), + ...color, + ...marker, + ...size, + + uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), + uInstanceCount: ValueCell.create(instanceCount), + uElementCount: ValueCell.create(group.elements.length), + + drawCount: ValueCell.create(vertices.length / 3), + instanceCount: ValueCell.create(instanceCount), + + dPointSizeAttenuation: ValueCell.create(true), + dUseFog: ValueCell.create(defaults(props.useFog, true)), + } + const state: RenderableState = { + depthMask: defaults(props.depthMask, true), + visible: defaults(props.visible, true) + } + + points = createPointRenderObject(values, state) + renderObjects.push(points) }, - update(props: PointProps) { - return Task.create('Point.update', async ctx => { - if (!points || !_units || !_elements) return false - - const newProps = { ...currentProps, ...props } - if (deepEqual(currentProps, newProps)) { - console.log('props identical, nothing to change') - return true - } - - // const elementCount = OrderedSet.size(_elementGroup.elements) - // const unitCount = _units.length - - // const vertexMap = VertexMap.create( - // elementCount, - // elementCount + 1, - // fillSerial(new Uint32Array(elementCount)), - // fillSerial(new Uint32Array(elementCount + 1)) - // ) - - if (!deepEqual(currentProps.colorTheme, newProps.colorTheme)) { - console.log('colorTheme changed', currentProps.colorTheme, newProps.colorTheme) - // await ctx.update('Computing point colors'); - // const color = createColors(_units, _elementGroup, vertexMap, newProps.colorTheme) - // ValueCell.update(points.props.color, color) - } - - if (!deepEqual(currentProps.sizeTheme, newProps.sizeTheme)) { - console.log('sizeTheme changed', currentProps.sizeTheme, newProps.sizeTheme) - } - - currentProps = newProps - return false - }) + async update(ctx: RuntimeContext, props: PointProps) { + if (!points || !_units || !_elements) return false + + const newProps = { ...currentProps, ...props } + if (deepEqual(currentProps, newProps)) { + console.log('props identical, nothing to change') + return true + } + + // const elementCount = OrderedSet.size(_elementGroup.elements) + // const unitCount = _units.length + + // const vertexMap = VertexMap.create( + // elementCount, + // elementCount + 1, + // fillSerial(new Uint32Array(elementCount)), + // fillSerial(new Uint32Array(elementCount + 1)) + // ) + + if (!deepEqual(currentProps.colorTheme, newProps.colorTheme)) { + console.log('colorTheme changed', currentProps.colorTheme, newProps.colorTheme) + // if (ctx.shouldUpdate) await ctx.update('Computing point colors'); + // const color = createColors(_units, _elementGroup, vertexMap, newProps.colorTheme) + // ValueCell.update(points.props.color, color) + } + + if (!deepEqual(currentProps.sizeTheme, newProps.sizeTheme)) { + console.log('sizeTheme changed', currentProps.sizeTheme, newProps.sizeTheme) + } + + currentProps = newProps + return false }, getLoci(pickingId: PickingId) { const { objectId, instanceId, elementId } = pickingId diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts index 15551433d..c3fad8f38 100644 --- a/src/mol-geo/representation/structure/spacefill.ts +++ b/src/mol-geo/representation/structure/spacefill.ts @@ -10,7 +10,7 @@ import { ValueCell } from 'mol-util/value-cell' import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object' import { Unit, Element, Queries } from 'mol-model/structure'; import { UnitsRepresentation, DefaultStructureProps } from './index'; -import { Task } from 'mol-task' +import { RuntimeContext } from 'mol-task' import { createTransforms, createColors, createSphereMesh, markElement } from './utils'; import VertexMap from '../../shape/vertex-map'; import { deepEqual, defaults } from 'mol-util'; @@ -23,7 +23,7 @@ import { OrderedSet } from 'mol-data/int'; import { createMarkers, MarkerAction } from '../../util/marker-data'; import { Loci, EmptyLoci } from 'mol-model/loci'; -function createSpacefillMesh(unit: Unit, detail: number, mesh?: Mesh) { +async function createSpacefillMesh(ctx: RuntimeContext, unit: Unit, detail: number, mesh?: Mesh) { let radius: Element.Property<number> if (Unit.isAtomic(unit)) { radius = Queries.props.atom.vdw_radius @@ -31,9 +31,9 @@ function createSpacefillMesh(unit: Unit, detail: number, mesh?: Mesh) { radius = Queries.props.coarse.sphere_radius } else { console.warn('Unsupported unit type') - return Task.constant('Empty mesh', Mesh.createEmpty(mesh)) + return Mesh.createEmpty(mesh) } - return createSphereMesh(unit, (l) => radius(l) * 0.3, detail, mesh) + return await createSphereMesh(ctx, unit, (l) => radius(l) * 0.3, detail, mesh) } export const DefaultSpacefillProps = { @@ -54,96 +54,92 @@ export default function SpacefillUnitsRepresentation(): UnitsRepresentation<Spac return { renderObjects, - create(group: Unit.SymmetryGroup, props: SpacefillProps = {}) { + async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: SpacefillProps = {}) { currentProps = Object.assign({}, DefaultSpacefillProps, props) - return Task.create('Spacefill.create', async ctx => { - renderObjects.length = 0 // clear - currentGroup = group + renderObjects.length = 0 // clear + currentGroup = group - const { detail, colorTheme } = { ...DefaultSpacefillProps, ...props } - const instanceCount = group.units.length - const elementCount = group.elements.length + const { detail, colorTheme } = { ...DefaultSpacefillProps, ...props } + const instanceCount = group.units.length + const elementCount = group.elements.length - mesh = await createSpacefillMesh(group.units[0], detail).runAsChild(ctx, 'Computing spacefill mesh') - // console.log(mesh) - vertexMap = VertexMap.fromMesh(mesh) + mesh = await createSpacefillMesh(ctx, group.units[0], detail) + // console.log(mesh) + vertexMap = VertexMap.fromMesh(mesh) - await ctx.update('Computing spacefill transforms'); - const transforms = createTransforms(group) + if (ctx.shouldUpdate) await ctx.update('Computing spacefill transforms'); + const transforms = createTransforms(group) - await ctx.update('Computing spacefill colors'); - const color = createColors(group, vertexMap, colorTheme) + if (ctx.shouldUpdate) await ctx.update('Computing spacefill colors'); + const color = createColors(group, vertexMap, colorTheme) - await ctx.update('Computing spacefill marks'); - const marker = createMarkers(instanceCount * elementCount) + if (ctx.shouldUpdate) await ctx.update('Computing spacefill marks'); + const marker = createMarkers(instanceCount * elementCount) - const values: MeshValues = { - ...getMeshData(mesh), - aTransform: transforms, - aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), - ...color, - ...marker, + const values: MeshValues = { + ...getMeshData(mesh), + aTransform: transforms, + aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), + ...color, + ...marker, - uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), - uInstanceCount: ValueCell.create(instanceCount), - uElementCount: ValueCell.create(elementCount), + uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), + uInstanceCount: ValueCell.create(instanceCount), + uElementCount: ValueCell.create(elementCount), - elements: mesh.indexBuffer, + elements: mesh.indexBuffer, - drawCount: ValueCell.create(mesh.triangleCount * 3), - instanceCount: ValueCell.create(instanceCount), + drawCount: ValueCell.create(mesh.triangleCount * 3), + instanceCount: ValueCell.create(instanceCount), - dDoubleSided: ValueCell.create(defaults(props.doubleSided, true)), - dFlatShaded: ValueCell.create(defaults(props.flatShaded, false)), - dFlipSided: ValueCell.create(defaults(props.flipSided, false)), - dUseFog: ValueCell.create(defaults(props.useFog, true)), - } - const state: RenderableState = { - depthMask: defaults(props.depthMask, true), - visible: defaults(props.visible, true) - } + dDoubleSided: ValueCell.create(defaults(props.doubleSided, true)), + dFlatShaded: ValueCell.create(defaults(props.flatShaded, false)), + dFlipSided: ValueCell.create(defaults(props.flipSided, false)), + dUseFog: ValueCell.create(defaults(props.useFog, true)), + } + const state: RenderableState = { + depthMask: defaults(props.depthMask, true), + visible: defaults(props.visible, true) + } - spheres = createMeshRenderObject(values, state) - renderObjects.push(spheres) - }) + spheres = createMeshRenderObject(values, state) + renderObjects.push(spheres) }, - update(props: SpacefillProps) { + async update(ctx: RuntimeContext, props: SpacefillProps) { const newProps = Object.assign({}, currentProps, props) - return Task.create('Spacefill.update', async ctx => { - if (!spheres) return false + if (!spheres) return false - let updateColor = false + let updateColor = false - if (newProps.detail !== currentProps.detail) { - mesh = await createSpacefillMesh(currentGroup.units[0], newProps.detail, mesh).runAsChild(ctx, 'Computing spacefill mesh') - ValueCell.update(spheres.values.drawCount, mesh.triangleCount * 3) - // TODO update in-place - vertexMap = VertexMap.fromMesh(mesh) - updateColor = true - } + if (newProps.detail !== currentProps.detail) { + mesh = await createSpacefillMesh(ctx, currentGroup.units[0], newProps.detail, mesh) + ValueCell.update(spheres.values.drawCount, mesh.triangleCount * 3) + // TODO update in-place + vertexMap = VertexMap.fromMesh(mesh) + updateColor = true + } - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } + if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { + updateColor = true + } - if (updateColor) { - await ctx.update('Computing spacefill colors'); - createColors(currentGroup, vertexMap, newProps.colorTheme, spheres.values) - } + if (updateColor) { + if (ctx.shouldUpdate) await ctx.update('Computing spacefill colors'); + createColors(currentGroup, vertexMap, newProps.colorTheme, spheres.values) + } - ValueCell.updateIfChanged(spheres.values.uAlpha, newProps.alpha) - ValueCell.updateIfChanged(spheres.values.dDoubleSided, newProps.doubleSided) - ValueCell.updateIfChanged(spheres.values.dFlipSided, newProps.flipSided) - ValueCell.updateIfChanged(spheres.values.dFlatShaded, newProps.flatShaded) + ValueCell.updateIfChanged(spheres.values.uAlpha, newProps.alpha) + ValueCell.updateIfChanged(spheres.values.dDoubleSided, newProps.doubleSided) + ValueCell.updateIfChanged(spheres.values.dFlipSided, newProps.flipSided) + ValueCell.updateIfChanged(spheres.values.dFlatShaded, newProps.flatShaded) - spheres.state.visible = newProps.visible - spheres.state.depthMask = newProps.depthMask + spheres.state.visible = newProps.visible + spheres.state.depthMask = newProps.depthMask - currentProps = newProps - return true - }) + currentProps = newProps + return true }, getLoci(pickingId: PickingId) { const { objectId, instanceId, elementId } = pickingId diff --git a/src/mol-geo/representation/structure/utils.ts b/src/mol-geo/representation/structure/utils.ts index aee0ab240..ada7c4309 100644 --- a/src/mol-geo/representation/structure/utils.ts +++ b/src/mol-geo/representation/structure/utils.ts @@ -16,7 +16,7 @@ import { ColorTheme, SizeTheme } from '../../theme'; import { elementIndexColorData, elementSymbolColorData, instanceIndexColorData, chainIdColorData } from '../../theme/structure/color'; import { ValueCell } from 'mol-util'; import { Mesh } from '../../shape/mesh'; -import { Task } from 'mol-task'; +import { RuntimeContext } from 'mol-task'; import { icosahedronVertexCount } from '../../primitive/icosahedron'; import { MeshBuilder } from '../../shape/mesh-builder'; import { TextureImage } from 'mol-gl/renderable/util'; @@ -58,35 +58,33 @@ export function createSizes(group: Unit.SymmetryGroup, vertexMap: VertexMap, pro } } -export function createSphereMesh(unit: Unit, radius: Element.Property<number>, detail: number, mesh?: Mesh) { - return Task.create('Sphere mesh', async ctx => { - const { elements } = unit; - const elementCount = elements.length; - const vertexCount = elementCount * icosahedronVertexCount(detail) - const meshBuilder = MeshBuilder.create(vertexCount, vertexCount / 2, mesh) +export async function createSphereMesh(ctx: RuntimeContext, unit: Unit, radius: Element.Property<number>, detail: number, mesh?: Mesh) { + const { elements } = unit; + const elementCount = elements.length; + const vertexCount = elementCount * icosahedronVertexCount(detail) + const meshBuilder = MeshBuilder.create(vertexCount, vertexCount / 2, mesh) - const v = Vec3.zero() - const m = Mat4.identity() + const v = Vec3.zero() + const m = Mat4.identity() - const { x, y, z } = unit.conformation - const l = Element.Location() - l.unit = unit + const { x, y, z } = unit.model.atomicConformation + const l = Element.Location() + l.unit = unit - for (let i = 0; i < elementCount; i++) { - l.element = elements[i] - v[0] = x(l.element); v[1] = y(l.element); v[2] = z(l.element) - Mat4.setTranslation(m, v) + for (let i = 0; i < elementCount; i++) { + l.element = elements[i] + v[0] = x[l.element]; v[1] = y[l.element]; v[2] = z[l.element] + Mat4.setTranslation(m, v) - meshBuilder.setId(i) - meshBuilder.addIcosahedron(m, { radius: radius(l), detail }) + meshBuilder.setId(i) + meshBuilder.addIcosahedron(m, { radius: radius(l), detail }) - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Sphere mesh', current: i, max: elementCount }); - } + if (i % 10000 === 0 && ctx.shouldUpdate) { + await ctx.update({ message: 'Sphere mesh', current: i, max: elementCount }); } + } - return meshBuilder.getMesh() - }) + return meshBuilder.getMesh() } diff --git a/src/mol-geo/representation/volume/index.ts b/src/mol-geo/representation/volume/index.ts index f0104fb99..c43fbba30 100644 --- a/src/mol-geo/representation/volume/index.ts +++ b/src/mol-geo/representation/volume/index.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Task } from 'mol-task' +import { Task, RuntimeContext } from 'mol-task' import { RenderObject } from 'mol-gl/render-object'; import { RepresentationProps, Representation } from '..'; import { VolumeData } from 'mol-model/volume'; @@ -14,8 +14,8 @@ import { MarkerAction } from '../../util/marker-data'; export interface VolumeElementRepresentation<P> { renderObjects: ReadonlyArray<RenderObject> - create: (volumeData: VolumeData, props: P) => Task<void> - update: (props: P) => Task<boolean> + create: (ctx: RuntimeContext, volumeData: VolumeData, props: P) => Promise<void> + update: (ctx: RuntimeContext, props: P) => Promise<boolean> getLoci: (pickingId: PickingId) => Loci mark: (loci: Loci, action: MarkerAction) => void } @@ -30,7 +30,7 @@ export function VolumeRepresentation<P>(reprCtor: () => VolumeElementRepresentat create(volumeData: VolumeData, props: P = {} as P) { return Task.create('VolumeRepresentation.create', async ctx => { const repr = reprCtor() - await repr.create(volumeData, props).runAsChild(ctx, { message: 'Building volume representation...', current: 0, max: 1 }); + await repr.create(ctx, volumeData, props) renderObjects.push(...repr.renderObjects) }); }, diff --git a/src/mol-geo/representation/volume/surface.ts b/src/mol-geo/representation/volume/surface.ts index c22140e97..80495047e 100644 --- a/src/mol-geo/representation/volume/surface.ts +++ b/src/mol-geo/representation/volume/surface.ts @@ -6,7 +6,7 @@ */ import { VolumeData, VolumeIsoValue } from 'mol-model/volume' -import { Task } from 'mol-task' +import { Task, RuntimeContext } from 'mol-task' import { computeMarchingCubes } from '../../util/marching-cubes/algorithm'; import { Mesh } from '../../shape/mesh'; import { VolumeElementRepresentation } from '.'; @@ -57,55 +57,51 @@ export default function Surface(): VolumeElementRepresentation<SurfaceProps> { return { renderObjects, - create(volume: VolumeData, props: SurfaceProps = {}) { - return Task.create('Point.create', async ctx => { - renderObjects.length = 0 // clear - props = { ...DefaultSurfaceProps, ...props } - - const mesh = await computeVolumeSurface(volume, curProps.isoValue).runAsChild(ctx) - if (!props.flatShaded) { - Mesh.computeNormalsImmediate(mesh) - } - - const instanceCount = 1 - const color = createUniformColor({ value: 0x7ec0ee }) - const marker = createEmptyMarkers() - - const values: MeshValues = { - ...getMeshData(mesh), - aTransform: ValueCell.create(new Float32Array(Mat4.identity())), - aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), - ...color, - ...marker, - - uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), - uInstanceCount: ValueCell.create(instanceCount), - uElementCount: ValueCell.create(mesh.triangleCount), - - elements: mesh.indexBuffer, - - drawCount: ValueCell.create(mesh.triangleCount * 3), - instanceCount: ValueCell.create(instanceCount), - - dDoubleSided: ValueCell.create(defaults(props.doubleSided, true)), - dFlatShaded: ValueCell.create(defaults(props.flatShaded, true)), - dFlipSided: ValueCell.create(false), - dUseFog: ValueCell.create(defaults(props.useFog, true)), - } - const state: RenderableState = { - depthMask: defaults(props.depthMask, true), - visible: defaults(props.visible, true) - } - - surface = createMeshRenderObject(values, state) - renderObjects.push(surface) - }) + async create(ctx: RuntimeContext, volume: VolumeData, props: SurfaceProps = {}) { + renderObjects.length = 0 // clear + props = { ...DefaultSurfaceProps, ...props } + + const mesh = await computeVolumeSurface(volume, curProps.isoValue).runAsChild(ctx) + if (!props.flatShaded) { + Mesh.computeNormalsImmediate(mesh) + } + + const instanceCount = 1 + const color = createUniformColor({ value: 0x7ec0ee }) + const marker = createEmptyMarkers() + + const values: MeshValues = { + ...getMeshData(mesh), + aTransform: ValueCell.create(new Float32Array(Mat4.identity())), + aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), + ...color, + ...marker, + + uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), + uInstanceCount: ValueCell.create(instanceCount), + uElementCount: ValueCell.create(mesh.triangleCount), + + elements: mesh.indexBuffer, + + drawCount: ValueCell.create(mesh.triangleCount * 3), + instanceCount: ValueCell.create(instanceCount), + + dDoubleSided: ValueCell.create(defaults(props.doubleSided, true)), + dFlatShaded: ValueCell.create(defaults(props.flatShaded, true)), + dFlipSided: ValueCell.create(false), + dUseFog: ValueCell.create(defaults(props.useFog, true)), + } + const state: RenderableState = { + depthMask: defaults(props.depthMask, true), + visible: defaults(props.visible, true) + } + + surface = createMeshRenderObject(values, state) + renderObjects.push(surface) }, - update(props: SurfaceProps) { - return Task.create('Surface.update', async ctx => { - // TODO - return false - }) + async update(ctx: RuntimeContext, props: SurfaceProps) { + // TODO + return false }, getLoci(pickingId: PickingId) { // TODO -- GitLab