diff --git a/src/apps/canvas/assembly-symmetry.ts b/src/apps/canvas/assembly-symmetry.ts index 0fe6a734730dd50f51c2a8af3ba15af36d5c0517..f4cdb2888466a56c6f9babcc311ea010249714db 100644 --- a/src/apps/canvas/assembly-symmetry.ts +++ b/src/apps/canvas/assembly-symmetry.ts @@ -66,10 +66,10 @@ export function getClusterColorTheme(symmetryId: number, assemblySymmetry: Assem const DefaultColor = Color(0xCCCCCC) const s = assemblySymmetry.db.rcsb_assembly_symmetry const symmetry = Table.pickRow(s, i => s.id.value(i) === symmetryId) - if (!symmetry) return { granularity: 'uniform', color: () => DefaultColor } + if (!symmetry) return { features: {}, granularity: 'uniform', color: () => DefaultColor } const clusters = assemblySymmetry.getClusters(symmetryId) - if (!clusters._rowCount) return { granularity: 'uniform', color: () => DefaultColor } + if (!clusters._rowCount) return { features: {}, granularity: 'uniform', color: () => DefaultColor } const clusterByMember = new Map<string, number>() for (let i = 0, il = clusters._rowCount; i < il; ++i) { @@ -83,6 +83,7 @@ export function getClusterColorTheme(symmetryId: number, assemblySymmetry: Assem const scale = ColorScale.create({ domain: [ 0, clusters._rowCount - 1 ] }) return { + features: {}, granularity: 'instance', color: (location: Location): Color => { if (StructureElement.isLocation(location)) { diff --git a/src/apps/canvas/component/representation.tsx b/src/apps/canvas/component/representation.tsx index 02fcdea19363ea0b39cc1db364d986908efd46a0..bb68eed9c9f071ec7741879df1e891a9c3422d84 100644 --- a/src/apps/canvas/component/representation.tsx +++ b/src/apps/canvas/component/representation.tsx @@ -41,7 +41,8 @@ export class RepresentationComponent extends React.Component<RepresentationCompo } async onChange(k: string, v: any) { - await this.props.app.runTask(this.props.repr.createOrUpdate({ [k]: v }).run( + const ctx = { webgl: this.props.canvas3d.webgl } + await this.props.app.runTask(this.props.repr.createOrUpdate(ctx, { [k]: v }).run( progress => this.props.app.log(progress) ), 'Representation Update') this.props.canvas3d.add(this.props.repr) diff --git a/src/apps/canvas/index.ts b/src/apps/canvas/index.ts index cbc1a3a568a9c81c31a702134dce10a4c80471d7..dd72f8aaa98406272ed4a2d583781a38dc97743e 100644 --- a/src/apps/canvas/index.ts +++ b/src/apps/canvas/index.ts @@ -25,8 +25,8 @@ if (pdbId) app.loadPdbIdOrMmcifUrl(pdbId, { assemblyId }) // app.loadPdbIdOrMmcifUrl('http://localhost:8091/ngl/data/1crn.cif') -app.loadPdbIdOrMmcifUrl('3pqr') -app.loadCcp4Url('http://localhost:8091/ngl/data/3pqr-mode0.ccp4') +// app.loadPdbIdOrMmcifUrl('3pqr') +// app.loadCcp4Url('http://localhost:8091/ngl/data/3pqr-mode0.ccp4') // app.loadPdbIdOrMmcifUrl('1lee') // app.loadCcp4Url('http://localhost:8091/ngl/data/1lee.ccp4') diff --git a/src/apps/canvas/structure-view.ts b/src/apps/canvas/structure-view.ts index 80bcac4134052e676c5ef77439c9131291fdb244..eeff5581a4cb6d4dcc4e95fe1055642be4122aee 100644 --- a/src/apps/canvas/structure-view.ts +++ b/src/apps/canvas/structure-view.ts @@ -208,8 +208,7 @@ export async function StructureView(app: App, canvas3d: Canvas3D, models: Readon console.log('createStructureRepr') for (const k in structureRepresentations) { if (active[k]) { - const p = { webgl: canvas3d.webgl } - await app.runTask(structureRepresentations[k].createOrUpdate(p, structure).run( + await app.runTask(structureRepresentations[k].createOrUpdate({ webgl: canvas3d.webgl }, {}, structure).run( progress => app.log(progress) ), 'Create/update representation') canvas3d.add(structureRepresentations[k]) @@ -265,7 +264,7 @@ export async function StructureView(app: App, canvas3d: Canvas3D, models: Readon // colorFunction: colorTheme.color, // colorGranularity: colorTheme.granularity, // }).run() - await symmetryAxes.createOrUpdate({}, axesShape).run() + await symmetryAxes.createOrUpdate({ webgl: canvas3d.webgl }, {}, axesShape).run() canvas3d.add(symmetryAxes) } else { canvas3d.remove(symmetryAxes) diff --git a/src/apps/canvas/volume-view.ts b/src/apps/canvas/volume-view.ts index bfe46d0e444d3047eea21886908b1d1b7ffba373..6c05559ef90422c25527822337f72f7e0e602d02 100644 --- a/src/apps/canvas/volume-view.ts +++ b/src/apps/canvas/volume-view.ts @@ -54,8 +54,7 @@ export async function VolumeView(app: App, viewer: Canvas3D, volume: VolumeData, async function createVolumeRepr() { for (const k in volumeRepresentations) { if (active[k]) { - const p = { webgl: viewer.webgl } - await app.runTask(volumeRepresentations[k].createOrUpdate(p, volume).run( + await app.runTask(volumeRepresentations[k].createOrUpdate({ webgl: viewer.webgl }, {}, volume).run( progress => app.log(progress) ), 'Create/update representation') viewer.add(volumeRepresentations[k]) diff --git a/src/apps/structure-info/volume.ts b/src/apps/structure-info/volume.ts index 3b7d8cc3f184d882b534f7c38417a8abfb91e6f0..d9921d7a4003693e1827c0db22399a3e6d2c73dd 100644 --- a/src/apps/structure-info/volume.ts +++ b/src/apps/structure-info/volume.ts @@ -38,7 +38,7 @@ function print(data: Volume) { } async function doMesh(data: Volume, filename: string) { - const mesh = await Task.create('', ctx => createVolumeIsosurface(ctx, data.volume, { isoValueAbsolute: VolumeIsoValue.calcAbsolute(data.volume.dataStats, 1.5) } )).run(); + const mesh = await Task.create('', runtime => createVolumeIsosurface({ runtime }, data.volume, { isoValueAbsolute: VolumeIsoValue.calcAbsolute(data.volume.dataStats, 1.5) } )).run(); console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount }); // Export the mesh in OBJ format. diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index 0d21ff0bebd0beaaf279e0a18f2b6c0bb5562fc6..ee2a3c419d1fd59cc3d3a8a74233db8c335b687a 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -24,10 +24,17 @@ import { PickingId, decodeIdRGB } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci'; import { Color } from 'mol-util/color'; -import { CombinedCamera } from './camera/combined'; +import { CombinedCamera, CombinedCameraMode } from './camera/combined'; + +export const DefaultCanvas3DProps = { + cameraPosition: Vec3.create(0, 0, 50), + cameraMode: 'perspective' as CombinedCameraMode, + backgroundColor: Color(0x000000), +} +export type Canvas3DProps = typeof DefaultCanvas3DProps interface Canvas3D { - webgl: WebGLContext, + readonly webgl: WebGLContext, center: (p: Vec3) => void @@ -47,23 +54,27 @@ interface Canvas3D { mark: (loci: Loci, action: MarkerAction) => void getLoci: (pickingId: PickingId) => Loci - reprCount: BehaviorSubject<number> - identified: BehaviorSubject<string> - didDraw: BehaviorSubject<number> + readonly reprCount: BehaviorSubject<number> + readonly identified: BehaviorSubject<string> + readonly didDraw: BehaviorSubject<number> handleResize: () => void resetCamera: () => void - camera: CombinedCamera + readonly camera: CombinedCamera downloadScreenshot: () => void getImageData: (variant: RenderVariant) => ImageData - input: InputObserver - stats: RendererStats + /** Returns a copy of the current Canvas3D instance props */ + readonly props: Canvas3DProps + readonly input: InputObserver + readonly stats: RendererStats dispose: () => void } namespace Canvas3D { - export function create(canvas: HTMLCanvasElement, container: Element): Canvas3D { + export function create(canvas: HTMLCanvasElement, container: Element, props: Partial<Canvas3DProps> = {}): Canvas3D { + const p = { ...props, ...DefaultCanvas3DProps } + const reprMap = new Map<Representation<any>, Set<RenderObject>>() const reprCount = new BehaviorSubject(0) const identified = new BehaviorSubject('') @@ -75,14 +86,9 @@ namespace Canvas3D { const camera = CombinedCamera.create({ near: 0.1, far: 10000, - position: Vec3.create(0, 0, 50), - mode: 'orthographic' + position: Vec3.clone(p.cameraPosition), + mode: p.cameraMode }) - // const camera = OrthographicCamera.create({ - // zoom: 8, - // position: Vec3.create(0, 0, 50) - // }) - // camera.lookAt(Vec3.create(0, 0, 0)) const gl = getGLContext(canvas, { alpha: false, @@ -93,18 +99,18 @@ namespace Canvas3D { if (gl === null) { throw new Error('Could not create a WebGL rendering context') } - const ctx = createContext(gl) + const webgl = createContext(gl) - const scene = Scene.create(ctx) + const scene = Scene.create(webgl) const controls = TrackballControls.create(input, camera, {}) - const renderer = Renderer.create(ctx, camera, { clearColor: Color(0x000000) }) + const renderer = Renderer.create(webgl, camera, { clearColor: p.backgroundColor }) const pickScale = 1 const pickWidth = Math.round(canvas.width * pickScale) const pickHeight = Math.round(canvas.height * pickScale) - const objectPickTarget = createRenderTarget(ctx, pickWidth, pickHeight) - const instancePickTarget = createRenderTarget(ctx, pickWidth, pickHeight) - const groupPickTarget = createRenderTarget(ctx, pickWidth, pickHeight) + const objectPickTarget = createRenderTarget(webgl, pickWidth, pickHeight) + const instancePickTarget = createRenderTarget(webgl, pickWidth, pickHeight) + const groupPickTarget = createRenderTarget(webgl, pickWidth, pickHeight) let pickDirty = true let isPicking = false @@ -173,7 +179,7 @@ namespace Canvas3D { case 'pickInstance': instancePickTarget.bind(); break; case 'pickGroup': groupPickTarget.bind(); break; case 'draw': - ctx.unbindFramebuffer(); + webgl.unbindFramebuffer(); renderer.setViewport(0, 0, canvas.width, canvas.height); break; } @@ -219,7 +225,7 @@ namespace Canvas3D { render('pickObject', pickDirty) render('pickInstance', pickDirty) render('pickGroup', pickDirty) - ctx.gl.finish() + webgl.gl.finish() pickDirty = false } @@ -229,8 +235,8 @@ namespace Canvas3D { isPicking = true - x *= ctx.pixelRatio - y *= ctx.pixelRatio + x *= webgl.pixelRatio + y *= webgl.pixelRatio y = canvas.height - y // flip y const buffer = new Uint8Array(4) @@ -238,15 +244,15 @@ namespace Canvas3D { const yp = Math.round(y * pickScale) objectPickTarget.bind() - await ctx.readPixelsAsync(xp, yp, 1, 1, buffer) + await webgl.readPixelsAsync(xp, yp, 1, 1, buffer) const objectId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) instancePickTarget.bind() - await ctx.readPixels(xp, yp, 1, 1, buffer) + await webgl.readPixels(xp, yp, 1, 1, buffer) const instanceId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) groupPickTarget.bind() - await ctx.readPixels(xp, yp, 1, 1, buffer) + await webgl.readPixels(xp, yp, 1, 1, buffer) const groupId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) isPicking = false @@ -262,7 +268,7 @@ namespace Canvas3D { handleResize() return { - webgl: ctx, + webgl, center: (p: Vec3) => { Vec3.set(controls.target, p[0], p[1], p[2]) @@ -336,6 +342,13 @@ namespace Canvas3D { identified, didDraw, + get props() { + return { + cameraPosition: Vec3.clone(camera.position), + cameraMode: camera.mode, + backgroundColor: renderer.props.clearColor + } + }, get input() { return input }, diff --git a/src/mol-geo/geometry/color-data.ts b/src/mol-geo/geometry/color-data.ts index cc66f80c9edd161b5a518d38acab4be1f9faedc1..59c2a16686bd0a4a97ee1e3877f51995965482c4 100644 --- a/src/mol-geo/geometry/color-data.ts +++ b/src/mol-geo/geometry/color-data.ts @@ -6,11 +6,11 @@ import { ValueCell } from 'mol-util'; import { TextureImage, createTextureImage } from 'mol-gl/renderable/util'; -import { Color } from 'mol-util/color'; +import { Color, ColorMap } from 'mol-util/color'; import { Vec2, Vec3 } from 'mol-math/linear-algebra'; import { LocationIterator } from '../util/location-iterator'; import { NullLocation } from 'mol-model/location'; -import { LocationColor, ColorThemeProps, ColorTheme, ColorThemeName, ScaleLegend, TableLegend } from 'mol-theme/color'; +import { LocationColor, ColorThemeProps, ColorTheme, ColorThemeName, ScaleLegend, TableLegend, ColorScaleName, getColorScaleFromName } from 'mol-theme/color'; import { RuntimeContext } from 'mol-task'; import { getGranularity } from './geometry'; import { Structure } from 'mol-model/structure'; @@ -27,6 +27,8 @@ export type ColorData = { export interface ColorProps { colorTheme: ColorThemeName + colorList?: Color[] | ColorScaleName + colorMap?: ColorMap<any> colorDomain?: [number, number] colorValue?: Color colorFunction?: LocationColor, @@ -41,6 +43,10 @@ export function getColorThemeProps(props: ColorProps): ColorThemeProps { name: props.colorTheme } if (props.colorDomain !== undefined) p.domain = props.colorDomain + if (props.colorList !== undefined) { + p.list = typeof props.colorList === 'string' ? getColorScaleFromName(props.colorList) : props.colorList + } + if (props.colorMap !== undefined) p.map = props.colorMap if (props.colorValue !== undefined) p.value = props.colorValue if (props.structure !== undefined) p.structure = props.structure if (props.colorFunction !== undefined) p.color = props.colorFunction diff --git a/src/mol-geo/geometry/direct-volume/transfer-function.ts b/src/mol-geo/geometry/direct-volume/transfer-function.ts index 98f496f143517cebdb1345d5a7a48168ecb9b94b..1679daa27fe7867c4e128141509e5bdd362f4a41 100644 --- a/src/mol-geo/geometry/direct-volume/transfer-function.ts +++ b/src/mol-geo/geometry/direct-volume/transfer-function.ts @@ -29,7 +29,7 @@ export function createTransferFunctionTexture(controlPoints: ControlPoint[], tex ] const scale = ColorScale.create({ domain: [0, 1], - colors: ColorMatplotlib.viridis + list: ColorMatplotlib.viridis }) const n = 256 diff --git a/src/mol-geo/geometry/geometry.ts b/src/mol-geo/geometry/geometry.ts index a1e1e221eb5315ced13742d3db3bb1199d44a1ed..57df5ab488d3f3c0d6f006ca8a4cf15223d8de6a 100644 --- a/src/mol-geo/geometry/geometry.ts +++ b/src/mol-geo/geometry/geometry.ts @@ -10,14 +10,13 @@ import { RenderableState } from 'mol-gl/renderable'; import { ValueCell } from 'mol-util'; import { BaseValues } from 'mol-gl/renderable/schema'; import { Color } from 'mol-util/color'; -import { ColorThemeOptions, ColorThemeName } from 'mol-theme/color'; +import { ColorThemeOptions, ColorThemeName, ColorScaleOptions, ColorScaleName } from 'mol-theme/color'; import { LocationIterator } from '../util/location-iterator'; import { ColorType } from './color-data'; import { SizeType } from './size-data'; import { Lines } from './lines/lines'; -import { paramDefaultValues, RangeParam, BooleanParam, SelectParam, ColorParam, ValueParam } from 'mol-util/parameter' +import { paramDefaultValues, RangeParam, BooleanParam, SelectParam, ColorParam } from 'mol-util/parameter' import { DirectVolume } from './direct-volume/direct-volume'; -import { WebGLContext } from 'mol-gl/webgl/context'; // @@ -66,8 +65,8 @@ export namespace Geometry { useFog: BooleanParam('Use Fog', '', false), quality: SelectParam<VisualQuality>('Quality', '', 'auto', VisualQualityOptions), colorTheme: SelectParam<ColorThemeName>('Color Theme', '', 'uniform', ColorThemeOptions), + colorList: SelectParam<ColorScaleName>('Color Scale', '', 'default', ColorScaleOptions), colorValue: ColorParam('Color Value', '', Color(0xCCCCCC)), - webgl: ValueParam('WebGL Context', '', undefined as WebGLContext | undefined), } export const DefaultProps = paramDefaultValues(Params) export type Props = typeof DefaultProps diff --git a/src/mol-geo/util/marching-cubes/algorithm.ts b/src/mol-geo/util/marching-cubes/algorithm.ts index d58abc44f87cd0931485a462cac063bcf27b8b35..e9d9e4ad46ee87691bc4c9d34b01dfe8a476b071 100644 --- a/src/mol-geo/util/marching-cubes/algorithm.ts +++ b/src/mol-geo/util/marching-cubes/algorithm.ts @@ -105,9 +105,7 @@ class MarchingCubesComputation { } async run() { - await this.ctx.update({ message: 'Computing surface...', current: 0, max: this.size }); await this.doSlices(); - await this.ctx.update('Finalizing...'); } constructor(private ctx: RuntimeContext, builder: MarchinCubesBuilder<any>, params: MarchingCubesInputParams) { diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index 39e422e602689b06f7b258b87f47655bb57bc235..4234cc38fb50fc17c1b144e2750d4c2a28049e54 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -34,6 +34,7 @@ export interface RendererStats { interface Renderer { readonly stats: RendererStats + readonly props: RendererProps render: (scene: Scene, variant: RenderVariant) => void setViewport: (x: number, y: number, width: number, height: number) => void @@ -46,10 +47,10 @@ export const DefaultRendererProps = { clearColor: 0x000000 as Color, viewport: Viewport.create(0, 0, 0, 0) } -export type RendererProps = Partial<typeof DefaultRendererProps> +export type RendererProps = typeof DefaultRendererProps namespace Renderer { - export function create(ctx: WebGLContext, camera: Camera, props: RendererProps = {}): Renderer { + export function create(ctx: WebGLContext, camera: Camera, props: Partial<RendererProps> = {}): Renderer { const { gl } = ctx let { clearColor, viewport: _viewport } = { ...DefaultRendererProps, ...props } @@ -64,6 +65,7 @@ namespace Renderer { const fogColor = Vec3.create(0.0, 0.0, 0.0) function setClearColor(color: Color) { + clearColor = color const [ r, g, b ] = Color.toRgbNormalized(color) gl.clearColor(r, g, b, 1.0) } @@ -192,6 +194,12 @@ namespace Renderer { return createImageData(buffer, width, height) }, + get props() { + return { + clearColor, + viewport + } + }, get stats(): RendererStats { return { programCount: ctx.programCache.count, diff --git a/src/mol-math/geometry/gaussian-density.ts b/src/mol-math/geometry/gaussian-density.ts index fc89c5fe9491713933427a86905aef784ec5576f..91675ddc156b804814c7651fbfbe88daebd335eb 100644 --- a/src/mol-math/geometry/gaussian-density.ts +++ b/src/mol-math/geometry/gaussian-density.ts @@ -21,7 +21,6 @@ export const DefaultGaussianDensityProps = { radiusOffset: 0, smoothness: 1.5, useGpu: true, - webgl: undefined as WebGLContext | undefined } export type GaussianDensityProps = typeof DefaultGaussianDensityProps @@ -39,10 +38,11 @@ export function computeGaussianDensity(position: PositionData, box: Box3D, radiu }); } -export async function GaussianDensity(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps): Promise<DensityData> { +export async function GaussianDensity(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, webgl?: WebGLContext): Promise<DensityData> { if (props.useGpu) { if (!GaussianDensityGPU) throw 'GPU computation not supported on this platform'; - return await GaussianDensityGPU(ctx, position, box, radius, props) + if (!webgl) throw 'No WebGL context provided'; + return await GaussianDensityGPU(ctx, position, box, radius, props, webgl) } else { return await GaussianDensityCPU(ctx, position, box, radius, props) } diff --git a/src/mol-math/geometry/gaussian-density/gpu.ts b/src/mol-math/geometry/gaussian-density/gpu.ts index 32dda1527f3999e14aa5d04694d08a849a106f39..e14fb754a15fa825b4b1b98dcfda5593a076c65e 100644 --- a/src/mol-math/geometry/gaussian-density/gpu.ts +++ b/src/mol-math/geometry/gaussian-density/gpu.ts @@ -12,10 +12,10 @@ import { GaussianDensityProps, getDelta } from '../gaussian-density' import { OrderedSet } from 'mol-data/int' import { Vec3, Tensor, Mat4 } from '../../linear-algebra' import { GaussianDensityValues } from 'mol-gl/renderable/gaussian-density' -import { ValueCell, defaults } from 'mol-util' +import { ValueCell } from 'mol-util' import { RenderableState, Renderable } from 'mol-gl/renderable' import { createRenderable, createGaussianDensityRenderObject } from 'mol-gl/render-object' -import { WebGLContext, createContext, getGLContext } from 'mol-gl/webgl/context'; +import { WebGLContext } from 'mol-gl/webgl/context'; import { createTexture, Texture } from 'mol-gl/webgl/texture'; import { GLRenderingContext } from 'mol-gl/webgl/compat'; import { decodeIdRGB } from 'mol-geo/geometry/picking'; @@ -23,8 +23,7 @@ import { decodeIdRGB } from 'mol-geo/geometry/picking'; /** name for shared framebuffer used for gpu gaussian surface operations */ const FramebufferName = 'gaussian-density-gpu' -export async function GaussianDensityGPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps): Promise<DensityData> { - const webgl = defaults(props.webgl, getWebGLContext()) +export async function GaussianDensityGPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, webgl: WebGLContext): Promise<DensityData> { // always use texture2d when the gaussian density needs to be downloaded from the GPU, // it's faster than texture3d // console.time('GaussianDensityTexture2d') @@ -110,7 +109,7 @@ async function GaussianDensityTexture2d(ctx: RuntimeContext, webgl: WebGLContext setupGroupIdRendering(webgl, renderable) render(texture) - await ctx.update({ message: 'gpu gaussian density calculation' }); + if (ctx.shouldUpdate) await ctx.update({ message: 'gpu gaussian density calculation' }) await webgl.waitForGpuCommandsComplete() return { texture, scale: Vec3.inverse(Vec3.zero(), delta), bbox: expandedBox, dim } @@ -165,21 +164,6 @@ async function GaussianDensityTexture3d(ctx: RuntimeContext, webgl: WebGLContext // -let webglContext: WebGLContext -function getWebGLContext() { - if (webglContext) return webglContext - const canvas = document.createElement('canvas') - const gl = getGLContext(canvas, { - alpha: true, - antialias: false, - depth: false, - preserveDrawingBuffer: true - }) - if (!gl) throw new Error('Could not create a WebGL rendering context') - webglContext = createContext(gl) - return webglContext -} - async function prepareGaussianDensityData(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps) { const { resolution, radiusOffset } = props diff --git a/src/mol-model/structure/structure/unit.ts b/src/mol-model/structure/structure/unit.ts index bce4b286b1aa335ef0e8f6ec589d37161593cf70..fd41f3db12facc596554f41aacc7d8af0d36c489 100644 --- a/src/mol-model/structure/structure/unit.ts +++ b/src/mol-model/structure/structure/unit.ts @@ -20,6 +20,7 @@ import { getAtomicPolymerElements, getCoarsePolymerElements, getAtomicGapElement import { getNucleotideElements } from './util/nucleotide'; import { GaussianDensityProps, computeUnitGaussianDensityCached } from './unit/gaussian-density'; import { RuntimeContext } from 'mol-task'; +import { WebGLContext } from 'mol-gl/webgl/context'; // A building block of a structure that corresponds to an atomic or a coarse grained representation // 'conveniently grouped together'. @@ -182,8 +183,8 @@ namespace Unit { return this.model.atomicHierarchy.residueAtomSegments.index[this.elements[elementIndex]]; } - async computeGaussianDensity(props: GaussianDensityProps, ctx?: RuntimeContext) { - return computeUnitGaussianDensityCached(this, props, this.props.gaussianDensities, ctx); + async computeGaussianDensity(props: GaussianDensityProps, ctx: RuntimeContext, webgl?: WebGLContext) { + return computeUnitGaussianDensityCached(this, props, this.props.gaussianDensities, ctx, webgl); } constructor(id: number, invariantId: number, model: Model, elements: StructureElement.Set, conformation: SymmetryOperator.ArrayMapping, props: AtomicProperties) { @@ -271,8 +272,8 @@ namespace Unit { return this.kind === Kind.Spheres ? this.model.coarseConformation.spheres : this.model.coarseConformation.gaussians; } - async computeGaussianDensity(props: GaussianDensityProps, ctx?: RuntimeContext): Promise<DensityData> { - return computeUnitGaussianDensityCached(this as Unit.Spheres | Unit.Gaussians, props, this.props.gaussianDensities, ctx); // TODO get rid of casting + async computeGaussianDensity(props: GaussianDensityProps, ctx: RuntimeContext, webgl?: WebGLContext): Promise<DensityData> { + return computeUnitGaussianDensityCached(this as Unit.Spheres | Unit.Gaussians, props, this.props.gaussianDensities, ctx, webgl); // TODO get rid of casting } constructor(id: number, invariantId: number, model: Model, kind: K, elements: StructureElement.Set, conformation: SymmetryOperator.ArrayMapping, props: CoarseProperties) { diff --git a/src/mol-model/structure/structure/unit/gaussian-density.ts b/src/mol-model/structure/structure/unit/gaussian-density.ts index b7895e3def40aab3624de5784dfb76227297e1ec..66290495e89ffef7a61fccd29bdd6f2273369483 100644 --- a/src/mol-model/structure/structure/unit/gaussian-density.ts +++ b/src/mol-model/structure/structure/unit/gaussian-density.ts @@ -9,10 +9,10 @@ import { SizeTheme } from 'mol-theme/size'; import { GaussianDensity } from 'mol-math/geometry/gaussian-density'; import { Task, RuntimeContext } from 'mol-task'; import { DensityData } from 'mol-math/geometry'; -import { NumberParam, paramDefaultValues, BooleanParam, ValueParam } from 'mol-util/parameter'; -import { WebGLContext } from 'mol-gl/webgl/context'; +import { NumberParam, paramDefaultValues, BooleanParam } from 'mol-util/parameter'; import { GaussianDensityTexture } from 'mol-math/geometry/gaussian-density/gpu'; import { Texture } from 'mol-gl/webgl/texture'; +import { WebGLContext } from 'mol-gl/webgl/context'; export const GaussianDensityParams = { resolution: NumberParam('Resolution', '', 1, 0.1, 10, 0.1), @@ -20,7 +20,6 @@ export const GaussianDensityParams = { smoothness: NumberParam('Smoothness', '', 1.5, 0.5, 2.5, 0.1), useGpu: BooleanParam('Use GPU', '', true), ignoreCache: BooleanParam('Ignore Cache', '', false), - webgl: ValueParam('WebGL Context', '', undefined as WebGLContext | undefined), } export const DefaultGaussianDensityProps = paramDefaultValues(GaussianDensityParams) export type GaussianDensityProps = typeof DefaultGaussianDensityProps @@ -53,27 +52,25 @@ function getConformationAndRadius(unit: Unit) { return { position, radius } } -export function computeUnitGaussianDensity(unit: Unit, props: GaussianDensityProps) { +export function computeUnitGaussianDensity(unit: Unit, props: GaussianDensityProps, webgl?: WebGLContext) { const { position, radius } = getConformationAndRadius(unit) return Task.create('Gaussian Density', async ctx => { - return await GaussianDensity(ctx, position, unit.lookup3d.boundary.box, radius, props); + return await GaussianDensity(ctx, position, unit.lookup3d.boundary.box, radius, props, webgl); }); } -export function computeUnitGaussianDensityTexture(unit: Unit, props: GaussianDensityProps, texture?: Texture) { - const webgl = props.webgl - if (!webgl) throw new Error('nned webgl context for computeUnitGaussianDensityTexture') +export function computeUnitGaussianDensityTexture(unit: Unit, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) { const { position, radius } = getConformationAndRadius(unit) return Task.create('Gaussian Density', async ctx => { return await GaussianDensityTexture(ctx, webgl, position, unit.lookup3d.boundary.box, radius, props, texture); }); } -export async function computeUnitGaussianDensityCached(unit: Unit, props: GaussianDensityProps, cache: Map<string, DensityData>, ctx?: RuntimeContext) { +export async function computeUnitGaussianDensityCached(unit: Unit, props: GaussianDensityProps, cache: Map<string, DensityData>, ctx: RuntimeContext, webgl?: WebGLContext) { const key = `${props.radiusOffset}|${props.resolution}|${props.smoothness}` let density = cache.get(key) if (density && !props.ignoreCache) return density - density = ctx ? await computeUnitGaussianDensity(unit, props).runInContext(ctx) : await computeUnitGaussianDensity(unit, props).run() + density = await computeUnitGaussianDensity(unit, props, webgl).runInContext(ctx) if (!props.ignoreCache) cache.set(key, density) return density } \ No newline at end of file diff --git a/src/mol-plugin/state/transforms/visuals.ts b/src/mol-plugin/state/transforms/visuals.ts index 9da25b631f8e6a6d03a2408c82d5fcc8c9d17a6b..f03e8bdc247dcf84d95b75ce2f31d88413e9cd48 100644 --- a/src/mol-plugin/state/transforms/visuals.ts +++ b/src/mol-plugin/state/transforms/visuals.ts @@ -18,13 +18,13 @@ export const CreateStructureRepresentation = PluginStateTransform.Create<SO.Stru apply({ a, params }) { return Task.create('Structure Representation', async ctx => { const repr = CartoonRepresentation(); - await repr.createOrUpdate({ ...DefaultCartoonProps }, a.data).runInContext(ctx); + await repr.createOrUpdate({ /* TODO add `webgl: WebGLContext` */ }, { ...DefaultCartoonProps }, a.data).runInContext(ctx); return new SO.StructureRepresentation3D({ label: 'Cartoon' }, { repr }); }); }, update({ a, b }) { return Task.create('Structure Representation', async ctx => { - await b.data.repr.createOrUpdate(b.data.repr.props, a.data).runInContext(ctx); + await b.data.repr.createOrUpdate({ /* TODO add `webgl: WebGLContext` */ }, b.data.repr.props, a.data).runInContext(ctx); return Transformer.UpdateResult.Updated; }); } diff --git a/src/mol-repr/index.ts b/src/mol-repr/index.ts index 83a39d2e0423353e61c93229d6c01395b6962e18..a293cf595c352db3bd053bf82228a0e3080f8be6 100644 --- a/src/mol-repr/index.ts +++ b/src/mol-repr/index.ts @@ -10,18 +10,24 @@ import { PickingId } from '../mol-geo/geometry/picking'; import { Loci, isEmptyLoci, EmptyLoci } from 'mol-model/loci'; import { MarkerAction } from '../mol-geo/geometry/marker-data'; import { Params, MultiSelectParam } from 'mol-util/parameter'; +import { WebGLContext } from 'mol-gl/webgl/context'; +// import { ColorTheme } from 'mol-theme/color'; // export interface RepresentationProps { // visuals?: string[] // } export type RepresentationProps = { [k: string]: any } +export interface RepresentationContext { + webgl?: WebGLContext +} + export interface Representation<D, P extends RepresentationProps = {}> { readonly label: string readonly params: Params readonly renderObjects: ReadonlyArray<RenderObject> readonly props: Readonly<P> - createOrUpdate: (props?: Partial<P>, data?: D) => Task<void> + createOrUpdate: (ctx: RepresentationContext, props?: Partial<P>, data?: D) => Task<void> getLoci: (pickingId: PickingId) => Loci mark: (loci: Loci, action: MarkerAction) => boolean destroy: () => void @@ -60,17 +66,17 @@ export namespace Representation { reprList.forEach(r => Object.assign(props, r.props)) return props as P }, - createOrUpdate: (props: Partial<P> = {}, data?: D) => { + createOrUpdate: (ctx: RepresentationContext, props: Partial<P> = {}, data?: D) => { if (data) currentData = data // const qualityProps = getQualityProps(Object.assign({}, currentProps, props), structure) // currentProps = Object.assign({}, DefaultCartoonProps, currentProps, props, qualityProps) currentProps = Object.assign({}, defaultProps, currentProps, props) const { visuals } = currentProps - return Task.create(`Creating '${label}' representation`, async ctx => { + return Task.create(`Creating '${label}' representation`, async runtime => { for (let i = 0, il = reprList.length; i < il; ++i) { if (!visuals || visuals.includes(i.toString())) { - await reprList[i].createOrUpdate(currentProps, currentData).runInContext(ctx) + await reprList[i].createOrUpdate(ctx, currentProps, currentData).runInContext(runtime) } } }) @@ -98,9 +104,17 @@ export namespace Representation { } } +// + +export interface VisualContext extends RepresentationContext { + runtime: RuntimeContext, + // TODO + // colorTheme: ColorTheme, +} + export interface Visual<D, P extends RepresentationProps> { readonly renderObject: RenderObject | undefined - createOrUpdate: (ctx: RuntimeContext, props?: Partial<P>, data?: D) => Promise<void> + createOrUpdate: (ctx: VisualContext, props?: Partial<P>, data?: D) => Promise<void> getLoci: (pickingId: PickingId) => Loci mark: (loci: Loci, action: MarkerAction) => boolean destroy: () => void diff --git a/src/mol-repr/shape/index.ts b/src/mol-repr/shape/index.ts index a953f8ecc75edb35c2504a38412bfe3372fea80c..209f2b2aa6142cb2c2d2fda564ab3cee6ea346d8 100644 --- a/src/mol-repr/shape/index.ts +++ b/src/mol-repr/shape/index.ts @@ -6,7 +6,7 @@ import { Task } from 'mol-task' import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'; -import { RepresentationProps, Representation } from '..'; +import { RepresentationProps, Representation, RepresentationContext } from '..'; import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; import { ValueCell } from 'mol-util'; import { ColorThemeName, ColorThemeOptions } from 'mol-theme/color'; @@ -38,11 +38,11 @@ export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation let _shape: Shape let currentProps: P - function createOrUpdate(props: Partial<P> = {}, shape?: Shape) { + function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, shape?: Shape) { currentProps = Object.assign({}, DefaultShapeProps, currentProps, props) if (shape) _shape = shape - return Task.create('ShapeRepresentation.create', async ctx => { + return Task.create('ShapeRepresentation.create', async runtime => { renderObjects.length = 0 if (!_shape) return @@ -51,7 +51,7 @@ export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation const locationIt = ShapeGroupIterator.fromShape(_shape) const transform = createIdentityTransform() - const values = await Mesh.createValues(ctx, mesh, transform, locationIt, currentProps) + const values = await Mesh.createValues(runtime, mesh, transform, locationIt, currentProps) const state = createRenderableState(currentProps) _renderObject = createMeshRenderObject(values, state) diff --git a/src/mol-repr/structure/complex-representation.ts b/src/mol-repr/structure/complex-representation.ts index 77dc1ac957bf8bdc3f8697fe096748ae47746ed2..62d828bb2c0d8b783c8c87dd58c21dd1eaefe374 100644 --- a/src/mol-repr/structure/complex-representation.ts +++ b/src/mol-repr/structure/complex-representation.ts @@ -12,17 +12,18 @@ import { StructureProps, StructureRepresentation, StructureParams } from './inde import { ComplexVisual } from './complex-visual'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; +import { RepresentationContext } from 'mol-repr'; export function ComplexRepresentation<P extends StructureProps>(label: string, visualCtor: () => ComplexVisual<P>): StructureRepresentation<P> { let visual: ComplexVisual<P> | undefined let _props: P - function createOrUpdate(props: Partial<P> = {}, structure?: Structure) { + function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, structure?: Structure) { _props = Object.assign({}, _props, props) - return Task.create('Creating or updating ComplexRepresentation', async ctx => { + return Task.create('Creating or updating ComplexRepresentation', async runtime => { if (!visual) visual = visualCtor() - await visual.createOrUpdate(ctx, _props, structure) + await visual.createOrUpdate({ ...ctx, runtime }, _props, structure) }); } diff --git a/src/mol-repr/structure/complex-visual.ts b/src/mol-repr/structure/complex-visual.ts index 4e7acbf7577d1647079ff316b606b4d2392cacc6..78856279772da9b6c2be60afd55140b69b9be298 100644 --- a/src/mol-repr/structure/complex-visual.ts +++ b/src/mol-repr/structure/complex-visual.ts @@ -5,9 +5,8 @@ */ import { Structure } from 'mol-model/structure'; -import { Visual } from '..'; +import { Visual, VisualContext } from '..'; import { MeshRenderObject, LinesRenderObject, PointsRenderObject, DirectVolumeRenderObject } from 'mol-gl/render-object'; -import { RuntimeContext } from 'mol-task'; import { createComplexMeshRenderObject, UnitKind, UnitKindOptions } from './visual/util/common'; import { StructureProps, StructureMeshParams, StructureParams } from './index'; import { deepEqual, ValueCell } from 'mol-util'; @@ -37,7 +36,7 @@ type ComplexRenderObject = MeshRenderObject | LinesRenderObject | PointsRenderOb interface ComplexVisualBuilder<P extends ComplexProps, G extends Geometry> { defaultProps: P - createGeometry(ctx: RuntimeContext, structure: Structure, props: P, geometry?: G): Promise<G> + createGeometry(ctx: VisualContext, structure: Structure, props: P, geometry?: G): Promise<G> createLocationIterator(structure: Structure): LocationIterator getLoci(pickingId: PickingId, structure: Structure, id: number): Loci mark(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean): boolean, @@ -46,7 +45,7 @@ interface ComplexVisualBuilder<P extends ComplexProps, G extends Geometry> { interface ComplexVisualGeometryBuilder<P extends ComplexProps, G extends Geometry> extends ComplexVisualBuilder<P, G> { createEmptyGeometry(geometry?: G): G - createRenderObject(ctx: RuntimeContext, structure: Structure, geometry: Geometry, locationIt: LocationIterator, currentProps: P): Promise<ComplexRenderObject> + createRenderObject(ctx: VisualContext, structure: Structure, geometry: Geometry, locationIt: LocationIterator, currentProps: P): Promise<ComplexRenderObject> updateValues(values: RenderableValues, newProps: P): void } @@ -62,7 +61,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual let locationIt: LocationIterator let conformationHash: number - async function create(ctx: RuntimeContext, structure: Structure, props: Partial<P> = {}) { + async function create(ctx: VisualContext, structure: Structure, props: Partial<P> = {}) { currentProps = Object.assign({}, defaultProps, props, { structure }) currentStructure = structure @@ -73,7 +72,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual renderObject = await createRenderObject(ctx, structure, geometry, locationIt, currentProps) } - async function update(ctx: RuntimeContext, props: Partial<P>) { + async function update(ctx: VisualContext, props: Partial<P>) { const newProps = Object.assign({}, currentProps, props, { structure: currentStructure }) if (!renderObject) return false @@ -102,12 +101,12 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual if (updateState.updateSize) { // not all geometries have size data, so check here if ('uSize' in renderObject.values) { - await createSizes(ctx, locationIt, newProps, renderObject.values) + await createSizes(ctx.runtime, locationIt, newProps, renderObject.values) } } if (updateState.updateColor) { - await createColors(ctx, locationIt, newProps, renderObject.values) + await createColors(ctx.runtime, locationIt, newProps, renderObject.values) } updateValues(renderObject.values, newProps) @@ -119,7 +118,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual return { get renderObject () { return renderObject }, - async createOrUpdate(ctx: RuntimeContext, props: Partial<P> = {}, structure?: Structure) { + async createOrUpdate(ctx: VisualContext, props: Partial<P> = {}, structure?: Structure) { if (!structure && !currentStructure) { throw new Error('missing structure') } else if (structure && (!currentStructure || !renderObject)) { diff --git a/src/mol-repr/structure/units-representation.ts b/src/mol-repr/structure/units-representation.ts index d0694f68ab48a9c4a9ead72c3ae11904c602032d..50e350f5cbef9a0c40fec28635278495f8fbc30e 100644 --- a/src/mol-repr/structure/units-representation.ts +++ b/src/mol-repr/structure/units-representation.ts @@ -8,7 +8,7 @@ import { Structure, Unit } from 'mol-model/structure'; import { Task } from 'mol-task' import { RenderObject } from 'mol-gl/render-object'; -import { RepresentationProps, Visual } from '..'; +import { RepresentationProps, Visual, RepresentationContext } from '..'; import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci'; import { StructureGroup } from './units-visual'; import { StructureProps, StructureParams, StructureRepresentation } from './index'; @@ -24,10 +24,10 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis let _structure: Structure let _groups: ReadonlyArray<Unit.SymmetryGroup> - function createOrUpdate(props: Partial<P> = {}, structure?: Structure) { + function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, structure?: Structure) { _props = Object.assign({}, _props, props) - return Task.create('Creating or updating UnitsRepresentation', async ctx => { + return Task.create('Creating or updating UnitsRepresentation', async runtime => { if (!_structure && !structure) { throw new Error('missing structure') } else if (structure && !_structure) { @@ -37,7 +37,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis for (let i = 0; i < _groups.length; i++) { const group = _groups[i]; const visual = visualCtor() - await visual.createOrUpdate(ctx, _props, { group, structure }) + await visual.createOrUpdate({ ...ctx, runtime }, _props, { group, structure }) visuals.set(group.hashCode, { visual, group }) } } else if (structure && _structure.hashCode !== structure.hashCode) { @@ -53,13 +53,13 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis const visualGroup = oldVisuals.get(group.hashCode) if (visualGroup) { const { visual } = visualGroup - await visual.createOrUpdate(ctx, _props, { group, structure }) + await visual.createOrUpdate({ ...ctx, runtime }, _props, { group, structure }) visuals.set(group.hashCode, { visual, group }) oldVisuals.delete(group.hashCode) } else { // newGroups.push(group) const visual = visualCtor() - await visual.createOrUpdate(ctx, _props, { group, structure }) + await visual.createOrUpdate({ ...ctx, runtime }, _props, { group, structure }) visuals.set(group.hashCode, { visual, group }) } } @@ -71,7 +71,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis // oldVisuals.forEach(({ visual }) => unusedVisuals.push(visual)) // newGroups.forEach(async group => { // const visual = unusedVisuals.pop() || visualCtor() - // await visual.createOrUpdate(ctx, _props, group) + // await visual.createOrUpdate({ ...ctx, runtime }, _props, group) // visuals.set(group.hashCode, { visual, group }) // }) // unusedVisuals.forEach(visual => visual.destroy()) @@ -85,7 +85,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis const group = _groups[i]; const visualGroup = visuals.get(group.hashCode) if (visualGroup) { - await visualGroup.visual.createOrUpdate(ctx, _props, { group, structure }) + await visualGroup.visual.createOrUpdate({ ...ctx, runtime }, _props, { group, structure }) visualGroup.group = group } else { throw new Error(`expected to find visual for hashCode ${group.hashCode}`) @@ -98,7 +98,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis visuals.forEach(({ visual, group }) => visualsList.push([ visual, group ])) for (let i = 0, il = visualsList.length; i < il; ++i) { const [ visual, group ] = visualsList[i] - await visual.createOrUpdate(ctx, _props, { group, structure: _structure }) + await visual.createOrUpdate({ ...ctx, runtime }, _props, { group, structure: _structure }) } } if (structure) _structure = structure diff --git a/src/mol-repr/structure/units-visual.ts b/src/mol-repr/structure/units-visual.ts index 641d232f6fe2e09783a2e4be3a88891109b01c3d..7f8ef19694e4f25bfb5362831550a9b2e8836a55 100644 --- a/src/mol-repr/structure/units-visual.ts +++ b/src/mol-repr/structure/units-visual.ts @@ -5,9 +5,8 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { RepresentationProps, Visual } from '../'; +import { RepresentationProps, Visual, VisualContext } from '../'; import { StructureMeshParams, StructurePointsParams, StructureLinesParams, StructureDirectVolumeParams, StructureParams } from './index'; -import { RuntimeContext } from 'mol-task'; import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci'; import { MeshRenderObject, PointsRenderObject, LinesRenderObject, DirectVolumeRenderObject } from 'mol-gl/render-object'; import { createUnitsMeshRenderObject, createUnitsPointsRenderObject, createUnitsTransform, createUnitsLinesRenderObject, createUnitsDirectVolumeRenderObject, UnitKind, UnitKindOptions, includesUnitKind } from './visual/util/common'; @@ -49,7 +48,7 @@ type UnitsRenderObject = MeshRenderObject | LinesRenderObject | PointsRenderObje interface UnitsVisualBuilder<P extends UnitsProps, G extends Geometry> { defaultProps: P - createGeometry(ctx: RuntimeContext, unit: Unit, structure: Structure, props: P, geometry?: G): Promise<G> + createGeometry(ctx: VisualContext, unit: Unit, structure: Structure, props: P, geometry?: G): Promise<G> createLocationIterator(group: Unit.SymmetryGroup): LocationIterator getLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number): Loci mark(loci: Loci, group: Unit.SymmetryGroup, apply: (interval: Interval) => boolean): boolean @@ -58,7 +57,7 @@ interface UnitsVisualBuilder<P extends UnitsProps, G extends Geometry> { interface UnitsVisualGeometryBuilder<P extends UnitsProps, G extends Geometry> extends UnitsVisualBuilder<P, G> { createEmptyGeometry(geometry?: G): G - createRenderObject(ctx: RuntimeContext, group: Unit.SymmetryGroup, geometry: Geometry, locationIt: LocationIterator, currentProps: P): Promise<UnitsRenderObject> + createRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, geometry: Geometry, locationIt: LocationIterator, currentProps: P): Promise<UnitsRenderObject> updateValues(values: RenderableValues, newProps: P): void } @@ -75,7 +74,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu let locationIt: LocationIterator let currentConformationId: UUID - async function create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: Partial<P> = {}) { + async function create(ctx: VisualContext, group: Unit.SymmetryGroup, props: Partial<P> = {}) { currentProps = Object.assign({}, defaultProps, props, { structure: currentStructure }) currentGroup = group @@ -90,7 +89,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu renderObject = await createRenderObject(ctx, group, geometry, locationIt, currentProps) } - async function update(ctx: RuntimeContext, props: Partial<P> = {}) { + async function update(ctx: VisualContext, props: Partial<P> = {}) { if (!renderObject) return const newProps = Object.assign({}, currentProps, props, { structure: currentStructure }) @@ -132,12 +131,12 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu if (updateState.updateSize) { // not all geometries have size data, so check here if ('uSize' in renderObject.values) { - await createSizes(ctx, locationIt, newProps, renderObject.values) + await createSizes(ctx.runtime, locationIt, newProps, renderObject.values) } } if (updateState.updateColor) { - await createColors(ctx, locationIt, newProps, renderObject.values) + await createColors(ctx.runtime, locationIt, newProps, renderObject.values) } updateValues(renderObject.values, newProps) @@ -148,7 +147,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu return { get renderObject () { return renderObject }, - async createOrUpdate(ctx: RuntimeContext, props: Partial<P> = {}, structureGroup?: StructureGroup) { + async createOrUpdate(ctx: VisualContext, props: Partial<P> = {}, structureGroup?: StructureGroup) { if (structureGroup) currentStructure = structureGroup.structure const group = structureGroup ? structureGroup.group : undefined if (!group && !currentGroup) { diff --git a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts index 8babf03f724fb46b27db2e0a4359956aab8e4a94..0b064012b8c56b7c9db6611e3f1524edf065a7b4 100644 --- a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts @@ -5,7 +5,6 @@ */ import { Structure, Link, StructureElement } from 'mol-model/structure'; -import { RuntimeContext } from 'mol-task' import { Loci, EmptyLoci } from 'mol-model/loci'; import { Vec3 } from 'mol-math/linear-algebra'; import { createLinkCylinderMesh, LinkCylinderProps, LinkCylinderParams } from './util/link'; @@ -20,6 +19,7 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { VisualUpdateState } from '../../util'; +import { VisualContext } from 'mol-repr'; // TODO create seperate visual // for (let i = 0, il = carbohydrates.terminalLinks.length; i < il; ++i) { @@ -35,7 +35,7 @@ import { VisualUpdateState } from '../../util'; const radiusFactor = 0.3 -async function createCarbohydrateLinkCylinderMesh(ctx: RuntimeContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { +async function createCarbohydrateLinkCylinderMesh(ctx: VisualContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { const { links, elements } = structure.carbohydrates const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue }) const location = StructureElement.create() diff --git a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts index 806fbd4dd35ce671beb618f44421725660902243..ddbd3215d3c7c9c4f9a9d30a9510b43d9bd572fa 100644 --- a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts +++ b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts @@ -10,7 +10,6 @@ import { OctagonalPyramid, PerforatedOctagonalPyramid } from 'mol-geo/primitive/ import { Star } from 'mol-geo/primitive/star'; import { Octahedron, PerforatedOctahedron } from 'mol-geo/primitive/octahedron'; import { DiamondPrism, PentagonalPrism, HexagonalPrism } from 'mol-geo/primitive/prism'; -import { RuntimeContext } from 'mol-task'; import { Structure, StructureElement } from 'mol-model/structure'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; @@ -25,6 +24,7 @@ import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { OrderedSet, Interval } from 'mol-data/int'; import { EmptyLoci, Loci } from 'mol-model/loci'; +import { VisualContext } from 'mol-repr'; const t = Mat4.identity() const sVec = Vec3.zero() @@ -44,7 +44,7 @@ const diamondPrism = DiamondPrism() const pentagonalPrism = PentagonalPrism() const hexagonalPrism = HexagonalPrism() -async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Structure, props: CarbohydrateSymbolProps, mesh?: Mesh) { +async function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Structure, props: CarbohydrateSymbolProps, mesh?: Mesh) { const builder = MeshBuilder.create(256, 128, mesh) const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue }) @@ -138,8 +138,8 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru break } - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Carbohydrate symbols', current: i, max: n }); + if (i % 10000 === 0 && ctx.runtime.shouldUpdate) { + await ctx.runtime.update({ message: 'Carbohydrate symbols', current: i, max: n }); } } diff --git a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts index e71655c2a555c7d0f80dfbbf993fc9f066d102d8..190565acb8ecba70588c608fbaf1822fcf4d50c1 100644 --- a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts +++ b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts @@ -7,7 +7,6 @@ import { Link, Structure, StructureElement } from 'mol-model/structure'; import { ComplexVisual } from '../index'; import { VisualUpdateState } from '../../util'; -import { RuntimeContext } from 'mol-task' import { LinkCylinderProps, createLinkCylinderMesh, LinkCylinderParams } from './util/link'; import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; @@ -20,8 +19,9 @@ import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; +import { VisualContext } from 'mol-repr'; -async function createCrossLinkRestraintCylinderMesh(ctx: RuntimeContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { +async function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { const crossLinks = structure.crossLinkRestraints if (!crossLinks.count) return Mesh.createEmpty(mesh) diff --git a/src/mol-repr/structure/visual/element-point.ts b/src/mol-repr/structure/visual/element-point.ts index d770bb0af5b2d42da434b1e9ed398f3703c5f870..c0b7ebb436024bd2cc0508021ebe0401d934e7a6 100644 --- a/src/mol-repr/structure/visual/element-point.ts +++ b/src/mol-repr/structure/visual/element-point.ts @@ -5,7 +5,6 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { RuntimeContext } from 'mol-task' import { UnitsVisual } from '../index'; import { VisualUpdateState } from '../../util'; import { getElementLoci, StructureElementIterator, markElement } from './util/element'; @@ -15,6 +14,7 @@ import { UnitsPointsVisual, UnitsPointsParams } from '../units-visual'; import { SelectParam, NumberParam, BooleanParam, paramDefaultValues } from 'mol-util/parameter'; import { Points } from 'mol-geo/geometry/points/points'; import { PointsBuilder } from 'mol-geo/geometry/points/points-builder'; +import { VisualContext } from 'mol-repr'; export const ElementPointParams = { ...UnitsPointsParams, @@ -27,7 +27,7 @@ export type ElementPointProps = typeof DefaultElementPointProps // TODO size -export async function createElementPoint(ctx: RuntimeContext, unit: Unit, structure: Structure, props: ElementPointProps, points: Points) { +export async function createElementPoint(ctx: VisualContext, unit: Unit, structure: Structure, props: ElementPointProps, points: Points) { const elements = unit.elements const n = elements.length const builder = PointsBuilder.create(n, n / 10, points) @@ -39,8 +39,8 @@ export async function createElementPoint(ctx: RuntimeContext, unit: Unit, struct pos(elements[i], p) builder.add(p[0], p[1], p[2], i) - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Creating points', current: i, max: n }); + if (i % 10000 === 0 && ctx.runtime.shouldUpdate) { + await ctx.runtime.update({ message: 'Creating points', current: i, max: n }); } } return builder.getPoints() diff --git a/src/mol-repr/structure/visual/gaussian-density-point.ts b/src/mol-repr/structure/visual/gaussian-density-point.ts index c4bfbc40208c7206a085bb865febfd626b981075..f14268e78eebe8ea5b51439a9b4746479d790310 100644 --- a/src/mol-repr/structure/visual/gaussian-density-point.ts +++ b/src/mol-repr/structure/visual/gaussian-density-point.ts @@ -5,7 +5,6 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { RuntimeContext } from 'mol-task' import { UnitsVisual } from '../index'; import { VisualUpdateState } from '../../util'; import { StructureElementIterator } from './util/element'; @@ -17,6 +16,7 @@ import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure import { paramDefaultValues, SelectParam, NumberParam, BooleanParam } from 'mol-util/parameter'; import { Points } from 'mol-geo/geometry/points/points'; import { PointsBuilder } from 'mol-geo/geometry/points/points-builder'; +import { VisualContext } from 'mol-repr'; export const GaussianDensityPointParams = { ...UnitsPointsParams, @@ -28,8 +28,8 @@ export const GaussianDensityPointParams = { export const DefaultGaussianDensityPointProps = paramDefaultValues(GaussianDensityPointParams) export type GaussianDensityPointProps = typeof DefaultGaussianDensityPointProps -export async function createGaussianDensityPoint(ctx: RuntimeContext, unit: Unit, structure: Structure, props: GaussianDensityProps, points?: Points) { - const { transform, field: { space, data } } = await unit.computeGaussianDensity(props, ctx) +export async function createGaussianDensityPoint(ctx: VisualContext, unit: Unit, structure: Structure, props: GaussianDensityProps, points?: Points) { + const { transform, field: { space, data } } = await unit.computeGaussianDensity(props, ctx.runtime, ctx.webgl) const { dimensions, get } = space const [ xn, yn, zn ] = dimensions @@ -48,8 +48,8 @@ export async function createGaussianDensityPoint(ctx: RuntimeContext, unit: Unit Vec3.transformMat4(p, p, transform) builder.add(p[0], p[1], p[2], i) } - if (i % 100000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Creating density points', current: i, max: n }); + if (i % 100000 === 0 && ctx.runtime.shouldUpdate) { + await ctx.runtime.update({ message: 'Creating density points', current: i, max: n }); } ++i } diff --git a/src/mol-repr/structure/visual/gaussian-density-volume.ts b/src/mol-repr/structure/visual/gaussian-density-volume.ts index 4179da8c11a01950daaf31575f434e9421c17a9e..e0b96b1f9c25c7cf092fa22d9e6284fddb5989c0 100644 --- a/src/mol-repr/structure/visual/gaussian-density-volume.ts +++ b/src/mol-repr/structure/visual/gaussian-density-volume.ts @@ -7,20 +7,20 @@ import { Unit, Structure } from 'mol-model/structure'; import { UnitsVisual } from '../index'; import { VisualUpdateState } from '../../util'; -import { RuntimeContext } from 'mol-task' import { UnitsDirectVolumeVisual, UnitsDirectVolumeParams } from '../units-visual'; import { StructureElementIterator, getElementLoci, markElement } from './util/element'; import { GaussianDensityProps, GaussianDensityParams, computeUnitGaussianDensityTexture } from 'mol-model/structure/structure/unit/gaussian-density'; import { paramDefaultValues } from 'mol-util/parameter'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; +import { VisualContext } from 'mol-repr'; -async function createGaussianDensityVolume(ctx: RuntimeContext, unit: Unit, structure: Structure, props: GaussianDensityProps, directVolume?: DirectVolume): Promise<DirectVolume> { - const { webgl } = props - if (webgl === undefined) throw new Error('createGaussianDensityVolume requires `webgl` in props') +async function createGaussianDensityVolume(ctx: VisualContext, unit: Unit, structure: Structure, props: GaussianDensityProps, directVolume?: DirectVolume): Promise<DirectVolume> { + const { runtime, webgl } = ctx + if (webgl === undefined) throw new Error('createGaussianDensityVolume requires `webgl` object in VisualContext') const p = { ...props, useGpu: true } const oldTexture = directVolume ? directVolume.gridTexture.ref.value : undefined - const densityTextureData = await computeUnitGaussianDensityTexture(unit, p, oldTexture).runInContext(ctx) + const densityTextureData = await computeUnitGaussianDensityTexture(unit, p, webgl, oldTexture).runInContext(runtime) const { transform, texture, bbox, gridDimension } = densityTextureData return DirectVolume.create(bbox, gridDimension, transform, texture, directVolume) diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts index 7982008eb57523049b55eb80474a830e4d558f1e..3e983cff2dc9e2d5657d932e98839e04a2b789af 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts @@ -7,24 +7,24 @@ import { Unit, Structure } from 'mol-model/structure'; import { UnitsVisual } from '../index'; import { VisualUpdateState } from '../../util'; -import { RuntimeContext } from 'mol-task' import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; import { StructureElementIterator, getElementLoci, markElement } from './util/element'; import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure/structure/unit/gaussian-density'; import { paramDefaultValues } from 'mol-util/parameter'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm'; +import { VisualContext } from 'mol-repr'; -async function createGaussianSurfaceMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: GaussianDensityProps, mesh?: Mesh): Promise<Mesh> { +async function createGaussianSurfaceMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: GaussianDensityProps, mesh?: Mesh): Promise<Mesh> { const { smoothness } = props - const { transform, field, idField } = await unit.computeGaussianDensity(props, ctx) + const { transform, field, idField } = await unit.computeGaussianDensity(props, ctx.runtime, ctx.webgl) const params = { isoLevel: Math.exp(-smoothness), scalarField: field, idField } - const surface = await computeMarchingCubesMesh(params, mesh).runAsChild(ctx) + const surface = await computeMarchingCubesMesh(params, mesh).runAsChild(ctx.runtime) Mesh.transformImmediate(surface, transform) Mesh.computeNormalsImmediate(surface) diff --git a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts index beb21243742d43009bf4c8ae9600ae6978b11ff4..1b3e3033144751186ca6637b197f7048ff6d9822 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts @@ -7,7 +7,6 @@ import { Unit, Structure } from 'mol-model/structure'; import { UnitsVisual } from '../index'; import { VisualUpdateState } from '../../util'; -import { RuntimeContext } from 'mol-task' import { UnitsLinesVisual, UnitsLinesParams } from '../units-visual'; import { StructureElementIterator, getElementLoci, markElement } from './util/element'; import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure/structure/unit/gaussian-density'; @@ -15,17 +14,18 @@ import { paramDefaultValues, SelectParam, NumberParam, BooleanParam } from 'mol- import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { Lines } from 'mol-geo/geometry/lines/lines'; import { computeMarchingCubesLines } from 'mol-geo/util/marching-cubes/algorithm'; +import { VisualContext } from 'mol-repr'; -async function createGaussianWireframe(ctx: RuntimeContext, unit: Unit, structure: Structure, props: GaussianDensityProps, lines?: Lines): Promise<Lines> { +async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure: Structure, props: GaussianDensityProps, lines?: Lines): Promise<Lines> { const { smoothness } = props - const { transform, field, idField } = await unit.computeGaussianDensity(props, ctx) + const { transform, field, idField } = await unit.computeGaussianDensity(props, ctx.runtime) const params = { isoLevel: Math.exp(-smoothness), scalarField: field, idField } - const wireframe = await computeMarchingCubesLines(params, lines).runAsChild(ctx) + const wireframe = await computeMarchingCubesLines(params, lines).runAsChild(ctx.runtime) Lines.transformImmediate(wireframe, transform) diff --git a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts index 4f2c957086e467c4abf67579331bbb4c2c396131..76a51d6805d4d925a91c2f2d2fa3e20356d02f83 100644 --- a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts @@ -7,7 +7,6 @@ import { Link, Structure, StructureElement } from 'mol-model/structure'; import { ComplexVisual } from '../index'; import { VisualUpdateState } from '../../util'; -import { RuntimeContext } from 'mol-task' import { LinkCylinderProps, createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link'; import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; @@ -18,8 +17,9 @@ import { BitFlags } from 'mol-util'; import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { PickingId } from 'mol-geo/geometry/picking'; +import { VisualContext } from 'mol-repr'; -async function createInterUnitLinkCylinderMesh(ctx: RuntimeContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { +async function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { const links = structure.links const { bondCount, bonds } = links diff --git a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts index 97179ec276ec08c01494f8569a38bdb1882095ed..b4239034cf5e80e3c974b7cf5db1655b9fbd6bd3 100644 --- a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts @@ -8,7 +8,6 @@ import { Unit, Link, StructureElement, Structure } from 'mol-model/structure'; import { UnitsVisual } from '../index'; import { VisualUpdateState } from '../../util'; -import { RuntimeContext } from 'mol-task' import { LinkCylinderProps, createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link'; import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; @@ -19,8 +18,9 @@ import { BitFlags } from 'mol-util'; import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { PickingId } from 'mol-geo/geometry/picking'; +import { VisualContext } from 'mol-repr'; -async function createIntraUnitLinkCylinderMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { +async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue, factor: props.sizeFactor }) diff --git a/src/mol-repr/structure/visual/nucleotide-block-mesh.ts b/src/mol-repr/structure/visual/nucleotide-block-mesh.ts index f7c0aa0a32a29330c4b2ebf8e2a82d19f2b40296..9a2e8372608dbd3bcfbba7806545b127096e5e3b 100644 --- a/src/mol-repr/structure/visual/nucleotide-block-mesh.ts +++ b/src/mol-repr/structure/visual/nucleotide-block-mesh.ts @@ -6,7 +6,6 @@ import { Unit, Structure } from 'mol-model/structure'; import { UnitsVisual } from '../index'; -import { RuntimeContext } from 'mol-task' import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { Segmentation } from 'mol-data/int'; import { MoleculeType, isNucleic, isPurinBase, isPyrimidineBase } from 'mol-model/structure/model/types'; @@ -18,6 +17,7 @@ import { Box } from 'mol-geo/primitive/box'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; +import { VisualContext } from 'mol-repr'; const p1 = Vec3.zero() const p2 = Vec3.zero() @@ -34,7 +34,7 @@ const sVec = Vec3.zero() const box = Box() // TODO define props, should be scalable -async function createNucleotideBlockMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: {}, mesh?: Mesh) { +async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: {}, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) // TODO better vertex count estimate @@ -100,8 +100,8 @@ async function createNucleotideBlockMesh(ctx: RuntimeContext, unit: Unit, struct } } - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Nucleotide block mesh', current: i }); + if (i % 10000 === 0 && ctx.runtime.shouldUpdate) { + await ctx.runtime.update({ message: 'Nucleotide block mesh', current: i }); } ++i } diff --git a/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts b/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts index b43c0dfc2231fdd5ae7c89c63c9dab192ec6e79f..6968ac9b53c676171198f5e113cec87672f3f51c 100644 --- a/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts +++ b/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts @@ -7,7 +7,6 @@ import { Unit, Structure } from 'mol-model/structure'; import { UnitsVisual } from '../index'; import { VisualUpdateState } from '../../util'; -import { RuntimeContext } from 'mol-task' import { PolymerBackboneIterator } from './util/polymer'; import { getElementLoci, markElement, StructureElementIterator } from './util/element'; import { Vec3 } from 'mol-math/linear-algebra'; @@ -19,6 +18,7 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { CylinderProps } from 'mol-geo/primitive/cylinder'; import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; +import { VisualContext } from 'mol-repr'; export const PolymerBackboneCylinderParams = { sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), @@ -28,7 +28,7 @@ export const PolymerBackboneCylinderParams = { export const DefaultPolymerBackboneCylinderProps = paramDefaultValues(PolymerBackboneCylinderParams) export type PolymerBackboneCylinderProps = typeof DefaultPolymerBackboneCylinderProps -async function createPolymerBackboneCylinderMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: PolymerBackboneCylinderProps, mesh?: Mesh) { +async function createPolymerBackboneCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: PolymerBackboneCylinderProps, mesh?: Mesh) { const polymerElementCount = unit.polymerElements.length if (!polymerElementCount) return Mesh.createEmpty(mesh) @@ -59,8 +59,8 @@ async function createPolymerBackboneCylinderMesh(ctx: RuntimeContext, unit: Unit builder.setGroup(OrderedSet.indexOf(elements, centerB.element)) addCylinder(builder, pB, pA, 0.5, cylinderProps) - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Backbone mesh', current: i, max: polymerElementCount }); + if (i % 10000 === 0 && ctx.runtime.shouldUpdate) { + await ctx.runtime.update({ message: 'Backbone mesh', current: i, max: polymerElementCount }); } ++i } diff --git a/src/mol-repr/structure/visual/polymer-direction-wedge.ts b/src/mol-repr/structure/visual/polymer-direction-wedge.ts index 68049ec37d1758e163325661e536927721b7d7b7..461df57daff267d3d244e8f1aff061a0dd8df159 100644 --- a/src/mol-repr/structure/visual/polymer-direction-wedge.ts +++ b/src/mol-repr/structure/visual/polymer-direction-wedge.ts @@ -6,7 +6,6 @@ import { Unit, Structure } from 'mol-model/structure'; import { UnitsVisual } from '../index'; -import { RuntimeContext } from 'mol-task' import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types'; @@ -16,6 +15,7 @@ import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter import { Wedge } from 'mol-geo/primitive/wedge'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; +import { VisualContext } from 'mol-repr'; const t = Mat4.identity() const sVec = Vec3.zero() @@ -36,7 +36,7 @@ export const PolymerDirectionWedgeParams = { export const DefaultPolymerDirectionWedgeProps = paramDefaultValues(PolymerDirectionWedgeParams) export type PolymerDirectionWedgeProps = typeof DefaultPolymerDirectionWedgeProps -async function createPolymerDirectionWedgeMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: PolymerDirectionWedgeProps, mesh?: Mesh) { +async function createPolymerDirectionWedgeMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: PolymerDirectionWedgeProps, mesh?: Mesh) { const polymerElementCount = unit.polymerElements.length if (!polymerElementCount) return Mesh.createEmpty(mesh) @@ -80,8 +80,8 @@ async function createPolymerDirectionWedgeMesh(ctx: RuntimeContext, unit: Unit, builder.add(t, wedge) } - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Polymer direction mesh', current: i, max: polymerElementCount }); + if (i % 10000 === 0 && ctx.runtime.shouldUpdate) { + await ctx.runtime.update({ message: 'Polymer direction mesh', current: i, max: polymerElementCount }); } ++i } diff --git a/src/mol-repr/structure/visual/polymer-gap-cylinder.ts b/src/mol-repr/structure/visual/polymer-gap-cylinder.ts index 389b494a229089a2c6da9c18299698de7b3528c3..c00559b244db6e1efc308e05c9cdb641d79c5769 100644 --- a/src/mol-repr/structure/visual/polymer-gap-cylinder.ts +++ b/src/mol-repr/structure/visual/polymer-gap-cylinder.ts @@ -7,7 +7,6 @@ import { Unit, Structure } from 'mol-model/structure'; import { UnitsVisual } from '../index'; import { VisualUpdateState } from '../../util'; -import { RuntimeContext } from 'mol-task' import { PolymerGapIterator, PolymerGapLocationIterator, markPolymerGapElement, getPolymerGapElementLoci } from './util/polymer'; import { Vec3 } from 'mol-math/linear-algebra'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; @@ -19,6 +18,7 @@ import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { CylinderProps } from 'mol-geo/primitive/cylinder'; import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; import { addFixedCountDashedCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; +import { VisualContext } from 'mol-repr'; const segmentCount = 10 @@ -31,7 +31,7 @@ export const PolymerGapCylinderParams = { export const DefaultPolymerGapCylinderProps = paramDefaultValues(PolymerGapCylinderParams) export type PolymerGapCylinderProps = typeof DefaultPolymerGapCylinderProps -async function createPolymerGapCylinderMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: PolymerGapCylinderProps, mesh?: Mesh) { +async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: PolymerGapCylinderProps, mesh?: Mesh) { const polymerGapCount = unit.gapElements.length if (!polymerGapCount) return Mesh.createEmpty(mesh) @@ -69,8 +69,8 @@ async function createPolymerGapCylinderMesh(ctx: RuntimeContext, unit: Unit, str addFixedCountDashedCylinder(builder, pB, pA, 0.5, segmentCount, cylinderProps) } - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Gap mesh', current: i, max: polymerGapCount }); + if (i % 10000 === 0 && ctx.runtime.shouldUpdate) { + await ctx.runtime.update({ message: 'Gap mesh', current: i, max: polymerGapCount }); } i += 2 } diff --git a/src/mol-repr/structure/visual/polymer-trace-mesh.ts b/src/mol-repr/structure/visual/polymer-trace-mesh.ts index 910f59b26e2d34ff85d078db1aeedb646ee1a65f..941d9d65148863cbe615120c238e0534f8ff75ee 100644 --- a/src/mol-repr/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-repr/structure/visual/polymer-trace-mesh.ts @@ -7,7 +7,6 @@ import { Unit, Structure } from 'mol-model/structure'; import { UnitsVisual } from '../index'; import { VisualUpdateState } from '../../util'; -import { RuntimeContext } from 'mol-task' import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer'; import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; @@ -17,6 +16,7 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { addSheet } from 'mol-geo/geometry/mesh/builder/sheet'; import { addTube } from 'mol-geo/geometry/mesh/builder/tube'; +import { VisualContext } from 'mol-repr'; export const PolymerTraceMeshParams = { sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), @@ -32,7 +32,7 @@ export type PolymerTraceMeshProps = typeof DefaultPolymerTraceMeshProps // TODO handle polymer ends properly -async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: PolymerTraceMeshProps, mesh?: Mesh) { +async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: PolymerTraceMeshProps, mesh?: Mesh) { const polymerElementCount = unit.polymerElements.length if (!polymerElementCount) return Mesh.createEmpty(mesh) @@ -80,8 +80,8 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, structure addTube(builder, curvePoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1, true, true) } - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Polymer trace mesh', current: i, max: polymerElementCount }); + if (i % 10000 === 0 && ctx.runtime.shouldUpdate) { + await ctx.runtime.update({ message: 'Polymer trace mesh', current: i, max: polymerElementCount }); } ++i } diff --git a/src/mol-repr/structure/visual/util/common.ts b/src/mol-repr/structure/visual/util/common.ts index 33f226f22aafb4fecb3019379eea8fdf58f27858..a0cff0c67bd20c61ab0626bfa00bc8dbdd48f064 100644 --- a/src/mol-repr/structure/visual/util/common.ts +++ b/src/mol-repr/structure/visual/util/common.ts @@ -7,7 +7,6 @@ import { Unit, Structure } from 'mol-model/structure'; import { StructureProps } from '../../index'; import { createMeshRenderObject, createPointsRenderObject, createLinesRenderObject, createDirectVolumeRenderObject } from 'mol-gl/render-object'; -import { RuntimeContext } from 'mol-task'; import { Mat4 } from 'mol-math/linear-algebra'; import { TransformData, createTransform, createIdentityTransform } from 'mol-geo/geometry/transform-data'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; @@ -16,6 +15,7 @@ import { createRenderableState } from 'mol-geo/geometry/geometry'; import { Points } from 'mol-geo/geometry/points/points'; import { Lines } from 'mol-geo/geometry/lines/lines'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; +import { VisualContext } from 'mol-repr'; export function createUnitsTransform({ units }: Unit.SymmetryGroup, transformData?: TransformData) { const unitCount = units.length @@ -49,16 +49,16 @@ export function includesUnitKind(unitKinds: UnitKind[], unit: Unit) { type StructureMeshProps = Mesh.Props & StructureProps -export async function createComplexMeshRenderObject(ctx: RuntimeContext, structure: Structure, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps) { +export async function createComplexMeshRenderObject(ctx: VisualContext, structure: Structure, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps) { const transform = createIdentityTransform() - const values = await Mesh.createValues(ctx, mesh, transform, locationIt, props) + const values = await Mesh.createValues(ctx.runtime, mesh, transform, locationIt, props) const state = createRenderableState(props) return createMeshRenderObject(values, state) } -export async function createUnitsMeshRenderObject(ctx: RuntimeContext, group: Unit.SymmetryGroup, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps) { +export async function createUnitsMeshRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps) { const transform = createUnitsTransform(group) - const values = await Mesh.createValues(ctx, mesh, transform, locationIt, props) + const values = await Mesh.createValues(ctx.runtime, mesh, transform, locationIt, props) const state = createRenderableState(props) return createMeshRenderObject(values, state) } @@ -67,9 +67,9 @@ export async function createUnitsMeshRenderObject(ctx: RuntimeContext, group: Un type StructurePointsProps = Points.Props & StructureProps -export async function createUnitsPointsRenderObject(ctx: RuntimeContext, group: Unit.SymmetryGroup, points: Points, locationIt: LocationIterator, props: StructurePointsProps) { +export async function createUnitsPointsRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, points: Points, locationIt: LocationIterator, props: StructurePointsProps) { const transform = createUnitsTransform(group) - const values = await Points.createValues(ctx, points, transform, locationIt, props) + const values = await Points.createValues(ctx.runtime, points, transform, locationIt, props) const state = createRenderableState(props) return createPointsRenderObject(values, state) } @@ -78,9 +78,9 @@ export async function createUnitsPointsRenderObject(ctx: RuntimeContext, group: type StructureLinesProps = Lines.Props & StructureProps -export async function createUnitsLinesRenderObject(ctx: RuntimeContext, group: Unit.SymmetryGroup, lines: Lines, locationIt: LocationIterator, props: StructureLinesProps) { +export async function createUnitsLinesRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, lines: Lines, locationIt: LocationIterator, props: StructureLinesProps) { const transform = createUnitsTransform(group) - const values = await Lines.createValues(ctx, lines, transform, locationIt, props) + const values = await Lines.createValues(ctx.runtime, lines, transform, locationIt, props) const state = createRenderableState(props) return createLinesRenderObject(values, state) } @@ -89,9 +89,9 @@ export async function createUnitsLinesRenderObject(ctx: RuntimeContext, group: U type StructureDirectVolumeProps = DirectVolume.Props & StructureProps -export async function createUnitsDirectVolumeRenderObject(ctx: RuntimeContext, group: Unit.SymmetryGroup, directVolume: DirectVolume, locationIt: LocationIterator, props: StructureDirectVolumeProps) { +export async function createUnitsDirectVolumeRenderObject(ctx: VisualContext, group: Unit.SymmetryGroup, directVolume: DirectVolume, locationIt: LocationIterator, props: StructureDirectVolumeProps) { const transform = createUnitsTransform(group) - const values = await DirectVolume.createValues(ctx, directVolume, transform, locationIt, props) + const values = await DirectVolume.createValues(ctx.runtime, directVolume, transform, locationIt, props) const state = createRenderableState(props) return createDirectVolumeRenderObject(values, state) } \ No newline at end of file diff --git a/src/mol-repr/structure/visual/util/element.ts b/src/mol-repr/structure/visual/util/element.ts index 4c1362033225ef4a8c9d1cbbacfe465d08bfda6e..909bce22aa260a8a8491c31d1cc015d4c7f90dac 100644 --- a/src/mol-repr/structure/visual/util/element.ts +++ b/src/mol-repr/structure/visual/util/element.ts @@ -6,7 +6,6 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { Unit, StructureElement, Structure } from 'mol-model/structure'; -import { RuntimeContext } from 'mol-task'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { Interval, OrderedSet } from 'mol-data/int'; import { SizeTheme, SizeThemeName } from 'mol-theme/size'; @@ -16,6 +15,7 @@ import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; import { PickingId } from 'mol-geo/geometry/picking'; import { LocationIterator } from 'mol-geo/util/location-iterator'; +import { VisualContext } from 'mol-repr'; export interface ElementSphereMeshProps { sizeTheme: SizeThemeName, @@ -23,7 +23,7 @@ export interface ElementSphereMeshProps { detail: number, } -export async function createElementSphereMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: ElementSphereMeshProps, mesh?: Mesh) { +export async function createElementSphereMesh(ctx: VisualContext, unit: Unit, structure: Structure, props: ElementSphereMeshProps, mesh?: Mesh) { const { detail } = props const { elements } = unit; @@ -44,8 +44,8 @@ export async function createElementSphereMesh(ctx: RuntimeContext, unit: Unit, s meshBuilder.setGroup(i) addSphere(meshBuilder, v, sizeTheme.size(l), detail) - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Sphere mesh', current: i, max: elementCount }); + if (i % 10000 === 0 && ctx.runtime.shouldUpdate) { + await ctx.runtime.update({ message: 'Sphere mesh', current: i, max: elementCount }); } } diff --git a/src/mol-repr/structure/visual/util/link.ts b/src/mol-repr/structure/visual/util/link.ts index 53d9688bcbd168100046207df44a5c80160a2c4b..4f3931f480ddf07a77f3dc13c3830542ff8b4a32 100644 --- a/src/mol-repr/structure/visual/util/link.ts +++ b/src/mol-repr/structure/visual/util/link.ts @@ -5,7 +5,6 @@ */ import { Vec3 } from 'mol-math/linear-algebra'; -import { RuntimeContext } from 'mol-task'; import { LinkType } from 'mol-model/structure/model/types'; import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { Unit, StructureElement, Structure, Link } from 'mol-model/structure'; @@ -15,6 +14,7 @@ import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { CylinderProps } from 'mol-geo/primitive/cylinder'; import { addFixedCountDashedCylinder, addCylinder, addDoubleCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; import { LocationIterator } from 'mol-geo/util/location-iterator'; +import { VisualContext } from 'mol-repr'; export const LinkCylinderParams = { sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), @@ -71,7 +71,7 @@ export interface LinkCylinderMeshBuilderProps { * Each edge is included twice to allow for coloring/picking * the half closer to the first vertex, i.e. vertex a. */ -export async function createLinkCylinderMesh(ctx: RuntimeContext, linkBuilder: LinkCylinderMeshBuilderProps, props: LinkCylinderProps, mesh?: Mesh) { +export async function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkCylinderMeshBuilderProps, props: LinkCylinderProps, mesh?: Mesh) { const { linkCount, referencePosition, position, order, flags, radius } = linkBuilder if (!linkCount) return Mesh.createEmpty(mesh) @@ -115,8 +115,8 @@ export async function createLinkCylinderMesh(ctx: RuntimeContext, linkBuilder: L addCylinder(meshBuilder, va, vb, 0.5, cylinderProps) } - if (edgeIndex % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Cylinder mesh', current: edgeIndex, max: linkCount }); + if (edgeIndex % 10000 === 0 && ctx.runtime.shouldUpdate) { + await ctx.runtime.update({ message: 'Cylinder mesh', current: edgeIndex, max: linkCount }); } } diff --git a/src/mol-repr/util.ts b/src/mol-repr/util.ts index 792e9ff05be9e3331d77b8323948daba894e4916..0b71cd247d96592ae3dc676a30a4fd54b88cb27b 100644 --- a/src/mol-repr/util.ts +++ b/src/mol-repr/util.ts @@ -44,7 +44,10 @@ export function sizeChanged(oldProps: SizeProps, newProps: SizeProps) { export function colorChanged(oldProps: ColorProps, newProps: ColorProps) { return ( oldProps.colorTheme !== newProps.colorTheme || - oldProps.colorValue !== newProps.colorValue + oldProps.colorValue !== newProps.colorValue || + oldProps.colorDomain !== newProps.colorDomain || + oldProps.colorList !== newProps.colorList || + oldProps.colorMap !== newProps.colorMap ) } diff --git a/src/mol-repr/volume/direct-volume.ts b/src/mol-repr/volume/direct-volume.ts index 5ec65ef71512ba9a5d0f93c7abaeb4dfad9f8809..ce412b099d4f6a811e62e9481cd05c2a1130a146 100644 --- a/src/mol-repr/volume/direct-volume.ts +++ b/src/mol-repr/volume/direct-volume.ts @@ -7,7 +7,7 @@ import { VolumeData } from 'mol-model/volume' import { RuntimeContext } from 'mol-task' import { VolumeVisual, VolumeRepresentation } from './index'; -import { DirectVolumeRenderObject, createDirectVolumeRenderObject } from 'mol-gl/render-object'; +import { createDirectVolumeRenderObject } from 'mol-gl/render-object'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { paramDefaultValues } from 'mol-util/parameter'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; @@ -15,12 +15,13 @@ import { Box3D } from 'mol-math/geometry'; import { WebGLContext } from 'mol-gl/webgl/context'; import { createTexture } from 'mol-gl/webgl/texture'; import { LocationIterator } from 'mol-geo/util/location-iterator'; -import { NullLocation } from 'mol-model/location'; import { createIdentityTransform } from 'mol-geo/geometry/transform-data'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; -import { Geometry, createRenderableState, updateRenderableState } from 'mol-geo/geometry/geometry'; +import { Geometry, createRenderableState } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; +import { VisualUpdateState } from 'mol-repr/util'; +import { VisualContext, RepresentationContext } from 'mol-repr'; function getBoundingBox(gridDimension: Vec3, transform: Mat4) { const bbox = Box3D.empty() @@ -168,6 +169,18 @@ export function createDirectVolume3d(ctx: RuntimeContext, webgl: WebGLContext, v return DirectVolume.create(bbox, gridDimension, transform, texture, directVolume) } +// + +export async function createDirectVolume(ctx: VisualContext, volume: VolumeData, props: DirectVolumeProps, directVolume?: DirectVolume) { + const { runtime, webgl } = ctx + if (webgl === undefined) throw new Error('DirectVolumeVisual requires `webgl` in props') + + return webgl.isWebGL2 ? + await createDirectVolume3d(runtime, webgl, volume, directVolume) : + await createDirectVolume2d(runtime, webgl, volume, directVolume) +} + + // export const DirectVolumeParams = { @@ -178,81 +191,21 @@ export const DefaultDirectVolumeProps = paramDefaultValues(DirectVolumeParams) export type DirectVolumeProps = typeof DefaultDirectVolumeProps export function DirectVolumeVisual(): VolumeVisual<DirectVolumeProps> { - let currentProps = DefaultDirectVolumeProps - let renderObject: DirectVolumeRenderObject - let currentVolume: VolumeData - let directVolume: DirectVolume - - async function create(ctx: RuntimeContext, volume: VolumeData, props: Partial<DirectVolumeProps> = {}) { - const { webgl } = props - if (webgl === undefined) throw new Error('DirectVolumeVisual requires `webgl` in props') - - currentProps = { ...DefaultDirectVolumeProps, ...props } - if (props.isoValueRelative) { - // currentProps.isoValueAbsolute = VolumeIsoValue.calcAbsolute(currentVolume.dataStats, props.isoValueRelative) - } - - const state = createRenderableState(currentProps) - const locationIt = LocationIterator(1, 1, () => NullLocation) - const transform = createIdentityTransform() - - if (webgl.isWebGL2) { - directVolume = await createDirectVolume3d(ctx, webgl, volume, directVolume) - const values = await DirectVolume.createValues(ctx, directVolume, transform, locationIt, currentProps) - renderObject = createDirectVolumeRenderObject(values, state) - } else { - directVolume = await createDirectVolume2d(ctx, webgl, volume, directVolume) - const values = await DirectVolume.createValues(ctx, directVolume, transform, locationIt, currentProps) - renderObject = createDirectVolumeRenderObject(values, state) - } - } - - async function update(ctx: RuntimeContext, props: Partial<DirectVolumeProps> = {}) { - const { webgl } = props - if (webgl === undefined) throw new Error('DirectVolumeVisual requires `webgl` in props') - - const newProps = { ...currentProps, ...props } - if (props.isoValueRelative) { - // newProps.isoValueAbsolute = VolumeIsoValue.calcAbsolute(currentVolume.dataStats, props.isoValueRelative) - } - - console.log('newProps.isoValueAbsolute', newProps.isoValueAbsolute) - - DirectVolume.updateValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - } - - return { - get renderObject () { return renderObject }, - async createOrUpdate(ctx: RuntimeContext, props: Partial<DirectVolumeProps> = {}, volume?: VolumeData) { - if (!volume && !currentVolume) { - throw new Error('missing volume') - } else if (volume && (!currentVolume || !renderObject)) { - currentVolume = volume - await create(ctx, volume, props) - } else if (volume && volume !== currentVolume) { - currentVolume = volume - await create(ctx, volume, props) - } else { - await update(ctx, props) - } - - currentProps = { ...DefaultDirectVolumeProps, ...props } - }, - getLoci(pickingId: PickingId) { - // TODO - return EmptyLoci + return VolumeVisual<DirectVolumeProps>({ + defaultProps: DefaultDirectVolumeProps, + createGeometry: createDirectVolume, + getLoci: () => EmptyLoci, + mark: () => false, + setUpdateState: (state: VisualUpdateState, newProps: DirectVolumeProps, currentProps: DirectVolumeProps) => { }, - mark(loci: Loci, action: MarkerAction) { - // TODO - return false + createRenderObject: async (ctx: VisualContext, geometry: DirectVolume, locationIt: LocationIterator, props: DirectVolumeProps) => { + const transform = createIdentityTransform() + const values = await DirectVolume.createValues(ctx.runtime, geometry, transform, locationIt, props) + const state = createRenderableState(props) + return createDirectVolumeRenderObject(values, state) }, - destroy() { - // TODO - } - } + updateValues: DirectVolume.updateValues + }) } export function DirectVolumeRepresentation(): VolumeRepresentation<DirectVolumeProps> { @@ -267,9 +220,9 @@ export function DirectVolumeRepresentation(): VolumeRepresentation<DirectVolumeP get props() { return { ...volumeRepr.props } }, - createOrUpdate: (props: Partial<DirectVolumeProps> = {}, volume?: VolumeData) => { + createOrUpdate: (ctx: RepresentationContext, props: Partial<DirectVolumeProps> = {}, volume?: VolumeData) => { currentProps = Object.assign({}, DefaultDirectVolumeProps, currentProps, props) - return volumeRepr.createOrUpdate(currentProps, volume) + return volumeRepr.createOrUpdate(ctx, currentProps, volume) }, getLoci: (pickingId: PickingId) => { return volumeRepr.getLoci(pickingId) diff --git a/src/mol-repr/volume/index.ts b/src/mol-repr/volume/index.ts index 49f6a31cbc4a82bb0b9a40027db320eef005075a..f7d0ddded2558081b882009f0301a535cdbaa51f 100644 --- a/src/mol-repr/volume/index.ts +++ b/src/mol-repr/volume/index.ts @@ -4,8 +4,8 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Task, RuntimeContext } from 'mol-task' -import { RepresentationProps, Representation, Visual } from '..'; +import { Task } from 'mol-task' +import { RepresentationProps, Representation, Visual, RepresentationContext, VisualContext } from '..'; import { VolumeData, VolumeIsoValue } from 'mol-model/volume'; import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; import { paramDefaultValues, RangeParam } from 'mol-util/parameter'; @@ -26,14 +26,14 @@ type VolumeRenderObject = MeshRenderObject | LinesRenderObject | PointsRenderObj interface VolumeVisualBuilder<P extends VolumeProps, G extends Geometry> { defaultProps: P - createGeometry(ctx: RuntimeContext, volumeData: VolumeData, props: P, geometry?: G): Promise<G> + createGeometry(ctx: VisualContext, volumeData: VolumeData, props: P, geometry?: G): Promise<G> getLoci(pickingId: PickingId, id: number): Loci mark(loci: Loci, apply: (interval: Interval) => boolean): boolean setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void } interface VolumeVisualGeometryBuilder<P extends VolumeProps, G extends Geometry> extends VolumeVisualBuilder<P, G> { - createRenderObject(ctx: RuntimeContext, geometry: G, locationIt: LocationIterator, currentProps: P): Promise<VolumeRenderObject> + createRenderObject(ctx: VisualContext, geometry: G, locationIt: LocationIterator, currentProps: P): Promise<VolumeRenderObject> updateValues(values: RenderableValues, newProps: P): void } @@ -48,7 +48,7 @@ export function VolumeVisual<P extends VolumeProps>(builder: VolumeVisualGeometr let geometry: Geometry let locationIt: LocationIterator - async function create(ctx: RuntimeContext, volume: VolumeData, props: Partial<VolumeProps> = {}) { + async function create(ctx: VisualContext, volume: VolumeData, props: Partial<VolumeProps> = {}) { currentProps = Object.assign({}, defaultProps, props) if (props.isoValueRelative) { currentProps.isoValueAbsolute = VolumeIsoValue.calcAbsolute(currentVolume.dataStats, props.isoValueRelative) @@ -60,7 +60,7 @@ export function VolumeVisual<P extends VolumeProps>(builder: VolumeVisualGeometr renderObject = await createRenderObject(ctx, geometry, locationIt, currentProps) } - async function update(ctx: RuntimeContext, props: Partial<VolumeProps> = {}) { + async function update(ctx: VisualContext, props: Partial<VolumeProps> = {}) { if (!renderObject) return const newProps = Object.assign({}, currentProps, props) @@ -85,7 +85,7 @@ export function VolumeVisual<P extends VolumeProps>(builder: VolumeVisualGeometr return { get renderObject () { return renderObject }, - async createOrUpdate(ctx: RuntimeContext, props: Partial<VolumeProps> = {}, volume?: VolumeData) { + async createOrUpdate(ctx: VisualContext, props: Partial<VolumeProps> = {}, volume?: VolumeData) { if (!volume && !currentVolume) { throw new Error('missing volume') } else if (volume && (!currentVolume || !renderObject)) { @@ -147,9 +147,9 @@ export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeD let _props: P let busy = false - function createOrUpdate(props: Partial<P> = {}, volumeData?: VolumeData) { + function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, volumeData?: VolumeData) { _props = Object.assign({}, DefaultVolumeProps, _props, props) - return Task.create('VolumeRepresentation.create', async ctx => { + return Task.create('VolumeRepresentation.create', async runtime => { // TODO queue it somehow if (busy) return @@ -158,11 +158,11 @@ export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeD } else if (volumeData && !visual) { busy = true visual = visualCtor(volumeData) - await visual.createOrUpdate(ctx, props, volumeData) + await visual.createOrUpdate({ ...ctx, runtime } , props, volumeData) busy = false } else { busy = true - await visual.createOrUpdate(ctx, props, volumeData) + await visual.createOrUpdate({ ...ctx, runtime }, props, volumeData) busy = false } }); diff --git a/src/mol-repr/volume/isosurface-mesh.ts b/src/mol-repr/volume/isosurface-mesh.ts index 0dd1b600d245b7f94de9f147d4b17f471b8f8033..1f81989e83bab70631a943033fe36d39a466d790 100644 --- a/src/mol-repr/volume/isosurface-mesh.ts +++ b/src/mol-repr/volume/isosurface-mesh.ts @@ -6,7 +6,6 @@ */ import { VolumeData } from 'mol-model/volume' -import { RuntimeContext } from 'mol-task' import { VolumeVisual, VolumeRepresentation } from './index'; import { createMeshRenderObject } from 'mol-gl/render-object'; import { Loci, EmptyLoci } from 'mol-model/loci'; @@ -19,21 +18,22 @@ import { createRenderableState } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; import { VisualUpdateState } from 'mol-repr/util'; +import { RepresentationContext, VisualContext } from 'mol-repr'; interface VolumeIsosurfaceProps { isoValueAbsolute: number } -export async function createVolumeIsosurface(ctx: RuntimeContext, volume: VolumeData, props: VolumeIsosurfaceProps, mesh?: Mesh) { - ctx.update({ message: 'Marching cubes...' }); +export async function createVolumeIsosurface(ctx: VisualContext, volume: VolumeData, props: VolumeIsosurfaceProps, mesh?: Mesh) { + ctx.runtime.update({ message: 'Marching cubes...' }); const surface = await computeMarchingCubesMesh({ isoLevel: props.isoValueAbsolute, scalarField: volume.data - }, mesh).runAsChild(ctx); + }, mesh).runAsChild(ctx.runtime); const transform = VolumeData.getGridToCartesianTransform(volume); - ctx.update({ message: 'Transforming mesh...' }); + ctx.runtime.update({ message: 'Transforming mesh...' }); Mesh.transformImmediate(surface, transform); Mesh.computeNormalsImmediate(surface) @@ -48,7 +48,7 @@ export const IsosurfaceParams = { export const DefaultIsosurfaceProps = paramDefaultValues(IsosurfaceParams) export type IsosurfaceProps = typeof DefaultIsosurfaceProps -export function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { +export function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { return VolumeVisual<IsosurfaceProps>({ defaultProps: DefaultIsosurfaceProps, createGeometry: createVolumeIsosurface, @@ -57,9 +57,9 @@ export function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { setUpdateState: (state: VisualUpdateState, newProps: IsosurfaceProps, currentProps: IsosurfaceProps) => { if (newProps.isoValueAbsolute !== currentProps.isoValueAbsolute) state.createGeometry = true }, - createRenderObject: async (ctx: RuntimeContext, geometry: Mesh, locationIt: LocationIterator, props: IsosurfaceProps) => { + createRenderObject: async (ctx: VisualContext, geometry: Mesh, locationIt: LocationIterator, props: IsosurfaceProps) => { const transform = createIdentityTransform() - const values = await Mesh.createValues(ctx, geometry, transform, locationIt, props) + const values = await Mesh.createValues(ctx.runtime, geometry, transform, locationIt, props) const state = createRenderableState(props) return createMeshRenderObject(values, state) }, @@ -79,9 +79,9 @@ export function IsosurfaceRepresentation(): VolumeRepresentation<IsosurfaceProps get props() { return { ...volumeRepr.props } }, - createOrUpdate: (props: Partial<IsosurfaceProps> = {}, volume?: VolumeData) => { + createOrUpdate: (ctx: RepresentationContext, props: Partial<IsosurfaceProps> = {}, volume?: VolumeData) => { currentProps = Object.assign({}, DefaultIsosurfaceProps, currentProps, props) - return volumeRepr.createOrUpdate(currentProps, volume) + return volumeRepr.createOrUpdate(ctx, currentProps, volume) }, getLoci: (pickingId: PickingId) => { return volumeRepr.getLoci(pickingId) diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts index c11848731cdae4a30529c7d2e62a9ed272b8cc26..d087e249c80cbd17e3e30f49102a5bdde537f012 100644 --- a/src/mol-theme/color.ts +++ b/src/mol-theme/color.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Color } from 'mol-util/color'; +import { Color, ColorMap } from 'mol-util/color'; import { Structure } from 'mol-model/structure'; import { Location } from 'mol-model/location'; import { ColorType } from 'mol-geo/geometry/color-data'; @@ -23,6 +23,7 @@ import { SequenceIdColorTheme } from './color/sequence-id'; import { SecondaryStructureColorTheme } from './color/secondary-structure'; import { MoleculeTypeColorTheme } from './color/molecule-type'; import { PolymerIndexColorTheme } from './color/polymer-index'; +import { ColorMatplotlib, ColorBrewer, ColorOther } from 'mol-util/color/tables'; export type LocationColor = (location: Location, isSecondary: boolean) => Color @@ -36,6 +37,29 @@ export function ScaleLegend(minLabel: string, maxLabel: string, colors: Color[]) return { kind: 'scale-legend', minLabel, maxLabel, colors } } +export type ColorScaleName = ( + 'default' | + keyof typeof ColorBrewer | keyof typeof ColorMatplotlib | keyof typeof ColorOther +) +export const ColorScaleNames = [ + 'default', + ...Object.keys(ColorBrewer), ...Object.keys(ColorMatplotlib), ...Object.keys(ColorOther) +] +export const ColorScaleOptions = ColorScaleNames.map(n => [n, n] as [ColorScaleName, string]) + +export function getColorScaleFromName(name: string) { + if (name === 'default') { + return + } else if (name in ColorBrewer) { + return ColorBrewer[name as keyof typeof ColorBrewer] + } else if (name in ColorMatplotlib) { + return ColorMatplotlib[name as keyof typeof ColorMatplotlib] + } else if (name in ColorOther) { + return ColorOther[name as keyof typeof ColorOther] + } + console.warn(`unknwon color list named '${name}'`) +} + export interface TableLegend { kind: 'table-legend' table: [ string, Color ][] @@ -44,7 +68,23 @@ export function TableLegend(table: [ string, Color ][]): TableLegend { return { kind: 'table-legend', table } } +export interface ColorThemeFeatures { + /** Does allow providing a structure object */ + structure?: boolean + /** Does allow providing a volume object */ + volume?: boolean + /** Does allow providing a list of colors (for creating a scale) */ + list?: boolean + /** Does allow providing a map of colors */ + map?: boolean + /** Does allow providing the boundaries for the scale */ + domain?: boolean + /** Does allow providing a single/special color value */ + value?: boolean +} + export interface ColorTheme { + features: ColorThemeFeatures granularity: ColorType color: LocationColor description?: string @@ -74,6 +114,8 @@ export interface ColorThemeProps { name: ColorThemeName domain?: [number, number] value?: Color + list?: Color[] + map?: ColorMap<any> structure?: Structure color?: LocationColor granularity?: ColorType, diff --git a/src/mol-theme/color/carbohydrate-symbol.ts b/src/mol-theme/color/carbohydrate-symbol.ts index c777c91d538684085041c23698ee19657fb18de7..a21853d87f941f899f7071ff3260b55b9d346541 100644 --- a/src/mol-theme/color/carbohydrate-symbol.ts +++ b/src/mol-theme/color/carbohydrate-symbol.ts @@ -47,6 +47,7 @@ export function CarbohydrateSymbolColorTheme(props: ColorThemeProps): ColorTheme } return { + features: {}, granularity: 'group', color: color, description: Description, diff --git a/src/mol-theme/color/chain-id.ts b/src/mol-theme/color/chain-id.ts index e281dc9a20dc39fd36c3f937ec8920bb87e1f9b3..0fd9e3955a12238e72496d5e527a8a7e71741944 100644 --- a/src/mol-theme/color/chain-id.ts +++ b/src/mol-theme/color/chain-id.ts @@ -63,6 +63,7 @@ export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme { } return { + features: {}, granularity: 'group', color, description: Description, diff --git a/src/mol-theme/color/cross-link.ts b/src/mol-theme/color/cross-link.ts index 6f8ab371e6ff957f71fd081850f25acc55b23ac0..bb3cf176c4f5a5c8fdbc330b63e7c69e5436c089 100644 --- a/src/mol-theme/color/cross-link.ts +++ b/src/mol-theme/color/cross-link.ts @@ -6,10 +6,12 @@ import { Link } from 'mol-model/structure'; -import { Color, ColorScale, ColorBrewer } from 'mol-util/color'; +import { Color, ColorScale } from 'mol-util/color'; import { Location } from 'mol-model/location'; import { ColorThemeProps, ColorTheme, LocationColor } from '../color'; import { Vec3 } from 'mol-math/linear-algebra'; +import { ColorBrewer } from 'mol-util/color/tables'; +import { defaults } from 'mol-util'; const DefaultColor = Color(0xCCCCCC) const Description = 'Colors cross-links by the deviation of the observed distance versus the modeled distance (e.g. `ihm_cross_link_restraint.distance_threshold`).' @@ -27,7 +29,10 @@ export function CrossLinkColorTheme(props: ColorThemeProps): ColorTheme { if (props.structure) { const crosslinks = props.structure.crossLinkRestraints - scale = ColorScale.create({ domain: [ -10, 10 ], colors: ColorBrewer.RdYlBu }) + scale = ColorScale.create({ + domain: defaults(props.domain, [ -10, 10 ]), + list: defaults(props.list, ColorBrewer.RdYlBu) + }) const scaleColor = scale.color color = (location: Location): Color => { @@ -44,6 +49,7 @@ export function CrossLinkColorTheme(props: ColorThemeProps): ColorTheme { } return { + features: { list: true, domain: true }, granularity: 'group', color, description: Description, diff --git a/src/mol-theme/color/custom.ts b/src/mol-theme/color/custom.ts index 4901ac06f6860660a7cfb1edb9a1505d9e052c17..4eb5a10ea4497ba5c419607e1467245b4758dc0e 100644 --- a/src/mol-theme/color/custom.ts +++ b/src/mol-theme/color/custom.ts @@ -13,6 +13,7 @@ const DefaultColor = Color(0xCCCCCC) export function CustomColorTheme(props: ColorThemeProps): ColorTheme { const value = defaults(props.value, DefaultColor) return { + features: {}, granularity: defaults(props.granularity, 'uniform'), color: defaults(props.color, () => value), description: props.description, diff --git a/src/mol-theme/color/element-index.ts b/src/mol-theme/color/element-index.ts index 8ca2d273a0c5c30c2d16c323adefd77ed043295d..ecce0a1c1bc0804043f2c9ee4c5f8aaabbc69882 100644 --- a/src/mol-theme/color/element-index.ts +++ b/src/mol-theme/color/element-index.ts @@ -29,7 +29,7 @@ export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme { elementCount += units[i].elements.length unitIdIndex.set(units[i].id, i) } - scale = ColorScale.create({ domain: [ 0, elementCount - 1 ] }) + scale = ColorScale.create({ domain: [ 0, elementCount - 1 ], list: props.list }) const scaleColor = scale.color color = (location: Location): Color => { @@ -48,6 +48,7 @@ export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme { } return { + features: { list: true }, granularity: 'groupInstance', color, description: Description, diff --git a/src/mol-theme/color/element-symbol.ts b/src/mol-theme/color/element-symbol.ts index e382f14d87f48d496faaa8eb2c0e794bbc04aa5c..8d7f87b21d0d99e686fea90c4011a3df572d7b2d 100644 --- a/src/mol-theme/color/element-symbol.ts +++ b/src/mol-theme/color/element-symbol.ts @@ -40,6 +40,7 @@ export function ElementSymbolColorTheme(props: ColorThemeProps): ColorTheme { } return { + features: {}, granularity: 'group', color, description: Description, diff --git a/src/mol-theme/color/molecule-type.ts b/src/mol-theme/color/molecule-type.ts index f2be520fe8c9791b3d4920d8634aa7da709d9662..9bdc21d39a52dae10358d5f0d3c61feda2cabd44 100644 --- a/src/mol-theme/color/molecule-type.ts +++ b/src/mol-theme/color/molecule-type.ts @@ -49,6 +49,7 @@ export function MoleculeTypeColorTheme(props: ColorThemeProps): ColorTheme { } return { + features: {}, granularity: 'group', color, description: Description, diff --git a/src/mol-theme/color/polymer-index.ts b/src/mol-theme/color/polymer-index.ts index 891b17300f72f94ab19e1c1883e19c303f9d0659..b32fa80cbaa1649bbdf2b0aed8d2ace1f6f9b3e8 100644 --- a/src/mol-theme/color/polymer-index.ts +++ b/src/mol-theme/color/polymer-index.ts @@ -22,7 +22,7 @@ export function PolymerIndexColorTheme(props: ColorThemeProps): ColorTheme { for (let i = 0, il = units.length; i <il; ++i) { if (units[i].polymerElements.length > 0) ++polymerCount } - scale = ColorScale.create({ domain: [ 0, polymerCount - 1 ] }) + scale = ColorScale.create({ list: props.list, domain: [ 0, polymerCount - 1 ] }) const unitIdColor = new Map<number, Color>() for (let i = 0, j = 0, il = units.length; i <il; ++i) { if (units[i].polymerElements.length > 0) { @@ -45,6 +45,7 @@ export function PolymerIndexColorTheme(props: ColorThemeProps): ColorTheme { } return { + features: { structure: true, list: true }, granularity: 'instance', color, description: Description, diff --git a/src/mol-theme/color/residue-name.ts b/src/mol-theme/color/residue-name.ts index 02f2425fbc446cc9ca174ae743073b9b047c2501..756ef8c482458704ceaca1f097cfbe8f9fa9216a 100644 --- a/src/mol-theme/color/residue-name.ts +++ b/src/mol-theme/color/residue-name.ts @@ -105,6 +105,7 @@ export function ResidueNameColorTheme(props: ColorThemeProps): ColorTheme { } return { + features: {}, granularity: 'group', color, description: Description, diff --git a/src/mol-theme/color/secondary-structure.ts b/src/mol-theme/color/secondary-structure.ts index 55e76a3da44858ad6703322fc7956abfc38f3434..d9a6fd7b6e15518dd354c721417e7e1c73ca75b6 100644 --- a/src/mol-theme/color/secondary-structure.ts +++ b/src/mol-theme/color/secondary-structure.ts @@ -72,6 +72,7 @@ export function SecondaryStructureColorTheme(props: ColorThemeProps): ColorTheme } return { + features: {}, granularity: 'group', color, description: Description, diff --git a/src/mol-theme/color/sequence-id.ts b/src/mol-theme/color/sequence-id.ts index 7f68bf57e787716054a599e67c789c1214e5814e..808e4ace55c17a952ee46d6dd8fc14f8c68dd8e5 100644 --- a/src/mol-theme/color/sequence-id.ts +++ b/src/mol-theme/color/sequence-id.ts @@ -10,6 +10,7 @@ import { ColorScale, Color } from 'mol-util/color'; import { Location } from 'mol-model/location'; import { ColorThemeProps, ColorTheme } from '../color'; import { ColorOther } from 'mol-util/color/tables'; +import { defaults } from 'mol-util'; const DefaultColor = Color(0xCCCCCC) const Description = 'Gives every polymer residue a color based on its `seq_id` value.' @@ -57,7 +58,7 @@ function getSequenceLength(unit: Unit, element: ElementIndex) { export function SequenceIdColorTheme(props: ColorThemeProps): ColorTheme { const p = { ...props, - colors: ColorOther.rainbow, + list: defaults(props.list, ColorOther.rainbow), minLabel: 'Start', maxLabel: 'End', } @@ -83,6 +84,7 @@ export function SequenceIdColorTheme(props: ColorThemeProps): ColorTheme { } return { + features: { list: true }, granularity: 'group', color, description: Description, diff --git a/src/mol-theme/color/shape-group.ts b/src/mol-theme/color/shape-group.ts index 6743791a3c58d823359eab0f6f8052c1bb8b55aa..0d74a08c77afa0c23f265036e0279daf2c1d76b5 100644 --- a/src/mol-theme/color/shape-group.ts +++ b/src/mol-theme/color/shape-group.ts @@ -13,6 +13,7 @@ const DefaultColor = Color(0xCCCCCC) export function ShapeGroupColorTheme(props: ColorThemeProps): ColorTheme { return { + features: {}, granularity: 'group', color: (location: Location): Color => { if (Shape.isLocation(location)) { diff --git a/src/mol-theme/color/uniform.ts b/src/mol-theme/color/uniform.ts index d9ab15c4db1cae6a21d6dd7b3376d3cd87817ce1..f7fb57769ecbdcfbdbe6a9ba6bda5507eedbd45f 100644 --- a/src/mol-theme/color/uniform.ts +++ b/src/mol-theme/color/uniform.ts @@ -14,6 +14,7 @@ export function UniformColorTheme(props: ColorThemeProps): ColorTheme { const color = props.value || DefaultColor return { + features: {}, granularity: 'uniform', color: () => color, description: Description, diff --git a/src/mol-theme/color/unit-index.ts b/src/mol-theme/color/unit-index.ts index 3e4fed18b986e43f85fa9c076d9d765695f73494..f41b29199a01f064b84b4c3155fd64b06da9c4cd 100644 --- a/src/mol-theme/color/unit-index.ts +++ b/src/mol-theme/color/unit-index.ts @@ -37,6 +37,7 @@ export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme { } return { + features: {}, granularity: 'instance', color, description: Description, diff --git a/src/mol-util/color/color.ts b/src/mol-util/color/color.ts index 1668282d9125336756abbd5b20296924472b2552..426c639b538118909cfc392688197f6db691020a 100644 --- a/src/mol-util/color/color.ts +++ b/src/mol-util/color/color.ts @@ -65,8 +65,8 @@ export namespace Color { } } -type ColorTable<T extends { [k: string]: number[] }> = { [k in keyof T]: Color[] } +export type ColorTable<T extends { [k: string]: number[] }> = { [k in keyof T]: Color[] } export function ColorTable<T extends { [k: string]: number[] }>(o: T) { return o as ColorTable<T> } -type ColorMap<T extends { [k: string]: number }> = { [k in keyof T]: Color } +export type ColorMap<T extends { [k: string]: number }> = { [k in keyof T]: Color } export function ColorMap<T extends { [k: string]: number }>(o: T) { return o as ColorMap<T> } \ No newline at end of file diff --git a/src/mol-util/color/index.ts b/src/mol-util/color/index.ts index 2332d4a24ec9502444a54e46e15a1b546b412f49..33691a4115e086ca31cd68ca87f5ee7fdb129885 100644 --- a/src/mol-util/color/index.ts +++ b/src/mol-util/color/index.ts @@ -4,6 +4,5 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -export { Color, ColorMap, ColorTable } from './color' -export { ColorScale } from './scale'; -export { ColorBrewer, ColorNames } from './tables' \ No newline at end of file +export { Color, ColorMap, ColorTable } from './color'; +export { ColorScale } from './scale'; \ No newline at end of file diff --git a/src/mol-util/color/scale.ts b/src/mol-util/color/scale.ts index e4bc9bb02e0efa3bd0f34b34dc4c6bf8b069d29d..c7cf7980c114e7b5363ede0cc7b80a1b176c0f5e 100644 --- a/src/mol-util/color/scale.ts +++ b/src/mol-util/color/scale.ts @@ -25,7 +25,7 @@ export interface ColorScale { export const DefaultColorScale = { domain: [0, 1], reverse: false, - colors: ColorBrewer.RdYlBu, + list: ColorBrewer.RdYlBu, minLabel: '' as string | undefined, maxLabel: '' as string | undefined, } @@ -33,8 +33,10 @@ export type ColorScaleProps = Partial<typeof DefaultColorScale> export namespace ColorScale { export function create(props: ColorScaleProps): ColorScale { - const { domain, reverse, colors: _colors } = { ...DefaultColorScale, ...props } - const colors = reverse ? _colors.slice().reverse() : _colors + // ensure that no undefined .list property exists so that the default assignment works + if (props.list === undefined) delete props.list + const { domain, reverse, list } = { ...DefaultColorScale, ...props } + const colors = reverse ? list.slice().reverse() : list const count1 = colors.length - 1 let diff = 0, min = 0, max = 0