UNPKG

molstar

Version:

A comprehensive macromolecular library.

196 lines (195 loc) 7.66 kB
/** * Copyright (c) 2018-2026 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { ParamDefinition as PD } from '../../mol-util/param-definition.js'; import { Theme } from '../../mol-theme/theme.js'; import { getNextMaterialId } from '../../mol-gl/render-object.js'; import { EmptyLoci, isEmptyLoci } from '../../mol-model/loci.js'; import { getQualityProps } from '../util.js'; import { EPSILON, Mat4 } from '../../mol-math/linear-algebra.js'; import { Representation } from '../representation.js'; import { BaseGeometry } from '../../mol-geo/geometry/base.js'; import { Subject } from 'rxjs'; import { Task } from '../../mol-task/index.js'; export function VolumeRepresentationProvider(p) { return p; } // export const VolumeParams = { ...BaseGeometry.Params, }; export function VolumeRepresentation(label, ctx, getParams, visualCtor, getLoci, getKeys = () => [-1]) { let version = 0; const { webgl } = ctx; const updated = new Subject(); const geometryState = new Representation.GeometryState(); const materialId = getNextMaterialId(); const renderObjects = []; const _state = Representation.createState(); const visuals = new Map(); let _volume; let _keys; let _params; let _props; let _theme = Theme.createEmpty(); async function visual(runtime, key) { var _a; let visual = visuals.get(key); if (!visual) { visual = visualCtor(materialId, _volume, key, _props, webgl); visuals.set(key, visual); } else if ((_a = visual.mustRecreate) === null || _a === void 0 ? void 0 : _a.call(visual, { volume: _volume, key }, _props, webgl)) { visual.destroy(); visual = visualCtor(materialId, _volume, key, _props, webgl); visuals.set(key, visual); } return visual.createOrUpdate({ webgl, runtime }, _theme, _props, { volume: _volume, key }); } function createOrUpdate(props = {}, volume) { if (volume && volume !== _volume) { _params = getParams(ctx, volume); _volume = volume; if (!_props) _props = PD.getDefaultValues(_params); } const qualityProps = getQualityProps(Object.assign({}, _props, props), _volume); Object.assign(_props, props, qualityProps); _keys = getKeys(_props, _volume); return Task.create('Creating or updating VolumeRepresentation', async (runtime) => { const toDelete = new Set(visuals.keys()); for (let i = 0, il = _keys.length; i < il; ++i) { const key = _keys[i]; toDelete.delete(key); const promise = visual(runtime, key); if (promise) await promise; } toDelete.forEach(key => { var _a; (_a = visuals.get(key)) === null || _a === void 0 ? void 0 : _a.destroy(); visuals.delete(key); }); // update list of renderObjects renderObjects.length = 0; visuals.forEach(visual => { if (visual.renderObject) { renderObjects.push(visual.renderObject); geometryState.add(visual.renderObject.id, visual.geometryVersion); } }); geometryState.snapshot(); // increment version updated.next(version++); }); } function mark(loci, action) { let changed = false; visuals.forEach(visual => { changed = visual.mark(loci, action) || changed; }); return changed; } function setVisualState(visual, state) { if (state.visible !== undefined && visual) visual.setVisibility(state.visible); if (state.alphaFactor !== undefined && visual) visual.setAlphaFactor(state.alphaFactor); if (state.pickable !== undefined && visual) visual.setPickable(state.pickable); if (state.overpaint !== undefined && visual) visual.setOverpaint(state.overpaint); if (state.transparency !== undefined && visual) visual.setTransparency(state.transparency); if (state.emissive !== undefined && visual) visual.setEmissive(state.emissive); if (state.substance !== undefined && visual) visual.setSubstance(state.substance); if (state.clipping !== undefined && visual) visual.setClipping(state.clipping); if (state.transform !== undefined && visual) visual.setTransform(state.transform); if (state.themeStrength !== undefined && visual) visual.setThemeStrength(state.themeStrength); } function setState(state) { const { visible, alphaFactor, pickable, overpaint, transparency, emissive, substance, clipping, transform, themeStrength, syncManually, markerActions } = state; const newState = {}; if (visible !== undefined) newState.visible = visible; if (alphaFactor !== undefined) newState.alphaFactor = alphaFactor; if (pickable !== undefined) newState.pickable = pickable; if (overpaint !== undefined) newState.overpaint = overpaint; if (transparency !== undefined) newState.transparency = transparency; if (emissive !== undefined) newState.emissive = emissive; if (substance !== undefined) newState.substance = substance; if (clipping !== undefined) newState.clipping = clipping; if (themeStrength !== undefined) newState.themeStrength = themeStrength; if (transform !== undefined && !Mat4.areEqual(transform, _state.transform, EPSILON)) { newState.transform = transform; } if (syncManually !== undefined) newState.syncManually = syncManually; if (markerActions !== undefined) newState.markerActions = markerActions; visuals.forEach(visual => setVisualState(visual, newState)); Representation.updateState(_state, state); } function setTheme(theme) { _theme = theme; } function destroy() { visuals.forEach(visual => visual.destroy()); visuals.clear(); } return { label, get groupCount() { let groupCount = 0; visuals.forEach(visual => { if (visual.renderObject) groupCount += visual.groupCount; }); return groupCount; }, get props() { return _props; }, get params() { return _params; }, get state() { return _state; }, get theme() { return _theme; }, get geometryVersion() { return geometryState.version; }, renderObjects, updated, createOrUpdate, setState, setTheme, getLoci: (pickingId) => { let loci = EmptyLoci; for (const visual of visuals.values()) { const _loci = visual.getLoci(pickingId); if (!isEmptyLoci(_loci)) { loci = _loci; break; } } return loci; }, getAllLoci: () => { return [getLoci(_volume, _props)]; }, eachLocation: (cb) => { visuals.forEach(visual => { visual.eachLocation(cb); }); }, mark, destroy }; }