Compare commits

...

27 Commits

Author SHA1 Message Date
dsehnal
05f1d8085a 2.0.3 2021-04-09 17:47:12 +02:00
dsehnal
38bbabd742 fix test 2021-04-09 17:45:51 +02:00
dsehnal
3ab958a93c changelog 2021-04-09 17:43:23 +02:00
dsehnal
f59d589a30 CubeGridFormat 2021-04-09 17:41:13 +02:00
David Sehnal
11f7e54704 Merge pull request #158 from molstar/gradient-themes
Add ColorTheme.palette support
2021-04-09 10:01:59 +02:00
dsehnal
16ebd8266e changelog 2021-04-09 10:01:21 +02:00
dsehnal
7a796a4d3d Merge branch 'master' of https://github.com/molstar/molstar into gradient-themes 2021-04-09 09:59:46 +02:00
Alexander Rose
1cbb915962 started a changelog 2021-04-08 23:14:55 -07:00
Alexander Rose
80486d58c3 async deflate (and zip) 2021-04-08 23:13:30 -07:00
dsehnal
81bc116c4d TextureImage.filter 2021-04-08 09:49:35 +02:00
dsehnal
4249064dd1 Add ColorTheme.palette support
- add example to basic-wrapper that uses it
2021-04-07 15:55:54 +02:00
dsehnal
028c02f50d 2.0.2 2021-03-29 12:48:26 +02:00
dsehnal
76e97d7b59 fix VolumeFromDensityServerCif label 2021-03-29 12:46:10 +02:00
dsehnal
ad1181a75b interpolate ModelFromTrajectory transform 2021-03-29 12:03:13 +02:00
Alexander Rose
5d683462fb add common non-standard amino-acids 2021-03-28 15:38:15 -07:00
Alexander Rose
42422bb0ea add canvas3d.getRenderObjects 2021-03-28 15:36:40 -07:00
dsehnal
861e5c3e97 SDF data item test 2021-03-24 16:02:53 +01:00
dsehnal
614cffda96 2.0.1 2021-03-23 15:44:24 +01:00
dsehnal
2e0379d202 npm ignore 2021-03-23 15:42:52 +01:00
dsehnal
b5cfdcd2a3 2.0.0 2021-03-23 15:31:18 +01:00
dsehnal
c00de6fde0 Merge branch 'master' of https://github.com/molstar/molstar 2021-03-23 11:16:26 +01:00
Alexander Rose
da3a8e56f3 handle negative isovalues in gpu mc 2021-03-22 22:06:49 -07:00
dsehnal
103d6fe775 alpha orbitals tryUseGpu param 2021-03-22 20:18:48 +01:00
dsehnal
5df55e6bf7 SDF delimiter bugfix + multi-molecule SDF support in mol-plugin 2021-03-22 17:21:47 +01:00
dsehnal
3b285086d4 rename files called "macro" due to Jest not being able to process them 2021-03-22 16:53:48 +01:00
dsehnal
91793bc3cc 2.0.0-dev.13 2021-03-22 13:29:42 +01:00
dsehnal
fa3828e820 add model-server-query transform support 2021-03-22 12:51:03 +01:00
43 changed files with 504 additions and 130 deletions

View File

@@ -1 +1 @@
tsconfig.commonjs.buildinfo
tsconfig.commonjs.tsbuildinfo

36
CHANGELOG.md Normal file
View File

@@ -0,0 +1,36 @@
# Change Log
All notable changes to this project will be documented in this file, following the suggestions of [Keep a CHANGELOG](http://keepachangelog.com/). This project adheres to [Semantic Versioning](http://semver.org/) for its most widely used - and defacto - public interfaces.
Note that since we don't clearly distinguish between a public and private interfaces there will be changes in non-major versions that are potentially breaking. If we make breaking changes to less used interfaces we will highlight it in here.
## [Unreleased]
## [v2.0.3] - 2021-04-09
### Added
- Support for ``ColorTheme.palette`` designed for providing gradient-like coloring.
### Changed
- [Breaking] The `zip` function is now asynchronous and expects a `RuntimeContext`. Also added `Zip()` returning a `Task`.
- [Breaking] Add ``CubeGridFormat`` in ``alpha-orbitals`` extension.
## [v2.0.2] - 2021-03-29
### Added
- `Canvas3D.getRenderObjects`.
- [WIP] Animate state interpolating, including model trajectories
### Changed
- Recognise MSE, SEP, TPO, PTR and PCA as non-standard amino-acids.
### Fixed
- VolumeFromDensityServerCif transform label
## [v2.0.1] - 2021-03-23
### Fixed
- Exclude tsconfig.commonjs.tsbuildinfo from npm bundle
## [v2.0.0] - 2021-03-23
Too many changes to list as this is the start of the changelog... Notably, default exports are now forbidden.

4
package-lock.json generated
View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "2.0.0-dev.12",
"version": "2.0.3",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -14,6 +14,7 @@
"lint": "eslint .",
"lint-fix": "eslint . --fix",
"test": "npm run lint && jest",
"jest": "jest",
"build": "npm run build-tsc && npm run build-extra && npm run build-webpack",
"build-viewer": "npm run build-tsc && npm run build-extra && npm run build-webpack-viewer",
"build-tsc": "concurrently \"tsc --incremental\" \"tsc --build tsconfig.commonjs.json --incremental\"",

View File

@@ -174,7 +174,8 @@ export class AlphaOrbitalsExample {
kind,
relativeIsovalue: this.state.value.isoValue,
pickable: false,
xrayShaded: true
xrayShaded: true,
tryUseGpu: false
};
}

View File

@@ -0,0 +1,51 @@
import { isPositionLocation } from '../../mol-geo/util/location-iterator';
import { Vec3 } from '../../mol-math/linear-algebra';
import { ColorTheme } from '../../mol-theme/color';
import { ThemeDataContext } from '../../mol-theme/theme';
import { Color } from '../../mol-util/color';
import { ColorNames } from '../../mol-util/color/names';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
export function CustomColorTheme(
ctx: ThemeDataContext,
props: PD.Values<{}>
): ColorTheme<{}> {
const { radius, center } = ctx.structure?.boundary.sphere!;
const radiusSq = Math.max(radius * radius, 0.001);
const scale = ColorTheme.PaletteScale;
return {
factory: CustomColorTheme,
granularity: 'vertex',
color: location => {
if (!isPositionLocation(location)) return ColorNames.black;
const dist = Vec3.squaredDistance(location.position, center);
const t = Math.min(dist / radiusSq, 1);
return ((t * scale) | 0) as Color;
},
palette: {
filter: 'nearest',
colors: [
ColorNames.red,
ColorNames.pink,
ColorNames.violet,
ColorNames.orange,
ColorNames.yellow,
ColorNames.green,
ColorNames.blue
]
},
props: props,
description: '',
};
}
export const CustomColorThemeProvider: ColorTheme.Provider<{}, 'basic-wrapper-custom-color-theme'> = {
name: 'basic-wrapper-custom-color-theme',
label: 'Custom Color Theme',
category: ColorTheme.Category.Misc,
factory: CustomColorTheme,
getParams: () => ({}),
defaultValues: { },
isApplicable: (ctx: ThemeDataContext) => true,
};

View File

@@ -97,6 +97,7 @@
addHeader('Misc');
addControl('Apply Stripes', () => BasicMolStarWrapper.coloring.applyStripes());
addControl('Apply Custom Theme', () => BasicMolStarWrapper.coloring.applyCustomTheme());
addControl('Default Coloring', () => BasicMolStarWrapper.coloring.applyDefault());
addHeader('Interactivity');

View File

@@ -18,6 +18,7 @@ import { Asset } from '../../mol-util/assets';
import { Color } from '../../mol-util/color';
import { StripedResidues } from './coloring';
import { CustomToastMessage } from './controls';
import { CustomColorThemeProvider } from './custom-theme';
import './index.html';
import { buildStaticSuperposition, dynamicSuperpositionTest, StaticSuperpositionTestData } from './superposition';
require('mol-plugin-ui/skin/light.scss');
@@ -42,6 +43,7 @@ class BasicWrapper {
});
this.plugin.representation.structure.themes.colorThemeRegistry.add(StripedResidues.colorThemeProvider!);
this.plugin.representation.structure.themes.colorThemeRegistry.add(CustomColorThemeProvider);
this.plugin.managers.lociLabels.addProvider(StripedResidues.labelProvider!);
this.plugin.customModelProperties.register(StripedResidues.propertyProvider, true);
}
@@ -103,6 +105,13 @@ class BasicWrapper {
}
});
},
applyCustomTheme: async () => {
this.plugin.dataTransaction(async () => {
for (const s of this.plugin.managers.structure.hierarchy.current.structures) {
await this.plugin.managers.structure.component.updateRepresentationsTheme(s.components, { color: CustomColorThemeProvider.name as any });
}
});
},
applyDefault: async () => {
this.plugin.dataTransaction(async () => {
for (const s of this.plugin.managers.structure.hierarchy.current.structures) {

View File

@@ -9,6 +9,7 @@ import { Grid } from '../../mol-model/volume';
import { SphericalBasisOrder } from './spherical-functions';
import { Box3D, RegularGrid3d } from '../../mol-math/geometry';
import { arrayMin, arrayMax, arrayRms, arrayMean } from '../../mol-util/array';
import { ModelFormat } from '../../mol-model-formats/format';
// Note: generally contracted gaussians are currently not supported.
export interface SphericalElectronShell {
@@ -59,6 +60,17 @@ export interface CubeGrid {
isovalues?: { negative?: number; positive?: number };
}
export type CubeGridFormat = ModelFormat<CubeGrid>;
// eslint-disable-next-line
export function CubeGridFormat(grid: CubeGrid): CubeGridFormat {
return { name: 'custom grid', kind: 'cube-grid', data: grid };
}
export function isCubeGridData(f: ModelFormat): f is CubeGridFormat {
return f.kind === 'cube-grid';
}
export function initCubeGrid(params: CubeGridComputationParams): CubeGridInfo {
const geometry = params.basis.atoms.map(a => a.center);
const { gridSpacing: spacing, boxExpand: expand } = params;

View File

@@ -17,7 +17,7 @@ import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers
import { StateTransformer } from '../../mol-state';
import { Theme } from '../../mol-theme/theme';
import { VolumeRepresentation3DHelpers } from '../../mol-plugin-state/transforms/representation';
import { AlphaOrbital, Basis, CubeGrid } from './data-model';
import { AlphaOrbital, Basis, CubeGrid, CubeGridFormat, isCubeGridData } from './data-model';
import { createSphericalCollocationDensityGrid } from './density';
import { Tensor } from '../../mol-math/linear-algebra';
@@ -114,7 +114,7 @@ export const CreateOrbitalVolume = PluginStateTransform.BuiltIn({
}, a.data.orbitals[params.index], plugin.canvas3d?.webgl).runInContext(ctx);
const volume: Volume = {
grid: data.grid,
sourceData: { name: 'custom grid', kind: 'alpha-orbitals', data },
sourceData: CubeGridFormat(data),
customProperties: new CustomProperties(),
_propertyData: Object.create(null),
};
@@ -146,7 +146,7 @@ export const CreateOrbitalDensityVolume = PluginStateTransform.BuiltIn({
}, a.data.orbitals, plugin.canvas3d?.webgl).runInContext(ctx);
const volume: Volume = {
grid: data.grid,
sourceData: { name: 'custom grid', kind: 'alpha-orbitals', data },
sourceData: CubeGridFormat(data),
customProperties: new CustomProperties(),
_propertyData: Object.create(null),
};
@@ -172,7 +172,8 @@ export const CreateOrbitalRepresentation3D = PluginStateTransform.BuiltIn({
color: PD.Color(ColorNames.blue),
alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }),
xrayShaded: PD.Boolean(false),
pickable: PD.Boolean(true)
pickable: PD.Boolean(true),
tryUseGpu: PD.Boolean(true)
}
})({
canAutoUpdate() {
@@ -209,9 +210,9 @@ export const CreateOrbitalRepresentation3D = PluginStateTransform.BuiltIn({
});
function volumeParams(plugin: PluginContext, volume: PluginStateObject.Volume.Data, params: StateTransformer.Params<typeof CreateOrbitalRepresentation3D>) {
if (volume.data.sourceData.kind !== 'alpha-orbitals') throw new Error('Invalid data source kind.');
if (!isCubeGridData(volume.data.sourceData)) throw new Error('Invalid data source kind.');
const { isovalues } = volume.data.sourceData.data as CubeGrid;
const { isovalues } = volume.data.sourceData.data;
if (!isovalues) throw new Error('Isovalues are not computed.');
const value = isovalues[params.kind];
@@ -230,7 +231,7 @@ function volumeParams(plugin: PluginContext, volume: PluginStateObject.Volume.Da
colorParams: { value: params.color }
} : {
type: 'isosurface',
typeParams: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, alpha: params.alpha, xrayShaded: params.xrayShaded },
typeParams: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, alpha: params.alpha, xrayShaded: params.xrayShaded, tryUseGpu: params.tryUseGpu },
color: 'uniform',
colorParams: { value: params.color }
});

View File

@@ -234,6 +234,7 @@ interface Canvas3D {
readonly boundingSphere: Readonly<Sphere3D>
setProps(props: PartialCanvas3DProps | ((old: Canvas3DProps) => Partial<Canvas3DProps> | void), doNotRequestDraw?: boolean /* = false */): void
getImagePass(props: Partial<ImageProps>): ImagePass
getRenderObjects(): GraphicsRenderObject[]
/** Returns a copy of the current Canvas3D instance props */
readonly props: Readonly<Canvas3DProps>
@@ -769,6 +770,11 @@ namespace Canvas3D {
getImagePass: (props: Partial<ImageProps> = {}) => {
return new ImagePass(webgl, renderer, scene, camera, helper, passes.draw.wboitEnabled, props);
},
getRenderObjects(): GraphicsRenderObject[] {
const renderObjects: GraphicsRenderObject[] = [];
scene.forEach((_, ro) => renderObjects.push(ro));
return renderObjects;
},
get props() {
return getProps();

View File

@@ -18,11 +18,24 @@ export type ColorType = 'uniform' | 'instance' | 'group' | 'groupInstance' | 've
export type ColorData = {
uColor: ValueCell<Vec3>,
tColor: ValueCell<TextureImage<Uint8Array>>,
tPalette: ValueCell<TextureImage<Uint8Array>>,
uColorTexDim: ValueCell<Vec2>,
dColorType: ValueCell<string>,
dUsePalette: ValueCell<boolean>,
}
export function createColors(locationIt: LocationIterator, positionIt: LocationIterator, colorTheme: ColorTheme<any>, colorData?: ColorData): ColorData {
const data = _createColors(locationIt, positionIt, colorTheme, colorData);
if (colorTheme.palette) {
ValueCell.updateIfChanged(data.dUsePalette, true);
updatePaletteTexture(colorTheme.palette, data.tPalette);
} else {
ValueCell.updateIfChanged(data.dUsePalette, false);
}
return data;
}
function _createColors(locationIt: LocationIterator, positionIt: LocationIterator, colorTheme: ColorTheme<any>, colorData?: ColorData): ColorData {
switch (Geometry.getGranularity(locationIt, colorTheme.granularity)) {
case 'uniform': return createUniformColor(locationIt, colorTheme.color, colorData);
case 'instance': return createInstanceColor(locationIt, colorTheme.color, colorData);
@@ -42,18 +55,20 @@ export function createValueColor(value: Color, colorData?: ColorData): ColorData
return {
uColor: ValueCell.create(Color.toVec3Normalized(Vec3(), value)),
tColor: ValueCell.create({ array: new Uint8Array(3), width: 1, height: 1 }),
tPalette: ValueCell.create({ array: new Uint8Array(3), width: 1, height: 1 }),
uColorTexDim: ValueCell.create(Vec2.create(1, 1)),
dColorType: ValueCell.create('uniform'),
dUsePalette: ValueCell.create(false),
};
}
}
/** Creates color uniform */
export function createUniformColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
function createUniformColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
return createValueColor(color(NullLocation, false), colorData);
}
export function createTextureColor(colors: TextureImage<Uint8Array>, type: ColorType, colorData?: ColorData): ColorData {
function createTextureColor(colors: TextureImage<Uint8Array>, type: ColorType, colorData?: ColorData): ColorData {
if (colorData) {
ValueCell.update(colorData.tColor, colors);
ValueCell.update(colorData.uColorTexDim, Vec2.create(colors.width, colors.height));
@@ -63,14 +78,16 @@ export function createTextureColor(colors: TextureImage<Uint8Array>, type: Color
return {
uColor: ValueCell.create(Vec3()),
tColor: ValueCell.create(colors),
tPalette: ValueCell.create({ array: new Uint8Array(3), width: 1, height: 1 }),
uColorTexDim: ValueCell.create(Vec2.create(colors.width, colors.height)),
dColorType: ValueCell.create(type),
dUsePalette: ValueCell.create(false),
};
}
}
/** Creates color texture with color for each instance */
export function createInstanceColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
function createInstanceColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
const { instanceCount } = locationIt;
const colors = createTextureImage(Math.max(1, instanceCount), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
locationIt.reset();
@@ -83,7 +100,7 @@ export function createInstanceColor(locationIt: LocationIterator, color: Locatio
}
/** Creates color texture with color for each group (i.e. shared across instances) */
export function createGroupColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
function createGroupColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
const { groupCount } = locationIt;
const colors = createTextureImage(Math.max(1, groupCount), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
locationIt.reset();
@@ -95,7 +112,7 @@ export function createGroupColor(locationIt: LocationIterator, color: LocationCo
}
/** Creates color texture with color for each group in each instance */
export function createGroupInstanceColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
function createGroupInstanceColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
const { groupCount, instanceCount } = locationIt;
const count = instanceCount * groupCount;
const colors = createTextureImage(Math.max(1, count), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
@@ -108,7 +125,7 @@ export function createGroupInstanceColor(locationIt: LocationIterator, color: Lo
}
/** Creates color texture with color for each vertex (i.e. shared across instances) */
export function createVertexColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
function createVertexColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
const { groupCount, stride } = locationIt;
const colors = createTextureImage(Math.max(1, groupCount), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
locationIt.reset();
@@ -124,7 +141,7 @@ export function createVertexColor(locationIt: LocationIterator, color: LocationC
}
/** Creates color texture with color for each vertex in each instance */
export function createVertexInstanceColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
function createVertexInstanceColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
const { groupCount, instanceCount, stride } = locationIt;
const count = instanceCount * groupCount;
const colors = createTextureImage(Math.max(1, count), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
@@ -138,3 +155,34 @@ export function createVertexInstanceColor(locationIt: LocationIterator, color: L
}
return createTextureColor(colors, 'vertexInstance', colorData);
}
function updatePaletteTexture(palette: ColorTheme.Palette, cell: ValueCell<TextureImage<Uint8Array>>) {
let isSynced = true;
const texture = cell.ref.value;
if (palette.colors.length !== texture.width || texture.filter !== palette.filter) {
isSynced = false;
} else {
const data = texture.array;
let o = 0;
for (const c of palette.colors) {
const [r, g, b] = Color.toRgb(c);
if (data[o++] !== r || data[o++] !== g || data[o++] !== b) {
isSynced = false;
break;
}
}
}
if (isSynced) return;
const array = new Uint8Array(palette.colors.length * 3);
let o = 0;
for (const c of palette.colors) {
const [r, g, b] = Color.toRgb(c);
array[o++] = r;
array[o++] = g;
array[o++] = b;
}
ValueCell.update(cell, { array, height: 1, width: palette.colors.length, filter: palette.filter });
}

View File

@@ -133,7 +133,7 @@ describe('renderer', () => {
scene.add(points);
scene.commit();
expect(ctx.stats.resourceCounts.attribute).toBe(ctx.isWebGL2 ? 4 : 5);
expect(ctx.stats.resourceCounts.texture).toBe(6);
expect(ctx.stats.resourceCounts.texture).toBe(7);
expect(ctx.stats.resourceCounts.vertexArray).toBe(6);
expect(ctx.stats.resourceCounts.program).toBe(6);
expect(ctx.stats.resourceCounts.shader).toBe(12);

View File

@@ -32,6 +32,7 @@ const IsosurfaceSchema = {
uSize: UniformSpec('f'),
uLevels: UniformSpec('f'),
uCount: UniformSpec('f'),
uInvert: UniformSpec('b'),
uGridDim: UniformSpec('v3'),
uGridTexDim: UniformSpec('v3'),
@@ -44,7 +45,7 @@ type IsosurfaceValues = Values<typeof IsosurfaceSchema>
const IsosurfaceName = 'isosurface';
function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, packedGroup: boolean): ComputeRenderable<IsosurfaceValues> {
function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean): ComputeRenderable<IsosurfaceValues> {
if (ctx.namedComputeRenderables[IsosurfaceName]) {
const v = ctx.namedComputeRenderables[IsosurfaceName].values as IsosurfaceValues;
@@ -56,6 +57,7 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture
ValueCell.updateIfChanged(v.uSize, Math.pow(2, levels));
ValueCell.updateIfChanged(v.uLevels, levels);
ValueCell.updateIfChanged(v.uCount, count);
ValueCell.updateIfChanged(v.uInvert, invert);
ValueCell.update(v.uGridDim, gridDim);
ValueCell.update(v.uGridTexDim, gridTexDim);
@@ -66,12 +68,12 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture
ctx.namedComputeRenderables[IsosurfaceName].update();
} else {
ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, packedGroup);
ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup);
}
return ctx.namedComputeRenderables[IsosurfaceName];
}
function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, packedGroup: boolean) {
function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean) {
// console.log('uSize', Math.pow(2, levels))
const values: IsosurfaceValues = {
...QuadValues,
@@ -85,6 +87,7 @@ function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Text
uSize: ValueCell.create(Math.pow(2, levels)),
uLevels: ValueCell.create(levels),
uCount: ValueCell.create(count),
uInvert: ValueCell.create(invert),
uGridDim: ValueCell.create(gridDim),
uGridTexDim: ValueCell.create(gridTexDim),
@@ -112,7 +115,7 @@ function setRenderingDefaults(ctx: WebGLContext) {
state.clearColor(0, 0, 0, 0);
}
export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
const { gl, resources, extensions } = ctx;
const { pyramidTex, height, levels, scale, count } = histogramPyramid;
const width = pyramidTex.getWidth();
@@ -167,7 +170,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
groupTexture.attachFramebuffer(framebuffer, 1);
normalTexture.attachFramebuffer(framebuffer, 2);
const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, packedGroup);
const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup);
ctx.state.currentRenderItemId = -1;
const { drawBuffers } = ctx.extensions;
@@ -201,7 +204,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
*
* Implementation based on http://www.miaumiau.cat/2016/10/stream-compaction-in-webgl/
*/
export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
// console.time('calcActiveVoxels');
const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale);
// ctx.waitForGpuCommandsCompleteSync();
@@ -213,7 +216,7 @@ export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDi
// console.timeEnd('createHistogramPyramid');
// console.time('createIsosurfaceBuffers');
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, packedGroup, vertexTexture, groupTexture, normalTexture);
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, invert, packedGroup, vertexTexture, groupTexture, normalTexture);
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('createIsosurfaceBuffers');

View File

@@ -185,7 +185,9 @@ export const ColorSchema = {
uColor: UniformSpec('v3', 'material'),
uColorTexDim: UniformSpec('v2'),
tColor: TextureSpec('image-uint8', 'rgb', 'ubyte', 'nearest'),
tPalette: TextureSpec('image-uint8', 'rgb', 'ubyte', 'nearest'),
dColorType: DefineSpec('string', ['uniform', 'attribute', 'instance', 'group', 'groupInstance', 'vertex', 'vertexInstance']),
dUsePalette: DefineSpec('boolean'),
} as const;
export type ColorSchema = typeof ColorSchema
export type ColorValues = Values<ColorSchema>

View File

@@ -7,6 +7,7 @@
import { Sphere3D } from '../../mol-math/geometry';
import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
import { BoundaryHelper } from '../../mol-math/geometry/boundary-helper';
import { TextureFilter } from '../webgl/texture';
export function calculateTextureInfo (n: number, itemSize: number) {
n = Math.max(n, 2); // observed issues with 1 pixel textures
@@ -22,6 +23,7 @@ export interface TextureImage<T extends Uint8Array | Float32Array | Int32Array>
readonly width: number
readonly height: number
readonly flipY?: boolean
readonly filter?: TextureFilter
}
export interface TextureVolume<T extends Uint8Array | Float32Array> {

View File

@@ -14,6 +14,10 @@ export const assign_color_varying = `
vColor.rgb = readFromTexture(tColor, int(aInstance) * uVertexCount + VertexID, uColorTexDim).rgb;
#endif
#ifdef dUsePalette
vPaletteV = ((vColor.r * 256.0 * 256.0 * 255.0 + vColor.g * 256.0 * 255.0 + vColor.b * 255.0) - 1.0) / 16777215.0;
#endif
#ifdef dOverpaint
vOverpaint = readFromTexture(tOverpaint, aInstance * float(uGroupCount) + group, uOverpaintTexDim);
#endif

View File

@@ -1,6 +1,8 @@
export const assign_material_color = `
#if defined(dRenderVariant_color)
#if defined(dColorType_uniform)
#if defined(dUsePalette)
vec4 material = vec4(texture2D(tPalette, vec2(vPaletteV, 0.5)).rgb, uAlpha);
#elif defined(dColorType_uniform)
vec4 material = vec4(uColor, uAlpha);
#elif defined(dColorType_varying)
vec4 material = vec4(vColor.rgb, uAlpha);

View File

@@ -21,4 +21,9 @@ export const color_frag_params = `
varying float vGroup;
varying float vTransparency;
#endif
#ifdef dUsePalette
uniform sampler2D tPalette;
varying float vPaletteV;
#endif
`;

View File

@@ -30,4 +30,8 @@ export const color_vert_params = `
uniform vec2 uTransparencyTexDim;
uniform sampler2D tTransparency;
#endif
#ifdef dUsePalette
varying float vPaletteV;
#endif
`;

View File

@@ -18,6 +18,7 @@ uniform float uIsoValue;
uniform float uLevels;
uniform float uSize;
uniform float uCount;
uniform bool uInvert;
uniform vec3 uGridDim;
uniform vec3 uGridTexDim;
@@ -163,6 +164,13 @@ void main(void) {
// current vertex for the up to 15 MC cases
int currentVertex = vI - idot4(m, starts);
// ensure winding-order is the same for negative and positive iso-levels
if (uInvert) {
int v = imod(currentVertex + 1, 3);
if (v == 1) currentVertex += 2;
else if (v == 0) currentVertex -= 2;
}
// get index into triIndices table
int mcIndex = 16 * int(edgeIndex) + currentVertex;
vec4 mcData = texture2D(tTriIndices, vec2(imod(mcIndex, 64), mcIndex / 64) / 64.);
@@ -273,11 +281,18 @@ void main(void) {
voxelPadded(b1 - c3).a - voxelPadded(b1 + c3).a,
voxelPadded(b1 - c4).a - voxelPadded(b1 + c4).a
));
mat3 normalMatrix = transpose3(inverse3(mat3(uGridTransform)));
gl_FragData[2].xyz = normalMatrix * -vec3(
gl_FragData[2].xyz = -vec3(
n0.x + t * (n0.x - n1.x),
n0.y + t * (n0.y - n1.y),
n0.z + t * (n0.z - n1.z)
);
// ensure normal-direction is the same for negative and positive iso-levels
if (uInvert) {
gl_FragData[2].xyz *= -1.0;
}
// apply normal matrix
gl_FragData[2].xyz *= transpose3(inverse3(mat3(uGridTransform)));
}
`;

View File

@@ -283,6 +283,9 @@ export function createTexture(gl: GLRenderingContext, extensions: WebGLExtension
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, format, type, data);
} else if (isTexture2d(data, target, gl)) {
const _filter = data.filter ? getFilter(gl, data.filter) : filter;
gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, _filter);
gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, _filter);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, !!data.flipY);
if (sub) {
gl.texSubImage2D(target, 0, 0, 0, data.width, data.height, format, type, data.array);

View File

@@ -17,7 +17,7 @@ const SdfString = `
M CHG 3 1 -1 3 -1 5 -1
M END
> <DATABASE_ID>
DB14523
0
> <DATABASE_NAME>
drugbank
@@ -112,7 +112,24 @@ Phosphate ion
> <SYNONYMS>
Orthophosphate; Phosphate
$$$$`;
$$$$
Comp 2
5 4 0 0 0 0 999 V2000
0.0000 0.8250 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
-0.8250 0.0000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
0.0000 -0.8250 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
0.0000 0.0000 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
0.8250 0.0000 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
4 1 1 0 0 0 0
4 2 2 0 0 0 0
4 3 1 0 0 0 0
4 5 1 0 0 0 0
M CHG 3 1 -1 3 -1 5 -1
M END
> <DATABASE_ID>
1`;
describe('sdf reader', () => {
it('basic', async () => {
@@ -120,14 +137,20 @@ describe('sdf reader', () => {
if (parsed.isError) {
throw new Error(parsed.message);
}
const compound = parsed.result.compounds[0];
const { molFile, dataItems } = compound;
const compound1 = parsed.result.compounds[0];
const compound2 = parsed.result.compounds[1];
const { molFile, dataItems } = compound1;
const { atoms, bonds } = molFile;
expect(parsed.result.compounds.length).toBe(2);
// number of structures
expect(atoms.count).toBe(5);
expect(bonds.count).toBe(4);
expect(compound2.molFile.atoms.count).toBe(5);
expect(compound2.molFile.bonds.count).toBe(4);
expect(atoms.x.value(0)).toBeCloseTo(0, 0.001);
expect(atoms.y.value(0)).toBeCloseTo(0.8250, 0.0001);
expect(atoms.z.value(0)).toBeCloseTo(0, 0.0001);
@@ -138,12 +161,15 @@ describe('sdf reader', () => {
expect(bonds.order.value(3)).toBe(1);
expect(dataItems.dataHeader.value(0)).toBe('DATABASE_ID');
expect(dataItems.data.value(0)).toBe('DB14523');
expect(dataItems.data.value(0)).toBe('0');
expect(dataItems.dataHeader.value(1)).toBe('DATABASE_NAME');
expect(dataItems.data.value(1)).toBe('drugbank');
expect(dataItems.dataHeader.value(31)).toBe('SYNONYMS');
expect(dataItems.data.value(31)).toBe('Orthophosphate; Phosphate');
expect(compound1.dataItems.data.value(0)).toBe('0');
expect(compound2.dataItems.data.value(0)).toBe('1');
});
});

View File

@@ -22,6 +22,7 @@ export interface SdfFile {
}[]
}
const delimiter = '$$$$';
function handleDataItems(tokenizer: Tokenizer): { dataHeader: Column<string>, data: Column<string> } {
const dataHeader = TokenBuilder.create(tokenizer.data, 32);
const data = TokenBuilder.create(tokenizer.data, 32);
@@ -29,6 +30,7 @@ function handleDataItems(tokenizer: Tokenizer): { dataHeader: Column<string>, da
let sawHeaderToken = false;
while (tokenizer.position < tokenizer.length) {
const line = Tokenizer.readLine(tokenizer);
if (line.startsWith(delimiter)) break;
if (!!line) {
if (line.startsWith('> <')) {
TokenBuilder.add(dataHeader, tokenizer.tokenStart + 3, tokenizer.tokenEnd - 1);
@@ -49,9 +51,7 @@ function handleDataItems(tokenizer: Tokenizer): { dataHeader: Column<string>, da
};
}
function handleMolFile(data: string) {
const tokenizer = Tokenizer(data);
function handleMolFile(tokenizer: Tokenizer) {
const title = Tokenizer.readLine(tokenizer).trim();
const program = Tokenizer.readLine(tokenizer).trim();
const comment = Tokenizer.readLine(tokenizer).trim();
@@ -60,6 +60,15 @@ function handleMolFile(data: string) {
const atomCount = +counts.substr(0, 3), bondCount = +counts.substr(3, 3);
if (Number.isNaN(atomCount) || Number.isNaN(bondCount)) {
// try to skip to next molecule
while (tokenizer.position < tokenizer.length) {
const line = Tokenizer.readLine(tokenizer);
if (line.startsWith(delimiter)) break;
}
return;
}
const atoms = handleAtoms(tokenizer, atomCount);
const bonds = handleBonds(tokenizer, bondCount);
const dataItems = handleDataItems(tokenizer);
@@ -70,10 +79,16 @@ function handleMolFile(data: string) {
};
}
const delimiter = '$$$$';
function parseInternal(data: string): Result<SdfFile> {
const result: SdfFile = { compounds: data.split(delimiter).map(d => handleMolFile(d)) };
return Result.success(result);
const tokenizer = Tokenizer(data);
const compounds: SdfFile['compounds'] = [];
while (tokenizer.position < tokenizer.length) {
const c = handleMolFile(tokenizer);
if (c) compounds.push(c);
}
return Result.success({ compounds });
}
export function parseSdf(data: string) {

View File

@@ -54,6 +54,12 @@ const StandardComponents = (function() {
{ id: 'SEC', name: 'SELENOCYSTEINE', type: 'L-peptide linking' },
{ id: 'PYL', name: 'PYRROLYSINE', type: 'L-peptide linking' },
{ id: 'MSE', name: 'SELENOMETHIONINE', type: 'L-peptide linking' },
{ id: 'SEP', name: 'PHOSPHOSERINE', type: 'L-peptide linking' },
{ id: 'TPO', name: 'PHOSPHOTHREONINE', type: 'L-peptide linking' },
{ id: 'PTR', name: 'O-PHOSPHOTYROSINE', type: 'L-peptide linking' },
{ id: 'PCA', name: 'PYROGLUTAMIC ACID', type: 'L-peptide linking' },
{ id: 'A', name: 'ADENOSINE-5\'-MONOPHOSPHATE', type: 'RNA linking' },
{ id: 'C', name: 'CYTIDINE-5\'-MONOPHOSPHATE', type: 'RNA linking' },
{ id: 'T', name: 'THYMIDINE-5\'-MONOPHOSPHATE', type: 'RNA linking' },

View File

@@ -245,7 +245,9 @@ export const WaterNames = new Set([
export const AminoAcidNamesL = new Set([
'HIS', 'ARG', 'LYS', 'ILE', 'PHE', 'LEU', 'TRP', 'ALA', 'MET', 'PRO', 'CYS',
'ASN', 'VAL', 'GLY', 'SER', 'GLN', 'TYR', 'ASP', 'GLU', 'THR', 'SEC', 'PYL',
'UNK' // unknown amino acid from CCD
'UNK', // unknown amino acid from CCD
'MSE', 'SEP', 'TPO', 'PTR', 'PCA' // common
]);
export const AminoAcidNamesD = new Set([
'DAL', // D-ALANINE

View File

@@ -6,12 +6,13 @@
import { PluginCommands } from '../../../mol-plugin/commands';
import { StateTransform } from '../../../mol-state';
import { shallowEqual } from '../../../mol-util';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { PluginStateAnimation } from '../model';
export const AnimateStateInterpolation = PluginStateAnimation.create({
name: 'built-in.animate-state-interpolation',
display: { name: 'Animate State Interpolation' },
display: { name: 'Animate State (experimental)' },
params: () => ({
transtionDurationInMs: PD.Numeric(2000, { min: 100, max: 30000, step: 10 })
}),
@@ -42,15 +43,25 @@ export const AnimateStateInterpolation = PluginStateAnimation.create({
for (const s of src) {
for (const t of tar) {
// TODO: better than quadratic alg.
// TODO: support for adding/removing nodes
if (t.ref !== s.ref) continue;
if (t.version === s.version) continue;
const e = StateTransform.fromJSON(s), f = StateTransform.fromJSON(t);
const oldState = state.cells.get(s.ref);
if (!oldState) continue;
let newState;
if (!e.transformer.definition.interpolate) {
update.to(s.ref).update(currentT <= 0.5 ? e.params : f.params);
newState = currentT <= 0.5 ? e.params : f.params;
} else {
update.to(s.ref).update(e.transformer.definition.interpolate(e.params, f.params, currentT, ctx.plugin));
newState = e.transformer.definition.interpolate(e.params, f.params, currentT, ctx.plugin);
}
if (!shallowEqual(oldState, newState)) {
update.to(s.ref).update(newState);
}
}
}

View File

@@ -123,14 +123,23 @@ export const GroProvider: TrajectoryFormatProvider = {
};
export const MolProvider: TrajectoryFormatProvider = {
label: 'MOL/SDF',
description: 'MOL/SDF',
label: 'MOL',
description: 'MOL',
category: TrajectoryFormatCategory,
stringExtensions: ['mol', 'sdf', 'sd'],
stringExtensions: ['mol'],
parse: directTrajectory(StateTransforms.Model.TrajectoryFromMOL),
visuals: defaultVisuals
};
export const SdfProvider: TrajectoryFormatProvider = {
label: 'SDF',
description: 'SDF',
category: TrajectoryFormatCategory,
stringExtensions: ['sdf', 'sd'],
parse: directTrajectory(StateTransforms.Model.TrajectoryFromSDF),
visuals: defaultVisuals
};
export const Mol2Provider: TrajectoryFormatProvider = {
label: 'MOL2',
description: 'MOL2',
@@ -148,6 +157,7 @@ export const BuiltInTrajectoryFormats = [
['gro', GroProvider] as const,
['xyz', XyzProvider] as const,
['mol', MolProvider] as const,
['sdf', SdfProvider] as const,
['mol2', Mol2Provider] as const,
] as const;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -12,7 +12,7 @@ import { StatefulPluginComponent } from '../component';
import { PluginContext } from '../../mol-plugin/context';
import { utf8ByteCount, utf8Write } from '../../mol-io/common/utf8';
import { Asset } from '../../mol-util/assets';
import { zip } from '../../mol-util/zip/zip';
import { Zip } from '../../mol-util/zip/zip';
import { readFromFile } from '../../mol-util/data-source';
import { objectForEach } from '../../mol-util/object';
import { PLUGIN_VERSION } from '../../mol-plugin/version';
@@ -217,7 +217,7 @@ class PluginStateSnapshotManager extends StatefulPluginComponent<{
zipDataObj['assets.json'] = data;
}
const zipFile = zip(zipDataObj);
const zipFile = await this.plugin.runTask(Zip(zipDataObj));
return new Blob([zipFile], {type : 'application/zip'});
}
}

View File

@@ -39,6 +39,7 @@ import { parseXtc } from '../../mol-io/reader/xtc/parser';
import { coordinatesFromXtc } from '../../mol-model-formats/structure/xtc';
import { parseXyz } from '../../mol-io/reader/xyz/parser';
import { trajectoryFromXyz } from '../../mol-model-formats/structure/xyz';
import { parseSdf } from '../../mol-io/reader/sdf/parser';
export { CoordinatesFromDcd };
export { CoordinatesFromXtc };
@@ -50,6 +51,7 @@ export { TrajectoryFromPDB };
export { TrajectoryFromGRO };
export { TrajectoryFromXYZ };
export { TrajectoryFromMOL };
export { TrajectoryFromSDF };
export { TrajectoryFromMOL2 };
export { TrajectoryFromCube };
export { TrajectoryFromCifCore };
@@ -292,6 +294,36 @@ const TrajectoryFromMOL = PluginStateTransform.BuiltIn({
}
});
type TrajectoryFromSDF = typeof TrajectoryFromSDF
const TrajectoryFromSDF = PluginStateTransform.BuiltIn({
name: 'trajectory-from-sdf',
display: { name: 'Parse SDF', description: 'Parse SDF string and create trajectory.' },
from: [SO.Data.String],
to: SO.Molecule.Trajectory
})({
apply({ a }) {
return Task.create('Parse SDF', async ctx => {
const parsed = await parseSdf(a.data).runInContext(ctx);
if (parsed.isError) throw new Error(parsed.message);
const models: Model[] = [];
for (const { molFile } of parsed.result.compounds) {
const traj = await trajectoryFromMol(molFile).runInContext(ctx);
for (let i = 0; i < traj.frameCount; i++) {
models.push(await Task.resolveInContext(traj.getFrameAtIndex(i), ctx));
}
}
const traj = new ArrayTrajectory(models);
const props = trajectoryProps(traj);
return new SO.Molecule.Trajectory(traj, props);
});
}
});
type TrajectoryFromMOL2 = typeof TrajectoryFromMOL
const TrajectoryFromMOL2 = PluginStateTransform.BuiltIn({
name: 'trajectory-from-mol2',
@@ -382,6 +414,10 @@ const ModelFromTrajectory = PluginStateTransform.BuiltIn({
return new SO.Molecule.Model(model, { label, description });
});
},
interpolate(a, b, t) {
const modelIndex = t >= 1 ? b.modelIndex : a.modelIndex + Math.floor((b.modelIndex - a.modelIndex + 1) * t);
return { modelIndex };
},
dispose({ b }) {
b?.data.customProperties.dispose();
}

View File

@@ -151,7 +151,7 @@ const VolumeFromDensityServerCif = PluginStateTransform.BuiltIn({
const densityServerCif = CIF.schema.densityServer(block);
const volume = await volumeFromDensityServerData(densityServerCif, { entryId: params.entryId }).runInContext(ctx);
const [x, y, z] = volume.grid.cells.space.dimensions;
const props = { label: densityServerCif.volume_data_3d_info.name.value(0), description: `Volume ${x}\u00D7${y}\u00D7${z}` };
const props = { label: params.entryId ?? densityServerCif.volume_data_3d_info.name.value(0), description: `Volume ${x}\u00D7${y}\u00D7${z}` };
return new SO.Volume.Data(volume, props);
});
},

View File

@@ -21,6 +21,7 @@ import { StateActions } from '../mol-plugin-state/actions';
import { AssignColorVolume } from '../mol-plugin-state/actions/volume';
import { StateTransforms } from '../mol-plugin-state/transforms';
import { BoxifyVolumeStreaming, CreateVolumeStreamingBehavior, InitVolumeStreaming } from '../mol-plugin/behavior/dynamic/volume-streaming/transformers';
import { AnimateStateInterpolation } from '../mol-plugin-state/animation/built-in/state-interpolation';
export { PluginSpec };
@@ -126,6 +127,7 @@ export const DefaultPluginSpec = (): PluginSpec => ({
AnimateModelIndex,
AnimateCameraSpin,
AnimateStateSnapshots,
AnimateAssemblyUnwind
AnimateAssemblyUnwind,
AnimateStateInterpolation
]
});

View File

@@ -182,7 +182,7 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit,
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, buffer?.vertex, buffer?.group, buffer?.normal);
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, false, true, buffer?.vertex, buffer?.group, buffer?.normal);
const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure));
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
@@ -241,7 +241,7 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, buffer?.vertex, buffer?.group, buffer?.normal);
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, false, true, buffer?.vertex, buffer?.group, buffer?.normal);
const boundingSphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure));
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);

View File

@@ -176,7 +176,7 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol
const { texture, gridDimension, gridTexDim, gridTexScale, transform } = VolumeIsosurfaceTexture.get(volume, ctx.webgl);
const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, false, buffer?.vertex, buffer?.group, buffer?.normal);
const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, value < 0, false, buffer?.vertex, buffer?.group, buffer?.normal);
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh);

View File

@@ -11,7 +11,7 @@ import { MolScriptSymbolTable as MolScript } from '../../language/symbol-table';
import { Type } from '../../language/type';
import { Types as StructureQueryTypes } from '../../language/symbol-table/structure-query';
import { MolScriptBuilder as B } from '../../language/builder';
import { getPositionalArgs, tryGetArg } from './macro';
import { getPositionalArgs, tryGetArg } from './script-macro';
export type MolScriptSymbol =
| { kind: 'alias', aliases: string[], symbol: MSymbol }

View File

@@ -35,6 +35,7 @@ import { OperatorHklColorThemeProvider } from './color/operator-hkl';
import { PartialChargeColorThemeProvider } from './color/partial-charge';
import { AtomIdColorThemeProvider } from './color/atom-id';
import { EntityIdColorThemeProvider } from './color/entity-id';
import { TextureFilter } from '../mol-gl/webgl/texture';
export type LocationColor = (location: Location, isSecondary: boolean) => Color
@@ -44,6 +45,9 @@ interface ColorTheme<P extends PD.Params> {
readonly granularity: ColorType
readonly color: LocationColor
readonly props: Readonly<PD.Values<P>>
// if palette is defined, 24bit RGB color value normalized to interval [0, 1]
// is used as index to the colors
readonly palette?: Readonly<ColorTheme.Palette>
readonly contextHash?: number
readonly description?: string
readonly legend?: Readonly<ScaleLegend | TableLegend>
@@ -58,6 +62,13 @@ namespace ColorTheme {
Misc = 'Miscellaneous',
}
export interface Palette {
filter?: TextureFilter,
colors: Color[]
}
export const PaletteScale = (1 << 24) - 1;
export type Props = { [k: string]: any }
export type Factory<P extends PD.Params> = (ctx: ThemeDataContext, props: PD.Values<P>) => ColorTheme<P>
export const EmptyFactory = () => Empty;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -10,16 +10,16 @@ import { SyncRuntimeContext } from '../../mol-task/execution/synchronous';
describe('zip', () => {
it('roundtrip deflate/inflate', async () => {
const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7]);
const deflated = deflate(data);
const deflated = await deflate(SyncRuntimeContext, data);
const inflated = await inflate(SyncRuntimeContext, deflated);
expect(inflated).toEqual(data);
});
it('roundtrip zip', async () => {
it('roundtrip zip/unzip', async () => {
const data = {
'test.foo': new Uint8Array([1, 2, 3, 4, 5, 6, 7])
};
const zipped = zip(data);
const zipped = await zip(SyncRuntimeContext, data);
const unzipped = await unzip(SyncRuntimeContext, zipped);
expect(unzipped).toEqual(data);
});

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*
@@ -7,65 +7,54 @@
* MIT License, Copyright (c) 2018 Photopea
*/
import { RuntimeContext } from '../../mol-task';
import { NumberArray } from '../type-helpers';
import { _hufTree } from './huffman';
import { U, revCodes, makeCodes } from './util';
export function _deflateRaw(data: Uint8Array, out: Uint8Array, opos: number, lvl: number) {
const opts = [
/*
ush good_length; /* reduce lazy search above this match length
ush max_lazy; /* do not perform lazy search above this match length
ush nice_length; /* quit search above this match length
*/
/* good lazy nice chain */
/* 0 */ [ 0, 0, 0, 0, 0], /* store only */
/* 1 */ [ 4, 4, 8, 4, 0], /* max speed, no lazy matches */
/* 2 */ [ 4, 5, 16, 8, 0],
/* 3 */ [ 4, 6, 16, 16, 0],
/* 4 */ [ 4, 10, 16, 32, 0], /* lazy matches */
/* 5 */ [ 8, 16, 32, 32, 0],
/* 6 */ [ 8, 16, 128, 128, 0],
/* 7 */ [ 8, 32, 128, 256, 0],
/* 8 */ [32, 128, 258, 1024, 1],
/* 9 */ [32, 258, 258, 4096, 1] /* max compression */
];
const opt = opts[lvl];
let i = 0, pos = opos << 3, cvrd = 0;
const dlen = data.length;
if(lvl === 0) {
while(i < dlen) {
const len = Math.min(0xffff, dlen - i);
_putsE(out, pos, (i + len === dlen ? 1 : 0));
pos = _copyExact(data, i, len, out, pos + 8);
i += len;
}
return pos >>> 3;
}
function DeflateContext(data: Uint8Array, out: Uint8Array, opos: number, lvl: number) {
const { lits, strt, prev } = U;
let li = 0, lc = 0, bs = 0, ebits = 0, c = 0, nc = 0; // last_item, literal_count, block_start
if(dlen > 2) {
nc = _hash(data, 0);
strt[nc] = 0;
}
return {
data,
out,
opt: Opts[lvl],
i: 0,
pos: opos << 3,
cvrd: 0,
dlen: data.length,
// let nmch = 0
// let nmci = 0
li: 0,
lc: 0,
bs: 0,
ebits: 0,
c: 0,
nc: 0,
for(i = 0; i < dlen; i++) {
lits,
strt,
prev
};
}
type DeflateContext = ReturnType<typeof DeflateContext>
function deflateChunk(ctx: DeflateContext, count: number) {
const { data, dlen, out, opt } = ctx;
let { i, pos, cvrd, li, lc, bs, ebits, c, nc } = ctx;
const { lits, strt, prev } = U;
const end = Math.min(i + count, dlen);
for(; i < end; i++) {
c = nc;
//*
if(i + 1 < dlen - 2) {
nc = _hash(data, i + 1);
const ii = ((i + 1) & 0x7fff);
prev[ii] = strt[nc];
strt[nc] = ii;
} // */
}
if(cvrd <= i) {
if((li > 14000 || lc > 26697) && (dlen - i) > 100) {
if(cvrd < i) {
@@ -79,19 +68,12 @@ export function _deflateRaw(data: Uint8Array, out: Uint8Array, opos: number, lvl
}
let mch = 0;
// if(nmci==i) mch= nmch; else
if(i < dlen - 2) {
mch = _bestMatch(data, i, prev, c, Math.min(opt[2], dlen - i), opt[3]);
}
/*
if(mch!=0 && opt[4]==1 && (mch>>>16)<opt[1] && i+1<dlen-2) {
nmch = UZIP.F._bestMatch(data, i+1, prev, nc, opt[2], opt[3]); nmci=i+1;
//var mch2 = UZIP.F._bestMatch(data, i+2, prev, nnc); //nmci=i+1;
if((nmch>>>16)>(mch>>>16)) mch=0;
}//*/
// const len = mch>>>16, dst = mch & 0xffff; // if(i-dst<0) throw "e";
if(mch !== 0) {
const len = mch >>> 16, dst = mch & 0xffff; // if(i-dst<0) throw "e";
const len = mch >>> 16, dst = mch & 0xffff;
const lgi = _goodIndex(len, U.of0); U.lhst[257 + lgi]++;
const dgi = _goodIndex(dst, U.df0); U.dhst[ dgi]++; ebits += U.exb[lgi] + U.dxb[dgi];
lits[li] = (len << 23) | (i - cvrd); lits[li + 1] = (dst << 16) | (lgi << 8) | dgi; li += 2;
@@ -102,6 +84,69 @@ export function _deflateRaw(data: Uint8Array, out: Uint8Array, opos: number, lvl
lc++;
}
}
ctx.i = i;
ctx.pos = pos;
ctx.cvrd = cvrd;
ctx.li = li;
ctx.lc = lc;
ctx.bs = bs;
ctx.ebits = ebits;
ctx.c = c;
ctx.nc = nc;
}
/**
* - good_length: reduce lazy search above this match length;
* - max_lazy: do not perform lazy search above this match length;
* - nice_length: quit search above this match length;
*/
const Opts = [
/* good lazy nice chain */
/* 0 */ [ 0, 0, 0, 0, 0], /* store only */
/* 1 */ [ 4, 4, 8, 4, 0], /* max speed, no lazy matches */
/* 2 */ [ 4, 5, 16, 8, 0],
/* 3 */ [ 4, 6, 16, 16, 0],
/* 4 */ [ 4, 10, 16, 32, 0], /* lazy matches */
/* 5 */ [ 8, 16, 32, 32, 0],
/* 6 */ [ 8, 16, 128, 128, 0],
/* 7 */ [ 8, 32, 128, 256, 0],
/* 8 */ [32, 128, 258, 1024, 1],
/* 9 */ [32, 258, 258, 4096, 1] /* max compression */
] as const;
export async function _deflateRaw(runtime: RuntimeContext, data: Uint8Array, out: Uint8Array, opos: number, lvl: number) {
const ctx = DeflateContext(data, out, opos, lvl);
const { dlen } = ctx;
if(lvl === 0) {
let { i, pos } = ctx;
while(i < dlen) {
const len = Math.min(0xffff, dlen - i);
_putsE(out, pos, (i + len === dlen ? 1 : 0));
pos = _copyExact(data, i, len, out, pos + 8);
i += len;
}
return pos >>> 3;
}
if(dlen > 2) {
ctx.nc = _hash(data, 0);
ctx.strt[ctx.nc] = 0;
}
while (ctx.i < dlen) {
if (runtime.shouldUpdate) {
await runtime.update({ message: 'Deflating...', current: ctx.pos, max: data.length });
}
deflateChunk(ctx, 1024 * 1024);
}
let { li, cvrd, pos } = ctx;
const { i, lits, bs, ebits } = ctx;
if(bs !== i || data.length === 0) {
if(cvrd < i) {
lits[li] = i - cvrd;
@@ -109,10 +154,6 @@ export function _deflateRaw(data: Uint8Array, out: Uint8Array, opos: number, lvl
cvrd = i;
}
pos = _writeBlock(1, lits, li, ebits, data, bs, i - bs, out, pos);
li = 0;
lc = 0;
li = lc = ebits = 0;
bs = i;
}
while((pos & 7) !== 0) pos++;
return pos >>> 3;

View File

@@ -13,7 +13,7 @@ import { writeUint, writeUshort, sizeUTF8, writeUTF8, readUshort, readUint, read
import { crc, adler } from './checksum';
import { _inflate } from './inflate';
import { _deflateRaw } from './deflate';
import { RuntimeContext } from '../../mol-task';
import { RuntimeContext, Task } from '../../mol-task';
export async function unzip(runtime: RuntimeContext, buf: ArrayBuffer, onlyNames = false) {
const out: { [k: string]: Uint8Array | { size: number, csize: number } } = Object.create(null);
@@ -174,12 +174,12 @@ export async function ungzip(runtime: RuntimeContext, file: Uint8Array, buf?: Ui
return inflated;
}
export function deflate(data: Uint8Array, opts?: { level: number }/* , buf, off*/) {
export async function deflate(runtime: RuntimeContext, data: Uint8Array, opts?: { level: number }/* , buf, off*/) {
if(opts === undefined) opts = { level: 6 };
let off = 0;
const buf = new Uint8Array(50 + Math.floor(data.length * 1.1));
buf[off] = 120; buf[off + 1] = 156; off += 2;
off = _deflateRaw(data, buf, off, opts.level);
off = await _deflateRaw(runtime, data, buf, off, opts.level);
const crcValue = adler(data, 0, data.length);
buf[off + 0] = ((crcValue >>> 24) & 255);
buf[off + 1] = ((crcValue >>> 16) & 255);
@@ -188,14 +188,18 @@ export function deflate(data: Uint8Array, opts?: { level: number }/* , buf, off*
return new Uint8Array(buf.buffer, 0, off + 4);
}
function deflateRaw(data: Uint8Array, opts?: { level: number }) {
async function deflateRaw(runtime: RuntimeContext, data: Uint8Array, opts?: { level: number }) {
if(opts === undefined) opts = { level: 6 };
const buf = new Uint8Array(50 + Math.floor(data.length * 1.1));
const off = _deflateRaw(data, buf, 0, opts.level);
const off = await _deflateRaw(runtime, data, buf, 0, opts.level);
return new Uint8Array(buf.buffer, 0, off);
}
export function zip(obj: { [k: string]: Uint8Array }, noCmpr = false) {
export function Zip(obj: { [k: string]: Uint8Array }, noCmpr = false) {
return Task.create('Zip', ctx => zip(ctx, obj, noCmpr));
}
export async function zip(runtime: RuntimeContext, obj: { [k: string]: Uint8Array }, noCmpr = false) {
let tot = 0;
const zpd: { [k: string]: { cpr: boolean, usize: number, crc: number, file: Uint8Array } } = {};
for(const p in obj) {
@@ -205,7 +209,7 @@ export function zip(obj: { [k: string]: Uint8Array }, noCmpr = false) {
cpr,
usize: buf.length,
crc: crcValue,
file: (cpr ? deflateRaw(buf) : buf)
file: (cpr ? await deflateRaw(runtime, buf) : buf)
};
}

View File

@@ -4,6 +4,7 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Mat4 } from '../../../mol-math/linear-algebra';
import { ConsoleLogger } from '../../../mol-util/console-logger';
import { now } from '../../../mol-util/now';
import { PerformanceMonitor } from '../../../mol-util/performance-monitor';
@@ -18,6 +19,8 @@ export type Entry<Q extends QueryName = QueryName> = {
query: Q,
modelNums?: number[],
copyAllCategories?: boolean,
// column major 4x4 transformation matrix, provided as array of 16 float values
transform?: number[],
params?: QueryParams<Q>,
}
@@ -43,6 +46,7 @@ export async function runLocal(input: LocalInput) {
queryName: q.query,
queryParams: q.params || { },
modelNums: q.modelNums,
transform: q.transform as Mat4 ?? Mat4.identity(),
copyAllCategories: !!q.copyAllCategories
})),
writer: job.asTarGz

View File

@@ -73,7 +73,7 @@ async function init() {
console.timeEnd('gpu mc pyramid2');
console.time('gpu mc vert2');
createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDim, densityTextureData2.gridTexDim, densityTextureData2.transform, isoValue, true);
createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDim, densityTextureData2.gridTexDim, densityTextureData2.transform, isoValue, false, true);
webgl.waitForGpuCommandsCompleteSync();
console.timeEnd('gpu mc vert2');
console.timeEnd('gpu mc2');
@@ -96,7 +96,7 @@ async function init() {
console.timeEnd('gpu mc pyramid');
console.time('gpu mc vert');
const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.transform, isoValue, true);
const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.transform, isoValue, false, true);
webgl.waitForGpuCommandsCompleteSync();
console.timeEnd('gpu mc vert');
console.timeEnd('gpu mc');