Skip to content
Snippets Groups Projects
Commit 0ab1d34b authored by Alexander Rose's avatar Alexander Rose
Browse files

wip, shape repr async creation

parent 934f5cfa
No related branches found
No related tags found
No related merge requests found
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
import { Task } from 'mol-task' import { Task, RuntimeContext } from 'mol-task'
import { createRenderObject, GraphicsRenderObject } from 'mol-gl/render-object'; import { createRenderObject, GraphicsRenderObject } from 'mol-gl/render-object';
import { Representation } from '../representation'; import { Representation } from '../representation';
import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
...@@ -27,7 +27,9 @@ import { Visual } from 'mol-repr/visual'; ...@@ -27,7 +27,9 @@ import { Visual } from 'mol-repr/visual';
export interface ShapeRepresentation<D, G extends Geometry, P extends Geometry.Params<G>> extends Representation<D, P> { } export interface ShapeRepresentation<D, G extends Geometry, P extends Geometry.Params<G>> extends Representation<D, P> { }
export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Params<G>>(getShape: (data: D, props: PD.Values<P>, shape?: Shape<G>) => Shape<G>, geometryUtils: GeometryUtils<G>): ShapeRepresentation<D, G, P> { export type ShapeGetter<D, G extends Geometry, P extends Geometry.Params<G>> = (ctx: RuntimeContext, data: D, props: PD.Values<P>, shape?: Shape<G>) => Shape<G> | Promise<Shape<G>>
export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Params<G>>(getShape: ShapeGetter<D, G, P>, geometryUtils: GeometryUtils<G>): ShapeRepresentation<D, G, P> {
let version = 0 let version = 0
const updated = new Subject<number>() const updated = new Subject<number>()
const _state = Representation.createState() const _state = Representation.createState()
...@@ -73,10 +75,10 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa ...@@ -73,10 +75,10 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
} }
function createOrUpdate(props: Partial<PD.Values<P>> = {}, data?: D) { function createOrUpdate(props: Partial<PD.Values<P>> = {}, data?: D) {
const newProps = Object.assign(currentProps, props)
const shape = data ? getShape(data, newProps, _shape) : undefined // TODO support async getShape
return Task.create('ShapeRepresentation.create', async runtime => { return Task.create('ShapeRepresentation.create', async runtime => {
const newProps = Object.assign(currentProps, props)
const shape = data ? await getShape(runtime, data, newProps, _shape) : undefined
prepareUpdate(shape) prepareUpdate(shape)
if (shape) { if (shape) {
......
...@@ -14,6 +14,7 @@ import { ShapeRepresentation } from 'mol-repr/shape/representation'; ...@@ -14,6 +14,7 @@ import { ShapeRepresentation } from 'mol-repr/shape/representation';
import { ColorNames } from 'mol-util/color/tables'; import { ColorNames } from 'mol-util/color/tables';
import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { Mesh } from 'mol-geo/geometry/mesh/mesh';
import { labelFirst } from 'mol-theme/label'; import { labelFirst } from 'mol-theme/label';
import { RuntimeContext, Progress } from 'mol-task';
const parent = document.getElementById('app')! const parent = document.getElementById('app')!
parent.style.width = '100%' parent.style.width = '100%'
...@@ -45,42 +46,67 @@ canvas3d.input.move.subscribe(async ({x, y}) => { ...@@ -45,42 +46,67 @@ canvas3d.input.move.subscribe(async ({x, y}) => {
info.innerText = label info.innerText = label
}) })
const builderState = MeshBuilder.createState() /**
const t = Mat4.identity() * Create a mesh of spheres at given centers
const sphere = Sphere(2) * - asynchronous (using async/await)
builderState.currentGroup = 0 * - progress tracking (via `ctx.update`)
MeshBuilder.addPrimitive(builderState, t, sphere) * - re-use storage from an existing mesh if given
const mesh = MeshBuilder.getMesh(builderState) */
async function getSphereMesh(ctx: RuntimeContext, centers: number[], mesh?: Mesh) {
const builderState = MeshBuilder.createState(centers.length * 128, centers.length * 128 / 2, mesh)
const t = Mat4.identity()
const v = Vec3.zero()
const sphere = Sphere(2)
builderState.currentGroup = 0
for (let i = 0, il = centers.length / 3; i < il; ++i) {
// for production, calls to update should be guarded by `if (ctx.shouldUpdate)`
await ctx.update({ current: i, max: il, message: `adding sphere ${i}` })
builderState.currentGroup = i
Mat4.setTranslation(t, Vec3.fromArray(v, centers, i * 3))
MeshBuilder.addPrimitive(builderState, t, sphere)
}
return MeshBuilder.getMesh(builderState)
}
const myData = { const myData = {
mesh, centers: [0, 0, 0, 0, 3, 0],
groupCount: 1,
colors: [ColorNames.tomato, ColorNames.springgreen], colors: [ColorNames.tomato, ColorNames.springgreen],
labels: ['FooBaz0', 'FooBaz1'], labels: ['Sphere 0, Instance A', 'Sphere 1, Instance A', 'Sphere 0, Instance B', 'Sphere 1, Instance B'],
transforms: [Mat4.identity(), Mat4.fromTranslation(Mat4.zero(), Vec3.create(3, 0, 0))] transforms: [Mat4.identity(), Mat4.fromTranslation(Mat4.zero(), Vec3.create(3, 0, 0))]
} }
type MyData = typeof myData type MyData = typeof myData
function getShape(data: MyData, props: {}, shape?: Shape<Mesh>) {
const { mesh, colors, labels, transforms, groupCount } = data /**
* Get shape from `MyData` object
*/
async function getShape(ctx: RuntimeContext, data: MyData, props: {}, shape?: Shape<Mesh>) {
await ctx.update('async creation of shape from myData')
const { centers, colors, labels, transforms } = data
const mesh = await getSphereMesh(ctx, centers, shape && shape.geometry)
const groupCount = centers.length / 3
return shape || Shape.create( return shape || Shape.create(
'test', mesh, 'test', mesh,
(groupId: number, instanceId: number) => colors[instanceId * groupCount + groupId], (groupId: number) => colors[groupId], // per group, same for instances
(groupId: number, instanceId: number) => labels[instanceId * groupCount + groupId], (groupId: number, instanceId: number) => labels[instanceId * groupCount + groupId], // per group and instance
transforms transforms
) )
} }
// Init ShapeRepresentation container
const repr = ShapeRepresentation(getShape, Mesh.Utils) const repr = ShapeRepresentation(getShape, Mesh.Utils)
async function add() { async function init() {
await repr.createOrUpdate({}, myData).run() // Create shape from myData and add to canvas3d
await repr.createOrUpdate({}, myData).run((p: Progress) => console.log(Progress.format(p)))
console.log(repr) console.log(repr)
canvas3d.add(repr) canvas3d.add(repr)
canvas3d.resetCamera() canvas3d.resetCamera()
}
add()
setTimeout(async () => { // Change color after 1s
myData.colors[0] = ColorNames.darkmagenta setTimeout(async () => {
await repr.createOrUpdate({}, myData).run() myData.colors[0] = ColorNames.darkmagenta
}, 1000) // Calling `createOrUpdate` with `data` will trigger color and transform update
\ No newline at end of file await repr.createOrUpdate({}, myData).run()
}, 1000)
}
init()
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment