mirror of
https://github.com/molstar/molstar.git
synced 2026-06-05 22:31:26 +08:00
Compare commits
115 Commits
clamp-cube
...
v3.27.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9255505a3b | ||
|
|
6c0dfd338d | ||
|
|
c306e988c8 | ||
|
|
2428a8efab | ||
|
|
e98d7931ca | ||
|
|
f8e2d2e3d0 | ||
|
|
4455bab6ac | ||
|
|
b21fb27041 | ||
|
|
5402ee0019 | ||
|
|
02654ea57b | ||
|
|
9cd4aeabaa | ||
|
|
d788511a83 | ||
|
|
378b5b8096 | ||
|
|
e26eb2f751 | ||
|
|
26264b15f7 | ||
|
|
309e3dd981 | ||
|
|
4ff5ed3b5d | ||
|
|
270a757756 | ||
|
|
79e4030ab4 | ||
|
|
fd86927e04 | ||
|
|
df3a7e5037 | ||
|
|
fefc6f14c9 | ||
|
|
923fbef0e4 | ||
|
|
601bd5ba7a | ||
|
|
5798f20c41 | ||
|
|
f2e26f91a8 | ||
|
|
e2cdc45be6 | ||
|
|
96493bc75e | ||
|
|
d78ad4a78e | ||
|
|
0c54b0dd6e | ||
|
|
65310e52de | ||
|
|
285d3cd9b8 | ||
|
|
10486abb64 | ||
|
|
8c1a9fc988 | ||
|
|
7bdd0b470b | ||
|
|
b7a51f12bf | ||
|
|
e002ac5474 | ||
|
|
211d339ce0 | ||
|
|
509fb14473 | ||
|
|
ef838a1b83 | ||
|
|
f84b5b633d | ||
|
|
8ec8c1170d | ||
|
|
920b98e4d1 | ||
|
|
c80f52d4bc | ||
|
|
0b6aa42daf | ||
|
|
04dc6427ef | ||
|
|
77e366b484 | ||
|
|
add7cfa0f2 | ||
|
|
14d4fa142c | ||
|
|
7fe1617f25 | ||
|
|
cbe4cb521c | ||
|
|
7c394525c1 | ||
|
|
12ed051fea | ||
|
|
014913c635 | ||
|
|
369e45c282 | ||
|
|
2892caec0c | ||
|
|
eb609e918a | ||
|
|
9217e58845 | ||
|
|
26b633618a | ||
|
|
e3054d6ee1 | ||
|
|
0b6294f4ec | ||
|
|
7b130dc0f3 | ||
|
|
d93c128c25 | ||
|
|
e1dd74775e | ||
|
|
e61e706607 | ||
|
|
a57d46deaa | ||
|
|
60efdc0071 | ||
|
|
4dc1155a9e | ||
|
|
5cabe6fb42 | ||
|
|
42239c305f | ||
|
|
fd3c763349 | ||
|
|
daa9bbf2c9 | ||
|
|
c7dad00908 | ||
|
|
24317717e8 | ||
|
|
dd3eac6db6 | ||
|
|
1606f8517f | ||
|
|
3a98401ada | ||
|
|
4764251241 | ||
|
|
3de04b7b9d | ||
|
|
04908495e9 | ||
|
|
3c835c848e | ||
|
|
0f1788f122 | ||
|
|
3d72e700a4 | ||
|
|
a5cf41e65f | ||
|
|
7029bc41d7 | ||
|
|
b87d40c844 | ||
|
|
9e154376d3 | ||
|
|
4a9fdbce57 | ||
|
|
775e335292 | ||
|
|
e553bf4deb | ||
|
|
db0e09ec6e | ||
|
|
ba50760f92 | ||
|
|
524e6d4f81 | ||
|
|
db93a669ab | ||
|
|
423f5b0502 | ||
|
|
2bc45c25fe | ||
|
|
d341463f67 | ||
|
|
19d1ecb36a | ||
|
|
ffe4047f97 | ||
|
|
15a3c29e7a | ||
|
|
42ff593004 | ||
|
|
5140af4e6f | ||
|
|
0f5b4c00a9 | ||
|
|
feb69f4987 | ||
|
|
84eb9a58ca | ||
|
|
fbd96f473a | ||
|
|
69228157dc | ||
|
|
6808f32b8d | ||
|
|
9e69f5dcfa | ||
|
|
409ed9ad67 | ||
|
|
06e78e19d0 | ||
|
|
9a1d746170 | ||
|
|
ef87ce3507 | ||
|
|
2b9053eac4 | ||
|
|
116ef719be |
43
CHANGELOG.md
43
CHANGELOG.md
@@ -6,18 +6,57 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
|
||||
## [v3.27.0] - 2022-12-15
|
||||
|
||||
- Add an `includeTransparent` parameter to hide/show outlines of components that are transparent
|
||||
- Fix 'once' for animations of systems with many frames
|
||||
- Better guard against issue (black fringes) with bumpiness in impostors
|
||||
- Improve impostor shaders
|
||||
- Fix sphere near-clipping with orthographic projection
|
||||
- Fix cylinder near-clipping
|
||||
- Add interior cylinder caps
|
||||
- Add per-pixel object clipping
|
||||
- Fix `QualityAssessment` assignment bug for structures with different auth vs label sequence numbering
|
||||
- Refresh `ApplyActionControl`'s param definition when toggling expanded state
|
||||
- Fix `struct_conn` bond assignment for ions
|
||||
- Ability to show only polar hydrogens
|
||||
|
||||
## [v3.26.0] - 2022-12-04
|
||||
|
||||
- Support for ``powerPreference`` webgl attribute. Add ``PluginConfig.General.PowerPreference`` and ``power-preference`` Viewer GET param.
|
||||
- Excluded common protein caps `NME` and `ACE` from the ligand selection query
|
||||
- Add screen-space shadow post-processing effect
|
||||
- Add "Structure Molecular Surface" visual
|
||||
- Add `external-volume` theme (coloring of arbitrary geometries by user-selected volume)
|
||||
|
||||
## [v3.25.1] - 2022-11-20
|
||||
|
||||
- Fix edge-case in `Structure.eachUnitPair` with single-element units
|
||||
- Fix 'auto' structure-quality for coarse models
|
||||
|
||||
## [v3.25.0] - 2022-11-16
|
||||
|
||||
- Fix handling of gzipped assets (reverts #615)
|
||||
|
||||
## [v3.24.0] - 2022-11-13
|
||||
|
||||
- Make `PluginContext.initContainer` checkered canvas background optional
|
||||
- Store URL of downloaded assets to detect zip/gzip based on extension (#615)
|
||||
- Add optional `operator.key`; can be referenced in `IndexPairBonds`
|
||||
- Add overpaint/transparency/substance theme strength to representations
|
||||
- Fix viewport color for transparent background
|
||||
|
||||
## [v3.23.0] - 2022-10-19
|
||||
|
||||
- Add `PluginContext.initContainer/mount/unmount` methods; these should make it easier to reuse a plugin context with both custom and built-in UI
|
||||
- Add `PluginContext.canvas3dInitialized`
|
||||
- `createPluginUI` now resolves after the 3d canvas has been initialized
|
||||
- Change EM Volume Streaming default from `Whote Structure` to `Auto`
|
||||
- Change EM Volume Streaming default from `Whole Structure` to `Auto`
|
||||
|
||||
## [v3.22.0] - 2022-10-17
|
||||
|
||||
- Replace `VolumeIsosurfaceParams.pickingGranularity` param with `Volume.PickingGranuality`
|
||||
- Replace `VolumeIsosurfaceParams.pickingGranularity` param with `Volume.PickingGranuality`
|
||||
|
||||
## [v3.21.0] - 2022-10-17
|
||||
|
||||
|
||||
28000
examples/long_animation.sdf
Normal file
28000
examples/long_animation.sdf
Normal file
File diff suppressed because it is too large
Load Diff
2814
package-lock.json
generated
2814
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
60
package.json
60
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.23.0",
|
||||
"version": "3.27.0",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -92,57 +92,59 @@
|
||||
"Panagiotis Tourlas <panagiot_tourlov@hotmail.com>",
|
||||
"Adam Midlik <midlik@gmail.com>",
|
||||
"Koya Sakuma <koya.sakuma.work@gmail.com>",
|
||||
"Gianluca Tomasello <giagitom@gmail.com>"
|
||||
"Gianluca Tomasello <giagitom@gmail.com>",
|
||||
"Jason Pattle <jpattle@exscientia.co.uk>",
|
||||
"David Williams <dwilliams@nobiastx.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/add": "^3.2.1",
|
||||
"@graphql-codegen/cli": "^2.13.7",
|
||||
"@graphql-codegen/cli": "^2.15.0",
|
||||
"@graphql-codegen/time": "^3.2.1",
|
||||
"@graphql-codegen/typescript": "^2.7.4",
|
||||
"@graphql-codegen/typescript": "^2.8.3",
|
||||
"@graphql-codegen/typescript-graphql-files-modules": "^2.2.1",
|
||||
"@graphql-codegen/typescript-graphql-request": "^4.5.6",
|
||||
"@graphql-codegen/typescript-operations": "^2.5.4",
|
||||
"@graphql-codegen/typescript-graphql-request": "^4.5.8",
|
||||
"@graphql-codegen/typescript-operations": "^2.5.8",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/gl": "^4.1.1",
|
||||
"@types/jest": "^29.1.2",
|
||||
"@types/react": "^18.0.21",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.40.0",
|
||||
"@typescript-eslint/parser": "^5.40.0",
|
||||
"@types/gl": "^6.0.2",
|
||||
"@types/jest": "^29.2.3",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||
"@typescript-eslint/parser": "^5.45.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"concurrently": "^7.4.0",
|
||||
"concurrently": "^7.6.0",
|
||||
"cpx2": "^4.2.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^6.7.1",
|
||||
"eslint": "^8.25.0",
|
||||
"css-loader": "^6.7.2",
|
||||
"eslint": "^8.29.0",
|
||||
"extra-watch-webpack-plugin": "^1.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"fs-extra": "^11.1.0",
|
||||
"graphql": "^16.6.0",
|
||||
"http-server": "^14.1.1",
|
||||
"jest": "^29.2.0",
|
||||
"mini-css-extract-plugin": "^2.6.1",
|
||||
"jest": "^29.3.1",
|
||||
"mini-css-extract-plugin": "^2.7.1",
|
||||
"path-browserify": "^1.0.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"sass": "^1.55.0",
|
||||
"sass-loader": "^13.1.0",
|
||||
"simple-git": "^3.14.1",
|
||||
"sass": "^1.56.1",
|
||||
"sass-loader": "^13.2.0",
|
||||
"simple-git": "^3.15.1",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "^4.8.4",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^4.10.0"
|
||||
"typescript": "^4.9.3",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/argparse": "^2.0.10",
|
||||
"@types/benchmark": "^2.1.2",
|
||||
"@types/compression": "1.7.2",
|
||||
"@types/express": "^4.17.14",
|
||||
"@types/node": "^16.11.66",
|
||||
"@types/node": "^16.18.4",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/swagger-ui-dist": "3.30.1",
|
||||
"argparse": "^2.0.1",
|
||||
@@ -151,12 +153,12 @@
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.2",
|
||||
"h264-mp4-encoder": "^1.0.12",
|
||||
"immer": "^9.0.15",
|
||||
"immer": "^9.0.16",
|
||||
"immutable": "^4.1.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"rxjs": "^7.5.7",
|
||||
"swagger-ui-dist": "^4.14.3",
|
||||
"tslib": "^2.4.0",
|
||||
"rxjs": "^7.6.0",
|
||||
"swagger-ui-dist": "^4.15.5",
|
||||
"tslib": "^2.4.1",
|
||||
"util.promisify": "^1.1.1",
|
||||
"xhr2": "^0.2.1"
|
||||
},
|
||||
|
||||
@@ -31,7 +31,8 @@ function shinyStyle(plugin: PluginContext) {
|
||||
postprocessing: {
|
||||
...plugin.canvas3d!.props.postprocessing,
|
||||
occlusion: { name: 'off', params: {} },
|
||||
outline: { name: 'off', params: {} }
|
||||
shadow: { name: 'off', params: {} },
|
||||
outline: { name: 'off', params: {} },
|
||||
}
|
||||
} });
|
||||
}
|
||||
@@ -48,13 +49,15 @@ function occlusionStyle(plugin: PluginContext) {
|
||||
blurKernelSize: 15,
|
||||
radius: 5,
|
||||
samples: 32,
|
||||
resolutionScale: 1
|
||||
resolutionScale: 1,
|
||||
} },
|
||||
outline: { name: 'on', params: {
|
||||
scale: 1.0,
|
||||
threshold: 0.33,
|
||||
color: Color(0x0000),
|
||||
} }
|
||||
includeTransparent: true,
|
||||
} },
|
||||
shadow: { name: 'off', params: {} },
|
||||
}
|
||||
} });
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ const DefaultViewerOptions = {
|
||||
enableDpoit: PluginConfig.General.EnableDpoit.defaultValue,
|
||||
preferWebgl1: PluginConfig.General.PreferWebGl1.defaultValue,
|
||||
allowMajorPerformanceCaveat: PluginConfig.General.AllowMajorPerformanceCaveat.defaultValue,
|
||||
powerPreference: PluginConfig.General.PowerPreference.defaultValue,
|
||||
|
||||
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
|
||||
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
|
||||
@@ -163,6 +164,7 @@ export class Viewer {
|
||||
[PluginConfig.General.EnableDpoit, o.enableDpoit],
|
||||
[PluginConfig.General.PreferWebGl1, o.preferWebgl1],
|
||||
[PluginConfig.General.AllowMajorPerformanceCaveat, o.allowMajorPerformanceCaveat],
|
||||
[PluginConfig.General.PowerPreference, o.powerPreference],
|
||||
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
|
||||
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
|
||||
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
var enableDpoit = getParam('enable-dpoit', '[^&]+').trim() === '1';
|
||||
var preferWebgl1 = getParam('prefer-webgl1', '[^&]+').trim() === '1' || void 0;
|
||||
var allowMajorPerformanceCaveat = getParam('allow-major-performance-caveat', '[^&]+').trim() === '1';
|
||||
var powerPreference = getParam('power-preference', '[^&]+').trim().toLowerCase();
|
||||
|
||||
molstar.Viewer.create('app', {
|
||||
layoutShowControls: !hideControls,
|
||||
@@ -80,6 +81,7 @@
|
||||
enableDpoit: enableDpoit ? true : void 0,
|
||||
preferWebgl1: preferWebgl1,
|
||||
allowMajorPerformanceCaveat: allowMajorPerformanceCaveat,
|
||||
powerPreference: powerPreference || 'high-performance',
|
||||
}).then(viewer => {
|
||||
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
|
||||
if (snapshotId) viewer.setRemoteSnapshot(snapshotId);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -25,7 +25,8 @@ const Canvas3DPresets = {
|
||||
canvas3d: <Preset>{
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } },
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000) } }
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000), includeTransparent: true, } },
|
||||
shadow: { name: 'off', params: {} },
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 1.0,
|
||||
@@ -37,7 +38,8 @@ const Canvas3DPresets = {
|
||||
canvas3d: <Preset>{
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } },
|
||||
outline: { name: 'off', params: {} }
|
||||
outline: { name: 'off', params: {} },
|
||||
shadow: { name: 'off', params: {} },
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 0.4,
|
||||
@@ -50,7 +52,8 @@ const Canvas3DPresets = {
|
||||
canvas3d: <Preset>{
|
||||
postprocessing: {
|
||||
occlusion: { name: 'off', params: {} },
|
||||
outline: { name: 'off', params: {} }
|
||||
outline: { name: 'off', params: {} },
|
||||
shadow: { name: 'off', params: {} },
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 0.4,
|
||||
|
||||
@@ -585,7 +585,7 @@ export const LoadCellPackModel = StateAction.build({
|
||||
... ctx.managers.structure.component.state.options,
|
||||
visualQuality: 'custom',
|
||||
ignoreLight: true,
|
||||
showHydrogens: false,
|
||||
hydrogens: 'hide-all',
|
||||
});
|
||||
ctx.canvas3d?.setProps({
|
||||
multiSample: { mode: 'off' },
|
||||
@@ -606,12 +606,22 @@ export const LoadCellPackModel = StateAction.build({
|
||||
resolutionScale: 1,
|
||||
}
|
||||
},
|
||||
shadow: {
|
||||
name: 'on',
|
||||
params: {
|
||||
bias: 0.6,
|
||||
maxDistance: 80,
|
||||
steps: 3,
|
||||
tolerance: 1.0,
|
||||
}
|
||||
},
|
||||
outline: {
|
||||
name: 'on',
|
||||
params: {
|
||||
scale: 1,
|
||||
threshold: 0.33,
|
||||
color: ColorNames.black,
|
||||
includeTransparent: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
@@ -14,6 +15,7 @@ import { CustomPropSymbol } from '../../../mol-script/language/symbol';
|
||||
import { Type } from '../../../mol-script/language/type';
|
||||
import { CustomPropertyDescriptor } from '../../../mol-model/custom-property';
|
||||
import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif';
|
||||
import { AtomicIndex } from '../../../mol-model/structure/model/properties/atomic';
|
||||
|
||||
export { QualityAssessment };
|
||||
|
||||
@@ -71,14 +73,28 @@ namespace QualityAssessment {
|
||||
localNames.set(ma_qa_metric.id.value(i), name);
|
||||
}
|
||||
|
||||
const residueKey: AtomicIndex.ResidueLabelKey = {
|
||||
label_entity_id: '',
|
||||
label_asym_id: '',
|
||||
label_seq_id: 0,
|
||||
pdbx_PDB_ins_code: undefined,
|
||||
};
|
||||
|
||||
for (let i = 0, il = ma_qa_metric_local._rowCount; i < il; i++) {
|
||||
if (model_id.value(i) !== model.modelNum) continue;
|
||||
|
||||
const labelAsymId = label_asym_id.value(i);
|
||||
const entityIndex = index.findEntity(labelAsymId);
|
||||
const rI = index.findResidue(model.entities.data.id.value(entityIndex), labelAsymId, label_seq_id.value(i));
|
||||
const name = localNames.get(metric_id.value(i))!;
|
||||
localMetrics.get(name)!.set(rI, metric_value.value(i));
|
||||
|
||||
residueKey.label_entity_id = model.entities.data.id.value(entityIndex);
|
||||
residueKey.label_asym_id = labelAsymId;
|
||||
residueKey.label_seq_id = label_seq_id.value(i);
|
||||
|
||||
const rI = index.findResidueLabel(residueKey);
|
||||
if (rI >= 0) {
|
||||
const name = localNames.get(metric_id.value(i))!;
|
||||
localMetrics.get(name)!.set(rI, metric_value.value(i));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -4,7 +4,7 @@ export type InputMaybe<T> = Maybe<T>;
|
||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
|
||||
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
|
||||
// Generated on 2022-08-20T16:36:05-07:00
|
||||
// Generated on 2022-12-03T21:55:37-08:00
|
||||
|
||||
/** All built-in and custom scalars, mapped to their actual values */
|
||||
export type Scalars = {
|
||||
@@ -343,6 +343,14 @@ export type Citation = {
|
||||
*
|
||||
*/
|
||||
readonly journal_abbrev?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* Full name of the cited journal; relevant for journal articles.
|
||||
*
|
||||
* Examples:
|
||||
* Journal of Molecular Biology
|
||||
*
|
||||
*/
|
||||
readonly journal_full?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The American Society for Testing and Materials (ASTM) code
|
||||
* assigned to the journal cited (also referred to as the CODEN
|
||||
@@ -550,6 +558,7 @@ export type CoreBranchedEntityInstance = {
|
||||
readonly rcsb_id: Scalars['String'];
|
||||
readonly rcsb_latest_revision?: Maybe<RcsbLatestRevision>;
|
||||
readonly rcsb_ligand_neighbors?: Maybe<ReadonlyArray<Maybe<RcsbLigandNeighbors>>>;
|
||||
readonly struct_asym?: Maybe<StructAsym>;
|
||||
};
|
||||
|
||||
export type CoreChemComp = {
|
||||
@@ -661,6 +670,7 @@ export type CoreEntry = {
|
||||
readonly exptl?: Maybe<ReadonlyArray<Maybe<Exptl>>>;
|
||||
readonly exptl_crystal?: Maybe<ReadonlyArray<Maybe<ExptlCrystal>>>;
|
||||
readonly exptl_crystal_grow?: Maybe<ReadonlyArray<Maybe<ExptlCrystalGrow>>>;
|
||||
readonly ma_data?: Maybe<ReadonlyArray<Maybe<MaData>>>;
|
||||
/** Get all non-polymer (non-solvent) entities for this PDB entry. */
|
||||
readonly nonpolymer_entities?: Maybe<ReadonlyArray<Maybe<CoreNonpolymerEntity>>>;
|
||||
readonly pdbx_SG_project?: Maybe<ReadonlyArray<Maybe<PdbxSgProject>>>;
|
||||
@@ -701,6 +711,7 @@ export type CoreEntry = {
|
||||
/** The list of content types associated with this entry. */
|
||||
readonly rcsb_associated_holdings?: Maybe<CurrentEntry>;
|
||||
readonly rcsb_binding_affinity?: Maybe<ReadonlyArray<Maybe<RcsbBindingAffinity>>>;
|
||||
readonly rcsb_comp_model_provenance?: Maybe<RcsbCompModelProvenance>;
|
||||
readonly rcsb_entry_container_identifiers: RcsbEntryContainerIdentifiers;
|
||||
readonly rcsb_entry_group_membership?: Maybe<ReadonlyArray<Maybe<RcsbEntryGroupMembership>>>;
|
||||
readonly rcsb_entry_info: RcsbEntryInfo;
|
||||
@@ -713,6 +724,7 @@ export type CoreEntry = {
|
||||
*
|
||||
*/
|
||||
readonly rcsb_id: Scalars['String'];
|
||||
readonly rcsb_ma_qa_metric_global?: Maybe<ReadonlyArray<Maybe<RcsbMaQaMetricGlobal>>>;
|
||||
readonly rcsb_primary_citation?: Maybe<RcsbPrimaryCitation>;
|
||||
readonly refine?: Maybe<ReadonlyArray<Maybe<Refine>>>;
|
||||
readonly refine_analyze?: Maybe<ReadonlyArray<Maybe<RefineAnalyze>>>;
|
||||
@@ -786,6 +798,7 @@ export type CoreNonpolymerEntityInstance = {
|
||||
readonly rcsb_nonpolymer_instance_validation_score?: Maybe<ReadonlyArray<Maybe<RcsbNonpolymerInstanceValidationScore>>>;
|
||||
readonly rcsb_nonpolymer_struct_conn?: Maybe<ReadonlyArray<Maybe<RcsbNonpolymerStructConn>>>;
|
||||
readonly rcsb_target_neighbors?: Maybe<ReadonlyArray<Maybe<RcsbTargetNeighbors>>>;
|
||||
readonly struct_asym?: Maybe<StructAsym>;
|
||||
};
|
||||
|
||||
export type CorePfam = {
|
||||
@@ -919,6 +932,7 @@ export type CorePolymerEntityInstance = {
|
||||
readonly rcsb_polymer_instance_feature?: Maybe<ReadonlyArray<Maybe<RcsbPolymerInstanceFeature>>>;
|
||||
readonly rcsb_polymer_instance_feature_summary?: Maybe<ReadonlyArray<Maybe<RcsbPolymerInstanceFeatureSummary>>>;
|
||||
readonly rcsb_polymer_struct_conn?: Maybe<ReadonlyArray<Maybe<RcsbPolymerStructConn>>>;
|
||||
readonly struct_asym?: Maybe<StructAsym>;
|
||||
};
|
||||
|
||||
export type CorePubmed = {
|
||||
@@ -1284,9 +1298,9 @@ export type Em2dCrystalEntity = {
|
||||
readonly id: Scalars['String'];
|
||||
/** pointer to _em_image_processing.id in the EM_IMAGE_PROCESSING category. */
|
||||
readonly image_processing_id: Scalars['String'];
|
||||
/** Unit-cell length a in Angstroms. */
|
||||
/** Unit-cell length a in angstroms. */
|
||||
readonly length_a?: Maybe<Scalars['Float']>;
|
||||
/** Unit-cell length b in Angstroms. */
|
||||
/** Unit-cell length b in angstroms. */
|
||||
readonly length_b?: Maybe<Scalars['Float']>;
|
||||
/** Thickness of 2D crystal */
|
||||
readonly length_c?: Maybe<Scalars['Float']>;
|
||||
@@ -1317,11 +1331,11 @@ export type Em3dCrystalEntity = {
|
||||
readonly id: Scalars['String'];
|
||||
/** pointer to _em_image_processing.id in the EM_IMAGE_PROCESSING category. */
|
||||
readonly image_processing_id: Scalars['String'];
|
||||
/** Unit-cell length a in Angstroms. */
|
||||
/** Unit-cell length a in angstroms. */
|
||||
readonly length_a?: Maybe<Scalars['Float']>;
|
||||
/** Unit-cell length b in Angstroms. */
|
||||
/** Unit-cell length b in angstroms. */
|
||||
readonly length_b?: Maybe<Scalars['Float']>;
|
||||
/** Unit-cell length c in Angstroms. */
|
||||
/** Unit-cell length c in angstroms. */
|
||||
readonly length_c?: Maybe<Scalars['Float']>;
|
||||
/**
|
||||
* Space group name.
|
||||
@@ -1482,7 +1496,7 @@ export type Em3dReconstruction = {
|
||||
*/
|
||||
readonly refinement_type?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The final resolution (in Angstroms)of the 3D reconstruction.
|
||||
* The final resolution (in angstroms)of the 3D reconstruction.
|
||||
*
|
||||
* Examples:
|
||||
* null, null
|
||||
@@ -1558,7 +1572,7 @@ export type EmDiffractionShell = {
|
||||
*/
|
||||
readonly fourier_space_coverage?: Maybe<Scalars['Float']>;
|
||||
/**
|
||||
* High resolution limit for this shell (Angstroms)
|
||||
* High resolution limit for this shell (angstroms)
|
||||
*
|
||||
* Examples:
|
||||
* null
|
||||
@@ -1568,7 +1582,7 @@ export type EmDiffractionShell = {
|
||||
/** Unique identifier for the category em_diffraction_shell */
|
||||
readonly id: Scalars['String'];
|
||||
/**
|
||||
* Low resolution limit for this shell (Angstroms)
|
||||
* Low resolution limit for this shell (angstroms)
|
||||
*
|
||||
* Examples:
|
||||
* null
|
||||
@@ -1614,7 +1628,7 @@ export type EmDiffractionStats = {
|
||||
*/
|
||||
readonly fourier_space_coverage?: Maybe<Scalars['Float']>;
|
||||
/**
|
||||
* High resolution limit of the structure factor data, in Angstroms
|
||||
* High resolution limit of the structure factor data, in angstroms
|
||||
*
|
||||
* Examples:
|
||||
* null
|
||||
@@ -1998,12 +2012,12 @@ export type EmImaging = {
|
||||
/** The magnification indicated by the microscope readout. */
|
||||
readonly nominal_magnification?: Maybe<Scalars['Int']>;
|
||||
/**
|
||||
* The specimen temperature maximum (degrees Kelvin) for the duration
|
||||
* The specimen temperature maximum (kelvin) for the duration
|
||||
* of imaging.
|
||||
*/
|
||||
readonly recording_temperature_maximum?: Maybe<Scalars['Float']>;
|
||||
/**
|
||||
* The specimen temperature minimum (degrees Kelvin) for the duration
|
||||
* The specimen temperature minimum (kelvin) for the duration
|
||||
* of imaging.
|
||||
*/
|
||||
readonly recording_temperature_minimum?: Maybe<Scalars['Float']>;
|
||||
@@ -2028,7 +2042,7 @@ export type EmImaging = {
|
||||
/** Foreign key to the EM_SPECIMEN category */
|
||||
readonly specimen_id?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The mean specimen stage temperature (degrees Kelvin) during imaging
|
||||
* The mean specimen stage temperature (in kelvin) during imaging
|
||||
* in the microscope.
|
||||
*/
|
||||
readonly temperature?: Maybe<Scalars['Float']>;
|
||||
@@ -2215,7 +2229,7 @@ export type EmStaining = {
|
||||
};
|
||||
|
||||
export type EmVitrification = {
|
||||
/** The temperature (in degrees Kelvin) of the sample just prior to vitrification. */
|
||||
/** The temperature (in kelvin) of the sample just prior to vitrification. */
|
||||
readonly chamber_temperature?: Maybe<Scalars['Float']>;
|
||||
/**
|
||||
* This is the name of the cryogen.
|
||||
@@ -2259,7 +2273,7 @@ export type EmVitrification = {
|
||||
/** This data item is a pointer to _em_specimen.id */
|
||||
readonly specimen_id: Scalars['String'];
|
||||
/**
|
||||
* The vitrification temperature (in degrees Kelvin), e.g.,
|
||||
* The vitrification temperature (in kelvin), e.g.,
|
||||
* temperature of the plunge instrument cryogen bath.
|
||||
*/
|
||||
readonly temp?: Maybe<Scalars['Float']>;
|
||||
@@ -2364,6 +2378,14 @@ export type EntityPoly = {
|
||||
*
|
||||
*/
|
||||
readonly pdbx_seq_one_letter_code_can?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* Evidence for the assignment of the polymer sequence.
|
||||
*
|
||||
* Allowable values:
|
||||
* depositor provided, derived from coordinates
|
||||
*
|
||||
*/
|
||||
readonly pdbx_sequence_evidence_code?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The PDB strand/chain id(s) corresponding to this polymer entity.
|
||||
*
|
||||
@@ -3005,6 +3027,8 @@ export type Entry = {
|
||||
* identifier.
|
||||
*/
|
||||
readonly id: Scalars['String'];
|
||||
/** An identifier for the model collection associated with the entry. */
|
||||
readonly ma_collection_id?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Exptl = {
|
||||
@@ -3263,6 +3287,29 @@ export type InterfacePartnerFeatureFeaturePositions = {
|
||||
readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['Float']>>>;
|
||||
};
|
||||
|
||||
export type MaData = {
|
||||
/**
|
||||
* The type of data held in the dataset.
|
||||
*
|
||||
* Allowable values:
|
||||
* coevolution MSA, input structure, model coordinates, other, polymeric template library, spatial restraints, target, target-template alignment, template structure
|
||||
*
|
||||
*/
|
||||
readonly content_type?: Maybe<Scalars['String']>;
|
||||
/** Details for other content types. */
|
||||
readonly content_type_other_details?: Maybe<Scalars['String']>;
|
||||
/** A unique identifier for the data. */
|
||||
readonly id: Scalars['Int'];
|
||||
/**
|
||||
* An author-given name for the content held in the dataset.
|
||||
*
|
||||
* Examples:
|
||||
* NMR NOE Distances, Target Template Alignment, Coevolution Data
|
||||
*
|
||||
*/
|
||||
readonly name?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type MethodDetails = {
|
||||
/** A description of special aspects of the clustering process */
|
||||
readonly description?: Maybe<Scalars['String']>;
|
||||
@@ -4199,7 +4246,7 @@ export type PdbxNmrExptlSampleConditions = {
|
||||
*/
|
||||
readonly pressure_units?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The temperature (in Kelvin) at which NMR data were
|
||||
* The temperature (in kelvin) at which NMR data were
|
||||
* collected.
|
||||
*/
|
||||
readonly temperature?: Maybe<Scalars['String']>;
|
||||
@@ -4453,7 +4500,7 @@ export type PdbxPrdAudit = {
|
||||
* An identifier for the wwPDB site creating or modifying the molecule.
|
||||
*
|
||||
* Allowable values:
|
||||
* BMRB, PDBC, PDBJ, PDBe, RCSB
|
||||
* BMRB, PDBC, PDBE, PDBJ, RCSB
|
||||
*
|
||||
*/
|
||||
readonly processing_site?: Maybe<Scalars['String']>;
|
||||
@@ -6817,7 +6864,7 @@ export type Query = {
|
||||
readonly assemblies?: Maybe<ReadonlyArray<Maybe<CoreAssembly>>>;
|
||||
/** Get an assembly given the PDB ID and ASSEMBLY ID. Here ASSEMBLY ID is '1', '2', '3', etc. or 'deposited' for deposited coordinates. */
|
||||
readonly assembly?: Maybe<CoreAssembly>;
|
||||
/** Get a list of PDB branched entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. */
|
||||
/** Get a list of PDB branched entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. Note that the ENTRY ID part must be upper case. */
|
||||
readonly branched_entities?: Maybe<ReadonlyArray<Maybe<CoreBranchedEntity>>>;
|
||||
/** Get a PDB branched entity, given the PDB ID and ENTITY ID. Here ENTITY ID is a '1', '2', '3', etc. */
|
||||
readonly branched_entity?: Maybe<CoreBranchedEntity>;
|
||||
@@ -6841,9 +6888,9 @@ export type Query = {
|
||||
readonly group_provenance?: Maybe<GroupProvenance>;
|
||||
/** Get a pairwise polymeric interface given the PDB ID, ASSEMBLY ID and INTERFACE ID. */
|
||||
readonly interface?: Maybe<CoreInterface>;
|
||||
/** Get a list of pairwise polymeric interfaces given a list of INTERFACE IDs. Here INTERFACE ID is a compound identifier that includes entry_id, assembly_id and interface_id e.g. 1XXX-1.1. */
|
||||
/** Get a list of pairwise polymeric interfaces given a list of INTERFACE IDs. Here INTERFACE ID is a compound identifier that includes entry_id, assembly_id and interface_id e.g. 1XXX-1.1. Note that the ENTRY ID part must be upper case. */
|
||||
readonly interfaces?: Maybe<ReadonlyArray<Maybe<CoreInterface>>>;
|
||||
/** Get a list of PDB non-polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. */
|
||||
/** Get a list of PDB non-polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. Note that the ENTRY ID part must be upper case. */
|
||||
readonly nonpolymer_entities?: Maybe<ReadonlyArray<Maybe<CoreNonpolymerEntity>>>;
|
||||
/** Get a PDB non-polymer entity, given the PDB ID and ENTITY ID. Here ENTITY ID is a '1', '2', '3', etc. */
|
||||
readonly nonpolymer_entity?: Maybe<CoreNonpolymerEntity>;
|
||||
@@ -6851,7 +6898,7 @@ export type Query = {
|
||||
readonly nonpolymer_entity_instance?: Maybe<CoreNonpolymerEntityInstance>;
|
||||
/** Get a list of PDB non-polymer entity instances (chains), given the list of ENTITY INSTANCE IDs. Here ENTITY INSTANCE ID identifies structural element in the asymmetric unit, e.g. 'A', 'B', etc. */
|
||||
readonly nonpolymer_entity_instances?: Maybe<ReadonlyArray<Maybe<CoreNonpolymerEntityInstance>>>;
|
||||
/** Get a list of PDB polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. */
|
||||
/** Get a list of PDB polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. Note that the ENTRY ID part must be upper case. */
|
||||
readonly polymer_entities?: Maybe<ReadonlyArray<Maybe<CorePolymerEntity>>>;
|
||||
/** Get a PDB polymer entity, given the PDB ID and ENTITY ID. Here ENTITY ID is a '1', '2', '3', etc. */
|
||||
readonly polymer_entity?: Maybe<CorePolymerEntity>;
|
||||
@@ -8421,6 +8468,29 @@ export type RcsbClusterMembership = {
|
||||
readonly identity?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type RcsbCompModelProvenance = {
|
||||
/**
|
||||
* Entry identifier corresponding to the computed structure model.
|
||||
*
|
||||
* Examples:
|
||||
* AF-P60325-F1, ma-bak-cepc-0019
|
||||
*
|
||||
*/
|
||||
readonly entry_id: Scalars['String'];
|
||||
/**
|
||||
* Source database for the computed structure model.
|
||||
*
|
||||
* Allowable values:
|
||||
* AlphaFoldDB, ModelArchive
|
||||
*
|
||||
*/
|
||||
readonly source_db?: Maybe<Scalars['String']>;
|
||||
/** Source filename for the computed structure model. */
|
||||
readonly source_filename?: Maybe<Scalars['String']>;
|
||||
/** Source URL for computed structure model file. */
|
||||
readonly source_url?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type RcsbEntityHostOrganism = {
|
||||
/**
|
||||
* The beginning polymer sequence position for the polymer section corresponding
|
||||
@@ -8657,7 +8727,7 @@ export type RcsbEntitySourceOrganism = {
|
||||
* A code indicating the provenance of the source organism details for the entity
|
||||
*
|
||||
* Allowable values:
|
||||
* PDB Primary Data
|
||||
* PDB Primary Data, UniProt
|
||||
*
|
||||
*/
|
||||
readonly provenance_source?: Maybe<Scalars['String']>;
|
||||
@@ -8731,7 +8801,7 @@ export type RcsbEntryContainerIdentifiers = {
|
||||
* Entry identifier for the container.
|
||||
*
|
||||
* Examples:
|
||||
* 1KIP, 4HHB
|
||||
* 4HHB, AF_AFP60325F1, MA_MABAKCEPC0019
|
||||
*
|
||||
*/
|
||||
readonly entry_id: Scalars['String'];
|
||||
@@ -8879,6 +8949,15 @@ export type RcsbEntryInfo = {
|
||||
*
|
||||
*/
|
||||
readonly na_polymer_entity_types?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* This data item identifies secondary structure
|
||||
* features of nucleic acids in the entry.
|
||||
*
|
||||
* Allowable values:
|
||||
* a-form double helix, b-form double helix, bulge loop, double helix, four-way junction, hairpin loop, internal loop, mismatched base pair, other right-handed double helix, parallel strands, quadruple helix, tetraloop, three-way junction, triple helix, two-way junction, z-form double helix
|
||||
*
|
||||
*/
|
||||
readonly ndb_struct_conf_na_feature_combined?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>;
|
||||
/** Bound nonpolymer components in this entry. */
|
||||
readonly nonpolymer_bound_components?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>;
|
||||
/** The number of distinct non-polymer entities in the structure entry exclusive of solvent. */
|
||||
@@ -8955,6 +9034,21 @@ export type RcsbEntryInfo = {
|
||||
readonly software_programs_combined?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>;
|
||||
/** The number of distinct solvent entities per deposited structure model. */
|
||||
readonly solvent_entity_count?: Maybe<Scalars['Int']>;
|
||||
/**
|
||||
* Indicates if the structure was determined using experimental or computational methods.
|
||||
*
|
||||
* Allowable values:
|
||||
* computational, experimental
|
||||
*
|
||||
*/
|
||||
readonly structure_determination_methodology: Scalars['String'];
|
||||
/**
|
||||
* Indicates the priority of the value in _rcsb_entry_info.structure_determination_methodology.
|
||||
* The lower the number the higher the priority.
|
||||
* Priority values for "experimental" structures is currently set to 10 and
|
||||
* the values for "computational" structures is set to 100.
|
||||
*/
|
||||
readonly structure_determination_methodology_priority?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type RcsbEntryInfoDiffrnResolutionHigh = {
|
||||
@@ -9294,6 +9388,49 @@ export type RcsbLigandNeighbors = {
|
||||
readonly seq_id?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type RcsbMaQaMetricGlobal = {
|
||||
readonly ma_qa_metric_global?: Maybe<ReadonlyArray<Maybe<RcsbMaQaMetricGlobalMaQaMetricGlobal>>>;
|
||||
/** The model identifier. */
|
||||
readonly model_id: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type RcsbMaQaMetricGlobalMaQaMetricGlobal = {
|
||||
/**
|
||||
* Description of the global QA metric.
|
||||
*
|
||||
* Examples:
|
||||
* confidence score predicting accuracy according to the CA-only Local Distance Difference Test (lDDT-CA) in [0,100]
|
||||
*
|
||||
*/
|
||||
readonly description?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* Name of the global QA metric.
|
||||
*
|
||||
* Examples:
|
||||
* pLDDT
|
||||
*
|
||||
*/
|
||||
readonly name: Scalars['String'];
|
||||
/**
|
||||
* The type of global QA metric.
|
||||
*
|
||||
* Allowable values:
|
||||
* PAE, contact probability, distance, energy, ipTM, normalized score, other, pLDDT, pLDDT all-atom, pLDDT all-atom in [0,1], pLDDT in [0,1], pTM, zscore
|
||||
*
|
||||
*/
|
||||
readonly type: Scalars['String'];
|
||||
/** Details for other type of global QA metric. */
|
||||
readonly type_other_details?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* Value of the global QA metric.
|
||||
*
|
||||
* Examples:
|
||||
* null
|
||||
*
|
||||
*/
|
||||
readonly value: Scalars['Float'];
|
||||
};
|
||||
|
||||
export type RcsbMembraneLineage = {
|
||||
/** Hierarchy depth. */
|
||||
readonly depth?: Maybe<Scalars['Int']>;
|
||||
@@ -10332,7 +10469,7 @@ export type RcsbPolymerEntityContainerIdentifiersReferenceSequenceIdentifiers =
|
||||
* Source of the reference database assignment
|
||||
*
|
||||
* Allowable values:
|
||||
* PDB, RCSB, SIFTS
|
||||
* PDB, RCSB, SIFTS, UniProt
|
||||
*
|
||||
*/
|
||||
readonly provenance_source?: Maybe<Scalars['String']>;
|
||||
@@ -10737,7 +10874,7 @@ export type RcsbPolymerInstanceFeature = {
|
||||
* A type or category of the feature.
|
||||
*
|
||||
* Allowable values:
|
||||
* ANGLE_OUTLIER, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SCOP, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ, ASA
|
||||
* ANGLE_OUTLIER, BEND, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, HELX_LH_PP_P, HELX_RH_3T_P, HELX_RH_AL_P, HELX_RH_PI_P, MA_QA_METRIC_LOCAL_TYPE_CONTACT_PROBABILITY, MA_QA_METRIC_LOCAL_TYPE_DISTANCE, MA_QA_METRIC_LOCAL_TYPE_ENERGY, MA_QA_METRIC_LOCAL_TYPE_IPTM, MA_QA_METRIC_LOCAL_TYPE_NORMALIZED_SCORE, MA_QA_METRIC_LOCAL_TYPE_OTHER, MA_QA_METRIC_LOCAL_TYPE_PAE, MA_QA_METRIC_LOCAL_TYPE_PLDDT, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM_[0,1], MA_QA_METRIC_LOCAL_TYPE_PLDDT_[0,1], MA_QA_METRIC_LOCAL_TYPE_PTM, MA_QA_METRIC_LOCAL_TYPE_ZSCORE, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SCOP, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, STRN, TURN_TY1_P, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ, ASA
|
||||
*
|
||||
*/
|
||||
readonly type?: Maybe<Scalars['String']>;
|
||||
@@ -10748,7 +10885,7 @@ export type RcsbPolymerInstanceFeatureAdditionalProperties = {
|
||||
* The additional property name.
|
||||
*
|
||||
* Allowable values:
|
||||
* CATH_DOMAIN_ID, CATH_NAME, ECOD_DOMAIN_ID, ECOD_FAMILY_NAME, OMEGA_ANGLE, PARTNER_ASYM_ID, PARTNER_BOND_DISTANCE, PARTNER_COMP_ID, SCOP2_DOMAIN_ID, SCOP2_FAMILY_ID, SCOP2_FAMILY_NAME, SCOP2_SUPERFAMILY_ID, SCOP2_SUPERFAMILY_NAME, SCOP_DOMAIN_ID, SCOP_NAME, SCOP_SUN_ID, SHEET_SENSE
|
||||
* CATH_DOMAIN_ID, CATH_NAME, ECOD_DOMAIN_ID, ECOD_FAMILY_NAME, MODELCIF_MODEL_ID, OMEGA_ANGLE, PARTNER_ASYM_ID, PARTNER_BOND_DISTANCE, PARTNER_COMP_ID, SCOP2_DOMAIN_ID, SCOP2_FAMILY_ID, SCOP2_FAMILY_NAME, SCOP2_SUPERFAMILY_ID, SCOP2_SUPERFAMILY_NAME, SCOP_DOMAIN_ID, SCOP_NAME, SCOP_SUN_ID, SHEET_SENSE
|
||||
*
|
||||
*/
|
||||
readonly name?: Maybe<Scalars['String']>;
|
||||
@@ -10818,7 +10955,7 @@ export type RcsbPolymerInstanceFeatureSummary = {
|
||||
* Type or category of the feature.
|
||||
*
|
||||
* Allowable values:
|
||||
* ANGLE_OUTLIER, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SAbDab Antibody Heavy Chain Subclass, SAbDab Antibody Light Chain Subclass, SAbDab Antibody Light Chain Type, SCOP, SCOP2 Family, SCOP2 Superfamily, SCOP2B Superfamily, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ
|
||||
* ANGLE_OUTLIER, BEND, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, HELX_LH_PP_P, HELX_RH_3T_P, HELX_RH_AL_P, HELX_RH_PI_P, MA_QA_METRIC_LOCAL_TYPE_CONTACT_PROBABILITY, MA_QA_METRIC_LOCAL_TYPE_DISTANCE, MA_QA_METRIC_LOCAL_TYPE_ENERGY, MA_QA_METRIC_LOCAL_TYPE_IPTM, MA_QA_METRIC_LOCAL_TYPE_NORMALIZED_SCORE, MA_QA_METRIC_LOCAL_TYPE_OTHER, MA_QA_METRIC_LOCAL_TYPE_PAE, MA_QA_METRIC_LOCAL_TYPE_PLDDT, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM_[0,1], MA_QA_METRIC_LOCAL_TYPE_PLDDT_[0,1], MA_QA_METRIC_LOCAL_TYPE_PTM, MA_QA_METRIC_LOCAL_TYPE_ZSCORE, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SCOP, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, STRN, TURN_TY1_P, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ
|
||||
*
|
||||
*/
|
||||
readonly type?: Maybe<Scalars['String']>;
|
||||
@@ -13377,6 +13514,11 @@ export type ReflnsShell = {
|
||||
};
|
||||
|
||||
export type Software = {
|
||||
/**
|
||||
* This data item is a pointer to _citation.id in the CITATION
|
||||
* category.
|
||||
*/
|
||||
readonly citation_id?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The classification of the program according to its
|
||||
* major function.
|
||||
@@ -13527,6 +13669,37 @@ export type Struct = {
|
||||
readonly title?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type StructAsym = {
|
||||
/**
|
||||
* This data item is a pointer to _atom_site.pdbx_PDB_strand_id the
|
||||
* ATOM_SITE category.
|
||||
*
|
||||
* Examples:
|
||||
* 1ABC
|
||||
*
|
||||
*/
|
||||
readonly pdbx_PDB_id?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* This data item is a pointer to _atom_site.ndb_alias_strand_id the
|
||||
* ATOM_SITE category.
|
||||
*/
|
||||
readonly pdbx_alt_id?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* This data item gives the order of the structural elements in the
|
||||
* ATOM_SITE category.
|
||||
*/
|
||||
readonly pdbx_order?: Maybe<Scalars['Int']>;
|
||||
/**
|
||||
* This data item describes the general type of the structural elements
|
||||
* in the ATOM_SITE category.
|
||||
*
|
||||
* Allowable values:
|
||||
* ATOMN, ATOMP, ATOMS, HETAC, HETAD, HETAI, HETAIN, HETAS, HETIC
|
||||
*
|
||||
*/
|
||||
readonly pdbx_type?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type StructKeywords = {
|
||||
/**
|
||||
* Terms characterizing the macromolecular structure.
|
||||
|
||||
@@ -120,6 +120,7 @@ interface Canvas3DContext {
|
||||
|
||||
namespace Canvas3DContext {
|
||||
export const DefaultAttribs = {
|
||||
powerPreference: 'high-performance' as WebGLContextAttributes['powerPreference'],
|
||||
failIfMajorPerformanceCaveat: false,
|
||||
/** true by default to avoid issues with Safari (Jan 2021) */
|
||||
antialias: true,
|
||||
@@ -140,8 +141,9 @@ namespace Canvas3DContext {
|
||||
|
||||
if (a.enableWboit && a.enableDpoit) throw new Error('Multiple transparency methods not allowed.');
|
||||
|
||||
const { failIfMajorPerformanceCaveat, antialias, preserveDrawingBuffer, pixelScale, preferWebGl1 } = a;
|
||||
const { powerPreference, failIfMajorPerformanceCaveat, antialias, preserveDrawingBuffer, pixelScale, preferWebGl1 } = a;
|
||||
const gl = getGLContext(canvas, {
|
||||
powerPreference,
|
||||
failIfMajorPerformanceCaveat,
|
||||
antialias,
|
||||
preserveDrawingBuffer,
|
||||
|
||||
@@ -142,7 +142,7 @@ export class DrawPass {
|
||||
}
|
||||
|
||||
if (PostprocessingPass.isEnabled(postprocessingProps)) {
|
||||
if (PostprocessingPass.isOutlineEnabled(postprocessingProps)) {
|
||||
if (PostprocessingPass.isTransparentOutlineEnabled(postprocessingProps)) {
|
||||
this.depthTargetTransparent.bind();
|
||||
renderer.clearDepth(true);
|
||||
if (scene.opacityAverage < 1) {
|
||||
@@ -150,7 +150,7 @@ export class DrawPass {
|
||||
}
|
||||
}
|
||||
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps);
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps, renderer.light);
|
||||
}
|
||||
|
||||
this.depthTextureOpaque.detachFramebuffer(this.colorTarget.framebuffer, 'depth');
|
||||
@@ -196,7 +196,7 @@ export class DrawPass {
|
||||
}
|
||||
|
||||
if (PostprocessingPass.isEnabled(postprocessingProps)) {
|
||||
if (PostprocessingPass.isOutlineEnabled(postprocessingProps)) {
|
||||
if (PostprocessingPass.isTransparentOutlineEnabled(postprocessingProps)) {
|
||||
this.depthTargetTransparent.bind();
|
||||
renderer.clearDepth(true);
|
||||
if (scene.opacityAverage < 1) {
|
||||
@@ -204,7 +204,7 @@ export class DrawPass {
|
||||
}
|
||||
}
|
||||
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps);
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps, renderer.light);
|
||||
}
|
||||
|
||||
// render transparent primitives and volumes
|
||||
@@ -260,7 +260,7 @@ export class DrawPass {
|
||||
this.colorTarget.depthRenderbuffer?.detachFramebuffer(this.postprocessing.target.framebuffer);
|
||||
}
|
||||
|
||||
if (PostprocessingPass.isOutlineEnabled(postprocessingProps)) {
|
||||
if (PostprocessingPass.isTransparentOutlineEnabled(postprocessingProps)) {
|
||||
this.depthTargetTransparent.bind();
|
||||
renderer.clearDepth(true);
|
||||
if (scene.opacityAverage < 1) {
|
||||
@@ -268,7 +268,7 @@ export class DrawPass {
|
||||
}
|
||||
}
|
||||
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps);
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps, renderer.light);
|
||||
|
||||
if (!this.packedDepth) {
|
||||
this.depthTextureOpaque.attachFramebuffer(this.postprocessing.target.framebuffer, 'depth');
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
|
||||
* @author Ludovic Autin <ludovic.autin@gmail.com>
|
||||
*/
|
||||
|
||||
import { CopyRenderable, createCopyRenderable, QuadSchema, QuadValues } from '../../mol-gl/compute/util';
|
||||
@@ -30,6 +31,8 @@ import { SmaaParams, SmaaPass } from './smaa';
|
||||
import { isTimingMode } from '../../mol-util/debug';
|
||||
import { BackgroundParams, BackgroundPass } from './background';
|
||||
import { AssetManager } from '../../mol-util/assets';
|
||||
import { Light } from '../../mol-gl/renderer';
|
||||
import { shadows_frag } from '../../mol-gl/shader/shadows.frag';
|
||||
|
||||
const OutlinesSchema = {
|
||||
...QuadSchema,
|
||||
@@ -42,10 +45,12 @@ const OutlinesSchema = {
|
||||
uFar: UniformSpec('f'),
|
||||
|
||||
uMaxPossibleViewZDiff: UniformSpec('f'),
|
||||
|
||||
dTransparentOutline: DefineSpec('boolean'),
|
||||
};
|
||||
type OutlinesRenderable = ComputeRenderable<Values<typeof OutlinesSchema>>
|
||||
|
||||
function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, depthTextureTransparent: Texture): OutlinesRenderable {
|
||||
function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, depthTextureTransparent: Texture, transparentOutline: boolean): OutlinesRenderable {
|
||||
const width = depthTextureOpaque.getWidth();
|
||||
const height = depthTextureOpaque.getHeight();
|
||||
|
||||
@@ -60,6 +65,8 @@ function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, d
|
||||
uFar: ValueCell.create(10000),
|
||||
|
||||
uMaxPossibleViewZDiff: ValueCell.create(0.5),
|
||||
|
||||
dTransparentOutline: ValueCell.create(transparentOutline),
|
||||
};
|
||||
|
||||
const schema = { ...OutlinesSchema };
|
||||
@@ -69,6 +76,64 @@ function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, d
|
||||
return createComputeRenderable(renderItem, values);
|
||||
}
|
||||
|
||||
const ShadowsSchema = {
|
||||
...QuadSchema,
|
||||
tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
uTexSize: UniformSpec('v2'),
|
||||
|
||||
uProjection: UniformSpec('m4'),
|
||||
uInvProjection: UniformSpec('m4'),
|
||||
uBounds: UniformSpec('v4'),
|
||||
|
||||
dOrthographic: DefineSpec('number'),
|
||||
uNear: UniformSpec('f'),
|
||||
uFar: UniformSpec('f'),
|
||||
|
||||
dSteps: DefineSpec('number'),
|
||||
uMaxDistance: UniformSpec('f'),
|
||||
uTolerance: UniformSpec('f'),
|
||||
uBias: UniformSpec('f'),
|
||||
|
||||
uLightDirection: UniformSpec('v3[]'),
|
||||
uLightColor: UniformSpec('v3[]'),
|
||||
dLightCount: DefineSpec('number'),
|
||||
};
|
||||
type ShadowsRenderable = ComputeRenderable<Values<typeof ShadowsSchema>>
|
||||
|
||||
function getShadowsRenderable(ctx: WebGLContext, depthTexture: Texture): ShadowsRenderable {
|
||||
const width = depthTexture.getWidth();
|
||||
const height = depthTexture.getHeight();
|
||||
|
||||
const values: Values<typeof ShadowsSchema> = {
|
||||
...QuadValues,
|
||||
tDepth: ValueCell.create(depthTexture),
|
||||
uTexSize: ValueCell.create(Vec2.create(width, height)),
|
||||
|
||||
uProjection: ValueCell.create(Mat4.identity()),
|
||||
uInvProjection: ValueCell.create(Mat4.identity()),
|
||||
uBounds: ValueCell.create(Vec4()),
|
||||
|
||||
dOrthographic: ValueCell.create(0),
|
||||
uNear: ValueCell.create(1),
|
||||
uFar: ValueCell.create(10000),
|
||||
|
||||
dSteps: ValueCell.create(1),
|
||||
uMaxDistance: ValueCell.create(3.0),
|
||||
uTolerance: ValueCell.create(1.0),
|
||||
uBias: ValueCell.create(0.6),
|
||||
|
||||
uLightDirection: ValueCell.create([]),
|
||||
uLightColor: ValueCell.create([]),
|
||||
dLightCount: ValueCell.create(0),
|
||||
};
|
||||
|
||||
const schema = { ...ShadowsSchema };
|
||||
const shaderCode = ShaderCode('shadows', quad_vert, shadows_frag);
|
||||
const renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values);
|
||||
|
||||
return createComputeRenderable(renderItem, values);
|
||||
}
|
||||
|
||||
const SsaoSchema = {
|
||||
...QuadSchema,
|
||||
tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
@@ -204,6 +269,7 @@ const PostprocessingSchema = {
|
||||
tColor: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
tDepthOpaque: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
tDepthTransparent: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
tShadows: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
tOutlines: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
uTexSize: UniformSpec('v2'),
|
||||
|
||||
@@ -221,19 +287,25 @@ const PostprocessingSchema = {
|
||||
dOcclusionEnable: DefineSpec('boolean'),
|
||||
uOcclusionOffset: UniformSpec('v2'),
|
||||
|
||||
dShadowEnable: DefineSpec('boolean'),
|
||||
|
||||
dOutlineEnable: DefineSpec('boolean'),
|
||||
dOutlineScale: DefineSpec('number'),
|
||||
uOutlineThreshold: UniformSpec('f'),
|
||||
|
||||
dTransparentOutline: DefineSpec('boolean'),
|
||||
};
|
||||
type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>>
|
||||
|
||||
function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture): PostprocessingRenderable {
|
||||
|
||||
function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, shadowsTexture: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture, transparentOutline: boolean): PostprocessingRenderable {
|
||||
const values: Values<typeof PostprocessingSchema> = {
|
||||
...QuadValues,
|
||||
tSsaoDepth: ValueCell.create(ssaoDepthTexture),
|
||||
tColor: ValueCell.create(colorTexture),
|
||||
tDepthOpaque: ValueCell.create(depthTextureOpaque),
|
||||
tDepthTransparent: ValueCell.create(depthTextureTransparent),
|
||||
tShadows: ValueCell.create(shadowsTexture),
|
||||
tOutlines: ValueCell.create(outlinesTexture),
|
||||
uTexSize: ValueCell.create(Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())),
|
||||
|
||||
@@ -251,9 +323,13 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
|
||||
dOcclusionEnable: ValueCell.create(true),
|
||||
uOcclusionOffset: ValueCell.create(Vec2.create(0, 0)),
|
||||
|
||||
dShadowEnable: ValueCell.create(false),
|
||||
|
||||
dOutlineEnable: ValueCell.create(false),
|
||||
dOutlineScale: ValueCell.create(1),
|
||||
uOutlineThreshold: ValueCell.create(0.33),
|
||||
|
||||
dTransparentOutline: ValueCell.create(transparentOutline),
|
||||
};
|
||||
|
||||
const schema = { ...PostprocessingSchema };
|
||||
@@ -274,11 +350,21 @@ export const PostprocessingParams = {
|
||||
}),
|
||||
off: PD.Group({})
|
||||
}, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }),
|
||||
shadow: PD.MappedStatic('off', {
|
||||
on: PD.Group({
|
||||
steps: PD.Numeric(1, { min: 1, max: 64, step: 1 }),
|
||||
bias: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }),
|
||||
maxDistance: PD.Numeric(3, { min: 0, max: 256, step: 1 }),
|
||||
tolerance: PD.Numeric(1.0, { min: 0.0, max: 10.0, step: 0.1 }),
|
||||
}),
|
||||
off: PD.Group({})
|
||||
}, { cycle: true, description: 'Simplistic shadows' }),
|
||||
outline: PD.MappedStatic('off', {
|
||||
on: PD.Group({
|
||||
scale: PD.Numeric(1, { min: 1, max: 5, step: 1 }),
|
||||
threshold: PD.Numeric(0.33, { min: 0.01, max: 1, step: 0.01 }),
|
||||
color: PD.Color(Color(0x000000)),
|
||||
includeTransparent: PD.Boolean(true, { description: 'Whether to show outline for transparent objects' }),
|
||||
}),
|
||||
off: PD.Group({})
|
||||
}, { cycle: true, description: 'Draw outline around 3D objects' }),
|
||||
@@ -289,15 +375,16 @@ export const PostprocessingParams = {
|
||||
}, { options: [['fxaa', 'FXAA'], ['smaa', 'SMAA'], ['off', 'Off']], description: 'Smooth pixel edges' }),
|
||||
background: PD.Group(BackgroundParams, { isFlat: true }),
|
||||
};
|
||||
|
||||
export type PostprocessingProps = PD.Values<typeof PostprocessingParams>
|
||||
|
||||
export class PostprocessingPass {
|
||||
static isEnabled(props: PostprocessingProps) {
|
||||
return props.occlusion.name === 'on' || props.outline.name === 'on' || props.background.variant.name !== 'off';
|
||||
return props.occlusion.name === 'on' || props.shadow.name === 'on' || props.outline.name === 'on' || props.background.variant.name !== 'off';
|
||||
}
|
||||
|
||||
static isOutlineEnabled(props: PostprocessingProps) {
|
||||
return props.outline.name === 'on';
|
||||
static isTransparentOutlineEnabled(props: PostprocessingProps) {
|
||||
return props.outline.name === 'on' && props.outline.params.includeTransparent;
|
||||
}
|
||||
|
||||
readonly target: RenderTarget;
|
||||
@@ -305,6 +392,9 @@ export class PostprocessingPass {
|
||||
private readonly outlinesTarget: RenderTarget;
|
||||
private readonly outlinesRenderable: OutlinesRenderable;
|
||||
|
||||
private readonly shadowsTarget: RenderTarget;
|
||||
private readonly shadowsRenderable: ShadowsRenderable;
|
||||
|
||||
private readonly ssaoFramebuffer: Framebuffer;
|
||||
private readonly ssaoBlurFirstPassFramebuffer: Framebuffer;
|
||||
private readonly ssaoBlurSecondPassFramebuffer: Framebuffer;
|
||||
@@ -348,7 +438,10 @@ export class PostprocessingPass {
|
||||
this.target = webgl.createRenderTarget(width, height, false, 'uint8', 'linear');
|
||||
|
||||
this.outlinesTarget = webgl.createRenderTarget(width, height, false);
|
||||
this.outlinesRenderable = getOutlinesRenderable(webgl, depthTextureOpaque, depthTextureTransparent);
|
||||
this.outlinesRenderable = getOutlinesRenderable(webgl, depthTextureOpaque, depthTextureTransparent, true);
|
||||
|
||||
this.shadowsTarget = webgl.createRenderTarget(width, height, false);
|
||||
this.shadowsRenderable = getShadowsRenderable(webgl, depthTextureOpaque);
|
||||
|
||||
this.ssaoFramebuffer = webgl.resources.framebuffer();
|
||||
this.ssaoBlurFirstPassFramebuffer = webgl.resources.framebuffer();
|
||||
@@ -373,7 +466,7 @@ export class PostprocessingPass {
|
||||
this.ssaoRenderable = getSsaoRenderable(webgl, this.downsampleFactor === 1 ? depthTextureOpaque : this.downsampledDepthTarget.texture);
|
||||
this.ssaoBlurFirstPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthTexture, 'horizontal');
|
||||
this.ssaoBlurSecondPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthBlurProxyTexture, 'vertical');
|
||||
this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.outlinesTarget.texture, this.ssaoDepthTexture);
|
||||
this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.shadowsTarget.texture, this.outlinesTarget.texture, this.ssaoDepthTexture, true);
|
||||
|
||||
this.background = new BackgroundPass(webgl, assetManager, width, height);
|
||||
}
|
||||
@@ -389,12 +482,14 @@ export class PostprocessingPass {
|
||||
const sh = Math.floor(height * this.ssaoScale);
|
||||
this.target.setSize(width, height);
|
||||
this.outlinesTarget.setSize(width, height);
|
||||
this.shadowsTarget.setSize(width, height);
|
||||
this.downsampledDepthTarget.setSize(sw, sh);
|
||||
this.ssaoDepthTexture.define(sw, sh);
|
||||
this.ssaoDepthBlurProxyTexture.define(sw, sh);
|
||||
|
||||
ValueCell.update(this.renderable.values.uTexSize, Vec2.set(this.renderable.values.uTexSize.ref.value, width, height));
|
||||
ValueCell.update(this.outlinesRenderable.values.uTexSize, Vec2.set(this.outlinesRenderable.values.uTexSize.ref.value, width, height));
|
||||
ValueCell.update(this.shadowsRenderable.values.uTexSize, Vec2.set(this.shadowsRenderable.values.uTexSize.ref.value, width, height));
|
||||
ValueCell.update(this.downsampleDepthRenderable.values.uTexSize, Vec2.set(this.downsampleDepthRenderable.values.uTexSize.ref.value, sw, sh));
|
||||
ValueCell.update(this.ssaoRenderable.values.uTexSize, Vec2.set(this.ssaoRenderable.values.uTexSize.ref.value, sw, sh));
|
||||
ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurFirstPassRenderable.values.uTexSize.ref.value, sw, sh));
|
||||
@@ -404,25 +499,29 @@ export class PostprocessingPass {
|
||||
}
|
||||
}
|
||||
|
||||
private updateState(camera: ICamera, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps) {
|
||||
private updateState(camera: ICamera, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps, light: Light) {
|
||||
let needsUpdateShadows = false;
|
||||
let needsUpdateMain = false;
|
||||
let needsUpdateSsao = false;
|
||||
let needsUpdateSsaoBlur = false;
|
||||
let needsUpdateOutlines = false;
|
||||
|
||||
const orthographic = camera.state.mode === 'orthographic' ? 1 : 0;
|
||||
const outlinesEnabled = props.outline.name === 'on';
|
||||
const shadowsEnabled = props.shadow.name === 'on';
|
||||
const occlusionEnabled = props.occlusion.name === 'on';
|
||||
|
||||
const invProjection = Mat4.identity();
|
||||
Mat4.invert(invProjection, camera.projection);
|
||||
|
||||
const [w, h] = this.renderable.values.uTexSize.ref.value;
|
||||
const v = camera.viewport;
|
||||
|
||||
if (props.occlusion.name === 'on') {
|
||||
ValueCell.update(this.ssaoRenderable.values.uProjection, camera.projection);
|
||||
ValueCell.update(this.ssaoRenderable.values.uInvProjection, invProjection);
|
||||
|
||||
const [w, h] = this.renderable.values.uTexSize.ref.value;
|
||||
const b = this.ssaoRenderable.values.uBounds;
|
||||
const v = camera.viewport;
|
||||
const s = this.ssaoScale;
|
||||
Vec4.set(b.ref.value,
|
||||
Math.floor(v.x * s) / (w * s),
|
||||
@@ -494,8 +593,41 @@ export class PostprocessingPass {
|
||||
}
|
||||
}
|
||||
|
||||
if (props.shadow.name === 'on') {
|
||||
ValueCell.update(this.shadowsRenderable.values.uProjection, camera.projection);
|
||||
ValueCell.update(this.shadowsRenderable.values.uInvProjection, invProjection);
|
||||
|
||||
Vec4.set(this.shadowsRenderable.values.uBounds.ref.value,
|
||||
v.x / w,
|
||||
v.y / h,
|
||||
(v.x + v.width) / w,
|
||||
(v.y + v.height) / h
|
||||
);
|
||||
ValueCell.update(this.shadowsRenderable.values.uBounds, this.shadowsRenderable.values.uBounds.ref.value);
|
||||
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uNear, camera.near);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uFar, camera.far);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.dOrthographic, orthographic);
|
||||
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uMaxDistance, props.shadow.params.maxDistance);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uTolerance, props.shadow.params.tolerance);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uBias, props.shadow.params.bias);
|
||||
if (this.shadowsRenderable.values.dSteps.ref.value !== props.shadow.params.steps) {
|
||||
ValueCell.update(this.shadowsRenderable.values.dSteps, props.shadow.params.steps);
|
||||
needsUpdateShadows = true;
|
||||
}
|
||||
|
||||
ValueCell.update(this.shadowsRenderable.values.uLightDirection, light.direction);
|
||||
ValueCell.update(this.shadowsRenderable.values.uLightColor, light.color);
|
||||
if (this.shadowsRenderable.values.dLightCount.ref.value !== light.count) {
|
||||
ValueCell.update(this.shadowsRenderable.values.dLightCount, light.count);
|
||||
needsUpdateShadows = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (props.outline.name === 'on') {
|
||||
let { threshold } = props.outline.params;
|
||||
let { threshold, includeTransparent } = props.outline.params;
|
||||
const transparentOutline = includeTransparent ?? true;
|
||||
// orthographic needs lower threshold
|
||||
if (camera.state.mode === 'orthographic') threshold /= 5;
|
||||
const factor = Math.pow(1000, threshold) / 1000;
|
||||
@@ -506,12 +638,16 @@ export class PostprocessingPass {
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.uNear, camera.near);
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.uFar, camera.far);
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
|
||||
if (this.renderable.values.dTransparentOutline.ref.value !== transparentOutline) { needsUpdateOutlines = true; }
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.dTransparentOutline, transparentOutline);
|
||||
|
||||
ValueCell.update(this.renderable.values.uOutlineColor, Color.toVec3Normalized(this.renderable.values.uOutlineColor.ref.value, props.outline.params.color));
|
||||
|
||||
ValueCell.updateIfChanged(this.renderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
|
||||
if (this.renderable.values.dOutlineScale.ref.value !== outlineScale) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOutlineScale, outlineScale);
|
||||
if (this.renderable.values.dTransparentOutline.ref.value !== transparentOutline) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dTransparentOutline, transparentOutline);
|
||||
}
|
||||
|
||||
ValueCell.updateIfChanged(this.renderable.values.uFar, camera.far);
|
||||
@@ -522,11 +658,22 @@ export class PostprocessingPass {
|
||||
ValueCell.updateIfChanged(this.renderable.values.uTransparentBackground, transparentBackground);
|
||||
if (this.renderable.values.dOrthographic.ref.value !== orthographic) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOrthographic, orthographic);
|
||||
|
||||
if (this.renderable.values.dOutlineEnable.ref.value !== outlinesEnabled) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOutlineEnable, outlinesEnabled);
|
||||
if (this.renderable.values.dShadowEnable.ref.value !== shadowsEnabled) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dShadowEnable, shadowsEnabled);
|
||||
if (this.renderable.values.dOcclusionEnable.ref.value !== occlusionEnabled) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, occlusionEnabled);
|
||||
|
||||
if (needsUpdateOutlines) {
|
||||
this.outlinesRenderable.update();
|
||||
}
|
||||
|
||||
if (needsUpdateShadows) {
|
||||
this.shadowsRenderable.update();
|
||||
}
|
||||
|
||||
if (needsUpdateSsao) {
|
||||
this.ssaoRenderable.update();
|
||||
}
|
||||
@@ -564,15 +711,20 @@ export class PostprocessingPass {
|
||||
this.transparentBackground = value;
|
||||
}
|
||||
|
||||
render(camera: ICamera, toDrawingBuffer: boolean, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps) {
|
||||
render(camera: ICamera, toDrawingBuffer: boolean, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps, light: Light) {
|
||||
if (isTimingMode) this.webgl.timer.mark('PostprocessingPass.render');
|
||||
this.updateState(camera, transparentBackground, backgroundColor, props);
|
||||
this.updateState(camera, transparentBackground, backgroundColor, props, light);
|
||||
|
||||
if (props.outline.name === 'on') {
|
||||
this.outlinesTarget.bind();
|
||||
this.outlinesRenderable.render();
|
||||
}
|
||||
|
||||
if (props.shadow.name === 'on') {
|
||||
this.shadowsTarget.bind();
|
||||
this.shadowsRenderable.render();
|
||||
}
|
||||
|
||||
// don't render occlusion if offset is given,
|
||||
// which will reuse the existing occlusion
|
||||
if (props.occlusion.name === 'on' && this.occlusionOffset[0] === 0 && this.occlusionOffset[1] === 0) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -21,6 +21,7 @@ export type OverpaintData = {
|
||||
uOverpaintGridDim: ValueCell<Vec3>,
|
||||
uOverpaintGridTransform: ValueCell<Vec4>,
|
||||
dOverpaintType: ValueCell<string>,
|
||||
uOverpaintStrength: ValueCell<number>,
|
||||
}
|
||||
|
||||
export function applyOverpaintColor(array: Uint8Array, start: number, end: number, color: Color) {
|
||||
@@ -54,6 +55,7 @@ export function createOverpaint(count: number, type: OverpaintType, overpaintDat
|
||||
uOverpaintGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uOverpaintGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dOverpaintType: ValueCell.create(type),
|
||||
uOverpaintStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -74,6 +76,7 @@ export function createEmptyOverpaint(overpaintData?: OverpaintData): OverpaintDa
|
||||
uOverpaintGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uOverpaintGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dOverpaintType: ValueCell.create('groupInstance'),
|
||||
uOverpaintStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2021-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -21,6 +21,7 @@ export type SubstanceData = {
|
||||
uSubstanceGridDim: ValueCell<Vec3>,
|
||||
uSubstanceGridTransform: ValueCell<Vec4>,
|
||||
dSubstanceType: ValueCell<string>,
|
||||
uSubstanceStrength: ValueCell<number>,
|
||||
}
|
||||
|
||||
export function applySubstanceMaterial(array: Uint8Array, start: number, end: number, material: Material) {
|
||||
@@ -54,6 +55,7 @@ export function createSubstance(count: number, type: SubstanceType, substanceDat
|
||||
uSubstanceGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uSubstanceGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dSubstanceType: ValueCell.create(type),
|
||||
uSubstanceStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -74,6 +76,7 @@ export function createEmptySubstance(substanceData?: SubstanceData): SubstanceDa
|
||||
uSubstanceGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uSubstanceGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dSubstanceType: ValueCell.create('groupInstance'),
|
||||
uSubstanceStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
import { ValueCell } from '../../../mol-util';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { LocationIterator } from '../../../mol-geo/util/location-iterator';
|
||||
import { LocationIterator, PositionLocation } from '../../../mol-geo/util/location-iterator';
|
||||
import { TransformData } from '../transform-data';
|
||||
import { createColors } from '../color-data';
|
||||
import { createMarkers } from '../marker-data';
|
||||
@@ -20,11 +20,12 @@ import { createEmptyTransparency } from '../transparency-data';
|
||||
import { TextureMeshValues } from '../../../mol-gl/renderable/texture-mesh';
|
||||
import { calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
|
||||
import { createNullTexture, Texture } from '../../../mol-gl/webgl/texture';
|
||||
import { Vec2, Vec4 } from '../../../mol-math/linear-algebra';
|
||||
import { Vec2, Vec3, Vec4 } from '../../../mol-math/linear-algebra';
|
||||
import { createEmptyClipping } from '../clipping-data';
|
||||
import { NullLocation } from '../../../mol-model/location';
|
||||
import { createEmptySubstance } from '../substance-data';
|
||||
import { RenderableState } from '../../../mol-gl/renderable';
|
||||
import { WebGLContext } from '../../../mol-gl/webgl/context';
|
||||
|
||||
export interface TextureMesh {
|
||||
readonly kind: 'texture-mesh',
|
||||
@@ -43,7 +44,10 @@ export interface TextureMesh {
|
||||
|
||||
readonly boundingSphere: Sphere3D
|
||||
|
||||
readonly meta: { [k: string]: unknown }
|
||||
readonly meta: {
|
||||
webgl?: WebGLContext
|
||||
[k: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export namespace TextureMesh {
|
||||
@@ -131,9 +135,42 @@ export namespace TextureMesh {
|
||||
updateBoundingSphere,
|
||||
createRenderableState,
|
||||
updateRenderableState,
|
||||
createPositionIterator: () => LocationIterator(1, 1, 1, () => NullLocation)
|
||||
createPositionIterator,
|
||||
};
|
||||
|
||||
const TextureMeshName = 'texture-mesh';
|
||||
|
||||
function createPositionIterator(textureMesh: TextureMesh, transform: TransformData): LocationIterator {
|
||||
const webgl = textureMesh.meta.webgl;
|
||||
if (!webgl) return LocationIterator(1, 1, 1, () => NullLocation);
|
||||
|
||||
if (!webgl.namedFramebuffers[TextureMeshName]) {
|
||||
webgl.namedFramebuffers[TextureMeshName] = webgl.resources.framebuffer();
|
||||
}
|
||||
const framebuffer = webgl.namedFramebuffers[TextureMeshName];
|
||||
const [width, height] = textureMesh.geoTextureDim.ref.value;
|
||||
const vertices = new Float32Array(width * height * 4);
|
||||
framebuffer.bind();
|
||||
textureMesh.vertexTexture.ref.value.attachFramebuffer(framebuffer, 0);
|
||||
webgl.readPixels(0, 0, width, height, vertices);
|
||||
|
||||
const groupCount = textureMesh.vertexCount;
|
||||
const instanceCount = transform.instanceCount.ref.value;
|
||||
const location = PositionLocation();
|
||||
const p = location.position;
|
||||
const v = vertices;
|
||||
const m = transform.aTransform.ref.value;
|
||||
const getLocation = (groupIndex: number, instanceIndex: number) => {
|
||||
if (instanceIndex < 0) {
|
||||
Vec3.fromArray(p, v, groupIndex * 4);
|
||||
} else {
|
||||
Vec3.transformMat4Offset(p, v, m, 0, groupIndex * 4, instanceIndex * 16);
|
||||
}
|
||||
return location;
|
||||
};
|
||||
return LocationIterator(groupCount, instanceCount, 1, getLocation);
|
||||
}
|
||||
|
||||
function createValues(textureMesh: TextureMesh, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: PD.Values<Params>): TextureMeshValues {
|
||||
const { instanceCount, groupCount } = locationIt;
|
||||
const positionIt = Utils.createPositionIterator(textureMesh, transform);
|
||||
|
||||
@@ -21,6 +21,7 @@ export type TransparencyData = {
|
||||
uTransparencyGridDim: ValueCell<Vec3>,
|
||||
uTransparencyGridTransform: ValueCell<Vec4>,
|
||||
dTransparencyType: ValueCell<string>,
|
||||
uTransparencyStrength: ValueCell<number>,
|
||||
}
|
||||
|
||||
export function applyTransparencyValue(array: Uint8Array, start: number, end: number, value: number) {
|
||||
@@ -63,6 +64,7 @@ export function createTransparency(count: number, type: TransparencyType, transp
|
||||
uTransparencyGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uTransparencyGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dTransparencyType: ValueCell.create(type),
|
||||
uTransparencyStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -84,6 +86,7 @@ export function createEmptyTransparency(transparencyData?: TransparencyData): Tr
|
||||
uTransparencyGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uTransparencyGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dTransparencyType: ValueCell.create('groupInstance'),
|
||||
uTransparencyStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -229,6 +229,7 @@ export const OverpaintSchema = {
|
||||
uOverpaintGridTransform: UniformSpec('v4'),
|
||||
tOverpaintGrid: TextureSpec('texture', 'rgba', 'ubyte', 'linear'),
|
||||
dOverpaintType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']),
|
||||
uOverpaintStrength: UniformSpec('f', 'material'),
|
||||
} as const;
|
||||
export type OverpaintSchema = typeof OverpaintSchema
|
||||
export type OverpaintValues = Values<OverpaintSchema>
|
||||
@@ -242,7 +243,8 @@ export const TransparencySchema = {
|
||||
uTransparencyGridDim: UniformSpec('v3'),
|
||||
uTransparencyGridTransform: UniformSpec('v4'),
|
||||
tTransparencyGrid: TextureSpec('texture', 'alpha', 'ubyte', 'linear'),
|
||||
dTransparencyType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance'])
|
||||
dTransparencyType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']),
|
||||
uTransparencyStrength: UniformSpec('f', 'material'),
|
||||
} as const;
|
||||
export type TransparencySchema = typeof TransparencySchema
|
||||
export type TransparencyValues = Values<TransparencySchema>
|
||||
@@ -256,6 +258,7 @@ export const SubstanceSchema = {
|
||||
uSubstanceGridTransform: UniformSpec('v4'),
|
||||
tSubstanceGrid: TextureSpec('texture', 'rgba', 'ubyte', 'linear'),
|
||||
dSubstanceType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']),
|
||||
uSubstanceStrength: UniformSpec('f', 'material'),
|
||||
} as const;
|
||||
export type SubstanceSchema = typeof SubstanceSchema
|
||||
export type SubstanceValues = Values<SubstanceSchema>
|
||||
|
||||
@@ -54,6 +54,7 @@ export const enum MarkingType {
|
||||
interface Renderer {
|
||||
readonly stats: RendererStats
|
||||
readonly props: Readonly<RendererProps>
|
||||
readonly light: Readonly<Light>
|
||||
|
||||
clear: (toBackgroundColor: boolean, ignoreTransparentBackground?: boolean) => void
|
||||
clearDepth: (packed?: boolean) => void
|
||||
@@ -103,13 +104,13 @@ export const RendererParams = {
|
||||
xrayEdgeFalloff: PD.Numeric(1, { min: 0.0, max: 3.0, step: 0.1 }),
|
||||
|
||||
light: PD.ObjectList({
|
||||
inclination: PD.Numeric(180, { min: 0, max: 180, step: 1 }),
|
||||
azimuth: PD.Numeric(0, { min: 0, max: 360, step: 1 }),
|
||||
inclination: PD.Numeric(150, { min: 0, max: 180, step: 1 }),
|
||||
azimuth: PD.Numeric(320, { min: 0, max: 360, step: 1 }),
|
||||
color: PD.Color(Color.fromNormalizedRgb(1.0, 1.0, 1.0)),
|
||||
intensity: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }),
|
||||
}, o => Color.toHexString(o.color), { defaultValue: [{
|
||||
inclination: 180,
|
||||
azimuth: 0,
|
||||
inclination: 150,
|
||||
azimuth: 320,
|
||||
color: Color.fromNormalizedRgb(1.0, 1.0, 1.0),
|
||||
intensity: 0.6
|
||||
}] }),
|
||||
@@ -118,7 +119,7 @@ export const RendererParams = {
|
||||
};
|
||||
export type RendererProps = PD.Values<typeof RendererParams>
|
||||
|
||||
type Light = {
|
||||
export type Light = {
|
||||
count: number
|
||||
direction: number[]
|
||||
color: number[]
|
||||
@@ -827,6 +828,9 @@ namespace Renderer {
|
||||
instancedDrawCount: stats.instancedDrawCount,
|
||||
};
|
||||
},
|
||||
get light(): Light {
|
||||
return light;
|
||||
},
|
||||
dispose: () => {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export const apply_light_color = `
|
||||
gl_FragColor = material;
|
||||
#else
|
||||
#ifdef bumpEnabled
|
||||
if (uBumpFrequency > 0.0 && uBumpAmplitude > 0.0) {
|
||||
if (uBumpFrequency > 0.0 && uBumpAmplitude > 0.0 && bumpiness > 0.0) {
|
||||
normal = perturbNormal(-vViewPosition, normal, fbm(vModelPosition * uBumpFrequency), (uBumpAmplitude * bumpiness) / uBumpFrequency);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -42,6 +42,7 @@ export const assign_color_varying = `
|
||||
#else
|
||||
vOverpaint.rgb = mix(vColor.rgb, vOverpaint.rgb, vOverpaint.a);
|
||||
#endif
|
||||
vOverpaint *= uOverpaintStrength;
|
||||
#endif
|
||||
|
||||
#ifdef dSubstance
|
||||
@@ -58,6 +59,7 @@ export const assign_color_varying = `
|
||||
|
||||
// pre-mix to avoid artifacts due to empty substance
|
||||
vSubstance.rgb = mix(vec3(uMetalness, uRoughness, uBumpiness), vSubstance.rgb, vSubstance.a);
|
||||
vSubstance *= uSubstanceStrength;
|
||||
#endif
|
||||
#elif defined(dRenderVariant_pick)
|
||||
#ifdef requiredDrawBuffers
|
||||
@@ -86,5 +88,6 @@ export const assign_color_varying = `
|
||||
vec3 tgridPos = (uTransparencyGridTransform.w * (vModelPosition - uTransparencyGridTransform.xyz)) / uTransparencyGridDim;
|
||||
vTransparency = texture3dFrom2dLinear(tTransparencyGrid, tgridPos, uTransparencyGridDim, uTransparencyTexDim).a;
|
||||
#endif
|
||||
vTransparency *= uTransparencyStrength;
|
||||
#endif
|
||||
`;
|
||||
@@ -1,12 +1,7 @@
|
||||
export const clip_instance = `
|
||||
#if defined(dClipVariant_instance) && dClipObjectCount != 0
|
||||
int flag = 0;
|
||||
#if defined(dClipping)
|
||||
flag = int(floor(vClipping * 255.0 + 0.5));
|
||||
#endif
|
||||
|
||||
vec4 mCenter = uModel * aTransform * vec4(uInvariantBoundingSphere.xyz, 1.0);
|
||||
if (clipTest(vec4(mCenter.xyz, uInvariantBoundingSphere.w), flag))
|
||||
if (clipTest(vec4(mCenter.xyz, uInvariantBoundingSphere.w)))
|
||||
// move out of [ -w, +w ] to 'discard' in vert shader
|
||||
gl_Position.z = 2.0 * gl_Position.w;
|
||||
#endif
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
export const clip_pixel = `
|
||||
#if defined(dClipVariant_pixel) && dClipObjectCount != 0
|
||||
#if defined(dClipping)
|
||||
int clippingFlag = int(floor(vClipping * 255.0 + 0.5));
|
||||
#else
|
||||
int clippingFlag = 0;
|
||||
#endif
|
||||
|
||||
if (clipTest(vec4(vModelPosition, 0.0), clippingFlag))
|
||||
if (clipTest(vec4(vModelPosition, 0.0)))
|
||||
discard;
|
||||
#endif
|
||||
`;
|
||||
@@ -39,6 +39,7 @@ uniform float uBumpiness;
|
||||
uniform vec4 uOverpaintGridTransform;
|
||||
uniform sampler2D tOverpaintGrid;
|
||||
#endif
|
||||
uniform float uOverpaintStrength;
|
||||
#endif
|
||||
|
||||
#ifdef dSubstance
|
||||
@@ -53,6 +54,7 @@ uniform float uBumpiness;
|
||||
uniform vec4 uSubstanceGridTransform;
|
||||
uniform sampler2D tSubstanceGrid;
|
||||
#endif
|
||||
uniform float uSubstanceStrength;
|
||||
#endif
|
||||
#elif defined(dRenderVariant_pick)
|
||||
#if __VERSION__ == 100 || !defined(dVaryingGroup)
|
||||
@@ -86,5 +88,6 @@ uniform float uBumpiness;
|
||||
uniform vec4 uTransparencyGridTransform;
|
||||
uniform sampler2D tTransparencyGrid;
|
||||
#endif
|
||||
uniform float uTransparencyStrength;
|
||||
#endif
|
||||
`;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Ludovic Autin <autin@scripps.edu>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
@@ -7,45 +7,45 @@
|
||||
|
||||
export const common_clip = `
|
||||
#if dClipObjectCount != 0
|
||||
vec3 quaternionTransform(vec4 q, vec3 v) {
|
||||
vec3 quaternionTransform(const in vec4 q, const in vec3 v) {
|
||||
vec3 t = 2.0 * cross(q.xyz, v);
|
||||
return v + q.w * t + cross(q.xyz, t);
|
||||
}
|
||||
|
||||
vec4 computePlane(vec3 normal, vec3 inPoint) {
|
||||
vec4 computePlane(const in vec3 normal, const in vec3 inPoint) {
|
||||
return vec4(normalize(normal), -dot(normal, inPoint));
|
||||
}
|
||||
|
||||
float planeSD(vec4 plane, vec3 center) {
|
||||
float planeSD(const in vec4 plane, const in vec3 center) {
|
||||
return -dot(plane.xyz, center - plane.xyz * -plane.w);
|
||||
}
|
||||
|
||||
float sphereSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
|
||||
float sphereSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) {
|
||||
return (
|
||||
length(quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position) / size) - 1.0
|
||||
) * min(min(size.x, size.y), size.z);
|
||||
}
|
||||
|
||||
float cubeSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
|
||||
float cubeSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) {
|
||||
vec3 d = abs(quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position)) - size;
|
||||
return min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d, 0.0));
|
||||
}
|
||||
|
||||
float cylinderSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
|
||||
float cylinderSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) {
|
||||
vec3 t = quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position);
|
||||
|
||||
vec2 d = abs(vec2(length(t.xz), t.y)) - size.xy;
|
||||
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
|
||||
}
|
||||
|
||||
float infiniteConeSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
|
||||
float infiniteConeSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) {
|
||||
vec3 t = quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position);
|
||||
|
||||
float q = length(t.xy);
|
||||
return dot(size.xy, vec2(q, t.z));
|
||||
}
|
||||
|
||||
float getSignedDistance(vec3 center, int type, vec3 position, vec4 rotation, vec3 scale) {
|
||||
float getSignedDistance(const in vec3 center, const in int type, const in vec3 position, const in vec4 rotation, const in vec3 scale) {
|
||||
if (type == 1) {
|
||||
vec3 normal = quaternionTransform(rotation, vec3(0.0, 1.0, 0.0));
|
||||
vec4 plane = computePlane(normal, position);
|
||||
@@ -65,7 +65,7 @@ export const common_clip = `
|
||||
|
||||
#if __VERSION__ == 100
|
||||
// 8-bit
|
||||
int bitwiseAnd(int a, int b) {
|
||||
int bitwiseAnd(const in int a, const in int b) {
|
||||
int d = 128;
|
||||
int result = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
@@ -78,17 +78,23 @@ export const common_clip = `
|
||||
return result;
|
||||
}
|
||||
|
||||
bool hasBit(int mask, int bit) {
|
||||
bool hasBit(const in int mask, const in int bit) {
|
||||
return bitwiseAnd(mask, bit) == 0;
|
||||
}
|
||||
#else
|
||||
bool hasBit(int mask, int bit) {
|
||||
bool hasBit(const in int mask, const in int bit) {
|
||||
return (mask & bit) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// flag is a bit-flag for clip-objects to ignore (note, object ids start at 1 not 0)
|
||||
bool clipTest(vec4 sphere, int flag) {
|
||||
bool clipTest(const in vec4 sphere) {
|
||||
// flag is a bit-flag for clip-objects to ignore (note, object ids start at 1 not 0)
|
||||
#if defined(dClipping)
|
||||
int flag = int(floor(vClipping * 255.0 + 0.5));
|
||||
#else
|
||||
int flag = 0;
|
||||
#endif
|
||||
|
||||
#pragma unroll_loop_start
|
||||
for (int i = 0; i < dClipObjectCount; ++i) {
|
||||
if (flag == 0 || hasBit(flag, UNROLLED_LOOP_INDEX + 1)) {
|
||||
|
||||
@@ -33,7 +33,8 @@ uniform mat4 uInvView;
|
||||
bool CylinderImpostor(
|
||||
in vec3 rayOrigin, in vec3 rayDir,
|
||||
in vec3 start, in vec3 end, in float radius,
|
||||
out vec4 intersection, out bool interior
|
||||
out vec3 cameraNormal, out bool interior,
|
||||
out vec3 modelPosition, out vec3 viewPosition, out float fragmentDepth
|
||||
){
|
||||
vec3 ba = end - start;
|
||||
vec3 oc = rayOrigin - start;
|
||||
@@ -42,7 +43,7 @@ bool CylinderImpostor(
|
||||
float bard = dot(ba, rayDir);
|
||||
float baoc = dot(ba, oc);
|
||||
|
||||
float k2 = baba - bard*bard;
|
||||
float k2 = baba - bard * bard;
|
||||
float k1 = baba * dot(oc, rayDir) - baoc * bard;
|
||||
float k0 = baba * dot(oc, oc) - baoc * baoc - radius * radius * baba;
|
||||
|
||||
@@ -58,8 +59,14 @@ bool CylinderImpostor(
|
||||
float y = baoc + t * bard;
|
||||
if (y > 0.0 && y < baba) {
|
||||
interior = false;
|
||||
intersection = vec4(t, (oc + t * rayDir - ba * y / baba) / radius);
|
||||
return true;
|
||||
cameraNormal = (oc + t * rayDir - ba * y / baba) / radius;
|
||||
modelPosition = rayOrigin + t * rayDir;
|
||||
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
|
||||
fragmentDepth = calcDepth(viewPosition);
|
||||
#if defined(dClipVariant_pixel) && dClipObjectCount != 0
|
||||
if (clipTest(vec4(modelPosition, 0.0))) fragmentDepth = -1.0;
|
||||
#endif
|
||||
if (fragmentDepth > 0.0) return true;
|
||||
}
|
||||
|
||||
if (topCap && y < 0.0) {
|
||||
@@ -67,16 +74,22 @@ bool CylinderImpostor(
|
||||
t = -baoc / bard;
|
||||
if (abs(k1 + k2 * t) < h) {
|
||||
interior = false;
|
||||
intersection = vec4(t, ba * sign(y) / baba);
|
||||
return true;
|
||||
cameraNormal = -ba / baba;
|
||||
modelPosition = rayOrigin + t * rayDir;
|
||||
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
|
||||
fragmentDepth = calcDepth(viewPosition);
|
||||
if (fragmentDepth > 0.0) return true;
|
||||
}
|
||||
} else if(bottomCap && y >= 0.0) {
|
||||
// bottom cap
|
||||
t = (baba - baoc) / bard;
|
||||
if (abs(k1 + k2 * t) < h) {
|
||||
interior = false;
|
||||
intersection = vec4(t, ba * sign(y) / baba);
|
||||
return true;
|
||||
cameraNormal = ba / baba;
|
||||
modelPosition = rayOrigin + t * rayDir;
|
||||
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
|
||||
fragmentDepth = calcDepth(viewPosition);
|
||||
if (fragmentDepth > 0.0) return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,36 +100,61 @@ bool CylinderImpostor(
|
||||
y = baoc + t * bard;
|
||||
if (y > 0.0 && y < baba) {
|
||||
interior = true;
|
||||
intersection = vec4(t, (oc + t * rayDir - ba * y / baba) / radius);
|
||||
cameraNormal = -(oc + t * rayDir - ba * y / baba) / radius;
|
||||
modelPosition = rayOrigin + t * rayDir;
|
||||
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
|
||||
fragmentDepth = calcDepth(viewPosition);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: handle inside caps???
|
||||
if (topCap && y < 0.0) {
|
||||
// top cap
|
||||
t = -baoc / bard;
|
||||
if (abs(k1 + k2 * t) < -h) {
|
||||
interior = true;
|
||||
cameraNormal = ba / baba;
|
||||
modelPosition = rayOrigin + t * rayDir;
|
||||
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
|
||||
fragmentDepth = calcDepth(viewPosition);
|
||||
if (fragmentDepth > 0.0) return true;
|
||||
}
|
||||
} else if(bottomCap && y >= 0.0) {
|
||||
// bottom cap
|
||||
t = (baba - baoc) / bard;
|
||||
if (abs(k1 + k2 * t) < -h) {
|
||||
interior = true;
|
||||
cameraNormal = -ba / baba;
|
||||
modelPosition = rayOrigin + t * rayDir;
|
||||
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
|
||||
fragmentDepth = calcDepth(viewPosition);
|
||||
if (fragmentDepth > 0.0) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void main() {
|
||||
#include clip_pixel
|
||||
|
||||
vec3 rayOrigin = vModelPosition;
|
||||
vec3 rayDir = mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho);
|
||||
|
||||
vec4 intersection;
|
||||
bool interior;
|
||||
bool hit = CylinderImpostor(vModelPosition, rayDir, vStart, vEnd, vSize, intersection, interior);
|
||||
vec3 cameraNormal;
|
||||
vec3 modelPosition;
|
||||
vec3 viewPosition;
|
||||
float fragmentDepth;
|
||||
bool hit = CylinderImpostor(rayOrigin, rayDir, vStart, vEnd, vSize, cameraNormal, interior, modelPosition, viewPosition, fragmentDepth);
|
||||
if (!hit) discard;
|
||||
|
||||
vec3 vViewPosition = vModelPosition + intersection.x * rayDir;
|
||||
vViewPosition = (uView * vec4(vViewPosition, 1.0)).xyz;
|
||||
float fragmentDepth = calcDepth(vViewPosition);
|
||||
|
||||
if (fragmentDepth < 0.0) discard;
|
||||
if (fragmentDepth > 1.0) discard;
|
||||
|
||||
gl_FragDepthEXT = fragmentDepth;
|
||||
|
||||
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
|
||||
vec3 vViewPosition = viewPosition;
|
||||
vec3 vModelPosition = modelPosition;
|
||||
|
||||
#include clip_pixel
|
||||
#include assign_material_color
|
||||
|
||||
#if defined(dRenderVariant_pick)
|
||||
@@ -135,7 +173,7 @@ void main() {
|
||||
gl_FragColor = material;
|
||||
#elif defined(dRenderVariant_color)
|
||||
mat3 normalMatrix = transpose3(inverse3(mat3(uView)));
|
||||
vec3 normal = normalize(normalMatrix * -normalize(intersection.yzw));
|
||||
vec3 normal = normalize(normalMatrix * -normalize(cameraNormal));
|
||||
#include apply_light_color
|
||||
|
||||
#include apply_interior_color
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -55,7 +55,12 @@ void main() {
|
||||
vec3 camDir = -mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho);
|
||||
vec3 dir = vEnd - vStart;
|
||||
// ensure cylinder 'dir' is pointing towards the camera
|
||||
if(dot(camDir, dir) < 0.0) dir = -dir;
|
||||
if(dot(camDir, dir) < 0.0) {
|
||||
dir = -dir;
|
||||
vec3 tmp = vStart;
|
||||
vStart = vEnd;
|
||||
vEnd = tmp;
|
||||
}
|
||||
|
||||
vec3 left = cross(camDir, dir);
|
||||
vec3 up = cross(left, dir);
|
||||
@@ -69,6 +74,9 @@ void main() {
|
||||
vViewPosition = mvPosition.xyz;
|
||||
gl_Position = uProjection * mvPosition;
|
||||
|
||||
mvPosition.z -= 2.0 * (length(vEnd - vStart) + vSize); // avoid clipping
|
||||
gl_Position.z = (uProjection * mvPosition).z;
|
||||
|
||||
#include clip_instance
|
||||
}
|
||||
`;
|
||||
@@ -229,7 +229,7 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) {
|
||||
|
||||
#if defined(dClipVariant_pixel) && dClipObjectCount != 0
|
||||
vec3 vModelPosition = v3m4(unitPos * uGridDim, modelTransform);
|
||||
if (clipTest(vec4(vModelPosition, 0.0), 0)) {
|
||||
if (clipTest(vec4(vModelPosition, 0.0))) {
|
||||
prevValue = value;
|
||||
pos += step;
|
||||
continue;
|
||||
@@ -270,16 +270,16 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) {
|
||||
#elif defined(dColorType_groupInstance)
|
||||
material.rgb = readFromTexture(tColor, vInstance * float(uGroupCount) + group, uColorTexDim).rgb;
|
||||
#elif defined(dColorType_vertex)
|
||||
material.rgb = texture3dFrom1dTrilinear(tColor, isoPos, uGridDim, uColorTexDim, 0.0).rgb;
|
||||
material.rgb = texture3dFrom1dTrilinear(tColor, unitPos, uGridDim, uColorTexDim, 0.0).rgb;
|
||||
#elif defined(dColorType_vertexInstance)
|
||||
material.rgb = texture3dFrom1dTrilinear(tColor, isoPos, uGridDim, uColorTexDim, vInstance * float(uVertexCount)).rgb;
|
||||
material.rgb = texture3dFrom1dTrilinear(tColor, unitPos, uGridDim, uColorTexDim, vInstance * float(uVertexCount)).rgb;
|
||||
#endif
|
||||
|
||||
#ifdef dOverpaint
|
||||
#if defined(dOverpaintType_groupInstance)
|
||||
overpaint = readFromTexture(tOverpaint, vInstance * float(uGroupCount) + group, uOverpaintTexDim);
|
||||
#elif defined(dOverpaintType_vertexInstance)
|
||||
overpaint = texture3dFrom1dTrilinear(tOverpaint, isoPos, uGridDim, uOverpaintTexDim, vInstance * float(uVertexCount));
|
||||
overpaint = texture3dFrom1dTrilinear(tOverpaint, unitPos, uGridDim, uOverpaintTexDim, vInstance * float(uVertexCount));
|
||||
#endif
|
||||
|
||||
material.rgb = mix(material.rgb, overpaint.rgb, overpaint.a);
|
||||
|
||||
@@ -38,7 +38,11 @@ float getDepthOpaque(const in vec2 coords) {
|
||||
}
|
||||
|
||||
float getDepthTransparent(const in vec2 coords) {
|
||||
return unpackRGBAToDepth(texture2D(tDepthTransparent, coords));
|
||||
#ifdef dTransparentOutline
|
||||
return unpackRGBAToDepth(texture2D(tDepthTransparent, coords));
|
||||
#else
|
||||
return 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isBackground(const in float depth) {
|
||||
|
||||
@@ -14,6 +14,7 @@ uniform sampler2D tSsaoDepth;
|
||||
uniform sampler2D tColor;
|
||||
uniform sampler2D tDepthOpaque;
|
||||
uniform sampler2D tDepthTransparent;
|
||||
uniform sampler2D tShadows;
|
||||
uniform sampler2D tOutlines;
|
||||
uniform vec2 uTexSize;
|
||||
|
||||
@@ -50,7 +51,11 @@ float getDepthOpaque(const in vec2 coords) {
|
||||
}
|
||||
|
||||
float getDepthTransparent(const in vec2 coords) {
|
||||
return unpackRGBAToDepth(texture2D(tDepthTransparent, coords));
|
||||
#ifdef dTransparentOutline
|
||||
return unpackRGBAToDepth(texture2D(tDepthTransparent, coords));
|
||||
#else
|
||||
return 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isBackground(const in float depth) {
|
||||
@@ -120,7 +125,20 @@ void main(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// outline needs to be handled after occlusion to keep them clean
|
||||
#ifdef dShadowEnable
|
||||
if (!isBackground(opaqueDepth)) {
|
||||
viewDist = abs(getViewZ(opaqueDepth));
|
||||
fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
|
||||
vec4 shadow = texture2D(tShadows, coords);
|
||||
if (!uTransparentBackground) {
|
||||
color.rgb = mix(mix(vec3(0), uFogColor, fogFactor), color.rgb, shadow.a);
|
||||
} else {
|
||||
color.rgb = mix(vec3(0) * (1.0 - fogFactor), color.rgb, shadow.a);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// outline needs to be handled after occlusion and shadow to keep them clean
|
||||
#ifdef dOutlineEnable
|
||||
float closestTexel;
|
||||
float outline = getOutline(coords, opaqueDepth, closestTexel);
|
||||
|
||||
131
src/mol-gl/shader/shadows.frag.ts
Normal file
131
src/mol-gl/shader/shadows.frag.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Ludovic Autin <ludovic.autin@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
export const shadows_frag = `
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
precision highp sampler2D;
|
||||
|
||||
#include common
|
||||
|
||||
uniform sampler2D tDepth;
|
||||
uniform vec2 uTexSize;
|
||||
uniform vec4 uBounds;
|
||||
|
||||
uniform float uNear;
|
||||
uniform float uFar;
|
||||
|
||||
#if dLightCount != 0
|
||||
uniform vec3 uLightDirection[dLightCount];
|
||||
uniform vec3 uLightColor[dLightCount];
|
||||
#endif
|
||||
|
||||
uniform mat4 uProjection;
|
||||
uniform mat4 uInvProjection;
|
||||
|
||||
uniform float uMaxDistance;
|
||||
uniform float uTolerance;
|
||||
uniform float uBias;
|
||||
|
||||
bool isBackground(const in float depth) {
|
||||
return depth == 1.0;
|
||||
}
|
||||
|
||||
bool outsideBounds(const in vec2 p) {
|
||||
return p.x < uBounds.x || p.y < uBounds.y || p.x > uBounds.z || p.y > uBounds.w;
|
||||
}
|
||||
|
||||
float getViewZ(const in float depth) {
|
||||
#if dOrthographic == 1
|
||||
return orthographicDepthToViewZ(depth, uNear, uFar);
|
||||
#else
|
||||
return perspectiveDepthToViewZ(depth, uNear, uFar);
|
||||
#endif
|
||||
}
|
||||
|
||||
float getDepth(const in vec2 coords) {
|
||||
#ifdef depthTextureSupport
|
||||
return texture2D(tDepth, coords).r;
|
||||
#else
|
||||
return unpackRGBAToDepth(texture2D(tDepth, coords));
|
||||
#endif
|
||||
}
|
||||
|
||||
float screenFade(const in vec2 coords) {
|
||||
vec2 c = (coords - uBounds.xy) / (uBounds.zw - uBounds.xy);
|
||||
vec2 fade = max(12.0 * abs(c - 0.5) - 5.0, vec2(0.0));
|
||||
return saturate(1.0 - dot(fade, fade));
|
||||
}
|
||||
|
||||
// based on https://panoskarabelas.com/posts/screen_space_shadows/
|
||||
float screenSpaceShadow(const in vec3 position, const in vec3 lightDirection, const in float stepLength) {
|
||||
// Ray position and direction (in view-space)
|
||||
vec3 rayPos = position;
|
||||
vec3 rayDir = -lightDirection;
|
||||
|
||||
// Compute ray step
|
||||
vec3 rayStep = rayDir * stepLength;
|
||||
|
||||
// Ray march towards the light
|
||||
float occlusion = 0.0;
|
||||
vec4 rayCoords = vec4(0.0);
|
||||
for (int i = 0; i < dSteps; ++i) {
|
||||
// Step the ray
|
||||
rayPos += rayStep;
|
||||
|
||||
rayCoords = uProjection * vec4(rayPos, 1.0);
|
||||
rayCoords.xyz = (rayCoords.xyz / rayCoords.w) * 0.5 + 0.5;
|
||||
|
||||
if (outsideBounds(rayCoords.xy))
|
||||
return 1.0;
|
||||
|
||||
// Compute the difference between the ray's and the camera's depth
|
||||
float depth = getDepth(rayCoords.xy);
|
||||
float viewZ = getViewZ(depth);
|
||||
float zDelta = rayPos.z - viewZ;
|
||||
|
||||
if (zDelta < uTolerance) {
|
||||
occlusion = 1.0;
|
||||
|
||||
// Fade out as we approach the edges of the screen
|
||||
occlusion *= screenFade(rayCoords.xy);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1.0 - (uBias * occlusion);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 invTexSize = 1.0 / uTexSize;
|
||||
vec2 selfCoords = gl_FragCoord.xy * invTexSize;
|
||||
|
||||
float selfDepth = getDepth(selfCoords);
|
||||
|
||||
if (isBackground(selfDepth)) {
|
||||
gl_FragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 selfViewPos = screenSpaceToViewSpace(vec3(selfCoords, selfDepth), uInvProjection);
|
||||
float stepLength = uMaxDistance / float(dSteps);
|
||||
|
||||
float o = 1.0;
|
||||
#if dLightCount != 0
|
||||
float sh[dLightCount];
|
||||
#pragma unroll_loop_start
|
||||
for (int i = 0; i < dLightCount; ++i) {
|
||||
sh[i] = screenSpaceShadow(selfViewPos, uLightDirection[i], stepLength);
|
||||
o = min(o, sh[i]);
|
||||
}
|
||||
#pragma unroll_loop_end
|
||||
#endif
|
||||
|
||||
gl_FragColor = vec4(o);
|
||||
}
|
||||
`;
|
||||
@@ -23,12 +23,8 @@ varying float vRadiusSq;
|
||||
varying vec3 vPoint;
|
||||
varying vec3 vPointViewPosition;
|
||||
|
||||
vec3 cameraPos;
|
||||
vec3 cameraNormal;
|
||||
|
||||
bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
|
||||
bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth, out bool clipped){
|
||||
vec3 cameraSpherePos = -vPointViewPosition;
|
||||
cameraSpherePos.z += vRadius;
|
||||
|
||||
vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho);
|
||||
vec3 rayDirection = mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), uIsOrtho);
|
||||
@@ -37,50 +33,61 @@ bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
|
||||
float B = dot(rayDirection, cameraSphereDir);
|
||||
float det = B * B + vRadiusSq - dot(cameraSphereDir, cameraSphereDir);
|
||||
|
||||
if (det < 0.0){
|
||||
discard;
|
||||
return false;
|
||||
}
|
||||
if (det < 0.0) return false;
|
||||
|
||||
float sqrtDet = sqrt(det);
|
||||
float posT = mix(B + sqrtDet, B + sqrtDet, uIsOrtho);
|
||||
float negT = mix(B - sqrtDet, sqrtDet - B, uIsOrtho);
|
||||
float posT = mix(B + sqrtDet, B - sqrtDet, uIsOrtho);
|
||||
float negT = mix(B - sqrtDet, B + sqrtDet, uIsOrtho);
|
||||
|
||||
cameraPos = rayDirection * negT + rayOrigin;
|
||||
modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz;
|
||||
fragmentDepth = calcDepth(cameraPos);
|
||||
|
||||
if (calcDepth(cameraPos) <= 0.0) {
|
||||
cameraPos = rayDirection * posT + rayOrigin;
|
||||
interior = true;
|
||||
} else {
|
||||
#if defined(dClipVariant_pixel) && dClipObjectCount != 0
|
||||
if (clipTest(vec4(modelPos, 0.0))) {
|
||||
clipped = true;
|
||||
fragmentDepth = -1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fragmentDepth > 0.0) {
|
||||
cameraNormal = normalize(cameraPos - cameraSpherePos);
|
||||
interior = false;
|
||||
return true;
|
||||
} else if (uDoubleSided) {
|
||||
cameraPos = rayDirection * posT + rayOrigin;
|
||||
modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz;
|
||||
fragmentDepth = calcDepth(cameraPos);
|
||||
cameraNormal = -normalize(cameraPos - cameraSpherePos);
|
||||
interior = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
cameraNormal = normalize(cameraPos - cameraSpherePos);
|
||||
cameraNormal *= float(!interior) * 2.0 - 1.0;
|
||||
|
||||
return !interior;
|
||||
return false;
|
||||
}
|
||||
|
||||
void main(void){
|
||||
#include clip_pixel
|
||||
|
||||
bool flag = Impostor(cameraPos, cameraNormal);
|
||||
if (!uDoubleSided) {
|
||||
if (interior) discard;
|
||||
}
|
||||
|
||||
vec3 vViewPosition = cameraPos;
|
||||
float fragmentDepth = calcDepth(vViewPosition);
|
||||
if (!flag && fragmentDepth >= 0.0) {
|
||||
fragmentDepth = 0.0 + (0.0000001 / vRadius);
|
||||
}
|
||||
vec3 modelPos;
|
||||
vec3 cameraPos;
|
||||
vec3 cameraNormal;
|
||||
float fragmentDepth;
|
||||
bool clipped = false;
|
||||
bool hit = SphereImpostor(modelPos, cameraPos, cameraNormal, interior, fragmentDepth, clipped);
|
||||
if (!hit) discard;
|
||||
|
||||
if (fragmentDepth < 0.0) discard;
|
||||
if (fragmentDepth > 1.0) discard;
|
||||
|
||||
vec3 vViewPosition = cameraPos;
|
||||
vec3 vModelPosition = modelPos;
|
||||
|
||||
if (interior && !clipped) {
|
||||
fragmentDepth = 0.0 + (0.0000001 / vRadius);
|
||||
}
|
||||
|
||||
gl_FragDepthEXT = fragmentDepth;
|
||||
|
||||
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
|
||||
#include clip_pixel
|
||||
#include assign_material_color
|
||||
|
||||
#if defined(dRenderVariant_pick)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -85,7 +85,6 @@ void main(void){
|
||||
|
||||
vec4 position4 = vec4(aPosition, 1.0);
|
||||
vec4 mvPosition = uModelView * aTransform * position4;
|
||||
mvPosition.z -= vRadius; // avoid clipping, added again in fragment shader
|
||||
|
||||
gl_Position = uProjection * vec4(mvPosition.xyz, 1.0);
|
||||
quadraticProjection(size, aPosition);
|
||||
@@ -97,6 +96,9 @@ void main(void){
|
||||
|
||||
vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader
|
||||
|
||||
mvPosition.z -= 2.0 * vRadius; // avoid clipping
|
||||
gl_Position.z = (uProjection * vec4(mvPosition.xyz, 1.0)).z;
|
||||
|
||||
#include clip_instance
|
||||
}
|
||||
`;
|
||||
@@ -19,6 +19,9 @@ export function isWebGL2(gl: any): gl is WebGL2RenderingContext {
|
||||
return typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/ANGLE_instanced_arrays/
|
||||
*/
|
||||
export interface COMPAT_instanced_arrays {
|
||||
drawArraysInstanced(mode: number, first: number, count: number, primcount: number): void;
|
||||
drawElementsInstanced(mode: number, count: number, type: number, offset: number, primcount: number): void;
|
||||
@@ -46,6 +49,9 @@ export function getInstancedArrays(gl: GLRenderingContext): COMPAT_instanced_arr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/OES_standard_derivatives/
|
||||
*/
|
||||
export interface COMPAT_standard_derivatives {
|
||||
readonly FRAGMENT_SHADER_DERIVATIVE_HINT: number;
|
||||
}
|
||||
@@ -60,6 +66,9 @@ export function getStandardDerivatives(gl: GLRenderingContext): COMPAT_standard_
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/OES_element_index_uint/
|
||||
*/
|
||||
export interface COMPAT_element_index_uint {
|
||||
}
|
||||
|
||||
@@ -67,6 +76,9 @@ export function getElementIndexUint(gl: GLRenderingContext): COMPAT_element_inde
|
||||
return isWebGL2(gl) ? {} : gl.getExtension('OES_element_index_uint');
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/OES_vertex_array_object/
|
||||
*/
|
||||
export interface COMPAT_vertex_array_object {
|
||||
readonly VERTEX_ARRAY_BINDING: number;
|
||||
bindVertexArray(arrayObject: WebGLVertexArrayObject | null): void;
|
||||
@@ -132,6 +144,9 @@ export function getTextureHalfFloatLinear(gl: GLRenderingContext): COMPAT_textur
|
||||
return gl.getExtension('OES_texture_half_float_linear');
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/EXT_blend_minmax/
|
||||
*/
|
||||
export interface COMPAT_blend_minmax {
|
||||
readonly MIN: number
|
||||
readonly MAX: number
|
||||
@@ -147,6 +162,9 @@ export function getBlendMinMax(gl: GLRenderingContext): COMPAT_blend_minmax | nu
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/EXT_frag_depth/
|
||||
*/
|
||||
export interface COMPAT_frag_depth {
|
||||
}
|
||||
|
||||
@@ -196,6 +214,9 @@ export function getColorBufferHalfFloat(gl: GLRenderingContext): COMPAT_color_bu
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/WEBGL_draw_buffers/
|
||||
*/
|
||||
export interface COMPAT_draw_buffers {
|
||||
drawBuffers(buffers: number[]): void;
|
||||
readonly COLOR_ATTACHMENT0: number;
|
||||
@@ -268,6 +289,73 @@ export function getDrawBuffers(gl: GLRenderingContext): COMPAT_draw_buffers | nu
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/OES_draw_buffers_indexed/
|
||||
*/
|
||||
export interface COMPAT_draw_buffers_indexed {
|
||||
/**
|
||||
* Enables blending for an individual draw buffer.
|
||||
*
|
||||
* @param target must be BLEND.
|
||||
* @param index is an integer i specifying the draw buffer associated with the symbolic constant DRAW_BUFFERi.
|
||||
*/
|
||||
enablei: (target: number, index: number) => void;
|
||||
/**
|
||||
* Disables blending for an individual draw buffer.
|
||||
*
|
||||
* @param target must be BLEND.
|
||||
* @param index is an integer i specifying the draw buffer associated with the symbolic constant DRAW_BUFFERi.
|
||||
*/
|
||||
disablei: (buf: number, mode: number) => void;
|
||||
/**
|
||||
* The buf argument is an integer i that indicates that the blend equations should be modified for DRAW_BUFFERi.
|
||||
*
|
||||
* mode accepts the same tokens as mode in blendEquation.
|
||||
*/
|
||||
blendEquationi: (target: number, index: number) => void;
|
||||
/**
|
||||
* The buf argument is an integer i that indicates that the blend equations should be modified for DRAW_BUFFERi.
|
||||
*
|
||||
* modeRGB and modeAlpha accept the same tokens as modeRGB and modeAlpha in blendEquationSeparate.
|
||||
*/
|
||||
blendEquationSeparatei: (buf: number, modeRGB: number, modeAlpha: number) => void;
|
||||
/**
|
||||
* The buf argument is an integer i that indicates that the blend functions should be modified for DRAW_BUFFERi.
|
||||
*
|
||||
* src and dst accept the same tokens as src and dst in blendFunc.
|
||||
*/
|
||||
blendFunci: (buf: number, src: number, dst: number) => void;
|
||||
/**
|
||||
* The buf argument is an integer i that indicates that the blend functions should be modified for DRAW_BUFFERi.
|
||||
*
|
||||
* srcRGB, dstRGB, srcAlpha, and dstAlpha accept the same tokens as srcRGB, dstRGB, srcAlpha, and dstAlpha parameters in blendEquationSeparate.
|
||||
*/
|
||||
blendFuncSeparatei: (buf: number, srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => void;
|
||||
/**
|
||||
* The buf argument is an integer i that indicates that the write mask should be modified for DRAW_BUFFERi.
|
||||
*
|
||||
* r, g, b, and a indicate whether R, G, B, or A values, respectively, are written or not (a value of TRUE means that the corresponding value is written).
|
||||
*/
|
||||
colorMaski: (buf: number, r: boolean, g: boolean, b: boolean, a: boolean) => void;
|
||||
}
|
||||
|
||||
export function getDrawBuffersIndexed(gl: GLRenderingContext): COMPAT_draw_buffers_indexed | null {
|
||||
const ext = gl.getExtension('OES_draw_buffers_indexed');
|
||||
if (ext === null) return null;
|
||||
return {
|
||||
enablei: ext.enableiOES.bind(ext),
|
||||
disablei: ext.disableiOES.bind(ext),
|
||||
blendEquationi: ext.blendEquationiOES.bind(ext),
|
||||
blendEquationSeparatei: ext.blendEquationSeparateiOES.bind(ext),
|
||||
blendFunci: ext.blendFunciOES.bind(ext),
|
||||
blendFuncSeparatei: ext.blendFuncSeparateiOES.bind(ext),
|
||||
colorMaski: ext.colorMaskiOES.bind(ext),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/EXT_shader_texture_lod/
|
||||
*/
|
||||
export interface COMPAT_shader_texture_lod {
|
||||
}
|
||||
|
||||
@@ -275,6 +363,9 @@ export function getShaderTextureLod(gl: GLRenderingContext): COMPAT_shader_textu
|
||||
return isWebGL2(gl) ? {} : gl.getExtension('EXT_shader_texture_lod');
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/WEBGL_depth_texture/
|
||||
*/
|
||||
export interface COMPAT_depth_texture {
|
||||
readonly UNSIGNED_INT_24_8: number;
|
||||
}
|
||||
@@ -293,6 +384,9 @@ export function getDepthTexture(gl: GLRenderingContext): COMPAT_depth_texture |
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/EXT_sRGB/
|
||||
*/
|
||||
export interface COMPAT_sRGB {
|
||||
readonly FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: number;
|
||||
readonly SRGB8_ALPHA8: number;
|
||||
@@ -320,6 +414,9 @@ export function getSRGB(gl: GLRenderingContext): COMPAT_sRGB | null {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/EXT_disjoint_timer_query/ and https://registry.khronos.org/webgl/extensions/EXT_disjoint_timer_query_webgl2/
|
||||
*/
|
||||
export interface COMPAT_disjoint_timer_query {
|
||||
/** A GLint indicating the number of bits used to hold the query result for the given target. */
|
||||
QUERY_COUNTER_BITS: number
|
||||
@@ -401,6 +498,31 @@ export function getDisjointTimerQuery(gl: GLRenderingContext): COMPAT_disjoint_t
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/KHR_parallel_shader_compile/
|
||||
*/
|
||||
export interface COMPAT_parallel_shader_compile {
|
||||
readonly COMPLETION_STATUS: number;
|
||||
}
|
||||
|
||||
export function getParallelShaderCompile(gl: GLRenderingContext): COMPAT_parallel_shader_compile | null {
|
||||
const ext = gl.getExtension('KHR_parallel_shader_compile');
|
||||
if (ext === null) return null;
|
||||
return {
|
||||
COMPLETION_STATUS: ext.COMPLETION_STATUS_KHR,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/OES_fbo_render_mipmap/
|
||||
*/
|
||||
export interface COMPAT_fboRenderMipmap {
|
||||
}
|
||||
|
||||
export function getFboRenderMipmap(gl: GLRenderingContext): COMPAT_fboRenderMipmap | null {
|
||||
return isWebGL2(gl) ? {} : gl.getExtension('OES_fbo_render_mipmap');
|
||||
}
|
||||
|
||||
export function getNoNonInstancedActiveAttribs(gl: GLRenderingContext): boolean {
|
||||
if (!isWebGL2(gl)) return false;
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture, COMPAT_sRGB, getSRGB, getTextureHalfFloat, getTextureHalfFloatLinear, COMPAT_texture_half_float, COMPAT_texture_half_float_linear, COMPAT_color_buffer_half_float, getColorBufferHalfFloat, getVertexArrayObject, getDisjointTimerQuery, COMPAT_disjoint_timer_query, getNoNonInstancedActiveAttribs } from './compat';
|
||||
import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture, COMPAT_sRGB, getSRGB, getTextureHalfFloat, getTextureHalfFloatLinear, COMPAT_texture_half_float, COMPAT_texture_half_float_linear, COMPAT_color_buffer_half_float, getColorBufferHalfFloat, getVertexArrayObject, getDisjointTimerQuery, COMPAT_disjoint_timer_query, getNoNonInstancedActiveAttribs, getDrawBuffersIndexed, COMPAT_draw_buffers_indexed, getParallelShaderCompile, COMPAT_parallel_shader_compile, getFboRenderMipmap, COMPAT_fboRenderMipmap } from './compat';
|
||||
import { isDebugMode } from '../../mol-util/debug';
|
||||
|
||||
export type WebGLExtensions = {
|
||||
instancedArrays: COMPAT_instanced_arrays
|
||||
elementIndexUint: COMPAT_element_index_uint
|
||||
standardDerivatives: COMPAT_standard_derivatives
|
||||
|
||||
standardDerivatives: COMPAT_standard_derivatives | null
|
||||
textureFloat: COMPAT_texture_float | null
|
||||
textureFloatLinear: COMPAT_texture_float_linear | null
|
||||
textureHalfFloat: COMPAT_texture_half_float | null
|
||||
@@ -23,9 +23,12 @@ export type WebGLExtensions = {
|
||||
colorBufferFloat: COMPAT_color_buffer_float | null
|
||||
colorBufferHalfFloat: COMPAT_color_buffer_half_float | null
|
||||
drawBuffers: COMPAT_draw_buffers | null
|
||||
drawBuffersIndexed: COMPAT_draw_buffers_indexed | null
|
||||
shaderTextureLod: COMPAT_shader_texture_lod | null
|
||||
sRGB: COMPAT_sRGB | null
|
||||
disjointTimerQuery: COMPAT_disjoint_timer_query | null
|
||||
parallelShaderCompile: COMPAT_parallel_shader_compile | null
|
||||
fboRenderMipmap: COMPAT_fboRenderMipmap | null
|
||||
|
||||
noNonInstancedActiveAttribs: boolean
|
||||
}
|
||||
@@ -94,6 +97,10 @@ export function createExtensions(gl: GLRenderingContext): WebGLExtensions {
|
||||
if (isDebugMode && drawBuffers === null) {
|
||||
console.log('Could not find support for "draw_buffers"');
|
||||
}
|
||||
const drawBuffersIndexed = getDrawBuffersIndexed(gl);
|
||||
if (isDebugMode && drawBuffersIndexed === null) {
|
||||
console.log('Could not find support for "draw_buffers_indexed"');
|
||||
}
|
||||
const shaderTextureLod = getShaderTextureLod(gl);
|
||||
if (isDebugMode && shaderTextureLod === null) {
|
||||
console.log('Could not find support for "shader_texture_lod"');
|
||||
@@ -106,28 +113,39 @@ export function createExtensions(gl: GLRenderingContext): WebGLExtensions {
|
||||
if (isDebugMode && disjointTimerQuery === null) {
|
||||
console.log('Could not find support for "disjoint_timer_query"');
|
||||
}
|
||||
const parallelShaderCompile = getParallelShaderCompile(gl);
|
||||
if (isDebugMode && parallelShaderCompile === null) {
|
||||
console.log('Could not find support for "parallel_shader_compile"');
|
||||
}
|
||||
const fboRenderMipmap = getFboRenderMipmap(gl);
|
||||
if (isDebugMode && fboRenderMipmap === null) {
|
||||
console.log('Could not find support for "fbo_render_mipmap"');
|
||||
}
|
||||
|
||||
const noNonInstancedActiveAttribs = getNoNonInstancedActiveAttribs(gl);
|
||||
|
||||
return {
|
||||
instancedArrays,
|
||||
standardDerivatives,
|
||||
elementIndexUint,
|
||||
|
||||
textureFloat,
|
||||
textureFloatLinear,
|
||||
textureHalfFloat,
|
||||
textureHalfFloatLinear,
|
||||
elementIndexUint,
|
||||
depthTexture,
|
||||
|
||||
blendMinMax,
|
||||
vertexArrayObject,
|
||||
fragDepth,
|
||||
colorBufferFloat,
|
||||
colorBufferHalfFloat,
|
||||
drawBuffers,
|
||||
drawBuffersIndexed,
|
||||
shaderTextureLod,
|
||||
sRGB,
|
||||
disjointTimerQuery,
|
||||
parallelShaderCompile,
|
||||
fboRenderMipmap,
|
||||
|
||||
noNonInstancedActiveAttribs,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.362, IHM 1.17, MA 1.4.3.
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.363, IHM 1.17, MA 1.4.3.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.362, IHM 1.17, MA 1.4.3.
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.363, IHM 1.17, MA 1.4.3.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.362, IHM 1.17, MA 1.4.3.
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.363, IHM 1.17, MA 1.4.3.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 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>
|
||||
*/
|
||||
|
||||
import { lerp as scalar_lerp } from '../../mol-math/interpolate';
|
||||
import { defaults } from '../../mol-util';
|
||||
import { Mat3 } from '../linear-algebra/3d/mat3';
|
||||
import { Mat4 } from '../linear-algebra/3d/mat4';
|
||||
import { Quat } from '../linear-algebra/3d/quat';
|
||||
@@ -29,11 +29,13 @@ interface SymmetryOperator {
|
||||
readonly hkl: Vec3,
|
||||
/** spacegroup symmetry operator index, -1 if not applicable */
|
||||
readonly spgrOp: number,
|
||||
/** unique (external) key, -1 if not available */
|
||||
readonly key: number,
|
||||
|
||||
readonly matrix: Mat4,
|
||||
// cache the inverse of the transform
|
||||
/** cache the inverse of the transform */
|
||||
readonly inverse: Mat4,
|
||||
// optimize the identity case
|
||||
/** optimize the identity case */
|
||||
readonly isIdentity: boolean,
|
||||
|
||||
/**
|
||||
@@ -51,19 +53,20 @@ namespace SymmetryOperator {
|
||||
|
||||
export const RotationTranslationEpsilon = 0.005;
|
||||
|
||||
export type CreateInfo = { assembly?: SymmetryOperator['assembly'], ncsId?: number, hkl?: Vec3, spgrOp?: number }
|
||||
export type CreateInfo = { assembly?: SymmetryOperator['assembly'], ncsId?: number, hkl?: Vec3, spgrOp?: number, key?: number }
|
||||
export function create(name: string, matrix: Mat4, info?: CreateInfo | SymmetryOperator): SymmetryOperator {
|
||||
let { assembly, ncsId, hkl, spgrOp } = info || { };
|
||||
let { assembly, ncsId, hkl, spgrOp, key } = info || { };
|
||||
const _hkl = hkl ? Vec3.clone(hkl) : Vec3();
|
||||
spgrOp = defaults(spgrOp, -1);
|
||||
spgrOp = spgrOp ?? -1;
|
||||
key = key ?? -1;
|
||||
ncsId = ncsId || -1;
|
||||
const isIdentity = Mat4.isIdentity(matrix);
|
||||
const suffix = getSuffix(info, isIdentity);
|
||||
if (isIdentity) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, spgrOp, ncsId, suffix };
|
||||
if (isIdentity) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, spgrOp, ncsId, suffix, key };
|
||||
if (!Mat4.isRotationAndTranslation(matrix, RotationTranslationEpsilon)) {
|
||||
console.warn(`Symmetry operator (${name}) should be a composition of rotation and translation.`);
|
||||
}
|
||||
return { name, assembly, matrix, inverse: Mat4.invert(Mat4(), matrix), isIdentity: false, hkl: _hkl, spgrOp, ncsId, suffix };
|
||||
return { name, assembly, matrix, inverse: Mat4.invert(Mat4(), matrix), isIdentity: false, hkl: _hkl, spgrOp, key, ncsId, suffix };
|
||||
}
|
||||
|
||||
function isSymmetryOperator(x: any): x is SymmetryOperator {
|
||||
|
||||
@@ -14,6 +14,8 @@ import { ElementIndex } from '../../../../mol-model/structure';
|
||||
|
||||
export type IndexPairsProps = {
|
||||
readonly key: ArrayLike<number>
|
||||
readonly operatorA: ArrayLike<number>
|
||||
readonly operatorB: ArrayLike<number>
|
||||
readonly order: ArrayLike<number>
|
||||
readonly distance: ArrayLike<number>
|
||||
readonly flag: ArrayLike<BondType.Flag>
|
||||
@@ -24,18 +26,22 @@ export type IndexPairBonds = { bonds: IndexPairs, maxDistance: number }
|
||||
function getGraph(indexA: ArrayLike<ElementIndex>, indexB: ArrayLike<ElementIndex>, props: Partial<IndexPairsProps>, count: number): IndexPairs {
|
||||
const builder = new IntAdjacencyGraph.EdgeBuilder(count, indexA, indexB);
|
||||
const key = new Int32Array(builder.slotCount);
|
||||
const operatorA = new Array(builder.slotCount);
|
||||
const operatorB = new Array(builder.slotCount);
|
||||
const order = new Int8Array(builder.slotCount);
|
||||
const distance = new Array(builder.slotCount);
|
||||
const flag = new Array(builder.slotCount);
|
||||
for (let i = 0, _i = builder.edgeCount; i < _i; i++) {
|
||||
builder.addNextEdge();
|
||||
builder.assignProperty(key, props.key ? props.key[i] : -1);
|
||||
builder.assignProperty(operatorA, props.operatorA ? props.operatorA[i] : -1);
|
||||
builder.assignProperty(operatorB, props.operatorB ? props.operatorB[i] : -1);
|
||||
builder.assignProperty(order, props.order ? props.order[i] : 1);
|
||||
builder.assignProperty(distance, props.distance ? props.distance[i] : -1);
|
||||
builder.assignProperty(flag, props.flag ? props.flag[i] : BondType.Flag.Covalent);
|
||||
}
|
||||
|
||||
return builder.createGraph({ key, order, distance, flag });
|
||||
return builder.createGraph({ key, operatorA, operatorB, order, distance, flag });
|
||||
}
|
||||
|
||||
export namespace IndexPairBonds {
|
||||
@@ -50,6 +56,10 @@ export namespace IndexPairBonds {
|
||||
indexA: Column<number>,
|
||||
indexB: Column<number>,
|
||||
key?: Column<number>,
|
||||
/** Operator key for indexA. Used in bond computation. */
|
||||
operatorA?: Column<number>,
|
||||
/** Operator key for indexB. Used in bond computation. */
|
||||
operatorB?: Column<number>,
|
||||
order?: Column<number>,
|
||||
/**
|
||||
* Useful for bonds in periodic cells. That is, only bonds within the given
|
||||
@@ -83,12 +93,30 @@ export namespace IndexPairBonds {
|
||||
const indexA = pairs.indexA.toArray() as ArrayLike<ElementIndex>;
|
||||
const indexB = pairs.indexB.toArray() as ArrayLike<ElementIndex>;
|
||||
const key = pairs.key && pairs.key.toArray();
|
||||
const operatorA = pairs.operatorA && pairs.operatorA.toArray();
|
||||
const operatorB = pairs.operatorB && pairs.operatorB.toArray();
|
||||
const order = pairs.order && pairs.order.toArray();
|
||||
const distance = pairs.distance && pairs.distance.toArray();
|
||||
const flag = pairs.flag && pairs.flag.toArray();
|
||||
return {
|
||||
bonds: getGraph(indexA, indexB, { key, order, distance, flag }, count),
|
||||
bonds: getGraph(indexA, indexB, { key, operatorA, operatorB, order, distance, flag }, count),
|
||||
maxDistance: p.maxDistance
|
||||
};
|
||||
}
|
||||
|
||||
/** Like `getEdgeIndex` but taking `edgeProps.operatorA` and `edgeProps.operatorB` into account */
|
||||
export function getEdgeIndexForOperators(bonds: IndexPairs, i: ElementIndex, j: ElementIndex, opI: number, opJ: number): number {
|
||||
let a, b, opA, opB;
|
||||
if (i < j) {
|
||||
a = i; b = j;
|
||||
opA = opI; opB = opJ;
|
||||
} else {
|
||||
a = j; b = i;
|
||||
opA = opJ; opB = opI;
|
||||
}
|
||||
for (let t = bonds.offset[a], _t = bonds.offset[a + 1]; t < _t; t++) {
|
||||
if (bonds.b[t] === b && bonds.edgeProps.operatorA[t] === opA && bonds.edgeProps.operatorB[t] === opB) return t;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace AlignSequences {
|
||||
score: number
|
||||
}
|
||||
|
||||
function createSeqIdIndicesMap(element: StructureElement.Loci.Element) {
|
||||
export function createSeqIdIndicesMap(element: StructureElement.Loci.Element) {
|
||||
const seqIds = new Map<number, StructureElement.UnitIndex[]>();
|
||||
if (Unit.isAtomic(element.unit)) {
|
||||
const { label_seq_id } = element.unit.model.atomicHierarchy.residues;
|
||||
@@ -94,7 +94,7 @@ namespace AlignSequences {
|
||||
}
|
||||
}
|
||||
|
||||
function entityKey(unit: Unit) {
|
||||
export function entityKey(unit: Unit) {
|
||||
switch (unit.kind) {
|
||||
case Unit.Kind.Atomic:
|
||||
return unit.model.atomicHierarchy.index.getEntityFromChain(unit.chainIndex[unit.elements[0]]);
|
||||
@@ -105,6 +105,6 @@ function entityKey(unit: Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
function getSequence(unit: Unit) {
|
||||
export function getSequence(unit: Unit) {
|
||||
return unit.model.sequence.byEntityKey[entityKey(unit)].sequence;
|
||||
}
|
||||
@@ -166,6 +166,14 @@ export interface AtomicIndex {
|
||||
findResidue(key: AtomicIndex.ResidueKey): ResidueIndex,
|
||||
findResidue(label_entity_id: string, label_asym_id: string, auth_seq_id: number, pdbx_PDB_ins_code?: string): ResidueIndex,
|
||||
|
||||
|
||||
/**
|
||||
* Index of the 1st occurence of this residue using "all-label" address.
|
||||
* Doesn't work for "ligands" as they don't have a label seq id assigned.
|
||||
* @returns index or -1 if not present.
|
||||
*/
|
||||
findResidueLabel(key: AtomicIndex.ResidueLabelKey): ResidueIndex,
|
||||
|
||||
/**
|
||||
* Index of the 1st occurence of this residue.
|
||||
* @param key.pdbx_PDB_ins_code Empty string for undefined
|
||||
|
||||
@@ -124,6 +124,14 @@ class Index implements AtomicIndex {
|
||||
return rm.has(id) ? rm.get(id)! : -1 as ResidueIndex;
|
||||
}
|
||||
|
||||
findResidueLabel(key: AtomicIndex.ResidueLabelKey): ResidueIndex {
|
||||
const cI = this.findChainLabel(key);
|
||||
if (cI < 0) return -1 as ResidueIndex;
|
||||
const rm = this.map.chain_index_label_seq_id.get(cI)!;
|
||||
const id = getResidueId(key.label_seq_id, key.pdbx_PDB_ins_code || '');
|
||||
return rm.has(id) ? rm.get(id)! : -1 as ResidueIndex;
|
||||
}
|
||||
|
||||
findResidueAuth(key: AtomicIndex.ResidueAuthKey): ResidueIndex {
|
||||
const cI = this.findChainAuth(key);
|
||||
if (cI < 0) return -1 as ResidueIndex;
|
||||
|
||||
@@ -285,6 +285,10 @@ export const AminoAcidNamesD = new Set([
|
||||
]);
|
||||
export const AminoAcidNames = SetUtils.unionMany(AminoAcidNamesL, AminoAcidNamesD);
|
||||
|
||||
export const CommonProteinCaps = new Set([
|
||||
'NME', 'ACE'
|
||||
]);
|
||||
|
||||
export const RnaBaseNames = new Set([
|
||||
'A', 'C', 'T', 'G', 'I', 'U',
|
||||
'N' // unknown RNA base from CCD
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -155,6 +155,6 @@ class QueryContextBondInfo<U extends Unit = Unit> {
|
||||
}
|
||||
|
||||
get length() {
|
||||
return StructureElement.Location.distance(this.a, this. b);
|
||||
return StructureElement.Location.distance(this.a, this.b);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 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>
|
||||
@@ -173,6 +173,7 @@ const unit = {
|
||||
multiChain: p(l => Unit.Traits.is(l.unit.traits, Unit.Trait.MultiChain)),
|
||||
object_primitive: p(l => l.unit.objectPrimitive),
|
||||
operator_name: p(l => l.unit.conformation.operator.name),
|
||||
operator_key: p(l => l.unit.conformation.operator.key),
|
||||
model_index: p(l => l.unit.model.modelNum),
|
||||
model_label: p(l => l.unit.model.label),
|
||||
model_entry_id: p(l => l.unit.model.entryId),
|
||||
|
||||
@@ -1224,7 +1224,7 @@ namespace Structure {
|
||||
const closeUnits = lookup.findUnitIndices(imageCenter[0], imageCenter[1], imageCenter[2], bs.radius + maxRadius);
|
||||
for (let i = 0; i < closeUnits.count; i++) {
|
||||
const other = structure.units[closeUnits.indices[i]];
|
||||
if (!Box3D.overlaps(bbox, other.boundary.box)) continue;
|
||||
if (other.elements.length > 3 && !Box3D.overlaps(bbox, other.boundary.box)) continue;
|
||||
if (!validUnit(other) || unit.id >= other.id || !validUnitPair(unit, other)) continue;
|
||||
|
||||
if (other.elements.length >= unit.elements.length) callback(unit, other);
|
||||
|
||||
@@ -71,6 +71,8 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput
|
||||
const testDistanceSq = (bRadius + maxRadius) * (bRadius + maxRadius);
|
||||
|
||||
builder.startUnitPair(unitA.id, unitB.id);
|
||||
const opKeyA = unitA.conformation.operator.key;
|
||||
const opKeyB = unitB.conformation.operator.key;
|
||||
|
||||
for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) {
|
||||
const aI = atomsA[_aI];
|
||||
@@ -80,7 +82,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput
|
||||
|
||||
if (!props.forceCompute && indexPairs) {
|
||||
const { maxDistance } = indexPairs;
|
||||
const { offset, b, edgeProps: { order, distance, flag, key } } = indexPairs.bonds;
|
||||
const { offset, b, edgeProps: { order, distance, flag, key, operatorA, operatorB } } = indexPairs.bonds;
|
||||
|
||||
const srcA = sourceIndex.value(aI);
|
||||
const aeI = getElementIdx(type_symbolA.value(aI));
|
||||
@@ -90,6 +92,11 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput
|
||||
const _bI = SortedArray.indexOf(unitB.elements, bI) as StructureElement.UnitIndex;
|
||||
if (_bI < 0) continue;
|
||||
|
||||
const opA = operatorA[i];
|
||||
const opB = operatorB[i];
|
||||
if ((opA >= 0 && opA !== opKeyA && opA !== opKeyB) ||
|
||||
(opB >= 0 && opB !== opKeyB && opB !== opKeyA)) continue;
|
||||
|
||||
const beI = getElementIdx(type_symbolA.value(bI));
|
||||
|
||||
const d = distance[i];
|
||||
@@ -242,13 +249,29 @@ function computeInterUnitBonds(structure: Structure, props?: Partial<InterBondCo
|
||||
(!Unit.isAtomic(a) || mtA[a.residueIndex[a.elements[0]]] !== MoleculeType.Water) &&
|
||||
(!Unit.isAtomic(b) || mtB[b.residueIndex[b.elements[0]]] !== MoleculeType.Water)
|
||||
);
|
||||
const notIon = (
|
||||
(!Unit.isAtomic(a) || mtA[a.residueIndex[a.elements[0]]] !== MoleculeType.Ion) &&
|
||||
(!Unit.isAtomic(b) || mtB[b.residueIndex[b.elements[0]]] !== MoleculeType.Ion)
|
||||
);
|
||||
|
||||
const sameModel = a.model === b.model;
|
||||
const notIonA = (!Unit.isAtomic(a) || mtA[a.residueIndex[a.elements[0]]] !== MoleculeType.Ion) || (sameModel && hasStructConnRecord(a));
|
||||
const notIonB = (!Unit.isAtomic(b) || mtB[b.residueIndex[b.elements[0]]] !== MoleculeType.Ion) || (sameModel && hasStructConnRecord(b));
|
||||
const notIon = notIonA && notIonB;
|
||||
return Structure.validUnitPair(s, a, b) && (notWater || !p.ignoreWater) && (notIon || !p.ignoreIon);
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
function hasStructConnRecord(unit: Unit) {
|
||||
if (!Unit.isAtomic(unit)) return false;
|
||||
|
||||
const elements = unit.elements;
|
||||
const structConn = StructConn.Provider.get(unit.model);
|
||||
if (structConn) {
|
||||
for (let i = 0, _i = elements.length; i < _i; i++) {
|
||||
if (structConn.byAtomIndex.get(elements[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export { computeInterUnitBonds };
|
||||
|
||||
@@ -55,7 +55,7 @@ function findIndexPairBonds(unit: Unit.Atomic) {
|
||||
const { type_symbol } = unit.model.atomicHierarchy.atoms;
|
||||
const atomCount = unit.elements.length;
|
||||
const { maxDistance } = indexPairs;
|
||||
const { offset, b, edgeProps: { order, distance, flag, key } } = indexPairs.bonds;
|
||||
const { offset, b, edgeProps: { order, distance, flag, key, operatorA, operatorB } } = indexPairs.bonds;
|
||||
|
||||
const { atomSourceIndex: sourceIndex } = unit.model.atomicHierarchy;
|
||||
const { invertedIndex } = Model.getInvertedAtomSourceIndex(unit.model);
|
||||
@@ -66,6 +66,8 @@ function findIndexPairBonds(unit: Unit.Atomic) {
|
||||
const orders: number[] = [];
|
||||
const keys: number[] = [];
|
||||
|
||||
const opKey = unit.conformation.operator.key;
|
||||
|
||||
for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) {
|
||||
const aI = atoms[_aI];
|
||||
const aeI = getElementIdx(type_symbol.value(aI));
|
||||
@@ -80,6 +82,10 @@ function findIndexPairBonds(unit: Unit.Atomic) {
|
||||
const _bI = SortedArray.indexOf(unit.elements, bI) as StructureElement.UnitIndex;
|
||||
if (_bI < 0) continue;
|
||||
|
||||
const opA = operatorA[i];
|
||||
const opB = operatorB[i];
|
||||
if ((opA >= 0 && opA !== opKey) || (opB >= 0 && opB !== opKey)) continue;
|
||||
|
||||
const beI = getElementIdx(type_symbol.value(bI));
|
||||
|
||||
const d = distance[i];
|
||||
|
||||
@@ -64,7 +64,7 @@ export function alignAndSuperpose(xs: StructureElement.Loci[]): AlignAndSuperpos
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getPositionTable(xs: StructureElement.Loci, n: number): MinimizeRmsd.Positions {
|
||||
export function getPositionTable(xs: StructureElement.Loci, n: number): MinimizeRmsd.Positions {
|
||||
const ret = MinimizeRmsd.Positions.empty(n);
|
||||
let o = 0;
|
||||
for (const u of xs.elements) {
|
||||
|
||||
@@ -124,6 +124,11 @@ export const AnimateModelIndex = PluginStateAnimation.create({
|
||||
? params.duration.params.durationInS * 1000
|
||||
: Math.ceil(1000 * traj.data.frameCount / params.duration.params.targetFps);
|
||||
|
||||
if (params.mode.name === 'once' && t.current >= durationInMs) {
|
||||
isEnd = true;
|
||||
return { modelIndex: traj.data.frameCount - 1 };
|
||||
}
|
||||
|
||||
let phase: number = (t.current % durationInMs) / durationInMs;
|
||||
if (params.mode.name === 'loop') {
|
||||
if (params.mode.params.direction === 'backward') {
|
||||
@@ -135,7 +140,6 @@ export const AnimateModelIndex = PluginStateAnimation.create({
|
||||
}
|
||||
|
||||
const modelIndex = Math.min(Math.floor(traj.data.frameCount * phase), traj.data.frameCount - 1);
|
||||
isEnd = isEnd || modelIndex === traj.data.frameCount - 1;
|
||||
return { modelIndex };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -37,6 +37,7 @@ export namespace StructureRepresentationPresetProvider {
|
||||
|
||||
export const CommonParams = {
|
||||
ignoreHydrogens: PD.Optional(PD.Boolean(false)),
|
||||
onlyPolarHydrogens: PD.Optional(PD.Boolean(false)),
|
||||
ignoreLight: PD.Optional(PD.Boolean(false)),
|
||||
quality: PD.Optional(PD.Select<VisualQuality>('auto', VisualQualityOptions)),
|
||||
theme: PD.Optional(PD.Group({
|
||||
@@ -70,11 +71,13 @@ export namespace StructureRepresentationPresetProvider {
|
||||
const builder = plugin.builders.structure.representation;
|
||||
const typeParams = {
|
||||
quality: plugin.managers.structure.component.state.options.visualQuality,
|
||||
ignoreHydrogens: !plugin.managers.structure.component.state.options.showHydrogens,
|
||||
ignoreHydrogens: plugin.managers.structure.component.state.options.hydrogens === 'hide-all',
|
||||
onlyPolarHydrogens: plugin.managers.structure.component.state.options.hydrogens === 'only-polar',
|
||||
ignoreLight: plugin.managers.structure.component.state.options.ignoreLight,
|
||||
};
|
||||
if (params.quality && params.quality !== 'auto') typeParams.quality = params.quality;
|
||||
if (params.ignoreHydrogens !== void 0) typeParams.ignoreHydrogens = !!params.ignoreHydrogens;
|
||||
if (params.onlyPolarHydrogens !== void 0) typeParams.onlyPolarHydrogens = !!params.onlyPolarHydrogens;
|
||||
if (params.ignoreLight !== void 0) typeParams.ignoreLight = !!params.ignoreLight;
|
||||
const color: ColorTheme.BuiltIn | undefined = params.theme?.globalName ? params.theme?.globalName : void 0;
|
||||
const ballAndStickColor: ColorTheme.BuiltInParams<'element-symbol'> = params.theme?.carbonColor !== undefined
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import { CustomProperty } from '../../mol-model-props/common/custom-property';
|
||||
import { QueryContext, Structure, StructureQuery, StructureSelection, StructureProperties, StructureElement } from '../../mol-model/structure';
|
||||
import { BondType, NucleicBackboneAtoms, ProteinBackboneAtoms, SecondaryStructureType, AminoAcidNamesL, RnaBaseNames, DnaBaseNames, WaterNames, ElementSymbol, PolymerNames } from '../../mol-model/structure/model/types';
|
||||
import { BondType, NucleicBackboneAtoms, ProteinBackboneAtoms, SecondaryStructureType, AminoAcidNamesL, RnaBaseNames, DnaBaseNames, WaterNames, ElementSymbol, PolymerNames, CommonProteinCaps } from '../../mol-model/structure/model/types';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
|
||||
import { Expression } from '../../mol-script/language/expression';
|
||||
@@ -350,14 +350,23 @@ const ligand = StructureSelectionQuery('Ligand', MS.struct.modifier.union([
|
||||
])
|
||||
]),
|
||||
]),
|
||||
by: MS.struct.modifier.union([
|
||||
by: MS.struct.combinator.merge([
|
||||
MS.struct.modifier.union([
|
||||
MS.struct.generator.atomGroups({
|
||||
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']),
|
||||
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
|
||||
'residue-test': MS.core.set.has([
|
||||
MS.set(...SetUtils.toArray(PolymerNames)), MS.ammp('label_comp_id')
|
||||
])
|
||||
}),
|
||||
]),
|
||||
MS.struct.generator.atomGroups({
|
||||
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']),
|
||||
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
|
||||
'residue-test': MS.core.set.has([
|
||||
MS.set(...SetUtils.toArray(PolymerNames)), MS.ammp('label_comp_id')
|
||||
])
|
||||
})
|
||||
MS.set(...SetUtils.toArray(CommonProteinCaps)),
|
||||
MS.ammp('label_comp_id'),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
})
|
||||
]), { category: StructureSelectionCategory.Type });
|
||||
|
||||
@@ -70,7 +70,8 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
|
||||
return this.plugin.dataTransaction(async () => {
|
||||
await update.commit();
|
||||
await this.plugin.state.updateBehavior(StructureFocusRepresentation, p => {
|
||||
p.ignoreHydrogens = !options.showHydrogens;
|
||||
p.ignoreHydrogens = options.hydrogens === 'hide-all';
|
||||
p.onlyPolarHydrogens = options.hydrogens === 'only-polar';
|
||||
p.ignoreLight = options.ignoreLight;
|
||||
p.material = options.materialStyle;
|
||||
p.clip = options.clipObjects;
|
||||
@@ -80,15 +81,17 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
|
||||
}
|
||||
|
||||
private updateReprParams(update: StateBuilder.Root, component: StructureComponentRef) {
|
||||
const { showHydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
|
||||
const ignoreHydrogens = !showHydrogens;
|
||||
const { hydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
|
||||
const ignoreHydrogens = hydrogens === 'hide-all';
|
||||
const onlyPolarHydrogens = hydrogens === 'only-polar';
|
||||
for (const r of component.representations) {
|
||||
if (r.cell.transform.transformer !== StructureRepresentation3D) continue;
|
||||
|
||||
const params = r.cell.transform.params as StateTransformer.Params<StructureRepresentation3D>;
|
||||
if (!!params.type.params.ignoreHydrogens !== ignoreHydrogens || params.type.params.quality !== quality || params.type.params.ignoreLight !== ignoreLight || !shallowEqual(params.type.params.material, material) || !PD.areEqual(Clip.Params, params.type.params.clip, clip)) {
|
||||
if (!!params.type.params.ignoreHydrogens !== ignoreHydrogens || !!params.type.params.onlyPolarHydrogens !== onlyPolarHydrogens || params.type.params.quality !== quality || params.type.params.ignoreLight !== ignoreLight || !shallowEqual(params.type.params.material, material) || !PD.areEqual(Clip.Params, params.type.params.clip, clip)) {
|
||||
update.to(r.cell).update(old => {
|
||||
old.type.params.ignoreHydrogens = ignoreHydrogens;
|
||||
old.type.params.onlyPolarHydrogens = onlyPolarHydrogens;
|
||||
old.type.params.quality = quality;
|
||||
old.type.params.ignoreLight = ignoreLight;
|
||||
old.type.params.material = material;
|
||||
@@ -311,9 +314,10 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
|
||||
addRepresentation(components: ReadonlyArray<StructureComponentRef>, type: string) {
|
||||
if (components.length === 0) return;
|
||||
|
||||
const { showHydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
|
||||
const ignoreHydrogens = !showHydrogens;
|
||||
const typeParams = { ignoreHydrogens, quality, ignoreLight, material, clip };
|
||||
const { hydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
|
||||
const ignoreHydrogens = hydrogens === 'hide-all';
|
||||
const onlyPolarHydrogens = hydrogens === 'only-polar';
|
||||
const typeParams = { ignoreHydrogens, onlyPolarHydrogens, quality, ignoreLight, material, clip };
|
||||
|
||||
return this.plugin.dataTransaction(async () => {
|
||||
for (const component of components) {
|
||||
@@ -348,9 +352,10 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
|
||||
const xs = structures || this.currentStructures;
|
||||
if (xs.length === 0) return;
|
||||
|
||||
const { showHydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
|
||||
const ignoreHydrogens = !showHydrogens;
|
||||
const typeParams = { ignoreHydrogens, quality, ignoreLight, material, clip };
|
||||
const { hydrogens, visualQuality: quality, ignoreLight, materialStyle: material, clipObjects: clip } = this.state.options;
|
||||
const ignoreHydrogens = hydrogens === 'hide-all';
|
||||
const onlyPolarHydrogens = hydrogens === 'only-polar';
|
||||
const typeParams = { ignoreHydrogens, onlyPolarHydrogens, quality, ignoreLight, material, clip };
|
||||
|
||||
const componentKey = UUID.create22();
|
||||
for (const s of xs) {
|
||||
@@ -458,9 +463,13 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
|
||||
|
||||
namespace StructureComponentManager {
|
||||
export const OptionsParams = {
|
||||
showHydrogens: PD.Boolean(true, { description: 'Toggle display of hydrogen atoms in representations' }),
|
||||
hydrogens: PD.Select(
|
||||
'all',
|
||||
[['all', 'Show All'], ['hide-all', 'Hide All'], ['only-polar', 'Only Polar']] as const,
|
||||
{ description: 'Determine display of hydrogen atoms in representations' }
|
||||
),
|
||||
visualQuality: PD.Select('auto', VisualQualityOptions, { description: 'Control the visual/rendering quality of representations' }),
|
||||
ignoreLight: PD.Boolean(false, { description: 'Ignore light for stylized rendering of representtions' }),
|
||||
ignoreLight: PD.Boolean(false, { description: 'Ignore light for stylized rendering of representations' }),
|
||||
materialStyle: Material.getParam(),
|
||||
clipObjects: PD.Group(Clip.Params),
|
||||
interactions: PD.Group(InteractionsProvider.defaultParams, { label: 'Non-covalent Interactions' }),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 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>
|
||||
@@ -43,6 +43,7 @@ import { Box3D } from '../../mol-math/geometry';
|
||||
import { PlaneParams, PlaneRepresentation } from '../../mol-repr/shape/loci/plane';
|
||||
import { Substance } from '../../mol-theme/substance';
|
||||
import { Material } from '../../mol-util/material';
|
||||
import { lerp } from '../../mol-math/interpolate';
|
||||
|
||||
export { StructureRepresentation3D };
|
||||
export { ExplodeStructureRepresentation3D };
|
||||
@@ -56,6 +57,7 @@ export { SubstanceStructureRepresentation3DFromScript };
|
||||
export { SubstanceStructureRepresentation3DFromBundle };
|
||||
export { ClippingStructureRepresentation3DFromScript };
|
||||
export { ClippingStructureRepresentation3DFromBundle };
|
||||
export { ThemeStrengthRepresentation3D };
|
||||
export { VolumeRepresentation3D };
|
||||
|
||||
type StructureRepresentation3D = typeof StructureRepresentation3D
|
||||
@@ -745,6 +747,62 @@ const ClippingStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn
|
||||
}
|
||||
});
|
||||
|
||||
type ThemeStrengthRepresentation3D = typeof ThemeStrengthRepresentation3D
|
||||
const ThemeStrengthRepresentation3D = PluginStateTransform.BuiltIn({
|
||||
name: 'theme-strength-representation-3d',
|
||||
display: 'Theme Strength 3D Representation',
|
||||
from: SO.Molecule.Structure.Representation3D,
|
||||
to: SO.Molecule.Structure.Representation3DState,
|
||||
params: () => ({
|
||||
overpaintStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }),
|
||||
transparencyStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }),
|
||||
substanceStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }),
|
||||
})
|
||||
})({
|
||||
canAutoUpdate() {
|
||||
return true;
|
||||
},
|
||||
apply({ a, params }) {
|
||||
return new SO.Molecule.Structure.Representation3DState({
|
||||
state: {
|
||||
themeStrength: {
|
||||
overpaint: params.overpaintStrength,
|
||||
transparency: params.transparencyStrength,
|
||||
substance: params.substanceStrength
|
||||
},
|
||||
},
|
||||
initialState: {
|
||||
themeStrength: { overpaint: 1, transparency: 1, substance: 1 },
|
||||
},
|
||||
info: { },
|
||||
repr: a.data.repr
|
||||
}, { label: 'Theme Strength', description: `${params.overpaintStrength.toFixed(2)}, ${params.transparencyStrength.toFixed(2)}, ${params.substanceStrength.toFixed(2)}` });
|
||||
},
|
||||
update({ a, b, newParams, oldParams }) {
|
||||
if (newParams.overpaintStrength === b.data.state.themeStrength?.overpaint &&
|
||||
newParams.transparencyStrength === b.data.state.themeStrength?.transparency &&
|
||||
newParams.substanceStrength === b.data.state.themeStrength?.substance
|
||||
) return StateTransformer.UpdateResult.Unchanged;
|
||||
|
||||
b.data.state.themeStrength = {
|
||||
overpaint: newParams.overpaintStrength,
|
||||
transparency: newParams.transparencyStrength,
|
||||
substance: newParams.substanceStrength,
|
||||
};
|
||||
b.data.repr = a.data.repr;
|
||||
b.label = 'Theme Strength';
|
||||
b.description = `${newParams.overpaintStrength.toFixed(2)}, ${newParams.transparencyStrength.toFixed(2)}, ${newParams.substanceStrength.toFixed(2)}`;
|
||||
return StateTransformer.UpdateResult.Updated;
|
||||
},
|
||||
interpolate(src, tar, t) {
|
||||
return {
|
||||
overpaintStrength: lerp(src.overpaintStrength, tar.overpaintStrength, t),
|
||||
transparencyStrength: lerp(src.transparencyStrength, tar.transparencyStrength, t),
|
||||
substanceStrength: lerp(src.substanceStrength, tar.substanceStrength, t),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
export namespace VolumeRepresentation3DHelpers {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { getPrecision } from '../../mol-util/number';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { ParamMapping } from '../../mol-util/param-mapping';
|
||||
import { camelCaseToWords } from '../../mol-util/string';
|
||||
import { PluginUIComponent } from '../base';
|
||||
import { PluginReactContext, PluginUIComponent } from '../base';
|
||||
import { PluginUIContext } from '../context';
|
||||
import { ActionMenu } from './action-menu';
|
||||
import { ColorOptions, ColorValueOption, CombinedColorControl } from './color';
|
||||
@@ -505,10 +505,12 @@ export class ValueRefControl extends React.PureComponent<ParamProps<PD.ValueRef<
|
||||
|
||||
toggle = () => this.setState({ showOptions: !this.state.showOptions });
|
||||
|
||||
items = memoizeLatest((param: PD.ValueRef) => ActionMenu.createItemsFromSelectOptions(param.getOptions()));
|
||||
private get items() {
|
||||
return ActionMenu.createItemsFromSelectOptions(this.props.param.getOptions(this.context));
|
||||
}
|
||||
|
||||
renderControl() {
|
||||
const items = this.items(this.props.param);
|
||||
const items = this.items;
|
||||
const current = this.props.value.ref ? ActionMenu.findItem(items, this.props.value.ref) : void 0;
|
||||
const label = current
|
||||
? current.label
|
||||
@@ -521,7 +523,7 @@ export class ValueRefControl extends React.PureComponent<ParamProps<PD.ValueRef<
|
||||
renderAddOn() {
|
||||
if (!this.state.showOptions) return null;
|
||||
|
||||
const items = this.items(this.props.param);
|
||||
const items = this.items;
|
||||
const current = ActionMenu.findItem(items, this.props.value.ref);
|
||||
|
||||
return <ActionMenu items={items} current={current} onSelect={this.onSelect} />;
|
||||
@@ -539,6 +541,7 @@ export class ValueRefControl extends React.PureComponent<ParamProps<PD.ValueRef<
|
||||
});
|
||||
}
|
||||
}
|
||||
ValueRefControl.contextType = PluginReactContext;
|
||||
|
||||
export class IntervalControl extends React.PureComponent<ParamProps<PD.Interval>, { isExpanded: boolean }> {
|
||||
state = { isExpanded: false };
|
||||
|
||||
@@ -29,7 +29,7 @@ const MaxDisplaySequenceLength = 5000;
|
||||
const MaxSelectOptionsCount = 1000;
|
||||
const MaxSequenceWrappersCount = 30;
|
||||
|
||||
function opKey(l: StructureElement.Location) {
|
||||
export function opKey(l: StructureElement.Location) {
|
||||
const ids = SP.unit.pdbx_struct_oper_list_ids(l);
|
||||
const ncs = SP.unit.struct_ncs_oper_id(l);
|
||||
const hkl = SP.unit.hkl(l);
|
||||
@@ -37,12 +37,12 @@ function opKey(l: StructureElement.Location) {
|
||||
return `${ids.sort().join(',')}|${ncs}|${hkl}|${spgrOp}`;
|
||||
}
|
||||
|
||||
function splitModelEntityId(modelEntityId: string) {
|
||||
export function splitModelEntityId(modelEntityId: string) {
|
||||
const [modelIdx, entityId] = modelEntityId.split('|');
|
||||
return [parseInt(modelIdx), entityId];
|
||||
}
|
||||
|
||||
function getSequenceWrapper(state: { structure: Structure, modelEntityId: string, chainGroupId: number, operatorKey: string }, structureSelection: StructureSelectionManager): SequenceWrapper.Any | string {
|
||||
export function getSequenceWrapper(state: { structure: Structure, modelEntityId: string, chainGroupId: number, operatorKey: string }, structureSelection: StructureSelectionManager): SequenceWrapper.Any | string {
|
||||
const { structure, modelEntityId, chainGroupId, operatorKey } = state;
|
||||
const l = StructureElement.Location.create(structure);
|
||||
const [modelIdx, entityId] = splitModelEntityId(modelEntityId);
|
||||
@@ -97,7 +97,7 @@ function getSequenceWrapper(state: { structure: Structure, modelEntityId: string
|
||||
}
|
||||
}
|
||||
|
||||
function getModelEntityOptions(structure: Structure, polymersOnly = false): [string, string][] {
|
||||
export function getModelEntityOptions(structure: Structure, polymersOnly = false): [string, string][] {
|
||||
const options: [string, string][] = [];
|
||||
const l = StructureElement.Location.create(structure);
|
||||
const seen = new Set<string>();
|
||||
@@ -131,7 +131,7 @@ function getModelEntityOptions(structure: Structure, polymersOnly = false): [str
|
||||
return options;
|
||||
}
|
||||
|
||||
function getChainOptions(structure: Structure, modelEntityId: string): [number, string][] {
|
||||
export function getChainOptions(structure: Structure, modelEntityId: string): [number, string][] {
|
||||
const options: [number, string][] = [];
|
||||
const l = StructureElement.Location.create(structure);
|
||||
const seen = new Set<number>();
|
||||
@@ -161,7 +161,7 @@ function getChainOptions(structure: Structure, modelEntityId: string): [number,
|
||||
return options;
|
||||
}
|
||||
|
||||
function getOperatorOptions(structure: Structure, modelEntityId: string, chainGroupId: number): [string, string][] {
|
||||
export function getOperatorOptions(structure: Structure, modelEntityId: string, chainGroupId: number): [string, string][] {
|
||||
const options: [string, string][] = [];
|
||||
const l = StructureElement.Location.create(structure);
|
||||
const seen = new Set<string>();
|
||||
@@ -189,7 +189,7 @@ function getOperatorOptions(structure: Structure, modelEntityId: string, chainGr
|
||||
return options;
|
||||
}
|
||||
|
||||
function getStructureOptions(state: State) {
|
||||
export function getStructureOptions(state: State) {
|
||||
const options: [string, string][] = [];
|
||||
const all: Structure[] = [];
|
||||
|
||||
|
||||
@@ -27,21 +27,21 @@ const MaxSequenceNumberSize = 5;
|
||||
|
||||
// TODO: this is somewhat inefficient and should be done using a canvas.
|
||||
export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
|
||||
private parentDiv = React.createRef<HTMLDivElement>();
|
||||
private lastMouseOverSeqIdx = -1;
|
||||
private highlightQueue = new Subject<{ seqIdx: number, buttons: number, button: number, modifiers: ModifiersKeys }>();
|
||||
protected parentDiv = React.createRef<HTMLDivElement>();
|
||||
protected lastMouseOverSeqIdx = -1;
|
||||
protected highlightQueue = new Subject<{ seqIdx: number, buttons: number, button: number, modifiers: ModifiersKeys }>();
|
||||
|
||||
private lociHighlightProvider = (loci: Representation.Loci, action: MarkerAction) => {
|
||||
protected lociHighlightProvider = (loci: Representation.Loci, action: MarkerAction) => {
|
||||
const changed = this.props.sequenceWrapper.markResidue(loci.loci, action);
|
||||
if (changed) this.updateMarker();
|
||||
};
|
||||
|
||||
private lociSelectionProvider = (loci: Representation.Loci, action: MarkerAction) => {
|
||||
protected lociSelectionProvider = (loci: Representation.Loci, action: MarkerAction) => {
|
||||
const changed = this.props.sequenceWrapper.markResidue(loci.loci, action);
|
||||
if (changed) this.updateMarker();
|
||||
};
|
||||
|
||||
private get sequenceNumberPeriod() {
|
||||
protected get sequenceNumberPeriod() {
|
||||
if (this.props.sequenceNumberPeriod !== undefined) {
|
||||
return this.props.sequenceNumberPeriod as number;
|
||||
}
|
||||
@@ -104,7 +104,7 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
private mouseDownLoci: StructureElement.Loci | undefined = undefined;
|
||||
protected mouseDownLoci: StructureElement.Loci | undefined = undefined;
|
||||
|
||||
mouseDown = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
@@ -148,7 +148,7 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
|
||||
this.mouseDownLoci = undefined;
|
||||
};
|
||||
|
||||
private getBackgroundColor(marker: number) {
|
||||
protected getBackgroundColor(marker: number) {
|
||||
// TODO: make marker color configurable
|
||||
if (typeof marker === 'undefined') console.error('unexpected marker value');
|
||||
return marker === 0
|
||||
@@ -158,17 +158,17 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
|
||||
: 'rgb(255, 102, 153)'; // highlighted
|
||||
}
|
||||
|
||||
private getResidueClass(seqIdx: number, label: string) {
|
||||
protected getResidueClass(seqIdx: number, label: string) {
|
||||
return label.length > 1
|
||||
? this.props.sequenceWrapper.residueClass(seqIdx) + (seqIdx === 0 ? ' msp-sequence-residue-long-begin' : ' msp-sequence-residue-long')
|
||||
: this.props.sequenceWrapper.residueClass(seqIdx);
|
||||
}
|
||||
|
||||
private residue(seqIdx: number, label: string, marker: number) {
|
||||
protected residue(seqIdx: number, label: string, marker: number) {
|
||||
return <span key={seqIdx} data-seqid={seqIdx} style={{ backgroundColor: this.getBackgroundColor(marker) }} className={this.getResidueClass(seqIdx, label)}>{`\u200b${label}\u200b`}</span>;
|
||||
}
|
||||
|
||||
private getSequenceNumberClass(seqIdx: number, seqNum: string, label: string) {
|
||||
protected getSequenceNumberClass(seqIdx: number, seqNum: string, label: string) {
|
||||
const classList = ['msp-sequence-number'];
|
||||
if (seqNum.startsWith('-')) {
|
||||
if (label.length > 1 && seqIdx > 0) classList.push('msp-sequence-number-long-negative');
|
||||
@@ -179,8 +179,8 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
|
||||
return classList.join(' ');
|
||||
}
|
||||
|
||||
private location = StructureElement.Location.create(void 0);
|
||||
private getSequenceNumber(seqIdx: number) {
|
||||
protected location = StructureElement.Location.create(void 0);
|
||||
protected getSequenceNumber(seqIdx: number) {
|
||||
let seqNum = '';
|
||||
const loci = this.props.sequenceWrapper.getLoci(seqIdx);
|
||||
const l = StructureElement.Loci.getFirstLocation(loci, this.location);
|
||||
@@ -196,16 +196,16 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
|
||||
return seqNum;
|
||||
}
|
||||
|
||||
private padSeqNum(n: string) {
|
||||
protected padSeqNum(n: string) {
|
||||
if (n.length < MaxSequenceNumberSize) return n + new Array(MaxSequenceNumberSize - n.length + 1).join('\u00A0');
|
||||
return n;
|
||||
}
|
||||
private getSequenceNumberSpan(seqIdx: number, label: string) {
|
||||
protected getSequenceNumberSpan(seqIdx: number, label: string) {
|
||||
const seqNum = this.getSequenceNumber(seqIdx);
|
||||
return <span key={`marker-${seqIdx}`} className={this.getSequenceNumberClass(seqIdx, seqNum, label)}>{this.padSeqNum(seqNum)}</span>;
|
||||
}
|
||||
|
||||
private updateMarker() {
|
||||
protected updateMarker() {
|
||||
if (!this.parentDiv.current) return;
|
||||
const xs = this.parentDiv.current.children;
|
||||
const { markerArray } = this.props.sequenceWrapper;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: black;
|
||||
background: $default-background;
|
||||
|
||||
.msp-btn-link {
|
||||
background: rgba(0,0,0,0.2);
|
||||
|
||||
@@ -28,7 +28,8 @@ namespace ApplyActionControl {
|
||||
params: any,
|
||||
error?: string,
|
||||
busy: boolean,
|
||||
isInitial: boolean
|
||||
isInitial: boolean,
|
||||
isCollapsed?: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +41,7 @@ class ApplyActionControl extends TransformControlBase<ApplyActionControl.Props,
|
||||
ref: this.props.nodeRef
|
||||
});
|
||||
}
|
||||
getInfo() { return this._getInfo(this.props.nodeRef, this.props.state.transforms.get(this.props.nodeRef).version); }
|
||||
getInfo() { return this._getInfo(this.props.nodeRef, this.props.state.transforms.get(this.props.nodeRef).version, this.state?.isCollapsed); }
|
||||
getTransformerId() { return this.props.state.transforms.get(this.props.nodeRef).transformer.id; }
|
||||
getHeader() { return this.props.hideHeader ? 'none' : this.props.action.definition.display; }
|
||||
canApply() { return !this.state.error && !this.state.busy; }
|
||||
@@ -49,9 +50,9 @@ class ApplyActionControl extends TransformControlBase<ApplyActionControl.Props,
|
||||
isUpdate() { return false; }
|
||||
getSourceAndTarget() { return { a: this.props.state.cells.get(this.props.nodeRef)!.obj }; }
|
||||
|
||||
private _getInfo = memoizeLatest((t: StateTransform.Ref, v: string) => StateTransformParameters.infoFromAction(this.plugin, this.props.state, this.props.action, this.props.nodeRef));
|
||||
private _getInfo = memoizeLatest((t: StateTransform.Ref, v: string, collapsed?: boolean) => StateTransformParameters.infoFromAction(this.plugin, this.props.state, this.props.action, this.props.nodeRef));
|
||||
|
||||
state = { plugin: this.plugin, ref: this.props.nodeRef, version: this.props.state.transforms.get(this.props.nodeRef).version, error: void 0, isInitial: true, params: this.getInfo().initialValues, busy: false, isCollapsed: this.props.initiallyCollapsed };
|
||||
state: ApplyActionControl.ComponentState = { plugin: this.plugin, ref: this.props.nodeRef, version: this.props.state.transforms.get(this.props.nodeRef).version, error: void 0, isInitial: true, params: this.getInfo().initialValues, busy: false, isCollapsed: this.props.initiallyCollapsed };
|
||||
|
||||
static getDerivedStateFromProps(props: ApplyActionControl.Props, state: ApplyActionControl.ComponentState) {
|
||||
const version = props.state.transforms.get(props.nodeRef).version;
|
||||
|
||||
@@ -56,12 +56,13 @@ export class QuickStyles extends PurePluginUIComponent {
|
||||
postprocessing: {
|
||||
outline: {
|
||||
name: 'on',
|
||||
params: { scale: 1, color: Color(0x000000), threshold: 0.25 }
|
||||
params: { scale: 1, color: Color(0x000000), threshold: 0.25, includeTransparent: true }
|
||||
},
|
||||
occlusion: {
|
||||
name: 'on',
|
||||
params: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1 }
|
||||
},
|
||||
shadow: { name: 'off', params: {} },
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -78,7 +79,7 @@ export class QuickStyles extends PurePluginUIComponent {
|
||||
name: 'on',
|
||||
params: pp.outline.name === 'on'
|
||||
? pp.outline.params
|
||||
: { scale: 1, color: Color(0x000000), threshold: 0.33 }
|
||||
: { scale: 1, color: Color(0x000000), threshold: 0.33, includeTransparent: true }
|
||||
},
|
||||
occlusion: {
|
||||
name: 'on',
|
||||
@@ -86,6 +87,7 @@ export class QuickStyles extends PurePluginUIComponent {
|
||||
? pp.occlusion.params
|
||||
: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1 }
|
||||
},
|
||||
shadow: { name: 'off', params: {} },
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ type SuperpositionControlsState = {
|
||||
options: StructureSuperpositionOptions
|
||||
}
|
||||
|
||||
interface LociEntry {
|
||||
export interface LociEntry {
|
||||
loci: StructureElement.Loci,
|
||||
label: string,
|
||||
cell: StateObjectCell<PluginStateObject.Molecule.Structure>
|
||||
|
||||
@@ -59,6 +59,7 @@ const SimpleSettingsParams = {
|
||||
}, { pivot: 'color' }),
|
||||
lighting: PD.Group({
|
||||
occlusion: Canvas3DParams.postprocessing.params.occlusion,
|
||||
shadow: Canvas3DParams.postprocessing.params.shadow,
|
||||
outline: Canvas3DParams.postprocessing.params.outline,
|
||||
fog: Canvas3DParams.cameraFog,
|
||||
}, { isFlat: true }),
|
||||
@@ -114,6 +115,7 @@ const SimpleSettingsMapping = ParamMapping({
|
||||
},
|
||||
lighting: {
|
||||
occlusion: canvas.postprocessing.occlusion,
|
||||
shadow: canvas.postprocessing.shadow,
|
||||
outline: canvas.postprocessing.outline,
|
||||
fog: canvas.cameraFog,
|
||||
},
|
||||
@@ -129,6 +131,7 @@ const SimpleSettingsMapping = ParamMapping({
|
||||
canvas.transparentBackground = s.background.transparent;
|
||||
canvas.renderer.backgroundColor = s.background.color;
|
||||
canvas.postprocessing.occlusion = s.lighting.occlusion;
|
||||
canvas.postprocessing.shadow = s.lighting.shadow;
|
||||
canvas.postprocessing.outline = s.lighting.outline;
|
||||
canvas.postprocessing.background = s.background.style;
|
||||
canvas.cameraFog = s.lighting.fog;
|
||||
|
||||
@@ -52,6 +52,7 @@ const StructureFocusRepresentationParams = (plugin: PluginContext) => {
|
||||
components: PD.MultiSelect(FocusComponents, PD.arrayToOptions(FocusComponents)),
|
||||
excludeTargetFromSurroundings: PD.Boolean(false, { label: 'Exclude Target', description: 'Exclude the focus "target" from the surroudings component.' }),
|
||||
ignoreHydrogens: PD.Boolean(false),
|
||||
onlyPolarHydrogens: PD.Boolean(false),
|
||||
ignoreLight: PD.Boolean(false),
|
||||
material: Material.getParam(),
|
||||
clip: PD.Group(Clip.Params),
|
||||
@@ -80,7 +81,7 @@ class StructureFocusRepresentationBehavior extends PluginBehavior.WithSubscriber
|
||||
...reprParams,
|
||||
type: {
|
||||
name: reprParams.type.name,
|
||||
params: { ...reprParams.type.params, ignoreHydrogens: this.params.ignoreHydrogens, ignoreLight: this.params.ignoreLight, material: this.params.material, clip: this.params.clip }
|
||||
params: { ...reprParams.type.params, ignoreHydrogens: this.params.ignoreHydrogens, onlyPolarHydrogens: this.params.onlyPolarHydrogens, ignoreLight: this.params.ignoreLight, material: this.params.material, clip: this.params.clip }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ export const PluginConfig = {
|
||||
// TODO: check back in a few weeks to see if it was fixed
|
||||
PreferWebGl1: item('plugin-config.prefer-webgl1', PluginFeatureDetection.preferWebGl1),
|
||||
AllowMajorPerformanceCaveat: item('plugin-config.allow-major-performance-caveat', false),
|
||||
PowerPreference: item<WebGLContextAttributes['powerPreference']>('plugin-config.power-preference', 'high-performance'),
|
||||
},
|
||||
State: {
|
||||
DefaultServer: item('plugin-state.server', 'https://webchem.ncbr.muni.cz/molstar-state'),
|
||||
|
||||
@@ -267,7 +267,8 @@ export class PluginContext {
|
||||
const enableDpoit = this.config.get(PluginConfig.General.EnableDpoit) || false;
|
||||
const preferWebGl1 = this.config.get(PluginConfig.General.PreferWebGl1) || false;
|
||||
const failIfMajorPerformanceCaveat = !(this.config.get(PluginConfig.General.AllowMajorPerformanceCaveat) ?? false);
|
||||
(this.canvas3dContext as Canvas3DContext) = Canvas3DContext.fromCanvas(canvas, this.managers.asset, { antialias, preserveDrawingBuffer, pixelScale, pickScale, pickPadding, enableWboit, enableDpoit, preferWebGl1, failIfMajorPerformanceCaveat });
|
||||
const powerPreference = this.config.get(PluginConfig.General.PowerPreference) || 'high-performance';
|
||||
(this.canvas3dContext as Canvas3DContext) = Canvas3DContext.fromCanvas(canvas, this.managers.asset, { antialias, preserveDrawingBuffer, pixelScale, pickScale, pickPadding, enableWboit, enableDpoit, preferWebGl1, failIfMajorPerformanceCaveat, powerPreference });
|
||||
}
|
||||
(this.canvas3d as Canvas3D) = Canvas3D.create(this.canvas3dContext!);
|
||||
this.canvas3dInit.next(true);
|
||||
|
||||
@@ -104,6 +104,7 @@ export const DefaultPluginSpec = (): PluginSpec => ({
|
||||
PluginSpec.Action(StateTransforms.Representation.TransparencyStructureRepresentation3DFromScript),
|
||||
PluginSpec.Action(StateTransforms.Representation.ClippingStructureRepresentation3DFromScript),
|
||||
PluginSpec.Action(StateTransforms.Representation.SubstanceStructureRepresentation3DFromScript),
|
||||
PluginSpec.Action(StateTransforms.Representation.ThemeStrengthRepresentation3D),
|
||||
|
||||
PluginSpec.Action(AssignColorVolume),
|
||||
PluginSpec.Action(StateTransforms.Volume.VolumeFromCcp4),
|
||||
|
||||
@@ -140,7 +140,7 @@ export class RepresentationRegistry<D, S extends Representation.State> {
|
||||
//
|
||||
|
||||
export { Representation };
|
||||
interface Representation<D, P extends PD.Params = {}, S extends Representation.State = Representation.State> {
|
||||
interface Representation<D, P extends PD.Params = PD.Params, S extends Representation.State = Representation.State> {
|
||||
readonly label: string
|
||||
readonly updated: Subject<number>
|
||||
/** Number of addressable groups in all visuals of the representation */
|
||||
@@ -191,6 +191,8 @@ namespace Representation {
|
||||
substance: Substance
|
||||
/** Bit mask of per group clipping applied to the representation's renderobjects */
|
||||
clipping: Clipping
|
||||
/** Strength of the representations overpaint, transparency, substance*/
|
||||
themeStrength: { overpaint: number, transparency: number, substance: number }
|
||||
/** Controls if the representation's renderobjects are synced automatically with GPU or not */
|
||||
syncManually: boolean
|
||||
/** A transformation applied to the representation's renderobjects */
|
||||
@@ -199,7 +201,20 @@ namespace Representation {
|
||||
markerActions: MarkerActions
|
||||
}
|
||||
export function createState(): State {
|
||||
return { visible: true, alphaFactor: 1, pickable: true, colorOnly: false, syncManually: false, transform: Mat4.identity(), overpaint: Overpaint.Empty, transparency: Transparency.Empty, substance: Substance.Empty, clipping: Clipping.Empty, markerActions: MarkerActions.All };
|
||||
return {
|
||||
visible: true,
|
||||
alphaFactor: 1,
|
||||
pickable: true,
|
||||
colorOnly: false,
|
||||
syncManually: false,
|
||||
transform: Mat4.identity(),
|
||||
overpaint: Overpaint.Empty,
|
||||
transparency: Transparency.Empty,
|
||||
substance: Substance.Empty,
|
||||
clipping: Clipping.Empty,
|
||||
themeStrength: { overpaint: 1, transparency: 1, substance: 1 },
|
||||
markerActions: MarkerActions.All
|
||||
};
|
||||
}
|
||||
export function updateState(state: State, update: Partial<State>) {
|
||||
if (update.visible !== undefined) state.visible = update.visible;
|
||||
@@ -210,6 +225,7 @@ namespace Representation {
|
||||
if (update.transparency !== undefined) state.transparency = update.transparency;
|
||||
if (update.substance !== undefined) state.substance = update.substance;
|
||||
if (update.clipping !== undefined) state.clipping = update.clipping;
|
||||
if (update.themeStrength !== undefined) state.themeStrength = update.themeStrength;
|
||||
if (update.syncManually !== undefined) state.syncManually = update.syncManually;
|
||||
if (update.transform !== undefined) Mat4.copy(state.transform, update.transform);
|
||||
if (update.markerActions !== undefined) state.markerActions = update.markerActions;
|
||||
@@ -220,7 +236,7 @@ namespace Representation {
|
||||
}
|
||||
export const StateBuilder: StateBuilder<State> = { create: createState, update: updateState };
|
||||
|
||||
export type Any = Representation<any, any, any>
|
||||
export type Any<P extends PD.Params = PD.Params, S extends State = State> = Representation<any, P, S>
|
||||
export const Empty: Any = {
|
||||
label: '', groupCount: 0, renderObjects: [], geometryVersion: -1, props: {}, params: {}, updated: new Subject(), state: createState(), theme: Theme.createEmpty(),
|
||||
createOrUpdate: () => Task.constant('', undefined),
|
||||
@@ -232,7 +248,7 @@ namespace Representation {
|
||||
destroy: () => {}
|
||||
};
|
||||
|
||||
export type Def<D, P extends PD.Params = {}, S extends State = State> = { [k: string]: RepresentationFactory<D, P, S> }
|
||||
export type Def<D, P extends PD.Params = PD.Params, S extends State = State> = { [k: string]: RepresentationFactory<D, P, S> }
|
||||
|
||||
export class GeometryState {
|
||||
private curr = new Set<number>();
|
||||
@@ -256,7 +272,7 @@ namespace Representation {
|
||||
}
|
||||
}
|
||||
|
||||
export function createMulti<D, P extends PD.Params = {}, S extends State = State>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<D, P>, stateBuilder: StateBuilder<S>, reprDefs: Def<D, P>): Representation<D, P, S> {
|
||||
export function createMulti<D, P extends PD.Params = PD.Params, S extends State = State>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<D, P>, stateBuilder: StateBuilder<S>, reprDefs: Def<D, P>): Representation<D, P, S> {
|
||||
let version = 0;
|
||||
const updated = new Subject<number>();
|
||||
const geometryState = new GeometryState();
|
||||
@@ -432,6 +448,7 @@ namespace Representation {
|
||||
if (state.substance !== undefined) {
|
||||
// TODO
|
||||
}
|
||||
if (state.themeStrength !== undefined) Visual.setThemeStrength(renderObject, state.themeStrength);
|
||||
if (state.transform !== undefined) Visual.setTransform(renderObject, state.transform);
|
||||
|
||||
Representation.updateState(currentState, state);
|
||||
|
||||
@@ -127,6 +127,7 @@ export function ComplexRepresentation<P extends StructureParams>(label: string,
|
||||
const remappedClipping = Clipping.remap(state.clipping, _structure);
|
||||
visual.setClipping(remappedClipping);
|
||||
}
|
||||
if (state.themeStrength !== undefined && visual) visual.setThemeStrength(state.themeStrength);
|
||||
if (state.transform !== undefined && visual) visual.setTransform(state.transform);
|
||||
if (state.unitTransforms !== undefined && visual) {
|
||||
// Since ComplexVisuals always renders geometries between units, the application
|
||||
|
||||
@@ -299,6 +299,9 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
|
||||
setClipping(clipping: Clipping) {
|
||||
Visual.setClipping(renderObject, clipping, lociApply, true);
|
||||
},
|
||||
setThemeStrength(strength: { overpaint: number, transparency: number, substance: number }) {
|
||||
Visual.setThemeStrength(renderObject, strength);
|
||||
},
|
||||
destroy() {
|
||||
dispose?.(geometry);
|
||||
if (renderObject) {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { MolecularSurfaceMeshVisual, MolecularSurfaceMeshParams } from '../visual/molecular-surface-mesh';
|
||||
import { MolecularSurfaceMeshVisual, MolecularSurfaceMeshParams, StructureMolecularSurfaceMeshVisual } from '../visual/molecular-surface-mesh';
|
||||
import { UnitsRepresentation } from '../units-representation';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../representation';
|
||||
import { ComplexRepresentation, StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../representation';
|
||||
import { Representation, RepresentationParamsGetter, RepresentationContext } from '../../../mol-repr/representation';
|
||||
import { ThemeRegistryContext } from '../../../mol-theme/theme';
|
||||
import { Structure } from '../../../mol-model/structure';
|
||||
@@ -16,6 +16,7 @@ import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
|
||||
const MolecularSurfaceVisuals = {
|
||||
'molecular-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, MolecularSurfaceMeshParams>) => UnitsRepresentation('Molecular surface mesh', ctx, getParams, MolecularSurfaceMeshVisual),
|
||||
'structure-molecular-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, MolecularSurfaceMeshParams>) => ComplexRepresentation('Structure Molecular surface mesh', ctx, getParams, StructureMolecularSurfaceMeshVisual),
|
||||
'molecular-surface-wireframe': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, MolecularSurfaceWireframeParams>) => UnitsRepresentation('Molecular surface wireframe', ctx, getParams, MolecularSurfaceWireframeVisual),
|
||||
};
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
|
||||
}
|
||||
|
||||
function setVisualState(visual: UnitsVisual<P>, group: Unit.SymmetryGroup, state: Partial<StructureRepresentationState>) {
|
||||
const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, transform, unitTransforms } = state;
|
||||
const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, themeStrength, transform, unitTransforms } = state;
|
||||
|
||||
if (visible !== undefined) visual.setVisibility(visible);
|
||||
if (alphaFactor !== undefined) visual.setAlphaFactor(alphaFactor);
|
||||
@@ -231,6 +231,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
|
||||
if (transparency !== undefined) visual.setTransparency(transparency, webgl);
|
||||
if (substance !== undefined) visual.setSubstance(substance, webgl);
|
||||
if (clipping !== undefined) visual.setClipping(clipping);
|
||||
if (themeStrength !== undefined) visual.setThemeStrength(themeStrength);
|
||||
if (transform !== undefined) visual.setTransform(transform);
|
||||
if (unitTransforms !== undefined) {
|
||||
if (unitTransforms) {
|
||||
@@ -243,7 +244,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
|
||||
}
|
||||
|
||||
function setState(state: Partial<StructureRepresentationState>) {
|
||||
const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, transform, unitTransforms, syncManually, markerActions } = state;
|
||||
const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, themeStrength, transform, unitTransforms, syncManually, markerActions } = state;
|
||||
const newState: Partial<StructureRepresentationState> = {};
|
||||
|
||||
if (visible !== _state.visible) newState.visible = visible;
|
||||
@@ -261,6 +262,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
|
||||
if (clipping !== undefined && _structure) {
|
||||
newState.clipping = Clipping.remap(clipping, _structure);
|
||||
}
|
||||
if (themeStrength !== undefined) newState.themeStrength = themeStrength;
|
||||
if (transform !== undefined && !Mat4.areEqual(transform, _state.transform, EPSILON)) {
|
||||
newState.transform = transform;
|
||||
}
|
||||
|
||||
@@ -381,6 +381,9 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
|
||||
setClipping(clipping: Clipping) {
|
||||
Visual.setClipping(renderObject, clipping, lociApply, true);
|
||||
},
|
||||
setThemeStrength(strength: { overpaint: number, transparency: number, substance: number }) {
|
||||
Visual.setThemeStrength(renderObject, strength);
|
||||
},
|
||||
destroy() {
|
||||
dispose?.(geometry);
|
||||
if (renderObject) {
|
||||
|
||||
@@ -222,6 +222,7 @@ export function InterUnitBondCylinderImpostorVisual(materialId: number): Complex
|
||||
newProps.linkScale !== currentProps.linkScale ||
|
||||
newProps.linkSpacing !== currentProps.linkSpacing ||
|
||||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
|
||||
newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
|
||||
newProps.linkCap !== currentProps.linkCap ||
|
||||
newProps.aromaticScale !== currentProps.aromaticScale ||
|
||||
newProps.aromaticSpacing !== currentProps.aromaticSpacing ||
|
||||
@@ -264,6 +265,7 @@ export function InterUnitBondCylinderMeshVisual(materialId: number): ComplexVisu
|
||||
newProps.linkScale !== currentProps.linkScale ||
|
||||
newProps.linkSpacing !== currentProps.linkSpacing ||
|
||||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
|
||||
newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
|
||||
newProps.linkCap !== currentProps.linkCap ||
|
||||
newProps.aromaticScale !== currentProps.aromaticScale ||
|
||||
newProps.aromaticSpacing !== currentProps.aromaticSpacing ||
|
||||
|
||||
@@ -138,6 +138,7 @@ export function InterUnitBondLineVisual(materialId: number): ComplexVisual<Inter
|
||||
newProps.aromaticDashCount !== currentProps.aromaticDashCount ||
|
||||
newProps.dashCount !== currentProps.dashCount ||
|
||||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
|
||||
newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
|
||||
!arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
|
||||
!arrayEqual(newProps.excludeTypes, currentProps.excludeTypes) ||
|
||||
newProps.multipleBonds !== currentProps.multipleBonds
|
||||
|
||||
@@ -239,6 +239,7 @@ export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVi
|
||||
newProps.linkScale !== currentProps.linkScale ||
|
||||
newProps.linkSpacing !== currentProps.linkSpacing ||
|
||||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
|
||||
newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
|
||||
newProps.linkCap !== currentProps.linkCap ||
|
||||
newProps.aromaticScale !== currentProps.aromaticScale ||
|
||||
newProps.aromaticSpacing !== currentProps.aromaticSpacing ||
|
||||
@@ -286,6 +287,7 @@ export function IntraUnitBondCylinderMeshVisual(materialId: number): UnitsVisual
|
||||
newProps.linkScale !== currentProps.linkScale ||
|
||||
newProps.linkSpacing !== currentProps.linkSpacing ||
|
||||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
|
||||
newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
|
||||
newProps.linkCap !== currentProps.linkCap ||
|
||||
newProps.aromaticScale !== currentProps.aromaticScale ||
|
||||
newProps.aromaticSpacing !== currentProps.aromaticSpacing ||
|
||||
|
||||
@@ -164,6 +164,7 @@ export function IntraUnitBondLineVisual(materialId: number): UnitsVisual<IntraUn
|
||||
newProps.aromaticDashCount !== currentProps.aromaticDashCount ||
|
||||
newProps.dashCount !== currentProps.dashCount ||
|
||||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
|
||||
newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
|
||||
!arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
|
||||
!arrayEqual(newProps.excludeTypes, currentProps.excludeTypes) ||
|
||||
newProps.aromaticBonds !== currentProps.aromaticBonds ||
|
||||
|
||||
@@ -27,6 +27,7 @@ export const ElementCrossParams = {
|
||||
...UnitsLinesParams,
|
||||
lineSizeAttenuation: PD.Boolean(false),
|
||||
ignoreHydrogens: PD.Boolean(false),
|
||||
onlyPolarHydrogens: PD.Boolean(false),
|
||||
traceOnly: PD.Boolean(false),
|
||||
crosses: PD.Select('lone', PD.arrayToOptions(['lone', 'all'] as const)),
|
||||
crossSize: PD.Numeric(0.35, { min: 0, max: 2, step: 0.01 }),
|
||||
@@ -85,6 +86,7 @@ export function ElementCrossVisual(materialId: number): UnitsVisual<ElementCross
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementCrossParams>, currentProps: PD.Values<ElementCrossParams>) => {
|
||||
state.createGeometry = (
|
||||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
|
||||
newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
|
||||
newProps.traceOnly !== currentProps.traceOnly ||
|
||||
newProps.crosses !== currentProps.crosses ||
|
||||
newProps.crossSize !== currentProps.crossSize
|
||||
|
||||
@@ -23,6 +23,7 @@ export const ElementPointParams = {
|
||||
...UnitsPointsParams,
|
||||
pointSizeAttenuation: PD.Boolean(false),
|
||||
ignoreHydrogens: PD.Boolean(false),
|
||||
onlyPolarHydrogens: PD.Boolean(false),
|
||||
traceOnly: PD.Boolean(false),
|
||||
};
|
||||
export type ElementPointParams = typeof ElementPointParams
|
||||
@@ -89,6 +90,7 @@ export function ElementPointVisual(materialId: number): UnitsVisual<ElementPoint
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementPointParams>, currentProps: PD.Values<ElementPointParams>) => {
|
||||
state.createGeometry = (
|
||||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
|
||||
newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
|
||||
newProps.traceOnly !== currentProps.traceOnly
|
||||
);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ export const ElementSphereParams = {
|
||||
sizeFactor: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }),
|
||||
detail: PD.Numeric(0, { min: 0, max: 3, step: 1 }, BaseGeometry.CustomQualityParamInfo),
|
||||
ignoreHydrogens: PD.Boolean(false),
|
||||
onlyPolarHydrogens: PD.Boolean(false),
|
||||
traceOnly: PD.Boolean(false),
|
||||
tryUseImpostor: PD.Boolean(true),
|
||||
};
|
||||
@@ -41,6 +42,7 @@ export function ElementSphereImpostorVisual(materialId: number): UnitsVisual<Ele
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementSphereParams>, currentProps: PD.Values<ElementSphereParams>) => {
|
||||
state.createGeometry = (
|
||||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
|
||||
newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
|
||||
newProps.traceOnly !== currentProps.traceOnly
|
||||
);
|
||||
},
|
||||
@@ -62,6 +64,7 @@ export function ElementSphereMeshVisual(materialId: number): UnitsVisual<Element
|
||||
newProps.sizeFactor !== currentProps.sizeFactor ||
|
||||
newProps.detail !== currentProps.detail ||
|
||||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
|
||||
newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens ||
|
||||
newProps.traceOnly !== currentProps.traceOnly
|
||||
);
|
||||
},
|
||||
|
||||
@@ -43,6 +43,7 @@ export const GaussianDensityVolumeParams = {
|
||||
...ComplexDirectVolumeParams,
|
||||
...GaussianDensityParams,
|
||||
ignoreHydrogens: PD.Boolean(false),
|
||||
onlyPolarHydrogens: PD.Boolean(false),
|
||||
includeParent: PD.Boolean(false, { isHidden: true }),
|
||||
};
|
||||
export type GaussianDensityVolumeParams = typeof GaussianDensityVolumeParams
|
||||
@@ -59,6 +60,7 @@ export function GaussianDensityVolumeVisual(materialId: number): ComplexVisual<G
|
||||
if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
|
||||
if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
|
||||
if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
|
||||
if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
|
||||
if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
|
||||
if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
|
||||
},
|
||||
@@ -99,6 +101,7 @@ export const UnitsGaussianDensityVolumeParams = {
|
||||
...UnitsDirectVolumeParams,
|
||||
...GaussianDensityParams,
|
||||
ignoreHydrogens: PD.Boolean(false),
|
||||
onlyPolarHydrogens: PD.Boolean(false),
|
||||
includeParent: PD.Boolean(false, { isHidden: true }),
|
||||
};
|
||||
export type UnitsGaussianDensityVolumeParams = typeof UnitsGaussianDensityVolumeParams
|
||||
@@ -115,6 +118,7 @@ export function UnitsGaussianDensityVolumeVisual(materialId: number): UnitsVisua
|
||||
if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
|
||||
if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
|
||||
if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
|
||||
if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
|
||||
if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
|
||||
if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
|
||||
},
|
||||
|
||||
@@ -34,6 +34,7 @@ const SharedParams = {
|
||||
...GaussianDensityParams,
|
||||
...ColorSmoothingParams,
|
||||
ignoreHydrogens: PD.Boolean(false),
|
||||
onlyPolarHydrogens: PD.Boolean(false),
|
||||
tryUseGpu: PD.Boolean(true),
|
||||
includeParent: PD.Boolean(false, { isHidden: true }),
|
||||
};
|
||||
@@ -127,6 +128,7 @@ export function GaussianSurfaceMeshVisual(materialId: number): UnitsVisual<Gauss
|
||||
if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
|
||||
if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
|
||||
if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
|
||||
if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
|
||||
if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
|
||||
if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
|
||||
if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
|
||||
@@ -193,6 +195,7 @@ export function StructureGaussianSurfaceMeshVisual(materialId: number): ComplexV
|
||||
if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
|
||||
if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
|
||||
if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
|
||||
if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
|
||||
if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
|
||||
if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
|
||||
state.updateColor = true;
|
||||
@@ -247,6 +250,7 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit,
|
||||
const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, densityTextureData.maxRadius);
|
||||
const surface = TextureMesh.create(gv.vertexCount, groupCount, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
|
||||
(surface.meta as GaussianSurfaceMeta).resolution = densityTextureData.resolution;
|
||||
surface.meta.webgl = ctx.webgl;
|
||||
|
||||
return surface;
|
||||
}
|
||||
@@ -263,6 +267,7 @@ export function GaussianSurfaceTextureMeshVisual(materialId: number): UnitsVisua
|
||||
if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
|
||||
if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
|
||||
if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
|
||||
if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
|
||||
if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
|
||||
if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
|
||||
if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
|
||||
@@ -321,6 +326,7 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str
|
||||
const boundingSphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, densityTextureData.maxRadius);
|
||||
const surface = TextureMesh.create(gv.vertexCount, groupCount, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
|
||||
(surface.meta as GaussianSurfaceMeta).resolution = densityTextureData.resolution;
|
||||
surface.meta.webgl = ctx.webgl;
|
||||
|
||||
return surface;
|
||||
}
|
||||
@@ -337,6 +343,7 @@ export function StructureGaussianSurfaceTextureMeshVisual(materialId: number): C
|
||||
if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
|
||||
if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
|
||||
if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
|
||||
if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
|
||||
if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
|
||||
if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
|
||||
if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
|
||||
|
||||
@@ -41,6 +41,7 @@ export const GaussianWireframeParams = {
|
||||
sizeFactor: PD.Numeric(3, { min: 0, max: 10, step: 0.1 }),
|
||||
lineSizeAttenuation: PD.Boolean(false),
|
||||
ignoreHydrogens: PD.Boolean(false),
|
||||
onlyPolarHydrogens: PD.Boolean(false),
|
||||
includeParent: PD.Boolean(false, { isHidden: true }),
|
||||
};
|
||||
export type GaussianWireframeParams = typeof GaussianWireframeParams
|
||||
@@ -57,6 +58,7 @@ export function GaussianWireframeVisual(materialId: number): UnitsVisual<Gaussia
|
||||
if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
|
||||
if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
|
||||
if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
|
||||
if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
|
||||
if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
|
||||
if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import { VisualContext } from '../../visual';
|
||||
import { Unit, Structure } from '../../../mol-model/structure';
|
||||
import { Theme } from '../../../mol-theme/theme';
|
||||
import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
|
||||
import { computeUnitMolecularSurface } from './util/molecular-surface';
|
||||
import { computeStructureMolecularSurface, computeUnitMolecularSurface } from './util/molecular-surface';
|
||||
import { computeMarchingCubesMesh } from '../../../mol-geo/util/marching-cubes/algorithm';
|
||||
import { ElementIterator, getElementLoci, eachElement } from './util/element';
|
||||
import { ElementIterator, getElementLoci, eachElement, getSerialElementLoci, eachSerialElement } from './util/element';
|
||||
import { VisualUpdateState } from '../../util';
|
||||
import { CommonSurfaceParams } from './util/common';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
@@ -23,6 +23,7 @@ import { WebGLContext } from '../../../mol-gl/webgl/context';
|
||||
import { applyMeshColorSmoothing } from '../../../mol-geo/geometry/mesh/color-smoothing';
|
||||
import { ColorSmoothingParams, getColorSmoothingProps } from '../../../mol-geo/geometry/base';
|
||||
import { ValueCell } from '../../../mol-util';
|
||||
import { ComplexMeshVisual, ComplexVisual } from '../complex-visual';
|
||||
|
||||
export const MolecularSurfaceMeshParams = {
|
||||
...UnitsMeshParams,
|
||||
@@ -82,6 +83,76 @@ export function MolecularSurfaceMeshVisual(materialId: number): UnitsVisual<Mole
|
||||
if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true;
|
||||
if (newProps.probePositions !== currentProps.probePositions) state.createGeometry = true;
|
||||
if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
|
||||
if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
|
||||
if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
|
||||
if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
|
||||
|
||||
if (newProps.smoothColors.name !== currentProps.smoothColors.name) {
|
||||
state.updateColor = true;
|
||||
} else if (newProps.smoothColors.name === 'on' && currentProps.smoothColors.name === 'on') {
|
||||
if (newProps.smoothColors.params.resolutionFactor !== currentProps.smoothColors.params.resolutionFactor) state.updateColor = true;
|
||||
if (newProps.smoothColors.params.sampleStride !== currentProps.smoothColors.params.sampleStride) state.updateColor = true;
|
||||
}
|
||||
},
|
||||
processValues: (values: MeshValues, geometry: Mesh, props: PD.Values<MolecularSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => {
|
||||
const { resolution, colorTexture } = geometry.meta as MolecularSurfaceMeta;
|
||||
const csp = getColorSmoothingProps(props.smoothColors, theme.color.preferSmoothing, resolution);
|
||||
if (csp) {
|
||||
applyMeshColorSmoothing(values, csp.resolution, csp.stride, webgl, colorTexture);
|
||||
(geometry.meta as MolecularSurfaceMeta).colorTexture = values.tColorGrid.ref.value;
|
||||
}
|
||||
},
|
||||
dispose: (geometry: Mesh) => {
|
||||
(geometry.meta as MolecularSurfaceMeta).colorTexture?.destroy();
|
||||
}
|
||||
}, materialId);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
async function createStructureMolecularSurfaceMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: MolecularSurfaceMeshProps, mesh?: Mesh): Promise<Mesh> {
|
||||
const { transform, field, idField, resolution, maxRadius } = await computeStructureMolecularSurface(structure, theme.size, props).runInContext(ctx.runtime);
|
||||
|
||||
const params = {
|
||||
isoLevel: props.probeRadius,
|
||||
scalarField: field,
|
||||
idField
|
||||
};
|
||||
const surface = await computeMarchingCubesMesh(params, mesh).runAsChild(ctx.runtime);
|
||||
|
||||
if (props.includeParent) {
|
||||
const iterations = Math.ceil(2 / props.resolution);
|
||||
Mesh.smoothEdges(surface, { iterations, maxNewEdgeLength: Math.sqrt(2) });
|
||||
}
|
||||
|
||||
Mesh.transform(surface, transform);
|
||||
if (ctx.webgl && !ctx.webgl.isWebGL2) {
|
||||
Mesh.uniformTriangleGroup(surface);
|
||||
ValueCell.updateIfChanged(surface.varyingGroup, false);
|
||||
} else {
|
||||
ValueCell.updateIfChanged(surface.varyingGroup, true);
|
||||
}
|
||||
|
||||
const sphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, maxRadius);
|
||||
surface.setBoundingSphere(sphere);
|
||||
(surface.meta as MolecularSurfaceMeta).resolution = resolution;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
export function StructureMolecularSurfaceMeshVisual(materialId: number): ComplexVisual<MolecularSurfaceMeshParams> {
|
||||
return ComplexMeshVisual<MolecularSurfaceMeshParams>({
|
||||
defaultProps: PD.getDefaultValues(MolecularSurfaceMeshParams),
|
||||
createGeometry: createStructureMolecularSurfaceMesh,
|
||||
createLocationIterator: ElementIterator.fromStructure,
|
||||
getLoci: getSerialElementLoci,
|
||||
eachLocation: eachSerialElement,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<MolecularSurfaceMeshParams>, currentProps: PD.Values<MolecularSurfaceMeshParams>) => {
|
||||
if (newProps.resolution !== currentProps.resolution) state.createGeometry = true;
|
||||
if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true;
|
||||
if (newProps.probePositions !== currentProps.probePositions) state.createGeometry = true;
|
||||
if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
|
||||
if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
|
||||
if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
|
||||
if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ export function MolecularSurfaceWireframeVisual(materialId: number): UnitsVisual
|
||||
if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true;
|
||||
if (newProps.probePositions !== currentProps.probePositions) state.createGeometry = true;
|
||||
if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
|
||||
if (newProps.onlyPolarHydrogens !== currentProps.onlyPolarHydrogens) state.createGeometry = true;
|
||||
if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
|
||||
}
|
||||
}, materialId);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { BondType } from '../../../../mol-model/structure/model/types';
|
||||
@@ -14,11 +15,13 @@ import { PickingId } from '../../../../mol-geo/geometry/picking';
|
||||
import { EmptyLoci, Loci } from '../../../../mol-model/loci';
|
||||
import { Interval, OrderedSet, SortedArray } from '../../../../mol-data/int';
|
||||
import { isH, isHydrogen, StructureGroup } from './common';
|
||||
import { hasPolarNeighbour } from '../../../../mol-model-props/computed/chemistry/functional-group';
|
||||
|
||||
export const BondParams = {
|
||||
includeTypes: PD.MultiSelect(ObjectKeys(BondType.Names), PD.objectToOptions(BondType.Names)),
|
||||
excludeTypes: PD.MultiSelect([] as BondType.Names[], PD.objectToOptions(BondType.Names)),
|
||||
ignoreHydrogens: PD.Boolean(false),
|
||||
onlyPolarHydrogens: PD.Boolean(false),
|
||||
aromaticBonds: PD.Boolean(true, { description: 'Display aromatic bonds with dashes' }),
|
||||
multipleBonds: PD.Select('symmetric', PD.arrayToOptions(['off', 'symmetric', 'offset'] as const)),
|
||||
};
|
||||
@@ -51,7 +54,7 @@ export function makeIntraBondIgnoreTest(structure: Structure, unit: Unit.Atomic,
|
||||
const { a, b, edgeProps } = bonds;
|
||||
const { flags: _flags } = edgeProps;
|
||||
|
||||
const { ignoreHydrogens, includeTypes, excludeTypes } = props;
|
||||
const { ignoreHydrogens, onlyPolarHydrogens, includeTypes, excludeTypes } = props;
|
||||
|
||||
const include = BondType.fromNames(includeTypes);
|
||||
const exclude = BondType.fromNames(excludeTypes);
|
||||
@@ -61,14 +64,31 @@ export function makeIntraBondIgnoreTest(structure: Structure, unit: Unit.Atomic,
|
||||
const childUnit = child?.unitMap.get(unit.id);
|
||||
if (child && !childUnit) throw new Error('expected childUnit to exist if child exists');
|
||||
|
||||
if (allBondTypes && !ignoreHydrogens && !child) return;
|
||||
if (allBondTypes && !onlyPolarHydrogens && !ignoreHydrogens && !child) return;
|
||||
|
||||
return (edgeIndex: number) => {
|
||||
return (
|
||||
(!!childUnit && !SortedArray.has(childUnit.elements, elements[a[edgeIndex]])) ||
|
||||
(ignoreHydrogens && (isH(atomicNumber, elements[a[edgeIndex]]) || isH(atomicNumber, elements[b[edgeIndex]]))) ||
|
||||
(!allBondTypes && ignoreBondType(include, exclude, _flags[edgeIndex]))
|
||||
);
|
||||
const aI = a[edgeIndex];
|
||||
const bI = b[edgeIndex];
|
||||
|
||||
if ((!!childUnit && !SortedArray.has(childUnit.elements, elements[aI]))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!allBondTypes && ignoreBondType(include, exclude, _flags[edgeIndex])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ignoreHydrogens && !onlyPolarHydrogens) return false;
|
||||
if (isH(atomicNumber, elements[aI])) {
|
||||
if (ignoreHydrogens) return true;
|
||||
if (onlyPolarHydrogens && !hasPolarNeighbour(structure, unit, aI)) return true;
|
||||
}
|
||||
if (isH(atomicNumber, elements[bI])) {
|
||||
if (ignoreHydrogens) return true;
|
||||
if (onlyPolarHydrogens && !hasPolarNeighbour(structure, unit, bI)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -76,7 +96,7 @@ export function makeInterBondIgnoreTest(structure: Structure, props: BondProps):
|
||||
const bonds = structure.interUnitBonds;
|
||||
const { edges } = bonds;
|
||||
|
||||
const { ignoreHydrogens, includeTypes, excludeTypes } = props;
|
||||
const { ignoreHydrogens, onlyPolarHydrogens, includeTypes, excludeTypes } = props;
|
||||
|
||||
const include = BondType.fromNames(includeTypes);
|
||||
const exclude = BondType.fromNames(excludeTypes);
|
||||
@@ -84,7 +104,7 @@ export function makeInterBondIgnoreTest(structure: Structure, props: BondProps):
|
||||
|
||||
const { child } = structure;
|
||||
|
||||
if (allBondTypes && !ignoreHydrogens && !child) return;
|
||||
if (allBondTypes && !onlyPolarHydrogens && !ignoreHydrogens && !child) return;
|
||||
|
||||
return (edgeIndex: number) => {
|
||||
if (child) {
|
||||
@@ -104,6 +124,18 @@ export function makeInterBondIgnoreTest(structure: Structure, props: BondProps):
|
||||
if (isHydrogen(uA, uA.elements[b.indexA]) || isHydrogen(uB, uB.elements[b.indexB])) return true;
|
||||
}
|
||||
|
||||
if (onlyPolarHydrogens) {
|
||||
const b = edges[edgeIndex];
|
||||
const uA = structure.unitMap.get(b.unitA);
|
||||
if (isHydrogen(uA, uA.elements[b.indexA]) && !hasPolarNeighbour(structure, uA as Unit.Atomic, b.indexA)) {
|
||||
return true;
|
||||
}
|
||||
const uB = structure.unitMap.get(b.unitB);
|
||||
if (isHydrogen(uB, uB.elements[b.indexB]) && !hasPolarNeighbour(structure, uB as Unit.Atomic, b.indexB)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!allBondTypes) {
|
||||
if (ignoreBondType(include, exclude, edges[edgeIndex].props.flag)) return true;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Unit, Structure, ElementIndex, StructureElement, ResidueIndex } from '../../../../mol-model/structure';
|
||||
@@ -16,6 +17,7 @@ import { AssignableArrayLike } from '../../../../mol-util/type-helpers';
|
||||
import { getBoundary } from '../../../../mol-math/geometry/boundary';
|
||||
import { Box3D } from '../../../../mol-math/geometry';
|
||||
import { SizeTheme } from '../../../../mol-theme/size';
|
||||
import { hasPolarNeighbour } from '../../../../mol-model-props/computed/chemistry/functional-group';
|
||||
|
||||
/** Return a Loci for the elements of a whole residue the elementIndex belongs to. */
|
||||
export function getResidueLoci(structure: Structure, unit: Unit.Atomic, elementIndex: ElementIndex): Loci {
|
||||
@@ -139,6 +141,7 @@ export function getConformation(unit: Unit) {
|
||||
|
||||
export const CommonSurfaceParams = {
|
||||
ignoreHydrogens: PD.Boolean(false, { description: 'Whether or not to include hydrogen atoms in the surface calculation.' }),
|
||||
onlyPolarHydrogens: PD.Boolean(false, { description: 'Whether or not to include polar hydrogen atoms in the surface calculation.' }),
|
||||
traceOnly: PD.Boolean(false, { description: 'Whether or not to only use trace atoms in the surface calculation.' }),
|
||||
includeParent: PD.Boolean(false, { description: 'Include elements of the parent structure in surface calculation to get a surface patch of the current structure.' }),
|
||||
};
|
||||
@@ -151,7 +154,7 @@ function squaredDistance(x: number, y: number, z: number, center: Vec3) {
|
||||
}
|
||||
|
||||
/** marks `indices` for filtering/ignoring in `id` when not in `elements` */
|
||||
function filterId(id: AssignableArrayLike<number>, elements: SortedArray, indices: SortedArray) {
|
||||
function filterUnitId(id: AssignableArrayLike<number>, elements: SortedArray, indices: SortedArray) {
|
||||
let start = 0;
|
||||
const end = elements.length;
|
||||
for (let i = 0, il = indices.length; i < il; ++i) {
|
||||
@@ -166,26 +169,28 @@ function filterId(id: AssignableArrayLike<number>, elements: SortedArray, indice
|
||||
}
|
||||
|
||||
export function getUnitConformationAndRadius(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: CommonSurfaceProps) {
|
||||
const { ignoreHydrogens, traceOnly, includeParent } = props;
|
||||
const { ignoreHydrogens, onlyPolarHydrogens, traceOnly, includeParent } = props;
|
||||
const rootUnit = includeParent ? structure.root.unitMap.get(unit.id) : unit;
|
||||
const differentRoot = includeParent && rootUnit !== unit;
|
||||
|
||||
const { x, y, z } = getConformation(rootUnit);
|
||||
const { elements } = rootUnit;
|
||||
const { center, radius: sphereRadius } = unit.boundary.sphere;
|
||||
const extraRadius = (2 + 1.5) * 2; // TODO should be twice (the max vdW/sphere radius plus the probe radius)
|
||||
const extraRadius = (4 + 1.5) * 2; // TODO should be twice (the max vdW/sphere radius plus the probe radius)
|
||||
const radiusSq = (sphereRadius + extraRadius) * (sphereRadius + extraRadius);
|
||||
|
||||
let indices: SortedArray<ElementIndex>;
|
||||
let id: AssignableArrayLike<number>;
|
||||
|
||||
if (ignoreHydrogens || traceOnly || (includeParent && rootUnit !== unit)) {
|
||||
const _indices = [];
|
||||
const _id = [];
|
||||
if (ignoreHydrogens || onlyPolarHydrogens || traceOnly || differentRoot) {
|
||||
const _indices: number[] = [];
|
||||
const _id: number[] = [];
|
||||
for (let i = 0, il = elements.length; i < il; ++i) {
|
||||
const eI = elements[i];
|
||||
if (ignoreHydrogens && isHydrogen(rootUnit, eI)) continue;
|
||||
if (onlyPolarHydrogens && isHydrogen(rootUnit, eI) && Unit.isAtomic(rootUnit) && !hasPolarNeighbour(structure, rootUnit, SortedArray.indexOf(rootUnit.elements, eI) as StructureElement.UnitIndex)) continue;
|
||||
if (traceOnly && !isTrace(rootUnit, eI)) continue;
|
||||
if (includeParent && squaredDistance(x[eI], y[eI], z[eI], center) > radiusSq) continue;
|
||||
if (differentRoot && squaredDistance(x[eI], y[eI], z[eI], center) > radiusSq) continue;
|
||||
|
||||
_indices.push(eI);
|
||||
_id.push(i);
|
||||
@@ -198,11 +203,11 @@ export function getUnitConformationAndRadius(structure: Structure, unit: Unit, s
|
||||
}
|
||||
|
||||
if (includeParent && rootUnit !== unit) {
|
||||
filterId(id, unit.elements, indices);
|
||||
filterUnitId(id, unit.elements, indices);
|
||||
}
|
||||
|
||||
const position = { indices, x, y, z, id };
|
||||
const boundary = unit === rootUnit ? unit.boundary : getBoundary(position);
|
||||
const boundary = differentRoot ? getBoundary(position) : unit.boundary;
|
||||
|
||||
const l = StructureElement.Location.create(structure, rootUnit);
|
||||
const radius = (index: number) => {
|
||||
@@ -213,43 +218,68 @@ export function getUnitConformationAndRadius(structure: Structure, unit: Unit, s
|
||||
return { position, boundary, radius };
|
||||
}
|
||||
|
||||
export function getStructureConformationAndRadius(structure: Structure, sizeTheme: SizeTheme<any>, ignoreHydrogens: boolean, traceOnly: boolean) {
|
||||
const l = StructureElement.Location.create(structure);
|
||||
export function getStructureConformationAndRadius(structure: Structure, sizeTheme: SizeTheme<any>, props: CommonSurfaceProps) {
|
||||
const { ignoreHydrogens, onlyPolarHydrogens, traceOnly, includeParent } = props;
|
||||
const differentRoot = includeParent && !!structure.parent;
|
||||
const l = StructureElement.Location.create(structure.root);
|
||||
|
||||
const { center, radius: sphereRadius } = structure.boundary.sphere;
|
||||
const extraRadius = (4 + 1.5) * 2; // TODO should be twice (the max vdW/sphere radius plus the probe radius)
|
||||
const radiusSq = (sphereRadius + extraRadius) * (sphereRadius + extraRadius);
|
||||
|
||||
let xs: ArrayLike<number>;
|
||||
let ys: ArrayLike<number>;
|
||||
let zs: ArrayLike<number>;
|
||||
let rs: ArrayLike<number>;
|
||||
let id: ArrayLike<number>;
|
||||
let id: AssignableArrayLike<number>;
|
||||
let indices: OrderedSet<number>;
|
||||
|
||||
if (ignoreHydrogens || onlyPolarHydrogens || traceOnly || differentRoot) {
|
||||
const { getSerialIndex } = structure.serialMapping;
|
||||
const units = differentRoot ? structure.root.units : structure.units;
|
||||
|
||||
if (ignoreHydrogens || traceOnly) {
|
||||
const _xs: number[] = [];
|
||||
const _ys: number[] = [];
|
||||
const _zs: number[] = [];
|
||||
const _rs: number[] = [];
|
||||
const _id: number[] = [];
|
||||
for (let i = 0, m = 0, il = structure.units.length; i < il; ++i) {
|
||||
const unit = structure.units[i];
|
||||
for (let i = 0, il = units.length; i < il; ++i) {
|
||||
const unit = units[i];
|
||||
const { elements } = unit;
|
||||
const { x, y, z } = unit.conformation;
|
||||
const childUnit = structure.unitMap.get(unit.id);
|
||||
|
||||
l.unit = unit;
|
||||
for (let j = 0, jl = elements.length; j < jl; ++j) {
|
||||
const eI = elements[j];
|
||||
if (ignoreHydrogens && isHydrogen(unit, eI)) continue;
|
||||
if (onlyPolarHydrogens && isHydrogen(unit, eI) && Unit.isAtomic(unit) && !hasPolarNeighbour(structure, unit, SortedArray.indexOf(unit.elements, eI) as StructureElement.UnitIndex)) continue;
|
||||
if (traceOnly && !isTrace(unit, eI)) continue;
|
||||
|
||||
_xs.push(x(eI));
|
||||
_ys.push(y(eI));
|
||||
_zs.push(z(eI));
|
||||
const _x = x(eI), _y = y(eI), _z = z(eI);
|
||||
if (differentRoot && squaredDistance(_x, _y, _z, center) > radiusSq) continue;
|
||||
|
||||
_xs.push(_x);
|
||||
_ys.push(_y);
|
||||
_zs.push(_z);
|
||||
l.element = eI;
|
||||
_rs.push(sizeTheme.size(l));
|
||||
_id.push(m + j);
|
||||
|
||||
if (differentRoot) {
|
||||
const idx = childUnit ? SortedArray.indexOf(childUnit.elements, eI) : -1;
|
||||
if (idx === -1) {
|
||||
_id.push(-2); // mark for filtering/ignoring when not in `elements`
|
||||
} else {
|
||||
_id.push(getSerialIndex(childUnit, eI));
|
||||
}
|
||||
} else {
|
||||
_id.push(getSerialIndex(unit, eI));
|
||||
}
|
||||
}
|
||||
m += elements.length;
|
||||
}
|
||||
xs = _xs, ys = _ys, zs = _zs, rs = _rs;
|
||||
id = _id;
|
||||
indices = OrderedSet.ofRange(0, id.length);
|
||||
} else {
|
||||
const { elementCount } = structure;
|
||||
const _xs = new Float32Array(elementCount);
|
||||
@@ -275,12 +305,14 @@ export function getStructureConformationAndRadius(structure: Structure, sizeThem
|
||||
}
|
||||
xs = _xs, ys = _ys, zs = _zs, rs = _rs;
|
||||
id = fillSerial(new Uint32Array(elementCount));
|
||||
indices = OrderedSet.ofRange(0, id.length);
|
||||
}
|
||||
|
||||
const position = { indices: OrderedSet.ofRange(0, id.length), x: xs, y: ys, z: zs, id };
|
||||
const position = { indices, x: xs, y: ys, z: zs, id };
|
||||
const boundary = differentRoot ? getBoundary(position) : structure.boundary;
|
||||
const radius = (index: number) => rs[index];
|
||||
|
||||
return { position, radius };
|
||||
return { position, boundary, radius };
|
||||
}
|
||||
|
||||
const _H = AtomicNumbers['H'];
|
||||
|
||||
@@ -21,12 +21,14 @@ import { Spheres } from '../../../../mol-geo/geometry/spheres/spheres';
|
||||
import { SpheresBuilder } from '../../../../mol-geo/geometry/spheres/spheres-builder';
|
||||
import { isTrace, isH, StructureGroup } from './common';
|
||||
import { Sphere3D } from '../../../../mol-math/geometry';
|
||||
import { hasPolarNeighbour } from '../../../../mol-model-props/computed/chemistry/functional-group';
|
||||
|
||||
// avoiding namespace lookup improved performance in Chrome (Aug 2020)
|
||||
const v3add = Vec3.add;
|
||||
|
||||
type ElementProps = {
|
||||
ignoreHydrogens: boolean,
|
||||
onlyPolarHydrogens: boolean,
|
||||
traceOnly: boolean,
|
||||
}
|
||||
|
||||
@@ -36,7 +38,7 @@ export type ElementSphereMeshProps = {
|
||||
} & ElementProps
|
||||
|
||||
export function makeElementIgnoreTest(structure: Structure, unit: Unit, props: ElementProps): undefined | ((i: ElementIndex) => boolean) {
|
||||
const { ignoreHydrogens, traceOnly } = props;
|
||||
const { ignoreHydrogens, onlyPolarHydrogens, traceOnly } = props;
|
||||
|
||||
const { atomicNumber } = unit.model.atomicHierarchy.derived.atom;
|
||||
const isCoarse = Unit.isCoarse(unit);
|
||||
@@ -45,14 +47,26 @@ export function makeElementIgnoreTest(structure: Structure, unit: Unit, props: E
|
||||
const childUnit = child?.unitMap.get(unit.id);
|
||||
if (child && !childUnit) throw new Error('expected childUnit to exist if child exists');
|
||||
|
||||
if (!child && !ignoreHydrogens && !traceOnly) return;
|
||||
if (!child && !ignoreHydrogens && !traceOnly && !onlyPolarHydrogens) return;
|
||||
|
||||
return (element: ElementIndex) => {
|
||||
return (
|
||||
(!!childUnit && !SortedArray.has(childUnit.elements, element)) ||
|
||||
(!isCoarse && ignoreHydrogens && isH(atomicNumber, element)) ||
|
||||
(traceOnly && !isTrace(unit, element))
|
||||
);
|
||||
if (!!childUnit && !SortedArray.has(childUnit.elements, element)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (traceOnly && !isTrace(unit, element)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isCoarse) return false;
|
||||
|
||||
if (!isH(atomicNumber, element)) return false;
|
||||
if (ignoreHydrogens) return true;
|
||||
if (onlyPolarHydrogens) {
|
||||
return !hasPolarNeighbour(structure, unit, SortedArray.indexOf(unit.elements, element) as StructureElement.UnitIndex);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -34,56 +34,51 @@ export function getTextureMaxCells(webgl: WebGLContext, structure?: Structure) {
|
||||
//
|
||||
|
||||
export function computeUnitGaussianDensity(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: GaussianDensityProps) {
|
||||
const { box } = unit.lookup3d.boundary;
|
||||
const p = ensureReasonableResolution(box, props);
|
||||
const { position, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, p);
|
||||
const { position, boundary, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, props);
|
||||
const p = ensureReasonableResolution(boundary.box, props);
|
||||
return Task.create('Gaussian Density', async ctx => {
|
||||
return await GaussianDensityCPU(ctx, position, box, radius, p);
|
||||
return await GaussianDensityCPU(ctx, position, boundary.box, radius, p);
|
||||
});
|
||||
}
|
||||
|
||||
export function computeUnitGaussianDensityTexture(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
|
||||
const { box } = unit.lookup3d.boundary;
|
||||
const p = ensureReasonableResolution(box, props, getTextureMaxCells(webgl, structure));
|
||||
const { position, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, p);
|
||||
const { position, boundary, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, props);
|
||||
const p = ensureReasonableResolution(boundary.box, props, getTextureMaxCells(webgl, structure));
|
||||
return Task.create('Gaussian Density', async ctx => {
|
||||
return GaussianDensityTexture(webgl, position, box, radius, p, texture);
|
||||
return GaussianDensityTexture(webgl, position, boundary.box, radius, p, texture);
|
||||
});
|
||||
}
|
||||
|
||||
export function computeUnitGaussianDensityTexture2d(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, powerOfTwo: boolean, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
|
||||
const { box } = unit.lookup3d.boundary;
|
||||
const p = ensureReasonableResolution(box, props, getTextureMaxCells(webgl, structure));
|
||||
const { position, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, p);
|
||||
const { position, boundary, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, props);
|
||||
const p = ensureReasonableResolution(boundary.box, props, getTextureMaxCells(webgl, structure));
|
||||
return Task.create('Gaussian Density', async ctx => {
|
||||
return GaussianDensityTexture2d(webgl, position, box, radius, powerOfTwo, p, texture);
|
||||
return GaussianDensityTexture2d(webgl, position, boundary.box, radius, powerOfTwo, p, texture);
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
export function computeStructureGaussianDensity(structure: Structure, sizeTheme: SizeTheme<any>, props: GaussianDensityProps) {
|
||||
const { box } = structure.lookup3d.boundary;
|
||||
const p = ensureReasonableResolution(box, props);
|
||||
const { position, radius } = getStructureConformationAndRadius(structure, sizeTheme, props.ignoreHydrogens, props.traceOnly);
|
||||
const { position, boundary, radius } = getStructureConformationAndRadius(structure, sizeTheme, props);
|
||||
const p = ensureReasonableResolution(boundary.box, props);
|
||||
return Task.create('Gaussian Density', async ctx => {
|
||||
return await GaussianDensityCPU(ctx, position, box, radius, p);
|
||||
return await GaussianDensityCPU(ctx, position, boundary.box, radius, p);
|
||||
});
|
||||
}
|
||||
|
||||
export function computeStructureGaussianDensityTexture(structure: Structure, sizeTheme: SizeTheme<any>, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
|
||||
const { box } = structure.lookup3d.boundary;
|
||||
const p = ensureReasonableResolution(box, props, getTextureMaxCells(webgl));
|
||||
const { position, radius } = getStructureConformationAndRadius(structure, sizeTheme, props.ignoreHydrogens, props.traceOnly);
|
||||
const { position, boundary, radius } = getStructureConformationAndRadius(structure, sizeTheme, props);
|
||||
const p = ensureReasonableResolution(boundary.box, props);
|
||||
return Task.create('Gaussian Density', async ctx => {
|
||||
return GaussianDensityTexture(webgl, position, box, radius, p, texture);
|
||||
return GaussianDensityTexture(webgl, position, boundary.box, radius, p, texture);
|
||||
});
|
||||
}
|
||||
|
||||
export function computeStructureGaussianDensityTexture2d(structure: Structure, sizeTheme: SizeTheme<any>, powerOfTwo: boolean, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
|
||||
const { box } = structure.lookup3d.boundary;
|
||||
const p = ensureReasonableResolution(box, props, getTextureMaxCells(webgl));
|
||||
const { position, radius } = getStructureConformationAndRadius(structure, sizeTheme, props.ignoreHydrogens, props.traceOnly);
|
||||
const { position, boundary, radius } = getStructureConformationAndRadius(structure, sizeTheme, props);
|
||||
const p = ensureReasonableResolution(boundary.box, props);
|
||||
return Task.create('Gaussian Density', async ctx => {
|
||||
return GaussianDensityTexture2d(webgl, position, box, radius, powerOfTwo, p, texture);
|
||||
});
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Unit, Structure } from '../../../../mol-model/structure';
|
||||
import { Task, RuntimeContext } from '../../../../mol-task';
|
||||
import { getUnitConformationAndRadius, CommonSurfaceProps, ensureReasonableResolution } from './common';
|
||||
import { getUnitConformationAndRadius, CommonSurfaceProps, ensureReasonableResolution, getStructureConformationAndRadius } from './common';
|
||||
import { PositionData, DensityData, Box3D } from '../../../../mol-math/geometry';
|
||||
import { MolecularSurfaceCalculationProps, calcMolecularSurface } from '../../../../mol-math/geometry/molecular-surface';
|
||||
import { OrderedSet } from '../../../../mol-data/int';
|
||||
@@ -15,7 +15,7 @@ import { SizeTheme } from '../../../../mol-theme/size';
|
||||
|
||||
export type MolecularSurfaceProps = MolecularSurfaceCalculationProps & CommonSurfaceProps
|
||||
|
||||
function getPositionDataAndMaxRadius(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: MolecularSurfaceProps) {
|
||||
function getUnitPositionDataAndMaxRadius(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: MolecularSurfaceProps) {
|
||||
const { probeRadius } = props;
|
||||
const { position, boundary, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, props);
|
||||
const { indices } = position;
|
||||
@@ -34,11 +34,38 @@ function getPositionDataAndMaxRadius(structure: Structure, unit: Unit, sizeTheme
|
||||
}
|
||||
|
||||
export function computeUnitMolecularSurface(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: MolecularSurfaceProps) {
|
||||
const { box } = unit.lookup3d.boundary;
|
||||
const p = ensureReasonableResolution(box, props);
|
||||
const { position, boundary, maxRadius } = getPositionDataAndMaxRadius(structure, unit, sizeTheme, p);
|
||||
const { position, boundary, maxRadius } = getUnitPositionDataAndMaxRadius(structure, unit, sizeTheme, props);
|
||||
const p = ensureReasonableResolution(boundary.box, props);
|
||||
return Task.create('Molecular Surface', async ctx => {
|
||||
return await MolecularSurface(ctx, position, boundary, maxRadius, box, p);
|
||||
return await MolecularSurface(ctx, position, boundary, maxRadius, boundary.box, p);
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
function getStructurePositionDataAndMaxRadius(structure: Structure, sizeTheme: SizeTheme<any>, props: MolecularSurfaceProps) {
|
||||
const { probeRadius } = props;
|
||||
const { position, boundary, radius } = getStructureConformationAndRadius(structure, sizeTheme, props);
|
||||
const { indices } = position;
|
||||
const n = OrderedSet.size(indices);
|
||||
const radii = new Float32Array(OrderedSet.end(indices));
|
||||
|
||||
let maxRadius = 0;
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const j = OrderedSet.getAt(indices, i);
|
||||
const r = radius(j);
|
||||
if (maxRadius < r) maxRadius = r;
|
||||
radii[j] = r + probeRadius;
|
||||
}
|
||||
|
||||
return { position: { ...position, radius: radii }, boundary, maxRadius };
|
||||
}
|
||||
|
||||
export function computeStructureMolecularSurface(structure: Structure, sizeTheme: SizeTheme<any>, props: MolecularSurfaceProps) {
|
||||
const { position, boundary, maxRadius } = getStructurePositionDataAndMaxRadius(structure, sizeTheme, props);
|
||||
const p = ensureReasonableResolution(boundary.box, props);
|
||||
return Task.create('Molecular Surface', async ctx => {
|
||||
return await MolecularSurface(ctx, position, boundary, maxRadius, boundary.box, p);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ export type QualityThresholds = typeof DefaultQualityThresholds
|
||||
export function getStructureQuality(structure: Structure, tresholds: Partial<QualityThresholds> = {}): VisualQuality {
|
||||
const t = { ...DefaultQualityThresholds, ...tresholds };
|
||||
let score = structure.elementCount * t.elementCountFactor;
|
||||
if (structure.isCoarseGrained) score *= t.coarseGrainedFactor;
|
||||
if (structure.isCoarseGrained || structure.isCoarse) score *= t.coarseGrainedFactor;
|
||||
if (score > t.lowestElementCount) {
|
||||
return 'lowest';
|
||||
} else if (score > t.lowerElementCount) {
|
||||
|
||||
@@ -55,6 +55,7 @@ interface Visual<D, P extends PD.Params> {
|
||||
setTransparency: (transparency: Transparency, webgl?: WebGLContext) => void
|
||||
setSubstance: (substance: Substance, webgl?: WebGLContext) => void
|
||||
setClipping: (clipping: Clipping) => void
|
||||
setThemeStrength: (strength: { overpaint: number, transparency: number, substance: number }) => void
|
||||
destroy: () => void
|
||||
mustRecreate?: (data: D, props: PD.Values<P>, webgl?: WebGLContext) => boolean
|
||||
}
|
||||
@@ -349,6 +350,14 @@ namespace Visual {
|
||||
ValueCell.updateIfChanged(dClipping, clipping.layers.length > 0);
|
||||
}
|
||||
|
||||
export function setThemeStrength(renderObject: GraphicsRenderObject | undefined, strength: { overpaint: number, transparency: number, substance: number }) {
|
||||
if (renderObject) {
|
||||
ValueCell.updateIfChanged(renderObject.values.uOverpaintStrength, strength.overpaint);
|
||||
ValueCell.updateIfChanged(renderObject.values.uTransparencyStrength, strength.transparency);
|
||||
ValueCell.updateIfChanged(renderObject.values.uSubstanceStrength, strength.substance);
|
||||
}
|
||||
}
|
||||
|
||||
export function setTransform(renderObject: GraphicsRenderObject | undefined, transform?: Mat4, instanceTransforms?: Float32Array | null) {
|
||||
if (!renderObject || (!transform && !instanceTransforms)) return;
|
||||
|
||||
|
||||
@@ -201,6 +201,7 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol
|
||||
|
||||
const groupCount = volume.grid.cells.data.length;
|
||||
const surface = TextureMesh.create(gv.vertexCount, groupCount, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh);
|
||||
surface.meta.webgl = ctx.webgl;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
@@ -252,6 +252,9 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet
|
||||
setClipping(clipping: Clipping) {
|
||||
return Visual.setClipping(renderObject, clipping, lociApply, true);
|
||||
},
|
||||
setThemeStrength(strength: { overpaint: number, transparency: number, substance: number }) {
|
||||
Visual.setThemeStrength(renderObject, strength);
|
||||
},
|
||||
destroy() {
|
||||
dispose?.(geometry);
|
||||
if (renderObject) {
|
||||
|
||||
@@ -273,6 +273,7 @@ const atomProperty = {
|
||||
|
||||
sourceIndex: atomProp(Type.Num, 'Index of the atom/element in the input file.'),
|
||||
operatorName: atomProp(Type.Str, 'Name of the symmetry operator applied to this element.'),
|
||||
operatorKey: atomProp(Type.Num, 'Key of the symmetry operator applied to this element.'),
|
||||
modelIndex: atomProp(Type.Num, 'Index of the model in the input file.'),
|
||||
modelLabel: atomProp(Type.Str, 'Label/header of the model in the input file.')
|
||||
},
|
||||
|
||||
@@ -299,6 +299,7 @@ const symbols = [
|
||||
D(MolScript.structureQuery.atomProperty.core.z, atomProp(StructureProperties.atom.z)),
|
||||
D(MolScript.structureQuery.atomProperty.core.sourceIndex, atomProp(StructureProperties.atom.sourceIndex)),
|
||||
D(MolScript.structureQuery.atomProperty.core.operatorName, atomProp(StructureProperties.unit.operator_name)),
|
||||
D(MolScript.structureQuery.atomProperty.core.operatorKey, atomProp(StructureProperties.unit.operator_key)),
|
||||
D(MolScript.structureQuery.atomProperty.core.modelIndex, atomProp(StructureProperties.unit.model_index)),
|
||||
D(MolScript.structureQuery.atomProperty.core.modelLabel, atomProp(StructureProperties.unit.model_label)),
|
||||
D(MolScript.structureQuery.atomProperty.core.atomKey, (ctx, xs) => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2018 Mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 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>
|
||||
*/
|
||||
|
||||
import { UniqueArray } from '../../../mol-data/generic';
|
||||
@@ -205,6 +206,7 @@ export const SymbolTable = [
|
||||
Alias(MolScript.structureQuery.atomProperty.core.z, 'atom.z'),
|
||||
Alias(MolScript.structureQuery.atomProperty.core.sourceIndex, 'atom.src-index'),
|
||||
Alias(MolScript.structureQuery.atomProperty.core.operatorName, 'atom.op-name'),
|
||||
Alias(MolScript.structureQuery.atomProperty.core.operatorKey, 'atom.op-key'),
|
||||
Alias(MolScript.structureQuery.atomProperty.core.modelIndex, 'atom.model-index'),
|
||||
Alias(MolScript.structureQuery.atomProperty.core.modelLabel, 'atom.model-label'),
|
||||
Alias(MolScript.structureQuery.atomProperty.core.atomKey, 'atom.key'),
|
||||
@@ -253,6 +255,7 @@ export const SymbolTable = [
|
||||
'Bond Properties',
|
||||
Alias(MolScript.structureQuery.bondProperty.order, 'bond.order'),
|
||||
Alias(MolScript.structureQuery.bondProperty.length, 'bond.length'),
|
||||
Alias(MolScript.structureQuery.bondProperty.key, 'bond.key'),
|
||||
Alias(MolScript.structureQuery.bondProperty.atomA, 'bond.atom-a'),
|
||||
Alias(MolScript.structureQuery.bondProperty.atomB, 'bond.atom-b'),
|
||||
Macro(MSymbol('bond.is', Arguments.List(StructureQueryTypes.BondFlag), Type.Bool,
|
||||
|
||||
@@ -40,6 +40,7 @@ import { VolumeValueColorThemeProvider } from './color/volume-value';
|
||||
import { Vec3, Vec4 } from '../mol-math/linear-algebra';
|
||||
import { ModelIndexColorThemeProvider } from './color/model-index';
|
||||
import { StructureIndexColorThemeProvider } from './color/structure-index';
|
||||
import { ExternalVolumeColorThemeProvider } from './color/external-volume';
|
||||
|
||||
export type LocationColor = (location: Location, isSecondary: boolean) => Color
|
||||
|
||||
@@ -152,6 +153,7 @@ namespace ColorTheme {
|
||||
'unit-index': UnitIndexColorThemeProvider,
|
||||
'uniform': UniformColorThemeProvider,
|
||||
'volume-value': VolumeValueColorThemeProvider,
|
||||
'external-volume': ExternalVolumeColorThemeProvider,
|
||||
};
|
||||
type _BuiltIn = typeof BuiltIn
|
||||
export type BuiltIn = keyof _BuiltIn
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user