UNPKG

molstar

Version:

A comprehensive macromolecular library.

263 lines 12.8 kB
/** * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { __awaiter, __generator } from "tslib"; import { Geometry } from '../../mol-geo/geometry/geometry'; import { Representation } from '../representation'; import { Shape, ShapeGroup } from '../../mol-model/shape'; import { Subject } from 'rxjs'; import { getNextMaterialId, createRenderObject } from '../../mol-gl/render-object'; import { Theme } from '../../mol-theme/theme'; import { VisualUpdateState } from '../util'; import { createMarkers } from '../../mol-geo/geometry/marker-data'; import { MarkerActions } from '../../mol-util/marker-action'; import { ValueCell } from '../../mol-util'; import { createColors } from '../../mol-geo/geometry/color-data'; import { createSizes } from '../../mol-geo/geometry/size-data'; import { isEveryLoci, EmptyLoci } from '../../mol-model/loci'; import { Interval, OrderedSet } from '../../mol-data/int'; import { Visual } from '../visual'; import { Task } from '../../mol-task'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { isDebugMode } from '../../mol-util/debug'; export function ShapeRepresentation(getShape, geometryUtils, builder) { if (builder === void 0) { builder = {}; } var version = 0; var updated = new Subject(); var _state = Representation.createState(); var materialId = getNextMaterialId(); var renderObjects = []; var _renderObject; var _shape; var _theme = Theme.createEmpty(); var currentProps = PD.getDefaultValues(geometryUtils.Params); // TODO avoid casting var currentParams; var locationIt; var positionIt; if (builder.modifyState) Representation.updateState(_state, builder.modifyState(_state)); var updateState = VisualUpdateState.create(); function prepareUpdate(props, shape) { if (props === void 0) { props = {}; } VisualUpdateState.reset(updateState); if (!shape && !_shape) { // console.error('no shape given') return; } else if (shape && !_shape) { // console.log('first shape') updateState.createNew = true; } else if (shape && _shape && shape.id === _shape.id) { // console.log('same shape') // nothing to set } else if (shape && _shape && shape.id !== _shape.id) { // console.log('new shape') updateState.updateTransform = true; updateState.createGeometry = true; } else if (!shape) { // console.log('only props') // nothing to set } else { console.warn('unexpected state'); } if (updateState.updateTransform) { updateState.updateColor = true; updateState.updateSize = true; } if (updateState.createGeometry) { updateState.updateColor = true; updateState.updateSize = true; } } function createOrUpdate(props, data) { var _this = this; if (props === void 0) { props = {}; } if (builder.modifyProps) props = builder.modifyProps(props); return Task.create('ShapeRepresentation.create', function (runtime) { return __awaiter(_this, void 0, void 0, function () { var newProps, shape, _a, transform, values, state, instanceCount, groupCount; return __generator(this, function (_b) { switch (_b.label) { case 0: newProps = Object.assign(currentProps, props); if (!data) return [3 /*break*/, 2]; return [4 /*yield*/, getShape(runtime, data, newProps, _shape)]; case 1: _a = _b.sent(); return [3 /*break*/, 3]; case 2: _a = undefined; _b.label = 3; case 3: shape = _a; prepareUpdate(props, shape); if (shape) { _shape = shape; Object.assign(_theme, Shape.getTheme(_shape)); } if (updateState.createNew) { renderObjects.length = 0; // clear list o renderObjects locationIt = Shape.groupIterator(_shape); transform = Shape.createTransform(_shape.transforms); values = geometryUtils.createValues(_shape.geometry, transform, locationIt, _theme, newProps); state = geometryUtils.createRenderableState(newProps); if (builder.modifyState) Object.assign(state, builder.modifyState(state)); Representation.updateState(_state, state); _renderObject = createRenderObject(_shape.geometry.kind, values, state, materialId); if (_renderObject) renderObjects.push(_renderObject); // add new renderObject to list positionIt = geometryUtils.createPositionIterator(_shape.geometry, _renderObject.values); } else { if (!_renderObject) { throw new Error('expected renderObject to be available'); } if (updateState.updateTransform) { // console.log('update transform') Shape.createTransform(_shape.transforms, _renderObject.values); locationIt = Shape.groupIterator(_shape); instanceCount = locationIt.instanceCount, groupCount = locationIt.groupCount; createMarkers(instanceCount * groupCount, _renderObject.values); } if (updateState.createGeometry) { // console.log('update geometry') ValueCell.updateIfChanged(_renderObject.values.drawCount, Geometry.getDrawCount(_shape.geometry)); ValueCell.updateIfChanged(_renderObject.values.uVertexCount, Geometry.getVertexCount(_shape.geometry)); } if (updateState.updateTransform || updateState.createGeometry) { // console.log('updateBoundingSphere') geometryUtils.updateBoundingSphere(_renderObject.values, _shape.geometry); positionIt = geometryUtils.createPositionIterator(_shape.geometry, _renderObject.values); } if (updateState.updateColor) { // console.log('update color') createColors(locationIt, positionIt, _theme.color, _renderObject.values); } if (updateState.updateSize) { // not all geometries have size data, so check here if ('uSize' in _renderObject.values) { // console.log('update size') createSizes(locationIt, _theme.size, _renderObject.values); } } geometryUtils.updateValues(_renderObject.values, newProps); geometryUtils.updateRenderableState(_renderObject.state, newProps); } currentProps = newProps; // increment version updated.next(version++); return [2 /*return*/]; } }); }); }); } function lociApply(loci, apply) { if (isEveryLoci(loci) || (Shape.isLoci(loci) && loci.shape === _shape)) { return apply(Interval.ofBounds(0, _shape.groupCount * _shape.transforms.length)); } else { return eachShapeGroup(loci, _shape, apply); } } return { label: 'Shape geometry', get groupCount() { return locationIt ? locationIt.count : 0; }, get props() { return currentProps; }, get params() { return currentParams; }, get state() { return _state; }, get theme() { return _theme; }, renderObjects: renderObjects, updated: updated, createOrUpdate: createOrUpdate, getLoci: function (pickingId) { if (pickingId === undefined) return Shape.Loci(_shape); var objectId = pickingId.objectId, groupId = pickingId.groupId, instanceId = pickingId.instanceId; if (_renderObject && _renderObject.id === objectId) { return ShapeGroup.Loci(_shape, [{ ids: OrderedSet.ofSingleton(groupId), instance: instanceId }]); } return EmptyLoci; }, mark: function (loci, action) { if (!MarkerActions.is(_state.markerActions, action)) return false; if (ShapeGroup.isLoci(loci) || Shape.isLoci(loci)) { if (loci.shape !== _shape) return false; } else if (!isEveryLoci(loci)) { return false; } return Visual.mark(_renderObject, loci, action, lociApply); }, setState: function (state) { if (builder.modifyState) state = builder.modifyState(state); if (_renderObject) { if (state.visible !== undefined) Visual.setVisibility(_renderObject, state.visible); if (state.alphaFactor !== undefined) Visual.setAlphaFactor(_renderObject, state.alphaFactor); if (state.pickable !== undefined) Visual.setPickable(_renderObject, state.pickable); if (state.colorOnly !== undefined) Visual.setColorOnly(_renderObject, state.colorOnly); if (state.overpaint !== undefined) { Visual.setOverpaint(_renderObject, state.overpaint, lociApply, true); } if (state.transparency !== undefined) { Visual.setTransparency(_renderObject, state.transparency, lociApply, true); } if (state.transform !== undefined) Visual.setTransform(_renderObject, state.transform); } Representation.updateState(_state, state); }, setTheme: function (theme) { if (isDebugMode) { console.warn('The `ShapeRepresentation` theme is fixed to `ShapeGroupColorTheme` and `ShapeGroupSizeTheme`. Colors are taken from `Shape.getColor` and sizes from `Shape.getSize`'); } }, destroy: function () { renderObjects.length = 0; if (_renderObject) { _renderObject.state.disposed = true; _renderObject = undefined; } } }; } function eachShapeGroup(loci, shape, apply) { if (!ShapeGroup.isLoci(loci)) return false; if (loci.shape !== shape) return false; var changed = false; var groupCount = shape.groupCount; var groups = loci.groups; for (var _a = 0, groups_1 = groups; _a < groups_1.length; _a++) { var _b = groups_1[_a], ids = _b.ids, instance = _b.instance; if (Interval.is(ids)) { var start = instance * groupCount + Interval.start(ids); var end = instance * groupCount + Interval.end(ids); if (apply(Interval.ofBounds(start, end))) changed = true; } else { for (var i = 0, _i = ids.length; i < _i; i++) { var idx = instance * groupCount + ids[i]; if (apply(Interval.ofSingleton(idx))) changed = true; } } } return changed; } //# sourceMappingURL=representation.js.map