Browse Source

Merge branch 'master' of https://github.com/molstar/molstar into dynbonds

Alexander Rose 3 years ago
parent
commit
e211abd5ae

+ 2 - 0
.gitignore

@@ -9,3 +9,5 @@ tsconfig.commonjs.tsbuildinfo
 
 *.sublime-workspace
 .idea
+
+.DS_Store

+ 10 - 0
CHANGELOG.md

@@ -6,6 +6,10 @@ Note that since we don't clearly distinguish between a public and private interf
 
 ## [Unreleased]
 
+- Add surronding atoms (5 Angstrom) structure selection query
+
+## [v2.2.0] - 2021-07-31
+
 - Add `tubularHelices` parameter to Cartoon representation
 - Add `SdfFormat` and update SDF parser to be able to parse data headers according to spec (hopefully :)) #230
 - Fix mononucleotides detected as polymer components (#229)
@@ -15,6 +19,12 @@ Note that since we don't clearly distinguish between a public and private interf
 - Add USDZ support to ``geo-export`` extension.
 - Fix `includeParent` support for multi-instance bond visuals.
 - Add `operator` Loci granularity, selecting everything with the same operator name.
+- Prefer ``_label_seq_id`` fields in secondary structure assignment.
+- Support new EMDB API (https://www.ebi.ac.uk/emdb/api/entry/map/[EMBD-ID]) for EM volume contour levels.
+- ``Canvas3D`` tweaks:
+    - Update ``forceDraw`` logic.
+    - Ensure the scene is re-rendered when viewport size changes.
+    - Support ``noDraw`` mode in ``PluginAnimationLoop``.
 
 ## [v2.1.0] - 2021-07-05
 

+ 2 - 2
package-lock.json

@@ -1,11 +1,11 @@
 {
   "name": "molstar",
-  "version": "2.2.0-dev.1",
+  "version": "2.2.0",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
-      "version": "2.0.7",
+      "version": "2.2.0",
       "license": "MIT",
       "dependencies": {
         "@types/argparse": "^1.0.38",

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "molstar",
-  "version": "2.2.0-dev.1",
+  "version": "2.2.0",
   "description": "A comprehensive macromolecular library.",
   "homepage": "https://github.com/molstar/molstar#readme",
   "repository": {

+ 18 - 11
src/mol-canvas3d/canvas3d.ts

@@ -222,9 +222,11 @@ interface Canvas3D {
     animate(): void
     /**
      * Pause animation loop and optionally any rendering
-     * @param noDraw pause any rendering
+     * @param noDraw pause any rendering (drawPaused = true)
      */
     pause(noDraw?: boolean): void
+    /** Sets drawPaused = false without starting the built in animation loop */
+    resume(): void
     identify(x: number, y: number): PickData | undefined
     mark(loci: Representation.Loci, action: MarkerAction): void
     getLoci(pickingId: PickingId | undefined): Representation.Loci
@@ -305,7 +307,6 @@ namespace Canvas3D {
         const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input, camera);
         const multiSampleHelper = new MultiSampleHelper(passes.multiSample);
 
-        let drawPending = false;
         let cameraResetRequested = false;
         let nextCameraResetDuration: number | undefined = void 0;
         let nextCameraResetSnapshot: Camera.SnapshotProvider | undefined = void 0;
@@ -373,9 +374,13 @@ namespace Canvas3D {
             let didRender = false;
             controls.update(currentTime);
             const cameraChanged = camera.update();
-            const multiSampleChanged = multiSampleHelper.update(force || cameraChanged, p.multiSample);
 
-            if (resized || force || cameraChanged || multiSampleChanged) {
+            const shouldRender = force || cameraChanged || resized || forceNextRender;
+            forceNextRender = false;
+
+            const multiSampleChanged = multiSampleHelper.update(shouldRender, p.multiSample);
+
+            if (shouldRender || multiSampleChanged) {
                 let cam: Camera | StereoCamera = camera;
                 if (p.camera.stereo.name === 'on') {
                     stereoCamera.update();
@@ -394,24 +399,20 @@ namespace Canvas3D {
             return didRender;
         }
 
-        let forceNextDraw = false;
+        let forceNextRender = false;
         let forceDrawAfterAllCommited = false;
         let currentTime = 0;
         let drawPaused = false;
 
         function draw(force?: boolean) {
             if (drawPaused) return;
-            if (render(!!force || forceNextDraw) && notifyDidDraw) {
+            if (render(!!force) && notifyDidDraw) {
                 didDraw.next(now() - startTime as now.Timestamp);
             }
-            forceNextDraw = false;
-            drawPending = false;
         }
 
         function requestDraw(force?: boolean) {
-            if (drawPending) return;
-            drawPending = true;
-            forceNextDraw = !!force;
+            forceNextRender = forceNextRender || !!force;
         }
 
         let animationFrameHandle = 0;
@@ -703,6 +704,7 @@ namespace Canvas3D {
             animate,
             resetTime,
             pause,
+            resume: () => { drawPaused = false; },
             identify,
             mark,
             getLoci,
@@ -816,6 +818,8 @@ namespace Canvas3D {
         };
 
         function updateViewport() {
+            const oldX = x, oldY = y, oldWidth = width, oldHeight = height;
+
             if (p.viewport.name === 'canvas') {
                 x = 0;
                 y = 0;
@@ -836,6 +840,9 @@ namespace Canvas3D {
                 // console.log({ x, y, width, height });
             }
 
+            if (oldX !== x || oldY !== y || oldWidth !== width || oldHeight !== height) {
+                forceNextRender = true;
+            }
         }
 
         function syncViewport() {

+ 0 - 3
src/mol-geo/geometry/mesh/mesh.ts

@@ -387,9 +387,6 @@ export namespace Mesh {
 
     function createValues(mesh: Mesh, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: PD.Values<Params>): MeshValues {
         const { instanceCount, groupCount } = locationIt;
-        if (instanceCount !== transform.instanceCount.ref.value) {
-            throw new Error('instanceCount values in TransformData and LocationIterator differ');
-        }
         const positionIt = createPositionIterator(mesh, transform);
 
         const color = createColors(locationIt, positionIt, theme.color);

+ 57 - 35
src/mol-model-formats/structure/property/secondary-structure.ts

@@ -19,6 +19,7 @@ export { ModelSecondaryStructure };
 
 type StructConf = Table<mmCIF_Schema['struct_conf']>
 type StructSheetRange = Table<mmCIF_Schema['struct_sheet_range']>
+type CoordinateType = 'label' | 'auth';
 
 namespace ModelSecondaryStructure {
     export const Descriptor: CustomPropertyDescriptor = {
@@ -30,9 +31,12 @@ namespace ModelSecondaryStructure {
     export function fromStruct(conf: StructConf, sheetRange: StructSheetRange, hierarchy: AtomicHierarchy): SecondaryStructure {
         const map: SecondaryStructureMap = new Map();
         const elements: SecondaryStructure.Element[] = [{ kind: 'none' }];
-        addHelices(conf, map, elements);
+
+        const coordinates = getCoordinateType(conf, sheetRange);
+
+        addHelices(conf, coordinates, map, elements);
         // must add Helices 1st because of 'key' value assignment.
-        addSheets(sheetRange, map, conf._rowCount, elements);
+        addSheets(sheetRange, coordinates, map, conf._rowCount, elements);
 
         const n = hierarchy.residues._rowCount;
         const getIndex = (rI: ResidueIndex) => rI;
@@ -43,15 +47,24 @@ namespace ModelSecondaryStructure {
             elements
         };
 
-        if (map.size > 0) assignSecondaryStructureRanges(hierarchy, map, secStruct);
+        if (map.size > 0) assignSecondaryStructureRanges(hierarchy, coordinates, map, secStruct);
         return SecondaryStructure(secStruct.type, secStruct.key, secStruct.elements, getIndex);
     }
 }
 
+function getCoordinateType(conf: StructConf, sheetRange: StructSheetRange): CoordinateType {
+    if (conf._rowCount > 0) {
+        if (conf.beg_label_seq_id.valueKind(0) !== Column.ValueKind.Present || conf.end_label_seq_id.valueKind(0) !== Column.ValueKind.Present) return 'auth';
+    } else if (sheetRange) {
+        if (sheetRange.beg_label_seq_id.valueKind(0) !== Column.ValueKind.Present || sheetRange.end_label_seq_id.valueKind(0) !== Column.ValueKind.Present) return 'auth';
+    }
+    return 'label';
+}
+
 type SecondaryStructureEntry = {
-    startSeqNumber: number,
+    startSeqId: number,
     startInsCode: string | null,
-    endSeqNumber: number,
+    endSeqId: number,
     endInsCode: string | null,
     type: SecondaryStructureType,
     key: number
@@ -59,13 +72,16 @@ type SecondaryStructureEntry = {
 type SecondaryStructureMap = Map<string, Map<number, SecondaryStructureEntry[]>>
 type SecondaryStructureData = { type: SecondaryStructureType[], key: number[], elements: SecondaryStructure.Element[] }
 
-function addHelices(cat: StructConf, map: SecondaryStructureMap, elements: SecondaryStructure.Element[]) {
+function addHelices(cat: StructConf, coordinates: CoordinateType, map: SecondaryStructureMap, elements: SecondaryStructure.Element[]) {
     if (!cat._rowCount) return;
 
-    const { beg_label_asym_id, beg_auth_seq_id, pdbx_beg_PDB_ins_code } = cat;
-    const { end_auth_seq_id, pdbx_end_PDB_ins_code } = cat;
+    const { beg_label_asym_id, beg_label_seq_id, beg_auth_seq_id, pdbx_beg_PDB_ins_code } = cat;
+    const { end_label_seq_id, end_auth_seq_id, pdbx_end_PDB_ins_code } = cat;
     const { pdbx_PDB_helix_class, conf_type_id, details } = cat;
 
+    const beg_seq_id = coordinates === 'label' ? beg_label_seq_id : beg_auth_seq_id;
+    const end_seq_id = coordinates === 'label' ? end_label_seq_id : end_auth_seq_id;
+
     for (let i = 0, _i = cat._rowCount; i < _i; i++) {
         const type = SecondaryStructureType.create(pdbx_PDB_helix_class.valueKind(i) === Column.ValueKind.Present
             ? SecondaryStructureType.SecondaryStructurePdb[pdbx_PDB_helix_class.value(i)]
@@ -81,9 +97,9 @@ function addHelices(cat: StructConf, map: SecondaryStructureMap, elements: Secon
             details: details.valueKind(i) === Column.ValueKind.Present ? details.value(i) : void 0
         };
         const entry: SecondaryStructureEntry = {
-            startSeqNumber: beg_auth_seq_id.value(i),
+            startSeqId: beg_seq_id.value(i),
             startInsCode: pdbx_beg_PDB_ins_code.value(i),
-            endSeqNumber: end_auth_seq_id.value(i),
+            endSeqId: end_seq_id.value(i),
             endInsCode: pdbx_end_PDB_ins_code.value(i),
             type,
             key: elements.length
@@ -94,24 +110,27 @@ function addHelices(cat: StructConf, map: SecondaryStructureMap, elements: Secon
         const asymId = beg_label_asym_id.value(i)!;
         if (map.has(asymId)) {
             const entries = map.get(asymId)!;
-            if (entries.has(entry.startSeqNumber)) {
-                entries.get(entry.startSeqNumber)!.push(entry);
+            if (entries.has(entry.startSeqId)) {
+                entries.get(entry.startSeqId)!.push(entry);
             } else {
-                entries.set(entry.startSeqNumber, [entry]);
+                entries.set(entry.startSeqId, [entry]);
             }
         } else {
-            map.set(asymId, new Map([[entry.startSeqNumber, [entry]]]));
+            map.set(asymId, new Map([[entry.startSeqId, [entry]]]));
         }
     }
 }
 
-function addSheets(cat: StructSheetRange, map: SecondaryStructureMap, sheetCount: number, elements: SecondaryStructure.Element[]) {
+function addSheets(cat: StructSheetRange, coordinates: CoordinateType, map: SecondaryStructureMap, sheetCount: number, elements: SecondaryStructure.Element[]) {
     if (!cat._rowCount) return;
 
-    const { beg_label_asym_id, beg_auth_seq_id, pdbx_beg_PDB_ins_code } = cat;
-    const { end_auth_seq_id, pdbx_end_PDB_ins_code } = cat;
+    const { beg_label_asym_id, beg_label_seq_id, beg_auth_seq_id, pdbx_beg_PDB_ins_code } = cat;
+    const { end_label_seq_id, end_auth_seq_id, pdbx_end_PDB_ins_code } = cat;
     const { sheet_id } = cat;
 
+    const beg_seq_id = coordinates === 'label' ? beg_label_seq_id : beg_auth_seq_id;
+    const end_seq_id = coordinates === 'label' ? end_label_seq_id : end_auth_seq_id;
+
     const sheet_id_key = new Map<string, number>();
     let currentKey = sheetCount + 1;
 
@@ -132,9 +151,9 @@ function addSheets(cat: StructSheetRange, map: SecondaryStructureMap, sheetCount
             symmetry: void 0
         };
         const entry: SecondaryStructureEntry = {
-            startSeqNumber: beg_auth_seq_id.value(i),
+            startSeqId: beg_seq_id.value(i),
             startInsCode: pdbx_beg_PDB_ins_code.value(i),
-            endSeqNumber: end_auth_seq_id.value(i),
+            endSeqId: end_seq_id.value(i),
             endInsCode: pdbx_end_PDB_ins_code.value(i),
             type,
             key: elements.length
@@ -145,31 +164,33 @@ function addSheets(cat: StructSheetRange, map: SecondaryStructureMap, sheetCount
         const asymId = beg_label_asym_id.value(i)!;
         if (map.has(asymId)) {
             const entries = map.get(asymId)!;
-            if (entries.has(entry.startSeqNumber)) {
-                entries.get(entry.startSeqNumber)!.push(entry);
+            if (entries.has(entry.startSeqId)) {
+                entries.get(entry.startSeqId)!.push(entry);
             } else {
-                entries.set(entry.startSeqNumber, [entry]);
+                entries.set(entry.startSeqId, [entry]);
             }
         } else {
-            map.set(asymId, new Map([[entry.startSeqNumber, [entry]]]));
+            map.set(asymId, new Map([[entry.startSeqId, [entry]]]));
         }
     }
 
     return;
 }
 
-function assignSecondaryStructureEntry(hierarchy: AtomicHierarchy, entry: SecondaryStructureEntry, resStart: ResidueIndex, resEnd: ResidueIndex, data: SecondaryStructureData) {
-    const { auth_seq_id, pdbx_PDB_ins_code } = hierarchy.residues;
-    const { endSeqNumber, endInsCode, key, type } = entry;
+function assignSecondaryStructureEntry(hierarchy: AtomicHierarchy, coordinates: CoordinateType, entry: SecondaryStructureEntry, resStart: ResidueIndex, resEnd: ResidueIndex, data: SecondaryStructureData) {
+    const { auth_seq_id, label_seq_id, pdbx_PDB_ins_code } = hierarchy.residues;
+    const { endSeqId, endInsCode, key, type } = entry;
+
+    const seq_id = coordinates === 'label' ? label_seq_id : auth_seq_id;
 
     let rI = resStart;
     while (rI < resEnd) {
-        const seqNumber = auth_seq_id.value(rI);
+        const seqNumber = seq_id.value(rI);
         data.type[rI] = type;
         data.key[rI] = key;
 
-        if ((seqNumber > endSeqNumber) ||
-            (seqNumber === endSeqNumber && pdbx_PDB_ins_code.value(rI) === endInsCode)) {
+        if ((seqNumber > endSeqId) ||
+            (seqNumber === endSeqId && pdbx_PDB_ins_code.value(rI) === endInsCode)) {
             break;
         }
 
@@ -177,10 +198,11 @@ function assignSecondaryStructureEntry(hierarchy: AtomicHierarchy, entry: Second
     }
 }
 
-function assignSecondaryStructureRanges(hierarchy: AtomicHierarchy, map: SecondaryStructureMap, data: SecondaryStructureData) {
+function assignSecondaryStructureRanges(hierarchy: AtomicHierarchy, coordinates: CoordinateType, map: SecondaryStructureMap, data: SecondaryStructureData) {
     const { count: chainCount } = hierarchy.chainAtomSegments;
     const { label_asym_id } = hierarchy.chains;
-    const { auth_seq_id, pdbx_PDB_ins_code } = hierarchy.residues;
+    const { auth_seq_id, label_seq_id, pdbx_PDB_ins_code } = hierarchy.residues;
+    const seq_id = coordinates === 'label' ? label_seq_id : auth_seq_id;
 
     for (let cI = 0 as ChainIndex; cI < chainCount; cI++) {
         const resStart = AtomicHierarchy.chainStartResidueIndex(hierarchy, cI), resEnd = AtomicHierarchy.chainEndResidueIndexExcl(hierarchy, cI);
@@ -189,13 +211,13 @@ function assignSecondaryStructureRanges(hierarchy: AtomicHierarchy, map: Seconda
             const entries = map.get(asymId)!;
 
             for (let rI = resStart; rI < resEnd; rI++) {
-                const seqNumber = auth_seq_id.value(rI);
-                if (entries.has(seqNumber)) {
-                    const entryList = entries.get(seqNumber)!;
+                const seqId = seq_id.value(rI);
+                if (entries.has(seqId)) {
+                    const entryList = entries.get(seqId)!;
                     for (const entry of entryList) {
                         const insCode = pdbx_PDB_ins_code.value(rI);
                         if (entry.startInsCode !== insCode) continue;
-                        assignSecondaryStructureEntry(hierarchy, entry, rI, resEnd, data);
+                        assignSecondaryStructureEntry(hierarchy, coordinates, entry, rI, resEnd, data);
                     }
                 }
             }

+ 16 - 0
src/mol-plugin-state/helpers/structure-selection-query.ts

@@ -472,6 +472,21 @@ const surroundingLigands = StructureSelectionQuery('Surrounding Ligands (5 \u212
     referencesCurrent: true
 });
 
+const surroundingAtoms = StructureSelectionQuery('Surrounding Atoms (5 \u212B) of Selection', MS.struct.modifier.union([
+    MS.struct.modifier.exceptBy({
+        0: MS.struct.modifier.includeSurroundings({
+            0: MS.internal.generator.current(),
+            radius: 5,
+            'as-whole-residues': false
+        }),
+        by: MS.internal.generator.current()
+    })
+]), {
+    description: 'Select atoms within 5 \u212B of the current selection.',
+    category: StructureSelectionCategory.Manipulate,
+    referencesCurrent: true
+});
+
 const complement = StructureSelectionQuery('Inverse / Complement of Selection', MS.struct.modifier.union([
     MS.struct.modifier.exceptBy({
         0: MS.struct.generator.all(),
@@ -694,6 +709,7 @@ export const StructureSelectionQueries = {
     aromaticRing,
     surroundings,
     surroundingLigands,
+    surroundingAtoms,
     complement,
     covalentlyBonded,
     covalentlyOrMetallicBonded,

+ 9 - 3
src/mol-plugin/animation-loop.ts

@@ -31,18 +31,24 @@ export class PluginAnimationLoop {
         this.plugin.canvas3d?.resetTime(t);
     }
 
-    start() {
+    start(options?: { immediate?: boolean }) {
+        this.plugin.canvas3d?.resume();
         this._isAnimating = true;
         this.resetTime();
-        this.currentFrame = requestAnimationFrame(this.frame);
+        // TODO: should immediate be the default mode?
+        if (options?.immediate) this.frame();
+        else this.currentFrame = requestAnimationFrame(this.frame);
     }
 
-    stop() {
+    stop(options?: { noDraw?: boolean }) {
         this._isAnimating = false;
         if (this.currentFrame !== void 0) {
             cancelAnimationFrame(this.currentFrame);
             this.currentFrame = void 0;
         }
+        if (options?.noDraw) {
+            this.plugin.canvas3d?.pause(options?.noDraw);
+        }
     }
 
     constructor(private plugin: PluginContext) {

+ 15 - 1
src/mol-plugin/behavior/dynamic/volume-streaming/util.ts

@@ -76,8 +76,22 @@ export async function getContourLevelEmdb(plugin: PluginContext, taskCtx: Runtim
 }
 
 export async function getContourLevelPdbe(plugin: PluginContext, taskCtx: RuntimeContext, emdbId: string) {
+    // TODO: parametrize URL in plugin settings?
+    emdbId = emdbId.toUpperCase();
+    const header = await plugin.fetch({ url: `https://www.ebi.ac.uk/emdb/api/entry/map/${emdbId}`, type: 'json' }).runInContext(taskCtx);
+    const contours = header?.map?.contour_list?.contour;
+
+    if (!contours || contours.length === 0) {
+        // try fallback to the old API
+        return getContourLevelPdbeLegacy(plugin, taskCtx, emdbId);
+    }
+
+    return contours.find((c: any) => c.primary)?.level ?? contours[0].level;
+}
+
+async function getContourLevelPdbeLegacy(plugin: PluginContext, taskCtx: RuntimeContext, emdbId: string) {
+    // TODO: parametrize URL in plugin settings?
     emdbId = emdbId.toUpperCase();
-    // TODO: parametrize to a differnt URL? in plugin settings perhaps
     const header = await plugin.fetch({ url: `https://www.ebi.ac.uk/pdbe/api/emdb/entry/map/${emdbId}`, type: 'json' }).runInContext(taskCtx);
     const emdbEntry = header?.[emdbId];
     let contourLevel: number | undefined = void 0;

+ 10 - 10
src/mol-repr/structure/visual/gaussian-surface-mesh.ts

@@ -130,9 +130,9 @@ export function GaussianSurfaceMeshVisual(materialId: number): UnitsVisual<Gauss
         },
         processValues: (values: MeshValues, geometry: Mesh, props: PD.Values<GaussianSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
             const { resolution, colorTexture } = geometry.meta as GaussianSurfaceMeta;
-            const csp = getColorSmoothingProps(props, theme, resolution, webgl);
+            const csp = getColorSmoothingProps(props, theme, resolution);
             if (csp) {
-                applyMeshColorSmoothing(values, csp.resolution, csp.stride, csp.webgl, colorTexture);
+                applyMeshColorSmoothing(values, csp.resolution, csp.stride, webgl, colorTexture);
                 (geometry.meta.colorTexture as GaussianSurfaceMeta['colorTexture']) = values.tColorGrid.ref.value;
             }
         },
@@ -190,9 +190,9 @@ export function StructureGaussianSurfaceMeshVisual(materialId: number): ComplexV
         },
         processValues: (values: MeshValues, geometry: Mesh, props: PD.Values<GaussianSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
             const { resolution, colorTexture } = geometry.meta as GaussianSurfaceMeta;
-            const csp = getColorSmoothingProps(props, theme, resolution, webgl);
+            const csp = getColorSmoothingProps(props, theme, resolution);
             if (csp) {
-                applyMeshColorSmoothing(values, csp.resolution, csp.stride, csp.webgl, colorTexture);
+                applyMeshColorSmoothing(values, csp.resolution, csp.stride, webgl, colorTexture);
                 (geometry.meta.colorTexture as GaussianSurfaceMeta['colorTexture']) = values.tColorGrid.ref.value;
             }
         },
@@ -263,9 +263,9 @@ export function GaussianSurfaceTextureMeshVisual(materialId: number): UnitsVisua
         },
         processValues: (values: TextureMeshValues, geometry: TextureMesh, props: PD.Values<GaussianSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
             const { resolution, colorTexture } = geometry.meta as GaussianSurfaceMeta;
-            const csp = getColorSmoothingProps(props, theme, resolution, webgl);
-            if (csp) {
-                applyTextureMeshColorSmoothing(values, csp.resolution, csp.stride, csp.webgl, colorTexture);
+            const csp = getColorSmoothingProps(props, theme, resolution);
+            if (csp && webgl) {
+                applyTextureMeshColorSmoothing(values, csp.resolution, csp.stride, webgl, colorTexture);
                 (geometry.meta as GaussianSurfaceMeta).colorTexture = values.tColorGrid.ref.value;
             }
         },
@@ -339,9 +339,9 @@ export function StructureGaussianSurfaceTextureMeshVisual(materialId: number): C
         },
         processValues: (values: TextureMeshValues, geometry: TextureMesh, props: PD.Values<GaussianSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
             const { resolution, colorTexture } = geometry.meta as GaussianSurfaceMeta;
-            const csp = getColorSmoothingProps(props, theme, resolution, webgl);
-            if (csp) {
-                applyTextureMeshColorSmoothing(values, csp.resolution, csp.stride, csp.webgl, colorTexture);
+            const csp = getColorSmoothingProps(props, theme, resolution);
+            if (csp && webgl) {
+                applyTextureMeshColorSmoothing(values, csp.resolution, csp.stride, webgl, colorTexture);
                 (geometry.meta as GaussianSurfaceMeta).colorTexture = values.tColorGrid.ref.value;
             }
         },

+ 2 - 2
src/mol-repr/structure/visual/molecular-surface-mesh.ts

@@ -80,9 +80,9 @@ export function MolecularSurfaceMeshVisual(materialId: number): UnitsVisual<Mole
         },
         processValues: (values: MeshValues, geometry: Mesh, props: PD.Values<MolecularSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
             const { resolution, colorTexture } = geometry.meta as MolecularSurfaceMeta;
-            const csp = getColorSmoothingProps(props, theme, resolution, webgl);
+            const csp = getColorSmoothingProps(props, theme, resolution);
             if (csp) {
-                applyMeshColorSmoothing(values, csp.resolution, csp.stride, csp.webgl, colorTexture);
+                applyMeshColorSmoothing(values, csp.resolution, csp.stride, webgl, colorTexture);
                 (geometry.meta.colorTexture as MolecularSurfaceMeta['colorTexture']) = values.tColorGrid.ref.value;
             }
         },

+ 3 - 3
src/mol-repr/structure/visual/util/color.ts

@@ -27,8 +27,8 @@ export const ColorSmoothingParams = {
 };
 export type ColorSmoothingParams = typeof ColorSmoothingParams
 
-export function getColorSmoothingProps(props: PD.Values<ColorSmoothingParams>, theme: Theme, resolution?: number, webgl?: WebGLContext) {
-    if ((props.smoothColors.name === 'on' || (props.smoothColors.name === 'auto' && theme.color.preferSmoothing)) && resolution && resolution < 3 && webgl) {
+export function getColorSmoothingProps(props: PD.Values<ColorSmoothingParams>, theme: Theme, resolution?: number) {
+    if ((props.smoothColors.name === 'on' || (props.smoothColors.name === 'auto' && theme.color.preferSmoothing)) && resolution && resolution < 3) {
         let stride = 3;
         if (props.smoothColors.name === 'on') {
             resolution *= props.smoothColors.params.resolutionFactor;
@@ -39,7 +39,7 @@ export function getColorSmoothingProps(props: PD.Values<ColorSmoothingParams>, t
             resolution = Math.max(0.5, resolution);
             if (resolution > 1.2) stride = 2;
         }
-        return { resolution, stride, webgl };
+        return { resolution, stride };
     };
 }