Browse Source

pass runtime ctx instead of creating new tasks

Alexander Rose 6 years ago
parent
commit
762048b76c

+ 92 - 98
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

+ 17 - 7
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)
                 }

+ 99 - 103
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

+ 67 - 71
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

+ 21 - 23
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()
 }
 
 

+ 4 - 4
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)
             });
         },

+ 45 - 49
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