Alexander Rose 6 lat temu
rodzic
commit
aba3b21a46

+ 4 - 0
src/mol-geo/geometry/overpaint-data.ts

@@ -23,6 +23,10 @@ export function applyOverpaintColor(array: Uint8Array, start: number, end: numbe
     return true
 }
 
+export function clearOverpaint(array: Uint8Array, start: number, end: number) {
+    array.fill(0, start, end)
+}
+
 export function createOverpaint(count: number, overpaintData?: OverpaintData): OverpaintData {
     const overpaint = createTextureImage(Math.max(1, count), 4, overpaintData && overpaintData.tOverpaint.ref.value.array)
     if (overpaintData) {

+ 39 - 23
src/mol-plugin/behavior/dynamic/representation.ts

@@ -7,7 +7,7 @@
 
 import { MarkerAction } from 'mol-geo/geometry/marker-data';
 import { Mat4, Vec3 } from 'mol-math/linear-algebra';
-import { EmptyLoci, EveryLoci } from 'mol-model/loci';
+import { EmptyLoci } from 'mol-model/loci';
 import { StructureUnitTransforms } from 'mol-model/structure/structure/util/unit-transforms';
 import { PluginContext } from 'mol-plugin/context';
 import { PluginStateObject } from 'mol-plugin/state/objects';
@@ -216,11 +216,28 @@ namespace ColorMappings {
 
 export namespace ColorRepresentation3D {
     export const Params = {
-        query: PD.ScriptExpression({ language: 'mol-script', expression: '(sel.atom.atom-groups :residue-test (= atom.resname LYS))' }),
-        color: PD.Color(ColorNames.blueviolet)
-        // colorMappings: PD.Value<ColorMappings>([{ query: MS.struct.generator.atomGroups({
-        //     'residue-test': MS.core.rel.eq([MS.ammp('auth_comp_id'), 'ALA'])
-        // }), color: ColorNames.greenyellow }], { isHidden: true }),
+        layers: PD.ObjectList({
+            query: PD.ScriptExpression({ language: 'mol-script', expression: '(sel.atom.atom-groups :residue-test (= atom.resname LYS))' }),
+            color: PD.Color(ColorNames.blueviolet)
+        }, e => `${Color.toRgbString(e.color)}`, {
+            defaultValue: [
+                {
+                    query: {
+                        language: 'mol-script',
+                        expression: '(sel.atom.atom-groups :residue-test (= atom.resname LYS))'
+                    },
+                    color: ColorNames.blueviolet
+                },
+                {
+                    query: {
+                        language: 'mol-script',
+                        expression: '(sel.atom.atom-groups :residue-test (= atom.resname ALA))'
+                    },
+                    color: ColorNames.chartreuse
+                }
+            ]
+        }),
+        alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity' }),
     }
     export type Params = PD.Values<typeof Params>
 
@@ -242,44 +259,43 @@ export namespace ColorRepresentation3D {
         }
 
         update(params: Params): boolean {
-            const parsed = parseMolScript(params.query.expression);
-            if (parsed.length === 0) throw new Error('No query');
-            const query = transpileMolScript(parsed[0]);
-
-            return this.applyMappings([{ query, color: params.color }])
+            const { layers, alpha } = params
+            const colorMappings: ColorMappings = []
+            for (let i = 0, il = params.layers.length; i < il; ++i) {
+                const { query, color } = layers[i]
+                const parsed = parseMolScript(query.expression);
+                if (parsed.length === 0) throw new Error('No query');
+                colorMappings.push({ query: transpileMolScript(parsed[0]), color })
+            }
+            return this.applyMappings(colorMappings, alpha)
         }
 
-        private applyMappings(colorMappings: ColorMappings): boolean {
+        private applyMappings(colorMappings: ColorMappings, alpha: number): boolean {
             if (!this.updateData() && ColorMappings.areEqual(colorMappings, this.currentColorMappings)) return false;
             this.currentColorMappings = colorMappings;
             if (!this.repr.data || !this.structure.data) return true;
 
-            const layers: Overpaint.Layers = [
-                // unsets the overpaint
-                // TODO do smarter by looking at the current color mappings
-                { loci: EveryLoci, color: ColorNames.black, alpha: 0 }
-            ]
-            // console.log('currentColorMappings', this.currentColorMappings)
+            const list: Overpaint.Layer[] = []
             for (let i = 0, il = this.currentColorMappings.length; i < il; ++i) {
                 const { query, color } = this.currentColorMappings[i]
                 const compiled = compile<StructureSelection>(query);
                 const result = compiled(new QueryContext(this.structure.data));
                 const loci = StructureSelection.toLoci2(result)
-                layers.push({ loci, color, alpha: 1 })
+                list.push({ loci, color })
             }
-            return this.applyLayers(layers)
+            return this.applyLayers({ alpha, list }, true)
         }
 
-        private applyLayers(layers: Overpaint.Layers): boolean {
+        private applyLayers(layers: Overpaint.Layers, clear: boolean): boolean {
             if (!this.repr.data) return true;
-            this.repr.data.setOverpaint(layers)
+            this.repr.data.setOverpaint(layers, clear)
             this.ctx.canvas3d.add(this.repr.data);
             this.ctx.canvas3d.requestDraw(true);
             return true;
         }
 
         unregister(): void {
-            this.applyLayers([{ loci: EveryLoci, color: ColorNames.black, alpha: 0 }]) // clear
+            this.applyLayers(Overpaint.EmptyLayers, true) // clear
             this.repr.cell = void 0;
             this.structure.cell = void 0;
         }

+ 1 - 1
src/mol-repr/representation.ts

@@ -122,7 +122,7 @@ interface Representation<D, P extends PD.Params = {}, S extends Representation.S
     createOrUpdate: (props?: Partial<PD.Values<P>>, data?: D) => Task<void>
     setState: (state: Partial<S>) => void
     setTheme: (theme: Theme) => void
-    setOverpaint: (layers: Overpaint.Layers) => void
+    setOverpaint: (layers: Overpaint.Layers, clear?: boolean) => void
     getLoci: (pickingId: PickingId) => ModelLoci
     mark: (loci: ModelLoci, action: MarkerAction) => boolean
     destroy: () => void

+ 13 - 7
src/mol-repr/shape/representation.ts

@@ -27,7 +27,7 @@ import { Visual } from 'mol-repr/visual';
 import { createSizes } from 'mol-geo/geometry/size-data';
 import { ShapeGroupSizeTheme } from 'mol-theme/size/shape-group';
 import { Overpaint } from 'mol-theme/overpaint';
-import { applyOverpaintColor } from 'mol-geo/geometry/overpaint-data';
+import { applyOverpaintColor, createOverpaint, clearOverpaint } from 'mol-geo/geometry/overpaint-data';
 
 export interface ShapeRepresentation<D, G extends Geometry, P extends Geometry.Params<G>> extends Representation<D, P> { }
 
@@ -203,21 +203,27 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
         setTheme(theme: Theme) {
             console.warn('The `ShapeRepresentation` theme is fixed to `ShapeGroupColorTheme` and `ShapeGroupSizeTheme`. Colors are taken from `Shape.getColor` and sizes from `Shape.getSize`')
         },
-        setOverpaint(layers: Overpaint.Layers) {
+        setOverpaint(layers: Overpaint.Layers, clear?: boolean) {
             if (!_renderObject) return false
             const { tOverpaint } = _renderObject.values
-            const { groupCount, instanceCount } = locationIt
+            const count = locationIt.groupCount * locationIt.instanceCount
+
+            // ensure texture has right size
+            createOverpaint(layers.list.length ? count : 0, _renderObject.values)
+
+            // clear if requested
+            if (clear) clearOverpaint(tOverpaint.ref.value.array, 0, count)
 
-            for (let i = 0, il = layers.length; i < il; ++i) {
-                const { loci, color, alpha } = layers[i]
+            for (let i = 0, il = layers.list.length; i < il; ++i) {
+                const { loci, color } = layers.list[i]
                 const apply = (interval: Interval) => {
                     const start = Interval.start(interval)
                     const end = Interval.end(interval)
-                    return applyOverpaintColor(tOverpaint.ref.value.array, start, end, color, alpha)
+                    return applyOverpaintColor(tOverpaint.ref.value.array, start, end, color, layers.alpha)
                 }
 
                 if (isEveryLoci(loci) || (Shape.isLoci(loci) && loci.shape === _shape)) {
-                    apply(Interval.ofBounds(0, groupCount * instanceCount))
+                    apply(Interval.ofBounds(0, count))
                 } else {
                     eachShapeLocation(loci, _shape, apply)
                 }

+ 2 - 2
src/mol-repr/structure/complex-representation.ts

@@ -79,8 +79,8 @@ export function ComplexRepresentation<P extends StructureParams>(label: string,
         _theme = theme
     }
 
-    function setOverpaint(layers: Overpaint.Layers) {
-        if (visual) visual.setOverpaint(layers)
+    function setOverpaint(layers: Overpaint.Layers, clear?: boolean) {
+        if (visual) visual.setOverpaint(layers, clear)
     }
 
     function destroy() {

+ 11 - 8
src/mol-repr/structure/complex-visual.ts

@@ -29,7 +29,7 @@ import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume';
 import { Mat4 } from 'mol-math/linear-algebra';
 import { createIdentityTransform } from 'mol-geo/geometry/transform-data';
 import { Overpaint } from 'mol-theme/overpaint';
-import { applyOverpaintColor, createOverpaint } from 'mol-geo/geometry/overpaint-data';
+import { applyOverpaintColor, createOverpaint, clearOverpaint } from 'mol-geo/geometry/overpaint-data';
 
 export interface  ComplexVisual<P extends StructureParams> extends Visual<Structure, P> { }
 
@@ -208,24 +208,27 @@ export function ComplexVisual<G extends Geometry, P extends ComplexParams & Geom
         setTransform(matrix?: Mat4, instanceMatrices?: Float32Array | null) {
             Visual.setTransform(renderObject, matrix, instanceMatrices)
         },
-        setOverpaint(layers: Overpaint.Layers) {
+        setOverpaint(layers: Overpaint.Layers, clear = false) {
             if (!renderObject) return false
             const { tOverpaint } = renderObject.values
-            const { groupCount, instanceCount } = locationIt
+            const count = locationIt.groupCount * locationIt.instanceCount
 
             // ensure texture has right size
-            createOverpaint(layers.length ? groupCount * instanceCount : 0, renderObject.values)
+            createOverpaint(layers.list.length ? count : 0, renderObject.values)
+
+            // clear if requested
+            if (clear) clearOverpaint(tOverpaint.ref.value.array, 0, count)
 
-            for (let i = 0, il = layers.length; i < il; ++i) {
-                const { loci, color, alpha } = layers[i]
+            for (let i = 0, il = layers.list.length; i < il; ++i) {
+                const { loci, color } = layers.list[i]
                 const apply = (interval: Interval) => {
                     const start = Interval.start(interval)
                     const end = Interval.end(interval)
-                    return applyOverpaintColor(tOverpaint.ref.value.array, start, end, color, alpha)
+                    return applyOverpaintColor(tOverpaint.ref.value.array, start, end, color, layers.alpha)
                 }
 
                 if (isEveryLoci(loci) || (Structure.isLoci(loci) && Structure.areEquivalent(loci.structure, currentStructure))) {
-                    apply(Interval.ofBounds(0, groupCount * instanceCount))
+                    apply(Interval.ofBounds(0, count))
                 } else {
                     eachLocation(loci, currentStructure, apply)
                 }

+ 2 - 2
src/mol-repr/structure/units-representation.ts

@@ -194,8 +194,8 @@ export function UnitsRepresentation<P extends UnitsParams>(label: string, ctx: R
         _theme = theme
     }
 
-    function setOverpaint(layers: Overpaint.Layers) {
-        visuals.forEach(({ visual }) => visual.setOverpaint(layers))
+    function setOverpaint(layers: Overpaint.Layers, clear?: boolean) {
+        visuals.forEach(({ visual }) => visual.setOverpaint(layers, clear))
     }
 
     function destroy() {

+ 11 - 8
src/mol-repr/structure/units-visual.ts

@@ -32,7 +32,7 @@ import { Mat4 } from 'mol-math/linear-algebra';
 import { Spheres } from 'mol-geo/geometry/spheres/spheres';
 import { createUnitsTransform, includesUnitKind } from './visual/util/common';
 import { Overpaint } from 'mol-theme/overpaint';
-import { applyOverpaintColor, createOverpaint } from 'mol-geo/geometry/overpaint-data';
+import { applyOverpaintColor, createOverpaint, clearOverpaint } from 'mol-geo/geometry/overpaint-data';
 
 export type StructureGroup = { structure: Structure, group: Unit.SymmetryGroup }
 
@@ -254,24 +254,27 @@ export function UnitsVisual<G extends Geometry, P extends UnitsParams & Geometry
         setTransform(matrix?: Mat4, instanceMatrices?: Float32Array | null) {
             Visual.setTransform(renderObject, matrix, instanceMatrices)
         },
-        setOverpaint(layers: Overpaint.Layers) {
+        setOverpaint(layers: Overpaint.Layers, clear = false) {
             if (!renderObject) return false
             const { tOverpaint } = renderObject.values
-            const { groupCount, instanceCount } = locationIt
+            const count = locationIt.groupCount * locationIt.instanceCount
 
             // ensure texture has right size
-            createOverpaint(layers.length ? groupCount * instanceCount : 0, renderObject.values)
+            createOverpaint(layers.list.length ? count : 0, renderObject.values)
+
+            // clear if requested
+            if (clear) clearOverpaint(tOverpaint.ref.value.array, 0, count)
 
-            for (let i = 0, il = layers.length; i < il; ++i) {
-                const { loci, color, alpha } = layers[i]
+            for (let i = 0, il = layers.list.length; i < il; ++i) {
+                const { loci, color } = layers.list[i]
                 const apply = (interval: Interval) => {
                     const start = Interval.start(interval)
                     const end = Interval.end(interval)
-                    return applyOverpaintColor(tOverpaint.ref.value.array, start, end, color, alpha)
+                    return applyOverpaintColor(tOverpaint.ref.value.array, start, end, color, layers.alpha)
                 }
 
                 if (isEveryLoci(loci) || (Structure.isLoci(loci) && Structure.areEquivalent(loci.structure, currentStructureGroup.structure))) {
-                    apply(Interval.ofBounds(0, groupCount * instanceCount))
+                    apply(Interval.ofBounds(0, count))
                 } else {
                     eachLocation(loci, currentStructureGroup, apply)
                 }

+ 1 - 1
src/mol-repr/visual.ts

@@ -36,7 +36,7 @@ interface Visual<D, P extends PD.Params> {
     setAlphaFactor: (alphaFactor: number) => void
     setPickable: (pickable: boolean) => void
     setTransform: (matrix?: Mat4, instanceMatrices?: Float32Array | null) => void
-    setOverpaint: (layers: Overpaint.Layers) => void
+    setOverpaint: (layers: Overpaint.Layers, clear?: boolean) => void
     destroy: () => void
 }
 namespace Visual {

+ 1 - 1
src/mol-repr/volume/representation.ts

@@ -194,7 +194,7 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet
         setTransform(matrix?: Mat4, instanceMatrices?: Float32Array | null) {
             Visual.setTransform(renderObject, matrix, instanceMatrices)
         },
-        setOverpaint(layers: Overpaint.Layers) {
+        setOverpaint(layers: Overpaint.Layers, clear?: boolean) {
             return false // TODO
         },
         destroy() {

+ 9 - 12
src/mol-theme/overpaint.ts

@@ -9,20 +9,17 @@ import { Color } from 'mol-util/color';
 
 export { Overpaint }
 namespace Overpaint {
-    export interface Layer {
-        loci: Loci
-        color: Color
-        alpha: number
-    }
-    export type Layers = Layer[]
+    export type Layer = { readonly loci: Loci, readonly color: Color }
+    export type Layers = { list: ReadonlyArray<Layer>, readonly alpha: number }
+    export const EmptyLayers: Layers = { list: [], alpha: 1 }
 
     export function areEqual(layersA: Layers, layersB: Layers) {
-        if (layersA.length === 0 && layersB.length === 0) return true
-        if (layersA.length !== layersB.length) return false
-        for (let i = 0, il = layersA.length; i < il; ++i) {
-            if (layersA[i].alpha !== layersB[i].alpha) return false
-            if (layersA[i].color !== layersB[i].color) return false
-            if (!Loci.areEqual(layersA[i].loci, layersB[i].loci)) return false
+        if (layersA.list.length === 0 && layersB.list.length === 0) return true
+        if (layersA.list.length !== layersB.list.length) return false
+        if (layersA.alpha !== layersB.alpha) return false
+        for (let i = 0, il = layersA.list.length; i < il; ++i) {
+            if (layersA.list[i].color !== layersB.list[i].color) return false
+            if (!Loci.areEqual(layersA.list[i].loci, layersB.list[i].loci)) return false
         }
         return true
     }