Compare commits

...

396 Commits

Author SHA1 Message Date
Alexander Rose
e7ce693e50 3.9.0 2022-05-30 11:46:42 -07:00
Alexander Rose
29e8fe7904 fix types 2022-05-30 11:41:40 -07:00
Alexander Rose
baf3a6077e package updates 2022-05-30 11:32:05 -07:00
Alexander Rose
e030e7a32d changelog 2022-05-30 11:29:23 -07:00
Alexander Rose
125566ed75 only call renderBlendedTransparent when needed 2022-05-30 11:27:58 -07:00
Alexander Rose
c51cb67519 Merge pull request #447 from molstar/pick-drawbuffers
use drawbuffers for picking
2022-05-29 23:35:53 -07:00
Alexander Rose
57f086b530 Merge branch 'master' into pick-drawbuffers 2022-05-29 23:32:57 -07:00
Alexander Rose
d1e17785b8 Merge pull request #446 from molstar/webgl-timer
Webgl timing support
2022-05-29 23:32:29 -07:00
Alexander Rose
774328a1d8 Merge branch 'master' into webgl-timer 2022-05-29 23:31:13 -07:00
Alexander Rose
175a0f48fa lint fix 2022-05-29 23:30:36 -07:00
Alexander Rose
60b91ff032 Merge branch 'master' into pick-drawbuffers 2022-05-29 11:11:29 -07:00
David Sehnal
2b003bc5b0 Merge pull request #445 from aliaksei-chareshneu/fix_bad_axis_order
Add check that a data block contains volume data before parsing
2022-05-29 16:00:10 +02:00
David Sehnal
029a2fcab1 Merge branch 'master' into fix_bad_axis_order 2022-05-29 15:59:52 +02:00
Alexander Rose
a828113d9b use drawbuffers for picking 2022-05-28 13:17:35 -07:00
Alexander Rose
ab4d509eda fix rendering volumes
- when wboit is switched off and postprocessing is enabled
2022-05-28 13:13:35 -07:00
Alexander Rose
1296f32fa8 tweak alpha-orbitals example 2022-05-28 11:54:33 -07:00
Alexander Rose
5aa1ec9876 add timing mode 2022-05-28 11:43:13 -07:00
Alexander Rose
f2cf1ab226 add support for GPU timer queries 2022-05-28 11:20:22 -07:00
Alexander Rose
2d34c2a40b fix Scene.clear not clearing primitives/volumes 2022-05-28 11:07:03 -07:00
Aliaksei
a7181e865c Skipping server data block
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-05-28 08:16:58 +02:00
Aliaksei
0a71b788b3 Apply suggestions from code review
fix bugs and optimizing the code related to iteration over data blocks

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-05-27 18:22:00 +02:00
aliaksei-chareshneu
1ed3d84043 fix to skip block with header SERVER 2022-05-27 14:26:42 +02:00
aliaksei-chareshneu
f472b75d0d iterate over all blocks as even 0th can contain data 2022-05-27 13:53:08 +02:00
aliaksei-chareshneu
072a9d1ccd add name and email to header; add changelog entry 2022-05-27 12:19:51 +02:00
aliaksei-chareshneu
8e26d1be68 fix bad axis ordering bug 2022-05-27 10:34:48 +02:00
Alexander Rose
c5871e9025 3.8.2 2022-05-22 08:36:50 -07:00
Alexander Rose
f26911b358 changelog 2022-05-22 08:31:57 -07:00
Alexander Rose
3a595b80b5 package updates 2022-05-22 08:30:15 -07:00
Alexander Rose
45760ddd41 fix Scene.opacityAverage not handling xray shaded 2022-05-22 08:22:39 -07:00
Alexander Rose
447d068bf1 3.8.1 2022-05-14 11:59:03 -07:00
Alexander Rose
7e1642a4a3 changelog 2022-05-14 11:53:55 -07:00
Alexander Rose
7781267e78 package updates 2022-05-14 11:53:18 -07:00
Alexander Rose
f824fdcfed improve scene marker/opacity average calculation 2022-05-14 11:43:24 -07:00
Alexander Rose
79dd441967 Merge pull request #436 from JonStargaryen/master
Fix Polymer Chain Instance Coloring
2022-05-09 22:41:33 -07:00
Sebastian Bittrich
9dcf9c0785 CHANGELOG 2022-05-09 15:58:22 -07:00
Sebastian Bittrich
83569462c6 fix instance coloring 2022-05-09 15:53:26 -07:00
Alexander Rose
947e169c3a Merge pull request #434 from JonStargaryen/master
proposed fix for headless-gl issues
2022-05-06 22:29:40 -07:00
Sebastian Bittrich
e6b36c52d1 CHANGELOG 2022-05-06 09:11:40 -07:00
Sebastian Bittrich
7fed3b84fa Merge remote-tracking branch 'upstream/master' 2022-05-06 09:08:53 -07:00
Sebastian Bittrich
cbc941f193 simplify array uniform check 2022-05-06 09:08:22 -07:00
Alexander Rose
a7ef0fb85f add interesting pdb entry 2022-05-05 22:41:16 -07:00
Alexander Rose
d10c36eaf5 fix issues with marking camera/handle helper 2022-05-05 22:40:52 -07:00
Sebastian Bittrich
e4c3a66753 proposed fix for headless-gl issues 2022-05-04 11:50:42 -07:00
Alexander Rose
f58f2cdc90 3.8.0 2022-04-30 16:11:07 -07:00
Alexander Rose
8f2676e91e schema updates 2022-04-30 16:05:30 -07:00
Alexander Rose
89d397898e changelog 2022-04-30 15:24:26 -07:00
Alexander Rose
2dc32be9ee Merge pull request #427 from molstar/transparent-object-outline
Transparent object outline
2022-04-30 15:08:46 -07:00
Alexander Rose
769220bd82 Merge pull request #421 from molstar/color-theme-typing
better color theme typing
2022-04-30 15:06:06 -07:00
Alexander Rose
c75aa5dd52 improve transparency & outlines
- proper per-group transparency with wboit off
- fixed outlines with transparent backgound
2022-04-30 12:53:14 -07:00
Alexander Rose
88f1cfd8c4 fix ignoreLight for direct-volume with webgl1 2022-04-30 09:24:39 -07:00
Alexander Rose
108279c1aa add clearDepth & blendColor to WebGLState 2022-04-30 08:42:01 -07:00
Alexander Rose
8150490aac Merge branch 'master' of https://github.com/molstar/molstar into transparent-object-outline 2022-04-30 08:39:16 -07:00
Alexander Rose
9497aa6362 package updates 2022-04-30 08:38:07 -07:00
Alexander Rose
3769da48a1 handle building GridLookup3D with zero cell size 2022-04-29 20:18:40 -07:00
Alexander Rose
3c21fcd53a fix FormatRegistry.isApplicable
- was returning true for unregistered formats
2022-04-29 20:16:09 -07:00
Alexander Rose
102ef2795d handle outlines for per-group transparency
- fix allowTransparentBackfaces for per-group transparency
2022-04-23 23:02:11 -07:00
Alexander Rose
0befa253c2 add WebGLState.depthFunc 2022-04-23 20:07:41 -07:00
Alexander Rose
87189cee58 support outlines for transparent objects
- cleanup of renderer and draw pass
2022-04-23 15:19:01 -07:00
Alexander Rose
3284f13fc6 fix spec of emptyDepthTexture in Renderer 2022-04-23 15:17:20 -07:00
Alexander Rose
70d219b120 improve Renderer.renderPick typing 2022-04-23 15:13:38 -07:00
Alexander Rose
a5ed3a08ea add Scene.getOpacityAverage 2022-04-23 15:12:16 -07:00
Alexander Rose
3665e7e999 expose RenderTarget.depthRenderbuffer 2022-04-23 15:10:40 -07:00
Alexander Rose
9b583b23ae add Renderbuffer.detachFramebuffer 2022-04-23 15:10:16 -07:00
Alexander Rose
d602415e98 check if WEBGL_depth_texture is supported 2022-04-23 15:09:44 -07:00
Alexander Rose
2c49a423e2 type assertion 2022-04-21 19:47:13 -07:00
Alexander Rose
8a266e70c8 fix handling of struct_conf mmCIF field (#425) 2022-04-21 19:46:50 -07:00
Alexander Rose
0df3bcd65d document supported file formats 2022-04-19 17:43:33 -07:00
dsehnal
f5ecf5648e 3.7.0 2022-04-13 20:04:01 +02:00
dsehnal
821f82fc3f changelog 2022-04-13 20:01:04 +02:00
David Sehnal
92305fe628 Merge pull request #420 from molstar/transparentBackfaces
improve transparentBackfaces handling
2022-04-13 19:57:29 +02:00
David Sehnal
17fe57b8a5 Merge pull request #423 from jpattle/option-to-disable-drag-overlay
Added an option to disable the drag overlay
2022-04-13 16:31:21 +02:00
Jason Pattle
47433a51d3 Added an option to the components spec to allow disabling of the drag-and-drop overlap for Molstar that loads files into the viewer. By default the drag overlay is enabled, just as it was before 2022-04-13 15:00:03 +01:00
Alexander Rose
e090827ced Merge branch 'master' of https://github.com/molstar/molstar into transparentBackfaces 2022-04-10 13:20:22 -07:00
Alexander Rose
856e6a8b74 use ColorTypeLocation as default
- for backwards compatibility
- most used
2022-04-09 19:27:06 -07:00
Alexander Rose
a813b4d40e Merge branch 'master' of https://github.com/molstar/molstar into color-theme-typing 2022-04-09 16:53:17 -07:00
dsehnal
98afc27442 fix react typing 2022-04-09 21:24:14 +02:00
Alexander Rose
9d4f28a395 fix type deps 2022-04-09 11:36:17 -07:00
Alexander Rose
50266d9a56 package updates 2022-04-09 11:20:28 -07:00
Alexander Rose
602a532cf2 better color theme typing 2022-04-09 10:38:03 -07:00
Alexander Rose
b23d610c94 improve transparentBackfaces handling
- off: don't show (default)
- on: show with transparency
- opaque: show fully opaque
2022-04-09 10:17:41 -07:00
Alexander Rose
119c43d527 fix xrayShaded for texture-mesh geometries 2022-04-09 10:04:06 -07:00
Alexander Rose
124feeb790 color theme tweaks
- add optional grid property
- handle dColorType_direct for non direct-volume shaders
2022-04-09 09:57:31 -07:00
dsehnal
2c0e7e84da 3.6.2 2022-04-05 17:59:48 +02:00
dsehnal
0d1e105343 changelog 2022-04-05 17:57:14 +02:00
dsehnal
f040c89ab3 React 18 friendly useBehavior hook 2022-04-05 17:51:13 +02:00
David Sehnal
5e9d8298ef Merge pull request #415 from JonStargaryen/master
ModelServer Ligand Export: Fix Alternate Locations & Mismatching Atoms
2022-04-05 17:49:16 +02:00
Sebastian Bittrich
7766ca2793 CHANGELOG 2022-04-04 11:36:39 -07:00
Sebastian Bittrich
fb2f22f120 Merge remote-tracking branch 'upstream/master' 2022-04-04 11:33:01 -07:00
Sebastian Bittrich
146fed3504 CHANGELOG 2022-04-04 11:32:51 -07:00
Sebastian Bittrich
0b7a6e3375 cleanup 2022-04-04 10:55:44 -07:00
Sebastian Bittrich
f1fbdeaca0 handle missing atoms (ignore hydrogen, fail for heavy) 2022-04-04 10:49:40 -07:00
Sebastian Bittrich
ee7e37f6bc handle deuterated part 2 2022-04-04 09:45:42 -07:00
Sebastian Bittrich
861f665ab3 handle deuterated 2022-04-04 09:17:39 -07:00
dsehnal
456de23ad4 remove console.log 2022-04-03 14:45:41 +02:00
dsehnal
6d3578c17e fix alpha orbitals example 2022-04-03 14:08:31 +02:00
dsehnal
57da7267e2 3.6.1 2022-04-03 13:50:46 +02:00
dsehnal
578b764406 fix react 18 ui: use hooks for overlay components 2022-04-03 13:48:05 +02:00
dsehnal
f65a38a085 TransformControlBase fix 2022-04-03 13:00:09 +02:00
dsehnal
d187757bbc 3.6.0 2022-04-03 11:19:12 +02:00
dsehnal
df83b24cf4 changelog 2022-04-03 11:16:16 +02:00
dsehnal
8e31ce0f5b react 18 support 2022-04-03 11:15:47 +02:00
David Sehnal
4f69eb7963 Merge pull request #414 from molstar/lowercase-str-column
lowercase column schema
2022-04-03 10:53:08 +02:00
Alexander Rose
4b9009216b mmcif schema: use lowercase instead of uppercase 2022-04-02 22:49:57 -07:00
Alexander Rose
895076c837 Merge branch 'master' of https://github.com/molstar/molstar into lowercase-str-column 2022-04-02 16:31:15 -07:00
Alexander Rose
6e398ee64a gh action 2022-04-02 16:13:24 -07:00
Alexander Rose
c2177272b5 gh action 2022-04-02 16:07:32 -07:00
Alexander Rose
4877de5839 re-add gl support to gh action 2022-04-02 15:55:22 -07:00
Alexander Rose
3cb9d10126 fix shader tests & cleanup shader code 2022-04-02 15:52:39 -07:00
Alexander Rose
23c53cd9fb fix disable-wboit Viewer GET param 2022-04-02 15:42:33 -07:00
Alexander Rose
3471743a63 changelog 2022-04-02 15:26:25 -07:00
Alexander Rose
1b0b1809ef handle case-insensitve mmcif fields
- support upper/lower case transforms
- handle case transform for CifField to Column
2022-04-02 15:24:01 -07:00
dsehnal
0833cffead fix undefined value handling and update alised type 2022-04-02 21:48:15 +02:00
Alexander Rose
a0a8ae88b7 Merge branch 'master' of https://github.com/molstar/molstar into lowercase-str-column 2022-04-02 12:27:40 -07:00
David Sehnal
e415cbeca4 Merge pull request #413 from molstar/allowTransparentBackfaces
add allowTransparentBackfaces parameter
2022-04-02 21:00:43 +02:00
dsehnal
4c15c93381 lowercase column schema 2022-04-02 20:54:35 +02:00
Alexander Rose
bd19822112 add allowTransparentBackfaces parameter
- for mesh, spheres, cylinders, texture-mesh geometries
2022-04-01 19:18:24 -07:00
Sebastian Bittrich
b87beb4a6e better msg for UNL 2022-04-01 16:58:32 -07:00
Sebastian Bittrich
62a58facb2 better error msg for unknown components 2022-04-01 15:51:00 -07:00
Sebastian Bittrich
5fa8178df7 fix handling of alternate locations in ligand-encoder#_getAtoms 2022-04-01 11:47:59 -07:00
David Sehnal
d6043e7d1f Merge pull request #411 from JonStargaryen/master
fix volume streaming for entries with multiple contour lists
2022-04-01 13:35:57 +02:00
Sebastian Bittrich
8e432dfbb4 CHANGELOG 2022-03-30 09:27:40 -07:00
Sebastian Bittrich
324ab3744b fix volume streaming for entries with multiple contour lists 2022-03-30 09:19:36 -07:00
Alexander Rose
33ee4d0418 Merge pull request #409 from JonStargaryen/master
Fix unit mapping in bondedAtomicPairs MolScript query
2022-03-29 18:11:59 -07:00
Alexander Rose
cbb104ccba Merge branch 'master' into master 2022-03-29 18:11:37 -07:00
Alexander Rose
0bda5461ae Merge pull request #403 from molstar/pdb-conect
improve pdb parsing
2022-03-29 18:01:56 -07:00
Sebastian Bittrich
4096a03de1 CHANGELOG 2022-03-29 11:40:46 -07:00
Sebastian Bittrich
fbee5f83df fix mapping issues in bondedAtomicPairs 2022-03-29 11:34:53 -07:00
Alexander Rose
84a1b19850 improve Model.hasSecondaryStructure
- check ModelSecondaryStructure.Provider.isApplicable
2022-03-28 18:51:54 -07:00
Alexander Rose
1df5bd6d03 make use of PDB TER record 2022-03-28 18:47:00 -07:00
Alexander Rose
8bd4221a85 improve pdb parsing
- handle non unique atom and chain names
- fixes #156
2022-03-26 11:26:20 -07:00
Alexander Rose
4d97ccdfb3 improve bonds assignment of coarse grained models
- check for IndexPairBonds and exhaustive StructConn
2022-03-26 11:22:04 -07:00
Alexander Rose
ca5e57ddbf fix aromatic rings assignment 2022-03-26 11:17:46 -07:00
Alexander Rose
ed6511799b check model and coordinates element count 2022-03-26 11:15:19 -07:00
Alexander Rose
9b1223ec15 improve webgl error/type handling 2022-03-26 11:12:28 -07:00
Alexander Rose
97210ee67a avoid calculating actionItems for isDisabled check 2022-03-26 11:11:22 -07:00
David Sehnal
308d1003ad Merge pull request #401 from molstar/dependabot/npm_and_yarn/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6
2022-03-25 14:07:50 +01:00
dependabot[bot]
ce9e193958 Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-25 12:50:11 +00:00
dsehnal
2a83afa8c1 3.5.0 2022-03-25 13:49:33 +01:00
dsehnal
8891fa328b cif2bcif BCIF => CIF conversion support 2022-03-25 13:45:00 +01:00
David Sehnal
a23c06c456 Merge pull request #399 from MadCatX/dnatco-changeable-colors
Make Confal pyramids colors changeable
2022-03-22 13:25:32 +01:00
Michal Malý
34e87121e1 Make Confal pyramids colors changeable 2022-03-21 09:07:49 +01:00
Alexander Rose
6e5c20f442 improve surface bounding-sphere
- use exact max radius to expand structure/unit sphere
2022-03-19 12:21:55 -07:00
Alexander Rose
8ac3bec451 improve color-smoothing
- use padded box
2022-03-19 12:20:12 -07:00
Alexander Rose
5128d0f405 improve Sphere3D.expand & Box3D.fromSphere3D
- ensure extrema are within radius
- avoid degenerate box for low number of points
2022-03-19 12:19:39 -07:00
Alexander Rose
6ae2121391 guard against zero window.devicePixelRatio 2022-03-19 11:43:41 -07:00
David Sehnal
749e0c5a47 Merge pull request #396 from MadCatX/dnatco-off-by-one
DNATCO extension: Fix off-by-one error in element lookup
2022-03-17 09:21:11 +01:00
Michal Malý
7b55ef85e1 DNATCO extension: Fix missing Confal pyramids in some structures 2022-03-17 07:47:47 +01:00
Alexander Rose
23ec35d1f9 3.4.0 2022-03-13 13:12:32 -07:00
Alexander Rose
ff089c2b9f changelog 2022-03-13 12:50:44 -07:00
Alexander Rose
1ab088718a package updates 2022-03-13 12:49:03 -07:00
Alexander Rose
0cb2e5857a Merge pull request #393 from molstar/zenodo-import
Zenodo import
2022-03-13 12:19:04 -07:00
Alexander Rose
7c5ae5d7ee tweak guessElementSymbolString 2022-03-13 12:16:12 -07:00
Alexander Rose
6e2665d98d Merge branch 'master' of https://github.com/molstar/molstar into zenodo-import 2022-03-12 18:03:45 -08:00
Alexander Rose
b3b4692237 add top format support 2022-03-12 17:46:29 -08:00
Alexander Rose
55ff1d4999 add nctraj format support 2022-03-12 14:17:58 -08:00
Alexander Rose
511c839237 add prmtop format support 2022-03-12 13:48:10 -08:00
Alexander Rose
384cd6e5d9 add trr format support 2022-03-12 13:02:50 -08:00
Alexander Rose
6fd9dcc72e split structure formats into topology & coordinates 2022-03-12 11:51:03 -08:00
Alexander Rose
12ca06fe91 fix handling of empty symmetry cell data 2022-03-12 11:44:27 -08:00
Alexander Rose
652f6c651b fix wrong element assignment 2022-03-12 10:58:33 -08:00
Alexander Rose
7dd808a772 add custom import controls 2022-03-12 10:52:43 -08:00
Alexander Rose
945e55f8a7 add formated file size 2022-03-07 22:06:22 -08:00
Alexander Rose
866a30abe5 cleanup getFileInfo 2022-03-07 22:05:11 -08:00
Alexander Rose
f0e33e1e4e fix legend of hydrophobicity color theme 2022-03-07 21:44:57 -08:00
Alexander Rose
8723ca38b4 improve saccharide detection 2022-03-07 21:31:33 -08:00
Alexander Rose
efffca0026 zenode import fixes 2022-03-06 21:57:42 -08:00
Alexander Rose
6c5eb3035f remove default record id 2022-03-06 17:55:52 -08:00
Alexander Rose
0bf385f2ca add zip file support to zenodo extension 2022-03-06 17:37:39 -08:00
Alexander Rose
9d5f51f513 improve handling of compressed files
- fix loading of some compressed files within sessions
- ignore some hidden MACOSX files
2022-03-06 17:32:56 -08:00
Alexander Rose
a1448131d8 add Zenodo import extension 2022-03-06 11:12:21 -08:00
Alexander Rose
664cacc7ac add LoadTrajectory action 2022-03-06 11:11:16 -08:00
Alexander Rose
1aec37dd05 fix 2022-03-06 11:09:51 -08:00
Alexander Rose
3ff2c0840e Merge pull request #392 from molstar/assert-unreachable
make use of assertUnreachable
2022-03-06 11:06:04 -08:00
Alexander Rose
5ca3c3ac52 Update src/mol-script/language/parser.ts 2022-03-06 11:04:58 -08:00
Alexander Rose
714ee50965 Update src/mol-script/language/parser.ts
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-03-06 11:03:33 -08:00
Alexander Rose
ae1df3c5aa Update src/mol-script/language/parser.ts
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-03-06 11:03:28 -08:00
Alexander Rose
28afb39550 make use of assertUnreachable 2022-03-05 10:18:40 -08:00
Alexander Rose
3466a8a024 Merge pull request #389 from molstar/cif-check-present
fix handling of mmcif with empty label_asym_id
2022-03-05 09:20:19 -08:00
Alexander Rose
90db3321f5 changelog
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-03-05 09:20:04 -08:00
Alexander Rose
bf4e5ed7c2 normalize mmcif data 2022-03-04 22:47:14 -08:00
Alexander Rose
d3b2c20c26 normalize atom_site early 2022-03-03 18:31:54 -08:00
Alexander Rose
c3afabb4b1 spelling 2022-03-02 19:50:30 -08:00
Alexander Rose
18cc9790d1 fix handling of mmcif with empty label_asym_id 2022-03-02 19:17:31 -08:00
Alexander Rose
d5ed3aa674 3.3.1 2022-02-27 18:45:45 -08:00
Alexander Rose
cfb9c9acfe changelog 2022-02-27 18:40:48 -08:00
Alexander Rose
67feef0b1d add option to ignore ions for inter-unit bonds 2022-02-27 18:40:27 -08:00
Alexander Rose
e0192ab5aa fix issue with unit boundary reuse
- do at visual level instead
2022-02-27 18:03:41 -08:00
Alexander Rose
eae7c11c55 3.3.0 2022-02-27 13:03:01 -08:00
Alexander Rose
b8251e1ade changelog 2022-02-27 12:57:51 -08:00
Alexander Rose
2ff2b9f348 schema updates 2022-02-27 12:50:48 -08:00
Alexander Rose
164e3f3343 package updates 2022-02-27 12:47:45 -08:00
Alexander Rose
4901a1bd87 rename occlusion scaleFactor to resolutionScale 2022-02-27 12:16:37 -08:00
Alexander Rose
cd194cca65 Merge pull request #385 from molstar/traj-anim
Coordinate trajectory related improvements
2022-02-27 12:04:28 -08:00
Alexander Rose
1748efbc18 Merge branch 'master' of https://github.com/molstar/molstar into traj-anim 2022-02-27 12:03:54 -08:00
Alexander Rose
4d60b40403 fix interUnitBonds parent check 2022-02-27 12:02:36 -08:00
Alexander Rose
6e5a41879f Merge pull request #386 from molstar/improve-ao
Improve AO performance
2022-02-27 11:58:50 -08:00
Alexander Rose
c5f9eb54da set default occlusion scaleFactor to 1 2022-02-26 23:51:21 -08:00
Alexander Rose
aebbfeb061 add support for lower resolution AO
- downsample depth for AO
- add scaleFactor param
- full res for image/video
2022-02-26 22:23:52 -08:00
Alexander Rose
a0a5a6b578 add encoder spec
- mostly as example
2022-02-26 17:43:37 -08:00
Alexander Rose
6bdafb85d7 Check if marking passes are needed
- add Scene.getMarkerAverage
2022-02-26 13:30:05 -08:00
Alexander Rose
0dd7debf5d reuse occlusion in multi-sample pass 2022-02-26 13:02:53 -08:00
Alexander Rose
962b9ee7af Merge pull request #378 from molstar/ar-bonds
fix visuals for aromatic/delocalized bonds
2022-02-26 11:34:42 -08:00
Alexander Rose
15bcc5df88 Merge branch 'master' into ar-bonds 2022-02-26 11:26:29 -08:00
Alexander Rose
8495d834c8 add getTripletIndices & triplets to UnitResonance 2022-02-26 11:25:35 -08:00
Alexander Rose
7282399709 fix/improve canRemap handling in IntraUnitBonds 2022-02-26 10:56:32 -08:00
Alexander Rose
780bdd6e7e don't compute InterUnitBonds when parent ones empty 2022-02-26 10:53:54 -08:00
Alexander Rose
ad08e7c67f reuse unit boundary if it has not changed too much 2022-02-26 10:52:26 -08:00
Alexander Rose
ff089964ca improve line visuals in polymerAndLigand preset 2022-02-26 10:50:02 -08:00
Alexander Rose
990191529a reuse Model.CoarseGrained for coordinate trajectories 2022-02-26 10:48:05 -08:00
Alexander Rose
ce1bec12b4 fix mononucleotides detected as polymer components 2022-02-26 10:46:51 -08:00
Alexander Rose
703ea9af53 change line geometry default scaleFactor to 2
- 3 is too big after fixing line rendering
2022-02-26 10:45:51 -08:00
David Sehnal
df0227ae1e Merge pull request #383 from molstar/batch-highlights
Resolve marking in main render loop
2022-02-24 07:46:44 +01:00
dsehnal
486d12b6ac Fix multisample pass "forceOn" 2022-02-24 07:20:03 +01:00
dsehnal
9c18375ab4 typo 2022-02-23 23:34:09 +01:00
dsehnal
e1708aed68 dispose mark buffer 2022-02-23 19:09:40 +01:00
dsehnal
a42d778b84 changelog 2022-02-23 12:04:38 +01:00
dsehnal
7692b59c7c resolve marking in main render loop insread of eagerly 2022-02-23 11:59:29 +01:00
dsehnal
82de9b36b3 addRing check tweak 2022-02-22 16:02:11 +01:00
dsehnal
49b3c8f65f ring computation algorithm fixes 2022-02-22 13:16:32 +01:00
Alexander Rose
90ad32d936 add ring example PDB IDs 2022-02-21 13:48:43 -08:00
David Sehnal
2509e91f1a Merge pull request #381 from russellp17/disable-ts-config-for-sourceMappingURL
Disable ts config that leads to sourceMappingURL comment
2022-02-21 15:20:00 +01:00
David Sehnal
80dc2219e4 Merge pull request #380 from russellp17/allow-react-16-in-peer-dependency
Allow React ^16.14.0 as peer dependency
2022-02-21 15:10:33 +01:00
Russell Parker
931cb0fa7d Disable ts config that leads to sourceMappingURL comment in transpilation 2022-02-21 08:24:09 -05:00
Russell Parker
4383f2ea90 Allow React ^16.14.0 as peer dependency 2022-02-21 08:20:55 -05:00
dsehnal
add79dc242 ring computation algorithm fix 2022-02-21 14:15:13 +01:00
Alexander Rose
b6e142f04c move delocalizedTriplets code to unit.resonance 2022-02-20 16:28:42 -08:00
Alexander Rose
105f6c3041 fix visuals for aromatic/delocalized bonds 2022-02-20 12:50:44 -08:00
Alexander Rose
4babbb65c1 fix spec 2022-02-19 17:22:25 -08:00
Alexander Rose
878159f7ed fix texture warnings (#319)
- bind real texture to tDepth in renderer
- ensure textures are not empty; init as 1x1(x1)
2022-02-19 16:59:03 -08:00
Alexander Rose
c320386019 changelog 2022-02-19 14:23:37 -08:00
Alexander Rose
1e7a0159f0 Merge pull request #377 from JonStargaryen/master
parse contour-level from emdb v3 header files
2022-02-19 14:20:48 -08:00
JonStargaryen
bbf4f1d1d3 break early 2022-02-19 11:02:30 -08:00
Alexander Rose
8cd1c69c76 css tweaks, fixes #376 2022-02-19 10:46:06 -08:00
JonStargaryen
2372a878ac parse contour-level from emdb v3 header files 2022-02-19 09:12:20 -08:00
dsehnal
9bec644997 3.2.0 2022-02-17 19:24:55 +01:00
dsehnal
650d38dff8 Store IndexPairBonds as a dynamic property 2022-02-17 19:21:49 +01:00
David Sehnal
097277e397 Merge pull request #373 from JonStargaryen/master
Add TraceOnly option for Structure Superposition
2022-02-14 19:53:51 +01:00
Sebastian Bittrich
82a4d5eedf cleanup 2022-02-14 10:46:03 -08:00
Sebastian Bittrich
2a00248812 determine trace during buildIndex 2022-02-14 10:41:10 -08:00
Sebastian Bittrich
9841c773cb reset camera after all alignments 2022-02-10 13:55:09 -08:00
Sebastian Bittrich
b21a78ad14 support shuffled atoms when aligning SIFTS trace 2022-02-10 13:49:37 -08:00
Sebastian Bittrich
7329fa597d options obj for alignAndSuperposeWithSIFTSMapping 2022-02-10 11:36:50 -08:00
Sebastian Bittrich
f1d8f0ecb4 auth 2022-02-10 11:32:21 -08:00
Sebastian Bittrich
1d127f2364 changelog 2022-02-10 11:30:55 -08:00
Sebastian Bittrich
b244405cc3 polymer-based query 2022-02-10 10:39:22 -08:00
Sebastian Bittrich
38adfe0ca6 cleanup 2022-02-10 10:29:34 -08:00
Sebastian Bittrich
6f0d798847 optional filtering for trace during alignment 2022-02-10 10:23:31 -08:00
Sebastian Bittrich
6e58bfd2b0 traceOnly param for superpos 2022-02-08 16:03:05 -08:00
David Sehnal
bc2e8d8ac4 Merge pull request #369 from molstar/pdbx_sifts-export
Better support for atom_site.pdbx_sifts_xref
2022-02-08 10:19:02 +01:00
dsehnal
7be654d47f tweak labels 2022-02-08 10:18:01 +01:00
dsehnal
bfe46e3604 pdbx_sifts_xref PR feedback 2022-02-08 10:12:21 +01:00
dsehnal
008b597fc5 changelog 2022-02-07 17:51:13 +01:00
dsehnal
c4b4f2e3b1 rename BestDatabaseSequenceMapping -> SIFTSMapping 2022-02-07 17:49:10 +01:00
dsehnal
76ee97301b atom_site.pdbx_label_index support 2022-02-07 17:44:03 +01:00
dsehnal
289dc09eae add support for atom_site.pdbx_sifts_xref export 2022-02-07 17:33:11 +01:00
Alexander Rose
f23f84f0f3 3.1.0 2022-02-06 15:56:41 -08:00
Alexander Rose
62259f3295 changelog 2022-02-06 15:51:40 -08:00
Alexander Rose
854a430a12 tweak quick-styles order 2022-02-06 15:46:40 -08:00
Alexander Rose
d27cdb5637 schema updates 2022-02-06 15:41:09 -08:00
Alexander Rose
7d12d9ee90 package udpdates 2022-02-06 15:38:09 -08:00
Alexander Rose
d70a4ff347 Merge pull request #366 from molstar/repr-defaults-tweaks
cleaner default representation style
2022-02-06 15:24:27 -08:00
Alexander Rose
49541558d1 Merge branch 'master' into repr-defaults-tweaks 2022-02-06 15:24:16 -08:00
Alexander Rose
7b00a1227c changelog 2022-02-06 15:22:50 -08:00
Alexander Rose
7800603c81 Merge pull request #367 from molstar/quick-styles
Quick styles
2022-02-06 15:16:43 -08:00
Alexander Rose
fca00c8116 variable naming 2022-02-06 15:15:55 -08:00
Alexander Rose
00fa549e44 Merge pull request #368 from JonStargaryen/master
iterate over `structure.unitSymmetryGroups`, fixes #364
2022-02-06 15:13:57 -08:00
Alexander Rose
36181b6b87 tweak quick style names 2022-02-06 15:13:15 -08:00
JonStargaryen
88a95162e9 iterate over structure.unitSymmetryGroups, fixes #364 2022-02-06 10:47:40 -08:00
Alexander Rose
9c1d59a2c8 add Quick Styles panel 2022-02-05 12:58:32 -08:00
Alexander Rose
fdd894956a fix representation preset side effects 2022-02-05 12:56:55 -08:00
Alexander Rose
eb6dc0859d cleaner default representation style 2022-02-05 12:23:28 -08:00
Alexander Rose
b99026bba2 add ignoreLight to component params 2022-02-05 12:10:56 -08:00
Alexander Rose
6fa50eb8d5 fix xrayShader & ignoreLight not working together 2022-02-05 11:57:39 -08:00
David Sehnal
e5046f15a9 Merge pull request #365 from JonStargaryen/master
Volume Streaming Error Message
2022-02-04 17:11:31 +01:00
JonStargaryen
09f1c066a0 logic 2022-02-03 17:11:50 -08:00
Sebastian Bittrich
ed2f0b34c9 volume streaming err msg 2022-02-03 16:11:10 -08:00
Alexander Rose
c7f75861de 3.0.2 2022-01-30 12:24:48 -08:00
Alexander Rose
ccd04dbc9d changelog 2022-01-30 12:19:49 -08:00
Alexander Rose
e71f8d2c10 Merge pull request #360 from molstar/fix/visual-visibility
Fix visual visibility edge case
2022-01-30 12:17:12 -08:00
dsehnal
d9b4c60239 Fix visual visibility edge case 2022-01-30 15:02:46 +01:00
Alexander Rose
103c1fca21 measurement options tweaks
- allow larger text size
- make customText essential
2022-01-29 19:30:03 -08:00
Alexander Rose
49559bf5fb citation tweak 2022-01-29 16:05:17 -08:00
Alexander Rose
26dceabf83 add citation file 2022-01-29 15:56:39 -08:00
Alexander Rose
abe506182e fix multi-instance entity label display
- fix empty elements created in extendToAllInstances
2022-01-29 11:21:48 -08:00
Alexander Rose
582a0e2a38 fix Sphere.expand for highly directional extrema 2022-01-29 11:13:19 -08:00
dsehnal
2784ccf379 3.0.1 2022-01-27 12:15:53 +01:00
dsehnal
0ad1d578fe changelog 2022-01-27 12:13:22 +01:00
David Sehnal
31fd1c9c68 Merge pull request #353 from molstar/drag-tweak
emit drag event whenever started within viewport
2022-01-27 12:12:07 +01:00
David Sehnal
9c961297a2 Merge branch 'master' into drag-tweak 2022-01-27 12:11:59 +01:00
David Sehnal
b920053349 Merge pull request #352 from molstar/var-fixes
Various fixes
2022-01-27 12:09:39 +01:00
David Sehnal
0a5c764e4a Merge pull request #351 from molstar/volume-server-data-fix
Volume server data fix
2022-01-27 11:37:31 +01:00
Alexander Rose
b9a71c83ff emit drag event whenever started within viewport 2022-01-26 21:32:14 -08:00
Alexander Rose
3255f207d0 Merge branch 'master' of https://github.com/molstar/molstar into var-fixes 2022-01-26 20:46:11 -08:00
Alexander Rose
e3b4ca8862 add entity-id and entity-source as carbonColor 2022-01-26 20:42:38 -08:00
Alexander Rose
6810793015 fix marking of InteractionsInterUnitVisual 2022-01-26 20:40:12 -08:00
Alexander Rose
1feb3c2095 fix entity-id coloring broken for non-ihm models 2022-01-26 20:38:46 -08:00
Alexander Rose
f2da6033d0 fix pdbe xray maps url 2022-01-26 20:36:52 -08:00
Alexander Rose
28bc212132 fix marking pass for transparentBackground 2022-01-26 20:35:38 -08:00
dsehnal
1a7c62eec6 remove gl from dependencies & install it on demand instead
- installing gl on M1 Mac was taking several minutes to compile on each update
2022-01-26 23:12:12 +01:00
dsehnal
de67dbacba iso-value adjustment for VolumeServer data in default Viewer 2022-01-26 17:47:23 +01:00
dsehnal
57223a0f9a Fix VolumeServer/query CLI 2022-01-26 16:49:18 +01:00
Alexander Rose
2ad0754b90 3.0.0 2022-01-23 18:12:48 -08:00
Alexander Rose
3ecb3af57b changelog 2022-01-23 18:08:01 -08:00
Alexander Rose
ec4f15f549 improve/fix InteractionsIntraUnitVisual marking 2022-01-23 17:55:51 -08:00
Alexander Rose
2458ea7b92 Merge pull request #349 from molstar/custom-theme-colors
add custom theme colors
2022-01-23 15:13:24 -08:00
Alexander Rose
c5e6bedf11 Merge branch 'master' into custom-theme-colors 2022-01-23 13:54:57 -08:00
dsehnal
8528e5a666 Support/bugfixes for atom_site.pdbx_sifts_xref categories 2022-01-23 20:46:49 +01:00
dsehnal
6ed232b3d9 fix using default values for webgl1/wboit features in the default viewer app 2022-01-23 19:25:09 +01:00
dsehnal
f8aae8cbd1 skip Coarse models in export extension 2022-01-23 16:13:02 +01:00
Alexander Rose
00c2517045 package updates 2022-01-22 14:06:26 -08:00
Alexander Rose
99b043a929 avoid circular dependency 2022-01-22 11:10:41 -08:00
Alexander Rose
5900e27e39 add custom theme colors
- element-symbol
- molecule-type
- residue-name
- secondary-structure
2022-01-22 10:51:41 -08:00
Alexander Rose
1b79d34907 fix marking of carbohydrate visuals 2022-01-22 08:53:47 -08:00
Alexander Rose
fc52e29c92 re-add using _struct_asym cat in getStructAsymMap
- needed for ihm model support
2022-01-22 08:50:29 -08:00
Alexander Rose
df23b3c0fe fix coarse model support in entity-id color theme
- add StructureProperties.coarse.entity_id
2022-01-22 08:48:07 -08:00
David Sehnal
5e25716c98 Merge pull request #334 from molstar/export-extension
Model export extension & related improvements
2022-01-18 13:23:11 +01:00
dsehnal
f70a10bc56 add info about CIF export failure 2022-01-18 13:20:53 +01:00
dsehnal
0ccb045f4e Merge branch 'master' of https://github.com/molstar/molstar into export-extension 2022-01-18 12:30:45 +01:00
Alexander Rose
fa18d0d852 3.0.0-dev.10 2022-01-17 14:08:28 -08:00
Alexander Rose
687c4342fb changelog 2022-01-17 14:03:55 -08:00
Alexander Rose
9459af46b8 Merge pull request #337 from molstar/anim-rock
Add rock animation
2022-01-17 13:38:08 -08:00
Alexander Rose
fc5832747a Merge pull request #345 from molstar/bump-immutable
bump immutable to 4.0
2022-01-17 13:37:19 -08:00
Alexander Rose
01205d244b tweak trackball speed calc 2022-01-17 13:16:19 -08:00
dsehnal
31a555255a bump immutable to 4.0 2022-01-17 17:56:39 +01:00
dsehnal
fbb60c9493 Treat empty string as non-present value in BinaryCIF 2022-01-17 16:21:14 +01:00
dsehnal
9f953ef51c add Model Export overlay 2022-01-17 15:47:56 +01:00
dsehnal
4871f1547c Generate structAsymMap from normalized atomic hierarchy
- Fixes issue with remapped chains
- Requires to parse PRD separately
2022-01-17 14:52:53 +01:00
dsehnal
d6413529f4 PR feedback 2022-01-17 13:58:20 +01:00
dsehnal
724cf5a0da Add integrations section to readme 2022-01-17 12:58:35 +01:00
dsehnal
b6847907ca Add ModelExport to viewer/app.ts 2022-01-17 11:37:49 +01:00
dsehnal
fb54a1aed7 Merge branch 'master' of https://github.com/molstar/molstar into export-extension 2022-01-17 11:37:16 +01:00
Alexander Rose
9815318daf add entity-source option to illustrative coloring 2022-01-16 23:08:43 -08:00
Alexander Rose
bc13b98111 Merge branch 'master' of https://github.com/molstar/molstar into anim-rock 2022-01-16 15:48:33 -08:00
Alexander Rose
238b70c121 simplify rock state/trackball animation
- use sin() instead of smoothstep()
2022-01-16 15:47:25 -08:00
Alexander Rose
dcd23bc0cb improve illustrative style support
- add illustrative representation preset
- add style option to illustrative color theme
2022-01-16 13:13:00 -08:00
Alexander Rose
4694ea85fa support custom colors in molecule-type theme 2022-01-16 13:05:43 -08:00
Alexander Rose
bdb17743d7 update schemas 2022-01-15 19:54:22 -08:00
Alexander Rose
8b76ff2461 update packages 2022-01-15 19:53:04 -08:00
Alexander Rose
ea5421002b add camera rock state animation 2022-01-15 18:59:12 -08:00
Alexander Rose
76ac55917d type, tweaks 2022-01-15 18:45:56 -08:00
Alexander Rose
5cfb2376c4 Merge branch 'master' of https://github.com/molstar/molstar into anim-rock 2022-01-15 15:56:55 -08:00
Alexander Rose
6b9d3fd80e cleaner MembraneOrientationVisuals defaults 2022-01-15 13:52:14 -08:00
dsehnal
a09752b62e changelog and contibutors in package.json 2022-01-14 12:53:51 +01:00
David Sehnal
3134e1d9f9 Merge pull request #341 from molstar/fix-camera-spin-stutter
Pass animation info to state animations
2022-01-14 12:51:51 +01:00
David Sehnal
e94ecf2a0b Merge pull request #314 from ptourlas/feature/formal-charge-labels
Feature/formal charge labels
2022-01-14 12:51:09 +01:00
ptourlas
1bd4d841a1 ADD: Test multiple charge lines in molfiles 2022-01-12 17:01:36 +02:00
ptourlas
8e349f47a5 (author tags) 2022-01-12 16:50:06 +02:00
ptourlas
119c0a4231 ADD: Test formal charge parsing in sdf reader 2022-01-12 16:25:23 +02:00
ptourlas
f009f533e0 TWEAK: Default charges in V3000 sdf files 2022-01-12 15:05:07 +02:00
ptourlas
3ab0c1e509 ADD: Test formal charge parsing in mol reader 2022-01-12 12:42:29 +02:00
dsehnal
e3d264e239 Pass animation info to state animations
+ Fix camera stutter for "camera spin"
2022-01-11 19:38:32 +01:00
dsehnal
9bd60f8e8e Fix getOperatorsForIndex 2022-01-11 17:34:43 +01:00
ptourlas
bcec1d9637 (forgot to cleanup) 2022-01-11 16:41:23 +02:00
ptourlas
1b431b1d20 RFR: Formal charge assignment at model creation 2022-01-11 16:04:46 +02:00
ptourlas
23c2dcdfd4 FIX: Use tokenizer to ensure the loop terminates 2022-01-11 15:01:15 +02:00
ptourlas
dd415bf802 FTR: Support multiple formal charge lines
* Start with two empty arrays for indexes and charges.
* Each `M CHG` line is passed to `handleFormalCharges()` and the
parsed elements are pushed to the arrays.
* The `Column`s are made at the end of this process.
2022-01-11 14:40:57 +02:00
ptourlas
7bc0e9db7c RFR: formalChargeMapper tweaks
* The key is of type number, no need to stringify it.
* Simplified `switch()`.
2022-01-11 00:18:25 +02:00
ptourlas
ca10bb01db Merge branch 'molstar:master' into feature/formal-charge-labels 2022-01-10 23:46:37 +02:00
Alexander Rose
c0f14b7c33 3.0.0-dev.9 2022-01-09 18:24:30 -08:00
Alexander Rose
b096f328fc changelog 2022-01-09 18:19:52 -08:00
Alexander Rose
88dbd43884 re-allow interaction during trackball animation
- was disallowed as a stop-gap measure
- ok after improving temporal multi sampling
2022-01-09 14:39:09 -08:00
Alexander Rose
ade5e4d4b8 re-allow interaction during trackball animation
- was disallowed as a stop-gap measure
- ok after improving temporal multi sampling
2022-01-09 14:30:43 -08:00
ptourlas
cb76b53a1b FTR: Add formal charges during model creation
This implementation takes into account both the property and atom block
cases and makes sure the latter is ignored if the first one is present.
2022-01-10 00:30:25 +02:00
Alexander Rose
b9423f70d4 Merge branch 'master' of https://github.com/molstar/molstar into anim-rock 2022-01-09 14:25:36 -08:00
Alexander Rose
d61e18e6f3 fix mol2 element symbol assignment 2022-01-09 14:04:31 -08:00
Alexander Rose
ca4a725a79 Merge pull request #336 from molstar/bond-dist-id
IndexPairBonds improvements
2022-01-09 13:37:38 -08:00
Alexander Rose
17a18d5fea tweak bond assignment from IndexPairBonds
- fix & clarify logic
2022-01-09 13:25:14 -08:00
Alexander Rose
73be238ac4 rename IndexPairBonds mapping field from id to key 2022-01-09 12:51:26 -08:00
Alexander Rose
796a034fec add rock animation to trackball controls 2022-01-08 17:02:33 -08:00
Alexander Rose
952b320975 Merge branch 'master' of https://github.com/molstar/molstar into bond-dist-id 2022-01-08 13:23:15 -08:00
Alexander Rose
be0f06ff0f fix mol2 crysin support 2022-01-08 13:22:26 -08:00
Alexander Rose
6294ef2db2 fix stats for single element in multi-chain unit
- observe in, e.g., label for water molecule in 3pqr
2022-01-08 12:42:37 -08:00
Alexander Rose
78b5d505bd improve IndexPairBonds
- add id field
- better distance-based assignment
2022-01-08 12:35:40 -08:00
Alexander Rose
22afdffa15 add mol2 symmetry support
- only for spacegroup setting 1
2022-01-08 12:14:14 -08:00
Alexander Rose
d1056eddeb Merge pull request #335 from molstar/standalone-viewer
move Viewer class to separate file
2022-01-08 11:55:53 -08:00
dsehnal
8655f4d85a move viewer app to separate file 2022-01-08 10:31:53 +01:00
ptourlas
f9deb54352 FIX: Found the right tokenizer operations
(at last)
2022-01-08 01:16:59 +02:00
ptourlas
eae3c1b33a FIX: Formal charges are all on the same line
Therefore we have to get the count of charges and iterate based on that.
A handle properties function is added so that new handler can be used based
the property type. Note that this function only returns the charges at
the moment for simplicity. A more general version should return multiple
properties.
2022-01-07 16:14:47 +02:00
ptourlas
5c5f8aa741 FTR:(WIP) Add formal charges during model creation 2022-01-06 16:12:44 +02:00
ptourlas
ba68ac2e32 FTR: Parse formal charges in the atom block 2022-01-06 15:58:49 +02:00
ptourlas
239fef281e Merge branch 'master' into feature/formal-charge-labels 2022-01-06 13:32:05 +02:00
dsehnal
c0880b647f changelog 2022-01-03 13:51:09 +01:00
dsehnal
039dc6a76b changelog 2022-01-03 13:49:59 +01:00
dsehnal
042a7625ad isWithoutOperator tweak 2022-01-03 13:46:13 +01:00
dsehnal
41827c478d open zip files with multiple entries 2022-01-03 13:42:37 +01:00
dsehnal
9a73180c3c support transformed export & structAsymMap parsing fix 2022-01-03 13:15:51 +01:00
dsehnal
333ee85fdb omit suffix for identity assembly operators 2022-01-03 12:52:05 +01:00
dsehnal
fa8ca45b6a do not include assembly categories in export if an operator has been applied 2022-01-03 12:34:37 +01:00
dsehnal
c2bae1aeb7 model export extension 2022-01-03 12:26:36 +01:00
Alexander Rose
ada7a45fe6 add PDBj pdb-provider option 2022-01-01 16:56:23 -08:00
ptourlas
13ea97bd98 Merge branch 'master' into feature/formal-charge-labels 2021-12-27 18:18:27 +02:00
ptourlas
009a17a9ca (forgot the author tag) 2021-12-27 17:56:25 +02:00
ptourlas
ca38d9adb1 (WIP) Formal charges handler implementation 2021-12-27 17:44:59 +02:00
ptourlas
4e5a86e3db (WIP) Add the formal charges handler to sdf parser 2021-12-27 17:37:52 +02:00
ptourlas
a736fe7989 Add formal charge option to atom site 2021-12-15 00:35:34 +02:00
ptourlas
1970b7f249 Spot the formal charge prefix 2021-12-15 00:34:06 +02:00
328 changed files with 32690 additions and 27314 deletions

View File

@@ -9,12 +9,12 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 17
node-version: 16
- run: npm ci
- run: sudo apt-get install xvfb
- name: Lint
run: npm run lint
- name: Test
run: xvfb-run --auto-servernum npm run jest
run: npm install --no-save "gl@^5.0.0" && xvfb-run --auto-servernum npm run jest
- name: Build
run: npm run build

View File

@@ -6,6 +6,203 @@ Note that since we don't clearly distinguish between a public and private interf
## [Unreleased]
## [v3.9.0] - 2022-05-30
- Improve picking by using drawbuffers (when available) to reduce number of drawcalls
- GPU timing support
- Add ``timing-mode`` Viewer GET param
- Add support for webgl timer queries
- Add timer marks around GPU render & compute operations
- Volume Server CIF: Add check that a data block contains volume data before parsing
- Fix ``Scene.clear`` not clearing primitives & volumes arrays (@JonStargaryen)
- Fix rendering volumes when wboit is switched off and postprocessing is enabled
## [v3.8.2] - 2022-05-22
- Fix ``Scene.opacityAverage`` not taking xray shaded into account
## [v3.8.1] - 2022-05-14
- Fix issues with marking camera/handle helper (#433)
- Fix issues with array uniforms when running with headless-gl
- Fix Polymer Chain Instance coloring
- Improve performance of scene marker/opacity average calculation
## [v3.8.0] - 2022-04-30
- Add support for outlines around transparent objects
- Improve per-group transparency when wboit is switched off
- Improve ``ColorTheme`` typing with ``ColorType`` generic.
- Defaults to ``ColorTypeLocation``
- Set when using ``ColorTypeDirect`` or ``ColorTypeGrid``
- Fix case handling of ``struct_conf`` mmCIF enumeration field (#425)
- Fix ``allowTransparentBackfaces`` for per-group transparency
- Fix ``FormatRegistry.isApplicable`` returning true for unregistered formats
- Fix: handle building of ``GridLookup3D`` with zero cell size
- Fix ``ignoreLight`` for direct-volume rendering with webgl1
- Fix (non-black) outlines when using transparent background
## [v3.7.0] - 2022-04-13
- Fix ``xrayShaded`` for texture-mesh geometries
- [Breaking] Change ``allowTransparentBackfaces`` to ``transparentBackfaces`` with options ``off``, ``on``, ``opaque``. This was only added in 3.6.0, so allowing a breaking change here.
- ``off``: don't show (default)
- ``on``: show with transparency
- ``opaque``: show fully opaque
- Add option to disable file drop overlay.
## [v3.6.2] - 2022-04-05
- ModelServer ligand queries: fixes for alternate locations, additional atoms & UNL ligand
- React 18 friendly ``useBehavior`` hook.
## [v3.6.1] - 2022-04-03
- Fix React18 related UI regressions.
## [v3.6.0] - 2022-04-03
- Check that model and coordinates have same element count when creating a trajectory
- Fix aromatic rings assignment: do not mix flags and planarity test
- Improve bonds assignment of coarse grained models: check for IndexPairBonds and exhaustive StructConn
- Fix unit mapping in bondedAtomicPairs MolScript query
- Improve pdb parsing: handle non unique atom and chain names (fixes #156)
- Fix volume streaming for entries with multiple contour lists
- Add ``allowTransparentBackfaces`` parameter to support double-sided rendering of transparent geometries
- Fix handling of case insensitive mmCIF enumeration fields (including entity.type)
- Fix ``disable-wboit`` Viewer GET param
- Add support for React 18.
- Used by importing ``createPluginUI`` from ``mol-plugin-ui/react18``;
- In Mol* 4.0, React 18 will become the default option.
## [v3.5.0] - 2022-03-25
- Fix issues with bounding-sphere & color-smoothing (mostly for small geometries)
- Support BCIF => CIF conversion in ``cif2bcif`` CLI tool
## [v3.4.0] - 2022-03-13
- Fix handling of mmcif with empty ``label_*`` fields
- Improve saccharide detection (compare against list from CCD)
- Fix legend label of hydrophobicity color theme
- Add ``LoadTrajectory`` action
- Add ``CustomImportControls`` to left panel
- Add Zenodo import extension (load structures, trajectories, volumes, and zip files)
- Fix loading of some compressed files within sessions
- Fix wrong element assignment for atoms with Charmm ion names
- Fix handling of empty symmetry cell data
- Add support for ``trr`` and ``nctraj`` coordinates files
- Add support for ``prmtop`` and ``top`` topology files
## [v3.3.1] - 2022-02-27
- Fix issue with unit boundary reuse (do at visual level instead)
- Add option to ignore ions for inter-unit bond computation
## [v3.3.0] - 2022-02-27
- Fix parsing contour-level from emdb v3 header files
- Fix invalid CSS (#376)
- Fix "texture not renderable" & "texture not bound" warnings (#319)
- Fix visual for bonds between two aromatic rings
- Fix visual for delocalized bonds (parsed from mmcif and mol2)
- Fix ring computation algorithm
- Add ``UnitResonance`` property with info about delocalized triplets
- Resolve marking in main renderer loop to improve overall performance
- Use ``throttleTime`` instead of ``debounceTime`` in sequence viewer for better responsiveness
- Change line geometry default ``scaleFactor`` to 2 (3 is too big after fixing line rendering)
- Trajectory animation performance improvements
- Reuse ``Model.CoarseGrained`` for coordinate trajectories
- Avoid calculating ``InterUnitBonds`` when ``Structure.parent`` ones are empty
- Reuse unit boundary if sphere has not changed too much
- Don't show 'inter-bond' and 'element-cross' visuals in line representations of polymerAndLigand preset
- Fix additional mononucleotides detected as polymer components
- Fix and improve ``canRemap`` handling in ``IntraUnitBonds``
- Reuse occlusion for secondary passes during multi-sampling
- Check if marking passes are needed before doing them
- Add ``resolutionScale`` parameter to allow trading quality of occlusion for performance
## [v3.2.0] - 2022-02-17
- Rename "best database mapping" to "SIFTS Mapping"
- Add schema and export support for ``atom_site.pdbx_sifts_xref_*`` fields
- Add schema export support for ``atom_site.pdbx_label_index`` field
- Add `traceOnly` parameter to chain/UniProt-based structure alignment
- Store ``IndexPairBonds`` as a dynamic property.
## [v3.1.0] - 2022-02-06
- Fix ``xrayShaded`` & ``ignoreLight`` params not working at the same time
- Add ``ignoreLight`` to component params
- Tweaks for cleaner default representation style
- Cartoon: use ``nucleotide-ring`` instead of ``nucleotide-block``
- Focus: use ``xrayShaded`` instead of opacity; adjust target size; don't show non-covalent interactions twice
- Fix representation preset side effects (changing post-processing parameters, see #363)
- Add Quick Styles panel (default, illustrative, stylized)
- Fix exported structure missing secondary-structure categories (#364)
- Fix volume streaming error message: distinguish between missing data and server error (#364)
## [v3.0.2] - 2022-01-30
- Fix color smoothing of elongated structures (by fixing ``Sphere.expand`` for spheres with highly directional extrema)
- Fix entity label not displayed when multiple instances of the same entity are highlighted
- Fix empty elements created in ``StructureElement.Loci.extendToAllInstances``
- Measurement options tweaks (allow larger ``textSize``; make ``customText`` essential)
- Fix visual visibility sync edge case when changing state snapshots
## [v3.0.1] - 2022-01-27
- Fix marking pass not working with ``transparentBackground``
- Fix pdbe xray maps url not https
- Fix entity-id color theme broken for non-IHM models
- Improve/fix marking of ``InteractionsInterUnitVisual`` (mark when all contact-feature members are given)
- Add missing "entity-id" and "enity-source" options for carbon coloring to "element-symbol" color theme
- Fix VolumeServer/query CLI
- Support automatic iso-value adjustment for VolumeServer data in ``Viewer.loadVolumeFromUrl``
- Emit drag event whenever started within viewport (not only for non-empty loci)
## [v3.0.0] - 2022-01-23
- Assembly handling tweaks:
- Do not include suffix for "identity assembly operators"
- Do not include assembly-related categories to export if the structure was composed from an assembly
- Special case for ``structAsymMap`` if Mol* asym id operator mapping is present
- Support for opening ZIP files with multiple entries
- Add Model Export extension
- Bugfix: Automatically treat empty string as "non-present" value in BinaryCIF writer.
- Fix coarse model support in entity-id color theme
- Fix marking of carbohydrate visuals (whole chain could get marked instead of single residue)
- Add custom colors to "element-symbol", "molecule-type", "residue-name", and "secondary-structure" themes
- Support/bugfixes for ``atom_site.pdbx_sifts_xref`` categories
- Improve/fix marking of ``InteractionsIntraUnitVisual`` (mark when all contact-feature members are given)
## [v3.0.0-dev.10] - 2022-01-17
- Fix ``getOperatorsForIndex``
- Pass animation info (current frame & count) to state animations
- Fix camera stutter for "camera spin" animation
- Add formal charge parsing support for MOL/SDF files (thanks @ptourlas)
- [Breaking] Cleaner looking ``MembraneOrientationVisuals`` defaults
- [Breaking] Add rock animation to trackball controls
- Add ``animate`` to ``TrackballControlsParams``, remove ``spin`` and ``spinSpeed``
- Add ``animate`` to ``SimpleSettingsParams``, remove ``spin``
- Add "camera rock" state animation
- Add support for custom colors to "molecule-type" theme
- [Breaking] Add style parameter to "illustrative" color theme
- Defaults to "entity-id" style instead of "chain-id"
- Add "illustrative" representation preset
## [v3.0.0-dev.9] - 2022-01-09
- Add PDBj as a ``pdb-provider`` option
- Move Viewer APP to a separate file to allow use without importing light theme & index.html
- Add symmetry support for mol2 files (only spacegroup setting 1)
- Fix mol2 files element symbol assignment
- Improve bond assignment from ``IndexPairBonds``
- Add ``key`` field for mapping to source data
- Fix assignment of bonds with unphysical length
- Fix label/stats of single atom selection in multi-chain units
## [v3.0.0-dev.8] - 2021-12-31
- Add ``PluginFeatureDetection`` and disable WBOIT in Safari 15.

72
CITATION.cff Normal file
View File

@@ -0,0 +1,72 @@
cff-version: 1.2.0
title: >-
Mol* library
message: >-
Please cite this software using the metadata from
'preferred-citation'.
authors:
- given-names: Alexander S
family-names: Rose
orcid: 'https://orcid.org/0000-0002-0893-5551'
- given-names: David
family-names: Sehnal
orcid: 'https://orcid.org/0000-0002-0682-3089'
- given-names: Sebastian
family-names: Bittrich
orcid: 'https://orcid.org/0000-0003-3576-0387'
- given-names: Áron Samuel
family-names: Kovács
- given-names: Ludovic
family-names: Autin
orcid: 'https://orcid.org/0000-0002-2197-191X'
- given-names: Michal
family-names: Malý
- given-names: Jiří
family-names: Černý
- given-names: Panagiotis
family-names: Tourlas
type: software
doi: 10.5281/zenodo.3947306
preferred-citation:
authors:
- given-names: David
family-names: Sehnal
orcid: 'https://orcid.org/0000-0002-0682-3089'
- given-names: Sebastian
family-names: Bittrich
orcid: 'https://orcid.org/0000-0003-3576-0387'
- given-names: Mandar
family-names: Deshpande
orcid: 'https://orcid.org/0000-0002-9043-7665'
- given-names: Radka
family-names: Svobodová
orcid: 'https://orcid.org/0000-0002-3840-8760'
- given-names: Karel
family-names: Berka
orcid: 'https://orcid.org/0000-0001-9472-2589'
- given-names: Václav
family-names: Bazgier
orcid: 'https://orcid.org/0000-0003-3393-3010'
- given-names: Sameer
family-names: Velankar
orcid: 'https://orcid.org/0000-0002-8439-5964'
- given-names: Stephen K
family-names: Burley
orcid: 'https://orcid.org/0000-0002-2487-9713'
- given-names: Jaroslav
family-names: Koča
orcid: 'https://orcid.org/0000-0002-2780-4901'
- given-names: Alexander S
family-names: Rose
orcid: 'https://orcid.org/0000-0002-0893-5551'
title: >-
Mol* Viewer: modern web app for 3D visualization
and analysis of large biomolecular structures
type: article
doi: 10.1093/nar/gkab314
journal: "Nucleic Acids Research"
issue: W1
volume: 49
year: 2021
month: 7
pages: "W431W437"

View File

@@ -11,6 +11,13 @@ When using Mol*, please cite:
David Sehnal, Sebastian Bittrich, Mandar Deshpande, Radka Svobodová, Karel Berka, Václav Bazgier, Sameer Velankar, Stephen K Burley, Jaroslav Koča, Alexander S Rose: [Mol* Viewer: modern web app for 3D visualization and analysis of large biomolecular structures](https://doi.org/10.1093/nar/gkab314), *Nucleic Acids Research*, 2021; https://doi.org/10.1093/nar/gkab314.
### Protein Data Bank Integrations
- The [pdbe-molstar](https://github.com/molstar/pdbe-molstar) library is the Mol* implementation used by EMBL-EBI data resources such as [PDBe](https://pdbe.org/), [PDBe-KB](https://pdbe-kb.org/) and [AlphaFold DB](https://alphafold.ebi.ac.uk/). This implementation can be used as a JS plugin and a Web component and supports property/attribute-based easy customisation. It provides helper methods to facilitate programmatic interactions between the web application and the 3D viewer. It also provides a superposition view for overlaying all the observed ligand molecules on representative protein conformations.
- [rcsb-molstar](https://github.com/molstar/rcsb-molstar) is the Mol* plugin used by [RCSB PDB](https://www.rcsb.org). The project provides additional presets for the visualization of structure alignments and structure motifs such as ligand binding sites. Furthermore, [rcsb-molstar](https://github.com/molstar/rcsb-molstar) allows to interactively add or hide of (parts of) chains, as seen in the [3D Protein Feature View](https://www.rcsb.org/3d-sequence/4hhb).
## Project Structure Overview
The core of Mol* consists of these modules (see under `src/`):
@@ -113,6 +120,9 @@ and navigate to `build/viewer`
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-ions.js src/mol-model/structure/model/types/ions.ts
**Saccharide names**
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-saccharides.js src/mol-model/structure/model/types/saccharides.ts
**GraphQL schemas**
@@ -131,7 +141,7 @@ and navigate to `build/viewer`
export NODE_PATH="lib"; node build/state-docs
**Convert any CIF to BinaryCIF**
**Convert any CIF to BinaryCIF (or vice versa)**
node lib/commonjs/servers/model/preprocess -i file.cif -ob file.bcif
@@ -141,6 +151,11 @@ Or
node lib/commonjs/cli/cif2bcif
E.g.
node lib/commonjs/cli/cif2bcif src.cif out.bcif.gz
node lib/commonjs/cli/cif2bcif src.bcif.gz out.cif
## Development
### Installation

View File

@@ -24,6 +24,11 @@ atom_site.auth_asym_id
atom_site.auth_seq_id
atom_site.pdbx_PDB_model_num
atom_site.ihm_model_id
atom_site.pdbx_label_index
atom_site.pdbx_sifts_xref_db_name
atom_site.pdbx_sifts_xref_db_acc
atom_site.pdbx_sifts_xref_db_num
atom_site.pdbx_sifts_xref_db_res
atom_site_anisotrop.id
atom_site_anisotrop.U
1 atom_sites.entry_id
24 atom_site.pdbx_PDB_model_num
25 atom_site.ihm_model_id
26 atom_site_anisotrop.id atom_site.pdbx_label_index
27 atom_site.pdbx_sifts_xref_db_name
28 atom_site.pdbx_sifts_xref_db_acc
29 atom_site.pdbx_sifts_xref_db_num
30 atom_site.pdbx_sifts_xref_db_res
31 atom_site_anisotrop.id
32 atom_site_anisotrop.U
33 atom_site_anisotrop.U_esd
34 atom_site_anisotrop.pdbx_PDB_ins_code

44
docs/file-formats.md Normal file
View File

@@ -0,0 +1,44 @@
Support file formats and their extensions.
## Structure
- MMCIF and CIFCORE (mmCIF and coreCIF schemas): cif, bcif, mmcif, mcif
- GRO: gro
- MOL: mol
- MOL2: mol2
- PDB/PDBQT: pdb, ent, pdbqt
- SDF: sdf, sd
- XYZ: xyz
## Topology
Need to be loaded together with Coordinates.
- PRMTOP: prmtop, parm7
- PSF: psf
- TOP: top
## Coordinates
Need to be loaded together with a Structure or Topology.
- DCD: dcd
- NCTRAJ: nc, nctraj
- TRR: trr
- XTC: xtc
## Volume
- CCP4/MRC/MAP: ccp4, mrc, map
- CUBE (may include a Structure): cub, cube
- DSN6/BRIX: dsn6, brix
- DX and DXBIN: dx, dxbin
- DSCIF (DensityServer CIF schema): cif, bcif
## Shape
- PLY

View File

@@ -13,6 +13,7 @@
* DZ has C1 instead of N1 (e.g. 6I4N)
* DP has N5 instead of C5 and C7 instead of N7 (e.g. 6I4N)
* Beta & Gamma peptides (e.g. 1GAC, 6PQF)
* Helices of D-amino acids (e.g. 7QDI)
* Mixed (heterogeneous) all-atom/trace-only RNA model (1JGQ)
* Polymers with residues with missing trace atoms (e.g. 2QFJ)
* Modified RNA bases (1y26, 5L4O)
@@ -34,6 +35,14 @@
* ACE (many, e.g. 5AGU, 1E1X)
* ACY in 7ABY
* NH2 (many, e.g. 6Y13)
* Ligands with many rings
* STU (e.g. 1U59) - many fused rings
* HT (e.g. 127D) - rings connected by a single bond
* J2C (e.g. 7EFJ) - rings connected by a single atom
* RBF (e.g. 7QF2) - three linearly fused rings
* TA1 (e.g. 1JFF) - many fused rings (incl. a 8-member rings)
* BPA (e.g. 1JDG) - many fused rings
* CLR (e.g. 3GKI) - four fused rings
Assembly symmetries
* 5M30 (Assembly 1, C3 local and pseudo)

47349
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "3.0.0-dev.8",
"version": "3.9.0",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -13,7 +13,7 @@
"scripts": {
"lint": "eslint .",
"lint-fix": "eslint . --fix",
"test": "npm run lint && jest",
"test": "npm install --no-save \"gl@^5.0.0\" && npm run lint && jest",
"jest": "jest",
"build": "npm run build-tsc && npm run build-extra && npm run build-webpack",
"clean": "node ./scripts/clean.js",
@@ -86,77 +86,77 @@
"Áron Samuel Kovács <aron.kovacs@mail.muni.cz>",
"Ludovic Autin <autin@scripps.edu>",
"Michal Malý <michal.maly@ibt.cas.cz>",
"Jiří Černý <jiri.cerny@ibt.cas.cz>"
"Jiří Černý <jiri.cerny@ibt.cas.cz>",
"Panagiotis Tourlas <panagiot_tourlov@hotmail.com>"
],
"license": "MIT",
"devDependencies": {
"@graphql-codegen/add": "^3.1.0",
"@graphql-codegen/cli": "^2.3.0",
"@graphql-codegen/time": "^3.1.0",
"@graphql-codegen/typescript": "^2.4.1",
"@graphql-codegen/typescript-graphql-files-modules": "^2.1.0",
"@graphql-codegen/typescript-graphql-request": "^4.3.1",
"@graphql-codegen/typescript-operations": "^2.2.1",
"@graphql-codegen/add": "^3.1.1",
"@graphql-codegen/cli": "^2.6.2",
"@graphql-codegen/time": "^3.1.1",
"@graphql-codegen/typescript": "^2.4.11",
"@graphql-codegen/typescript-graphql-files-modules": "^2.1.1",
"@graphql-codegen/typescript-graphql-request": "^4.4.8",
"@graphql-codegen/typescript-operations": "^2.4.0",
"@types/cors": "^2.8.12",
"@types/gl": "^4.1.0",
"@types/jest": "^27.0.3",
"@typescript-eslint/eslint-plugin": "^5.5.0",
"@typescript-eslint/parser": "^5.5.0",
"@types/jest": "^27.5.1",
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.5",
"@typescript-eslint/eslint-plugin": "^5.27.0",
"@typescript-eslint/parser": "^5.27.0",
"benchmark": "^2.1.4",
"concurrently": "^6.4.0",
"cpx2": "^4.0.0",
"concurrently": "^7.2.1",
"cpx2": "^4.2.0",
"crypto-browserify": "^3.12.0",
"css-loader": "^6.5.1",
"eslint": "^8.3.0",
"css-loader": "^6.7.1",
"eslint": "^8.16.0",
"extra-watch-webpack-plugin": "^1.0.3",
"file-loader": "^6.2.0",
"fs-extra": "^10.0.0",
"graphql": "^15.7.2",
"http-server": "^14.0.0",
"jest": "^27.3.1",
"mini-css-extract-plugin": "^2.4.5",
"fs-extra": "^10.1.0",
"graphql": "^16.5.0",
"http-server": "^14.1.0",
"jest": "^28.1.0",
"mini-css-extract-plugin": "^2.6.0",
"path-browserify": "^1.0.1",
"raw-loader": "^4.0.2",
"sass": "^1.43.5",
"sass-loader": "^12.3.0",
"simple-git": "^2.47.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"sass": "^1.52.1",
"sass-loader": "^13.0.0",
"simple-git": "^3.7.1",
"stream-browserify": "^3.0.0",
"style-loader": "^3.3.1",
"ts-jest": "^27.0.7",
"typescript": "^4.5.2",
"webpack": "^5.64.4",
"webpack-cli": "^4.9.1"
"ts-jest": "^28.0.3",
"typescript": "^4.7.2",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2"
},
"dependencies": {
"@types/argparse": "^2.0.10",
"@types/benchmark": "^2.1.1",
"@types/compression": "1.7.2",
"@types/express": "^4.17.13",
"@types/node": "^16.11.10",
"@types/node-fetch": "^2.5.12",
"@types/react": "^17.0.37",
"@types/react-dom": "^17.0.11",
"@types/node": "^16.11.36",
"@types/node-fetch": "^2.6.1",
"@types/swagger-ui-dist": "3.30.1",
"argparse": "^2.0.1",
"body-parser": "^1.19.0",
"body-parser": "^1.20.0",
"compression": "^1.7.4",
"cors": "^2.8.5",
"express": "^4.17.1",
"express": "^4.18.1",
"h264-mp4-encoder": "^1.0.12",
"immer": "^9.0.7",
"immutable": "^3.8.2",
"node-fetch": "^2.6.2",
"rxjs": "^7.4.0",
"swagger-ui-dist": "^4.1.1",
"tslib": "^2.3.1",
"immer": "^9.0.14",
"immutable": "^4.1.0",
"node-fetch": "^2.6.7",
"rxjs": "^7.5.5",
"swagger-ui-dist": "^4.11.1",
"tslib": "^2.4.0",
"util.promisify": "^1.1.1",
"xhr2": "^0.2.1"
},
"peerDependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"optionalDependencies": {
"gl": "^4.9.2"
"react": "^18.1.0 || ^17.0.2 || ^16.14.0",
"react-dom": "^18.1.0 || ^17.0.2 || ^16.14.0"
}
}

View File

@@ -8,7 +8,7 @@
import { Structure } from '../../mol-model/structure';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { PluginStateObject as PSO, PluginStateTransform } from '../../mol-plugin-state/objects';
import { createPluginUI } from '../../mol-plugin-ui';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';

View File

@@ -44,10 +44,11 @@ function occlusionStyle(plugin: PluginContext) {
postprocessing: {
...plugin.canvas3d!.props.postprocessing,
occlusion: { name: 'on', params: {
samples: 64,
radius: 8,
bias: 1.0,
blurKernelSize: 13
bias: 0.8,
blurKernelSize: 15,
radius: 5,
samples: 32,
resolutionScale: 1
} },
outline: { name: 'on', params: {
scale: 1.0,

494
src/apps/viewer/app.ts Normal file
View File

@@ -0,0 +1,494 @@
/**
* 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 { ANVILMembraneOrientation } from '../../extensions/anvil/behavior';
import { CellPack } from '../../extensions/cellpack';
import { DnatcoConfalPyramids } from '../../extensions/dnatco';
import { G3DFormat, G3dProvider } from '../../extensions/g3d/format';
import { GeometryExport } from '../../extensions/geo-export';
import { MAQualityAssessment } from '../../extensions/model-archive/quality-assessment/behavior';
import { QualityAssessmentPLDDTPreset, QualityAssessmentQmeanPreset } from '../../extensions/model-archive/quality-assessment/behavior';
import { QualityAssessment } from '../../extensions/model-archive/quality-assessment/prop';
import { ModelExport } from '../../extensions/model-export';
import { Mp4Export } from '../../extensions/mp4-export';
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
import { RCSBAssemblySymmetry, RCSBValidationReport } from '../../extensions/rcsb';
import { ZenodoImport } from '../../extensions/zenodo';
import { Volume } from '../../mol-model/volume';
import { DownloadStructure, PdbDownloadProvider } from '../../mol-plugin-state/actions/structure';
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
import { PresetTrajectoryHierarchy } from '../../mol-plugin-state/builder/structure/hierarchy-preset';
import { PresetStructureRepresentations, StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
import { BuiltInTopologyFormat } from '../../mol-plugin-state/formats/topology';
import { BuiltInCoordinatesFormat } from '../../mol-plugin-state/formats/coordinates';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { BuildInVolumeFormat } from '../../mol-plugin-state/formats/volume';
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { TrajectoryFromModelAndCoordinates } from '../../mol-plugin-state/transforms/model';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginConfig } from '../../mol-plugin/config';
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
import { PluginSpec } from '../../mol-plugin/spec';
import { PluginState } from '../../mol-plugin/state';
import { StateObjectRef, StateObjectSelector } from '../../mol-state';
import { Asset } from '../../mol-util/assets';
import { Color } from '../../mol-util/color';
import '../../mol-util/polyfill';
import { ObjectKeys } from '../../mol-util/type-helpers';
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
export { setDebugMode, setProductionMode, setTimingMode } from '../../mol-util/debug';
const CustomFormats = [
['g3d', G3dProvider] as const
];
const Extensions = {
'cellpack': PluginSpec.Behavior(CellPack),
'dnatco-confal-pyramids': PluginSpec.Behavior(DnatcoConfalPyramids),
'pdbe-structure-quality-report': PluginSpec.Behavior(PDBeStructureQualityReport),
'rcsb-assembly-symmetry': PluginSpec.Behavior(RCSBAssemblySymmetry),
'rcsb-validation-report': PluginSpec.Behavior(RCSBValidationReport),
'anvil-membrane-orientation': PluginSpec.Behavior(ANVILMembraneOrientation),
'g3d': PluginSpec.Behavior(G3DFormat),
'model-export': PluginSpec.Behavior(ModelExport),
'mp4-export': PluginSpec.Behavior(Mp4Export),
'geo-export': PluginSpec.Behavior(GeometryExport),
'ma-quality-assessment': PluginSpec.Behavior(MAQualityAssessment),
'zenodo-import': PluginSpec.Behavior(ZenodoImport),
};
const DefaultViewerOptions = {
customFormats: CustomFormats as [string, DataFormatProvider][],
extensions: ObjectKeys(Extensions),
layoutIsExpanded: true,
layoutShowControls: true,
layoutShowRemoteState: true,
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
layoutShowSequence: true,
layoutShowLog: true,
layoutShowLeftPanel: true,
collapseLeftPanel: false,
collapseRightPanel: false,
disableAntialiasing: PluginConfig.General.DisableAntialiasing.defaultValue,
pixelScale: PluginConfig.General.PixelScale.defaultValue,
pickScale: PluginConfig.General.PickScale.defaultValue,
pickPadding: PluginConfig.General.PickPadding.defaultValue,
enableWboit: PluginConfig.General.EnableWboit.defaultValue,
preferWebgl1: PluginConfig.General.PreferWebGl1.defaultValue,
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
volumeStreamingDisabled: !PluginConfig.VolumeStreaming.Enabled.defaultValue,
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
};
type ViewerOptions = typeof DefaultViewerOptions;
export class Viewer {
constructor(public plugin: PluginUIContext) {
}
static async create(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
const definedOptions = {} as any;
// filter for defined properies only so the default values
// are property applied
for (const p of Object.keys(options) as (keyof ViewerOptions)[]) {
if (options[p] !== void 0) definedOptions[p] = options[p];
}
const o: ViewerOptions = { ...DefaultViewerOptions, ...definedOptions };
const defaultSpec = DefaultPluginUISpec();
const spec: PluginUISpec = {
actions: defaultSpec.actions,
behaviors: [
...defaultSpec.behaviors,
...o.extensions.map(e => Extensions[e]),
],
animations: [...defaultSpec.animations || []],
customParamEditors: defaultSpec.customParamEditors,
customFormats: o?.customFormats,
layout: {
initial: {
isExpanded: o.layoutIsExpanded,
showControls: o.layoutShowControls,
controlsDisplay: o.layoutControlsDisplay,
regionState: {
bottom: 'full',
left: o.collapseLeftPanel ? 'collapsed' : 'full',
right: o.collapseRightPanel ? 'hidden' : 'full',
top: 'full',
}
},
},
components: {
...defaultSpec.components,
controls: {
...defaultSpec.components?.controls,
top: o.layoutShowSequence ? undefined : 'none',
bottom: o.layoutShowLog ? undefined : 'none',
left: o.layoutShowLeftPanel ? undefined : 'none',
},
remoteState: o.layoutShowRemoteState ? 'default' : 'none',
},
config: [
[PluginConfig.General.DisableAntialiasing, o.disableAntialiasing],
[PluginConfig.General.PixelScale, o.pixelScale],
[PluginConfig.General.PickScale, o.pickScale],
[PluginConfig.General.PickPadding, o.pickPadding],
[PluginConfig.General.EnableWboit, o.enableWboit],
[PluginConfig.General.PreferWebGl1, o.preferWebgl1],
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
[PluginConfig.Viewport.ShowSelectionMode, o.viewportShowSelectionMode],
[PluginConfig.Viewport.ShowAnimation, o.viewportShowAnimation],
[PluginConfig.State.DefaultServer, o.pluginStateServer],
[PluginConfig.State.CurrentServer, o.pluginStateServer],
[PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
[PluginConfig.VolumeStreaming.Enabled, !o.volumeStreamingDisabled],
[PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider],
[PluginConfig.Structure.DefaultRepresentationPreset, ViewerAutoPreset.id],
]
};
const element = typeof elementOrId === 'string'
? document.getElementById(elementOrId)
: elementOrId;
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
const plugin = await createPluginUI(element, spec, {
onBeforeUIRender: plugin => {
// the preset needs to be added before the UI renders otherwise
// "Download Structure" wont be able to pick it up
plugin.builders.structure.representation.registerPreset(ViewerAutoPreset);
}
});
return new Viewer(plugin);
}
setRemoteSnapshot(id: string) {
const url = `${this.plugin.config.get(PluginConfig.State.CurrentServer)}/get/${id}`;
return PluginCommands.State.Snapshots.Fetch(this.plugin, { url });
}
loadSnapshotFromUrl(url: string, type: PluginState.SnapshotType) {
return PluginCommands.State.Snapshots.OpenUrl(this.plugin, { url, type });
}
loadStructureFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'url',
params: {
url: Asset.Url(url),
format: format as any,
isBinary,
options: { ...params.source.params.options, representationParams: options?.representationParams as any },
}
}
}));
}
async loadAllModelsOrAssemblyFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
const plugin = this.plugin;
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'all-models', { useDefaultIfSingleModel: true, representationPresetParams: options?.representationParams });
}
async loadStructureFromData(data: string | number[], format: BuiltInTrajectoryFormat, options?: { dataLabel?: string }) {
const _data = await this.plugin.builders.data.rawData({ data, label: options?.dataLabel });
const trajectory = await this.plugin.builders.structure.parseTrajectory(_data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default');
}
loadPdb(pdb: string, options?: LoadStructureOptions) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
const provider = this.plugin.config.get(PluginConfig.Download.DefaultPdbProvider)!;
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'pdb' as const,
params: {
provider: {
id: pdb,
server: {
name: provider,
params: PdbDownloadProvider[provider].defaultValue as any
}
},
options: { ...params.source.params.options, representationParams: options?.representationParams as any },
}
}
}));
}
loadPdbDev(pdbDev: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'pdb-dev' as const,
params: {
provider: {
id: pdbDev,
encoding: 'bcif',
},
options: params.source.params.options,
}
}
}));
}
loadEmdb(emdb: string, options?: { detail?: number }) {
const provider = this.plugin.config.get(PluginConfig.Download.DefaultEmdbProvider)!;
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadDensity, {
source: {
name: 'pdb-emd-ds' as const,
params: {
provider: {
id: emdb,
server: provider,
},
detail: options?.detail ?? 3,
}
}
}));
}
loadAlphaFoldDb(afdb: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'alphafolddb' as const,
params: {
id: afdb,
options: {
...params.source.params.options,
representation: 'preset-structure-representation-ma-quality-assessment-plddt'
},
}
}
}));
}
loadModelArchive(id: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'modelarchive' as const,
params: {
id,
options: params.source.params.options,
}
}
}));
}
/**
* @example Load X-ray density from volume server
viewer.loadVolumeFromUrl({
url: 'https://www.ebi.ac.uk/pdbe/densities/x-ray/1tqn/cell?detail=3',
format: 'dscif',
isBinary: true
}, [{
type: 'relative',
value: 1.5,
color: 0x3362B2
}, {
type: 'relative',
value: 3,
color: 0x33BB33,
volumeIndex: 1
}, {
type: 'relative',
value: -3,
color: 0xBB3333,
volumeIndex: 1
}], {
entryId: ['2FO-FC', 'FO-FC'],
isLazy: true
});
* *********************
* @example Load EM density from volume server
viewer.loadVolumeFromUrl({
url: 'https://maps.rcsb.org/em/emd-30210/cell?detail=6',
format: 'dscif',
isBinary: true
}, [{
type: 'relative',
value: 1,
color: 0x3377aa
}], {
entryId: 'EMD-30210',
isLazy: true
});
*/
async loadVolumeFromUrl({ url, format, isBinary }: { url: string, format: BuildInVolumeFormat, isBinary: boolean }, isovalues: VolumeIsovalueInfo[], options?: { entryId?: string | string[], isLazy?: boolean }) {
const plugin = this.plugin;
if (!plugin.dataFormats.get(format)) {
throw new Error(`Unknown density format: ${format}`);
}
if (options?.isLazy) {
const update = this.plugin.build();
update.toRoot().apply(StateTransforms.Data.LazyVolume, {
url,
format,
entryId: options?.entryId,
isBinary,
isovalues: isovalues.map(v => ({ alpha: 1, volumeIndex: 0, ...v }))
});
return update.commit();
}
return plugin.dataTransaction(async () => {
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
const parsed = await plugin.dataFormats.get(format)!.parse(plugin, data, { entryId: options?.entryId });
const firstVolume = (parsed.volume || parsed.volumes[0]) as StateObjectSelector<PluginStateObject.Volume.Data>;
if (!firstVolume?.isOk) throw new Error('Failed to parse any volume.');
const repr = plugin.build();
for (const iso of isovalues) {
const volume: StateObjectSelector<PluginStateObject.Volume.Data> = parsed.volumes?.[iso.volumeIndex ?? 0] ?? parsed.volume;
const volumeData = volume.cell!.obj!.data;
repr
.to(volume)
.apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(this.plugin, firstVolume.data!, {
type: 'isosurface',
typeParams: { alpha: iso.alpha ?? 1, isoValue: Volume.adjustedIsoValue(volumeData, iso.value, iso.type) },
color: 'uniform',
colorParams: { value: iso.color }
}));
}
await repr.commit();
});
}
/**
* @example
* viewer.loadTrajectory({
* model: { kind: 'model-url', url: 'villin.gro', format: 'gro' },
* coordinates: { kind: 'coordinates-url', url: 'villin.xtc', format: 'xtc', isBinary: true },
* preset: 'all-models' // or 'default'
* });
*/
async loadTrajectory(params: LoadTrajectoryParams) {
const plugin = this.plugin;
let model: StateObjectSelector, coords: StateObjectSelector;
if (params.model.kind === 'model-data' || params.model.kind === 'model-url') {
const data = params.model.kind === 'model-data'
? await plugin.builders.data.rawData({ data: params.model.data, label: params.modelLabel })
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
const trajectory = await plugin.builders.structure.parseTrajectory(data, params.model.format ?? 'mmcif');
model = await plugin.builders.structure.createModel(trajectory);
} else {
const data = params.model.kind === 'topology-data'
? await plugin.builders.data.rawData({ data: params.model.data, label: params.modelLabel })
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
const provider = plugin.dataFormats.get(params.model.format);
model = await provider!.parse(plugin, data);
}
{
const data = params.coordinates.kind === 'coordinates-data'
? await plugin.builders.data.rawData({ data: params.coordinates.data, label: params.coordinatesLabel })
: await plugin.builders.data.download({ url: params.coordinates.url, isBinary: params.coordinates.isBinary, label: params.coordinatesLabel });
const provider = plugin.dataFormats.get(params.coordinates.format);
coords = await provider!.parse(plugin, data);
}
const trajectory = await plugin.build().toRoot()
.apply(TrajectoryFromModelAndCoordinates, {
modelRef: model.ref,
coordinatesRef: coords.ref
}, { dependsOn: [model.ref, coords.ref] })
.commit();
const preset = await plugin.builders.structure.hierarchy.applyPreset(trajectory, params.preset ?? 'default');
return { model, coords, preset };
}
handleResize() {
this.plugin.layout.events.updated.next(void 0);
}
}
export interface LoadStructureOptions {
representationParams?: StructureRepresentationPresetProvider.CommonParams
}
export interface VolumeIsovalueInfo {
type: 'absolute' | 'relative',
value: number,
color: Color,
alpha?: number,
volumeIndex?: number
}
export interface LoadTrajectoryParams {
model: { kind: 'model-url', url: string, format?: BuiltInTrajectoryFormat /* mmcif */, isBinary?: boolean }
| { kind: 'model-data', data: string | number[] | ArrayBuffer | Uint8Array, format?: BuiltInTrajectoryFormat /* mmcif */ }
| { kind: 'topology-url', url: string, format: BuiltInTopologyFormat, isBinary?: boolean }
| { kind: 'topology-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuiltInTopologyFormat },
modelLabel?: string,
coordinates: { kind: 'coordinates-url', url: string, format: BuiltInCoordinatesFormat, isBinary?: boolean }
| { kind: 'coordinates-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuiltInCoordinatesFormat },
coordinatesLabel?: string,
preset?: keyof PresetTrajectoryHierarchy
}
export const ViewerAutoPreset = StructureRepresentationPresetProvider({
id: 'preset-structure-representation-viewer-auto',
display: {
name: 'Automatic (w/ Annotation)', group: 'Annotation',
description: 'Show standard automatic representation but colored by quality assessment (if available in the model).'
},
isApplicable(a) {
return (
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT')) ||
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))
);
},
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT'))) {
return await QualityAssessmentPLDDTPreset.apply(ref, params, plugin);
} else if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))) {
return await QualityAssessmentQmeanPreset.apply(ref, params, plugin);
} else {
return await PresetStructureRepresentations.auto.apply(ref, params, plugin);
}
}
});

View File

@@ -46,7 +46,10 @@
}
var debugMode = getParam('debug-mode', '[^&]+').trim() === '1';
if (debugMode) molstar.setDebugMode(debugMode, debugMode);
if (debugMode) molstar.setDebugMode(debugMode);
var timingMode = getParam('timing-mode', '[^&]+').trim() === '1';
if (timingMode) molstar.setTimingMode(timingMode);
var hideControls = getParam('hide-controls', '[^&]+').trim() === '1';
var collapseLeftPanel = getParam('collapse-left-panel', '[^&]+').trim() === '1';
@@ -57,7 +60,7 @@
var pickScale = getParam('pick-scale', '[^&]+').trim();
var pickPadding = getParam('pick-padding', '[^&]+').trim();
var disableWboit = getParam('disable-wboit', '[^&]+').trim() === '1';
var preferWebgl1 = getParam('prefer-webgl1', '[^&]+').trim() === '1';
var preferWebgl1 = getParam('prefer-webgl1', '[^&]+').trim() === '1' || void 0;
molstar.Viewer.create('app', {
layoutShowControls: !hideControls,
@@ -71,7 +74,7 @@
pixelScale: parseFloat(pixelScale) || 1,
pickScale: parseFloat(pickScale) || 0.25,
pickPadding: isNaN(parseFloat(pickPadding)) ? 1 : parseFloat(pickPadding),
enableWboit: !disableWboit,
enableWboit: disableWboit ? false : void 0, // use default value if disable-wboit is not set
preferWebgl1: preferWebgl1,
}).then(viewer => {
var snapshotId = getParam('snapshot-id', '[^&]+').trim();

View File

@@ -1,484 +1,12 @@
/**
* 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>
*/
import { ANVILMembraneOrientation } from '../../extensions/anvil/behavior';
import { CellPack } from '../../extensions/cellpack';
import { DnatcoConfalPyramids } from '../../extensions/dnatco';
import { G3DFormat, G3dProvider } from '../../extensions/g3d/format';
import { GeometryExport } from '../../extensions/geo-export';
import { MAQualityAssessment } from '../../extensions/model-archive/quality-assessment/behavior';
import { QualityAssessmentPLDDTPreset, QualityAssessmentQmeanPreset } from '../../extensions/model-archive/quality-assessment/behavior';
import { QualityAssessment } from '../../extensions/model-archive/quality-assessment/prop';
import { Mp4Export } from '../../extensions/mp4-export';
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
import { RCSBAssemblySymmetry, RCSBValidationReport } from '../../extensions/rcsb';
import { DownloadStructure, PdbDownloadProvider } from '../../mol-plugin-state/actions/structure';
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
import { PresetTrajectoryHierarchy } from '../../mol-plugin-state/builder/structure/hierarchy-preset';
import { PresetStructureRepresentations, StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
import { BuildInStructureFormat } from '../../mol-plugin-state/formats/structure';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { BuildInVolumeFormat } from '../../mol-plugin-state/formats/volume';
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { TrajectoryFromModelAndCoordinates } from '../../mol-plugin-state/transforms/model';
import { createPluginUI } from '../../mol-plugin-ui';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginConfig } from '../../mol-plugin/config';
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
import { PluginSpec } from '../../mol-plugin/spec';
import { PluginState } from '../../mol-plugin/state';
import { StateObjectRef, StateObjectSelector } from '../../mol-state';
import { Asset } from '../../mol-util/assets';
import { Color } from '../../mol-util/color';
import '../../mol-util/polyfill';
import { ObjectKeys } from '../../mol-util/type-helpers';
import './embedded.html';
import './favicon.ico';
import './index.html';
require('mol-plugin-ui/skin/light.scss');
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
export { setDebugMode, setProductionMode } from '../../mol-util/debug';
const CustomFormats = [
['g3d', G3dProvider] as const
];
const Extensions = {
'cellpack': PluginSpec.Behavior(CellPack),
'dnatco-confal-pyramids': PluginSpec.Behavior(DnatcoConfalPyramids),
'pdbe-structure-quality-report': PluginSpec.Behavior(PDBeStructureQualityReport),
'rcsb-assembly-symmetry': PluginSpec.Behavior(RCSBAssemblySymmetry),
'rcsb-validation-report': PluginSpec.Behavior(RCSBValidationReport),
'anvil-membrane-orientation': PluginSpec.Behavior(ANVILMembraneOrientation),
'g3d': PluginSpec.Behavior(G3DFormat),
'mp4-export': PluginSpec.Behavior(Mp4Export),
'geo-export': PluginSpec.Behavior(GeometryExport),
'ma-quality-assessment': PluginSpec.Behavior(MAQualityAssessment),
};
const DefaultViewerOptions = {
customFormats: CustomFormats as [string, DataFormatProvider][],
extensions: ObjectKeys(Extensions),
layoutIsExpanded: true,
layoutShowControls: true,
layoutShowRemoteState: true,
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
layoutShowSequence: true,
layoutShowLog: true,
layoutShowLeftPanel: true,
collapseLeftPanel: false,
collapseRightPanel: false,
disableAntialiasing: PluginConfig.General.DisableAntialiasing.defaultValue,
pixelScale: PluginConfig.General.PixelScale.defaultValue,
pickScale: PluginConfig.General.PickScale.defaultValue,
pickPadding: PluginConfig.General.PickPadding.defaultValue,
enableWboit: PluginConfig.General.EnableWboit.defaultValue,
preferWebgl1: PluginConfig.General.PreferWebGl1.defaultValue,
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
volumeStreamingDisabled: !PluginConfig.VolumeStreaming.Enabled.defaultValue,
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
};
type ViewerOptions = typeof DefaultViewerOptions;
export class Viewer {
constructor(public plugin: PluginUIContext) {
}
static async create(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
const o = { ...DefaultViewerOptions, ...options };
const defaultSpec = DefaultPluginUISpec();
const spec: PluginUISpec = {
actions: defaultSpec.actions,
behaviors: [
...defaultSpec.behaviors,
...o.extensions.map(e => Extensions[e]),
],
animations: [...defaultSpec.animations || []],
customParamEditors: defaultSpec.customParamEditors,
customFormats: o?.customFormats,
layout: {
initial: {
isExpanded: o.layoutIsExpanded,
showControls: o.layoutShowControls,
controlsDisplay: o.layoutControlsDisplay,
regionState: {
bottom: 'full',
left: o.collapseLeftPanel ? 'collapsed' : 'full',
right: o.collapseRightPanel ? 'hidden' : 'full',
top: 'full',
}
},
},
components: {
...defaultSpec.components,
controls: {
...defaultSpec.components?.controls,
top: o.layoutShowSequence ? undefined : 'none',
bottom: o.layoutShowLog ? undefined : 'none',
left: o.layoutShowLeftPanel ? undefined : 'none',
},
remoteState: o.layoutShowRemoteState ? 'default' : 'none',
},
config: [
[PluginConfig.General.DisableAntialiasing, o.disableAntialiasing],
[PluginConfig.General.PixelScale, o.pixelScale],
[PluginConfig.General.PickScale, o.pickScale],
[PluginConfig.General.PickPadding, o.pickPadding],
[PluginConfig.General.EnableWboit, o.enableWboit],
[PluginConfig.General.PreferWebGl1, o.preferWebgl1],
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
[PluginConfig.Viewport.ShowSelectionMode, o.viewportShowSelectionMode],
[PluginConfig.Viewport.ShowAnimation, o.viewportShowAnimation],
[PluginConfig.State.DefaultServer, o.pluginStateServer],
[PluginConfig.State.CurrentServer, o.pluginStateServer],
[PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
[PluginConfig.VolumeStreaming.Enabled, !o.volumeStreamingDisabled],
[PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider],
[PluginConfig.Structure.DefaultRepresentationPreset, ViewerAutoPreset.id],
]
};
const element = typeof elementOrId === 'string'
? document.getElementById(elementOrId)
: elementOrId;
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
const plugin = await createPluginUI(element, spec, {
onBeforeUIRender: plugin => {
// the preset needs to be added before the UI renders otherwise
// "Download Structure" wont be able to pick it up
plugin.builders.structure.representation.registerPreset(ViewerAutoPreset);
}
});
return new Viewer(plugin);
}
setRemoteSnapshot(id: string) {
const url = `${this.plugin.config.get(PluginConfig.State.CurrentServer)}/get/${id}`;
return PluginCommands.State.Snapshots.Fetch(this.plugin, { url });
}
loadSnapshotFromUrl(url: string, type: PluginState.SnapshotType) {
return PluginCommands.State.Snapshots.OpenUrl(this.plugin, { url, type });
}
loadStructureFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'url',
params: {
url: Asset.Url(url),
format: format as any,
isBinary,
options: { ...params.source.params.options, representationParams: options?.representationParams as any },
}
}
}));
}
async loadAllModelsOrAssemblyFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
const plugin = this.plugin;
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'all-models', { useDefaultIfSingleModel: true, representationPresetParams: options?.representationParams });
}
async loadStructureFromData(data: string | number[], format: BuiltInTrajectoryFormat, options?: { dataLabel?: string }) {
const _data = await this.plugin.builders.data.rawData({ data, label: options?.dataLabel });
const trajectory = await this.plugin.builders.structure.parseTrajectory(_data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default');
}
loadPdb(pdb: string, options?: LoadStructureOptions) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
const provider = this.plugin.config.get(PluginConfig.Download.DefaultPdbProvider)!;
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'pdb' as const,
params: {
provider: {
id: pdb,
server: {
name: provider,
params: PdbDownloadProvider[provider].defaultValue as any
}
},
options: { ...params.source.params.options, representationParams: options?.representationParams as any },
}
}
}));
}
loadPdbDev(pdbDev: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'pdb-dev' as const,
params: {
provider: {
id: pdbDev,
encoding: 'bcif',
},
options: params.source.params.options,
}
}
}));
}
loadEmdb(emdb: string, options?: { detail?: number }) {
const provider = this.plugin.config.get(PluginConfig.Download.DefaultEmdbProvider)!;
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadDensity, {
source: {
name: 'pdb-emd-ds' as const,
params: {
provider: {
id: emdb,
server: provider,
},
detail: options?.detail ?? 3,
}
}
}));
}
loadAlphaFoldDb(afdb: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'alphafolddb' as const,
params: {
id: afdb,
options: {
...params.source.params.options,
representation: 'preset-structure-representation-ma-quality-assessment-plddt'
},
}
}
}));
}
loadModelArchive(id: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'modelarchive' as const,
params: {
id,
options: params.source.params.options,
}
}
}));
}
/**
* @example Load X-ray density from volume server
viewer.loadVolumeFromUrl({
url: 'https://www.ebi.ac.uk/pdbe/densities/x-ray/1tqn/cell?detail=3',
format: 'dscif',
isBinary: true
}, [{
type: 'relative',
value: 1.5,
color: 0x3362B2
}, {
type: 'relative',
value: 3,
color: 0x33BB33,
volumeIndex: 1
}, {
type: 'relative',
value: -3,
color: 0xBB3333,
volumeIndex: 1
}], {
entryId: ['2FO-FC', 'FO-FC'],
isLazy: true
});
* *********************
* @example Load EM density from volume server
viewer.loadVolumeFromUrl({
url: 'https://maps.rcsb.org/em/emd-30210/cell?detail=6',
format: 'dscif',
isBinary: true
}, [{
type: 'relative',
value: 1,
color: 0x3377aa
}], {
entryId: 'EMD-30210',
isLazy: true
});
*/
async loadVolumeFromUrl({ url, format, isBinary }: { url: string, format: BuildInVolumeFormat, isBinary: boolean }, isovalues: VolumeIsovalueInfo[], options?: { entryId?: string | string[], isLazy?: boolean }) {
const plugin = this.plugin;
if (!plugin.dataFormats.get(format)) {
throw new Error(`Unknown density format: ${format}`);
}
if (options?.isLazy) {
const update = this.plugin.build();
update.toRoot().apply(StateTransforms.Data.LazyVolume, {
url,
format,
entryId: options?.entryId,
isBinary,
isovalues: isovalues.map(v => ({ alpha: 1, volumeIndex: 0, ...v }))
});
return update.commit();
}
return plugin.dataTransaction(async () => {
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
const parsed = await plugin.dataFormats.get(format)!.parse(plugin, data, { entryId: options?.entryId });
const firstVolume = (parsed.volume || parsed.volumes[0]) as StateObjectSelector<PluginStateObject.Volume.Data>;
if (!firstVolume?.isOk) throw new Error('Failed to parse any volume.');
const repr = plugin.build();
for (const iso of isovalues) {
repr
.to(parsed.volumes?.[iso.volumeIndex ?? 0] ?? parsed.volume)
.apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(this.plugin, firstVolume.data!, {
type: 'isosurface',
typeParams: { alpha: iso.alpha ?? 1, isoValue: iso.type === 'absolute' ? { kind: 'absolute', absoluteValue: iso.value } : { kind: 'relative', relativeValue: iso.value } },
color: 'uniform',
colorParams: { value: iso.color }
}));
}
await repr.commit();
});
}
/**
* @example
* viewer.loadTrajectory({
* model: { kind: 'model-url', url: 'villin.gro', format: 'gro' },
* coordinates: { kind: 'coordinates-url', url: 'villin.xtc', format: 'xtc', isBinary: true },
* preset: 'all-models' // or 'default'
* });
*/
async loadTrajectory(params: LoadTrajectoryParams) {
const plugin = this.plugin;
let model: StateObjectSelector, coords: StateObjectSelector;
if (params.model.kind === 'model-data' || params.model.kind === 'model-url') {
const data = params.model.kind === 'model-data'
? await plugin.builders.data.rawData({ data: params.model.data, label: params.modelLabel })
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
const trajectory = await plugin.builders.structure.parseTrajectory(data, params.model.format ?? 'mmcif');
model = await plugin.builders.structure.createModel(trajectory);
} else {
const data = params.model.kind === 'topology-data'
? await plugin.builders.data.rawData({ data: params.model.data, label: params.modelLabel })
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
const provider = plugin.dataFormats.get(params.model.format);
model = await provider!.parse(plugin, data);
}
{
const data = params.coordinates.kind === 'coordinates-data'
? await plugin.builders.data.rawData({ data: params.coordinates.data, label: params.coordinatesLabel })
: await plugin.builders.data.download({ url: params.coordinates.url, isBinary: params.coordinates.isBinary, label: params.coordinatesLabel });
const provider = plugin.dataFormats.get(params.coordinates.format);
coords = await provider!.parse(plugin, data);
}
const trajectory = await plugin.build().toRoot()
.apply(TrajectoryFromModelAndCoordinates, {
modelRef: model.ref,
coordinatesRef: coords.ref
}, { dependsOn: [model.ref, coords.ref] })
.commit();
const preset = await plugin.builders.structure.hierarchy.applyPreset(trajectory, params.preset ?? 'default');
return { model, coords, preset };
}
handleResize() {
this.plugin.layout.events.updated.next(void 0);
}
}
export interface LoadStructureOptions {
representationParams?: StructureRepresentationPresetProvider.CommonParams
}
export interface VolumeIsovalueInfo {
type: 'absolute' | 'relative',
value: number,
color: Color,
alpha?: number,
volumeIndex?: number
}
export interface LoadTrajectoryParams {
model: { kind: 'model-url', url: string, format?: BuiltInTrajectoryFormat /* mmcif */, isBinary?: boolean }
| { kind: 'model-data', data: string | number[] | ArrayBuffer | Uint8Array, format?: BuiltInTrajectoryFormat /* mmcif */ }
| { kind: 'topology-url', url: string, format: BuildInStructureFormat, isBinary?: boolean }
| { kind: 'topology-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuildInStructureFormat },
modelLabel?: string,
coordinates: { kind: 'coordinates-url', url: string, format: BuildInStructureFormat, isBinary?: boolean }
| { kind: 'coordinates-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuildInStructureFormat },
coordinatesLabel?: string,
preset?: keyof PresetTrajectoryHierarchy
}
export const ViewerAutoPreset = StructureRepresentationPresetProvider({
id: 'preset-structure-representation-viewer-auto',
display: {
name: 'Automatic (w/ Annotation)', group: 'Annotation',
description: 'Show standard automatic representation but colored by quality assessment (if available in the model).'
},
isApplicable(a) {
return (
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT')) ||
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))
);
},
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT'))) {
return await QualityAssessmentPLDDTPreset.apply(ref, params, plugin);
} else if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))) {
return await QualityAssessmentQmeanPreset.apply(ref, params, plugin);
} else {
return await PresetStructureRepresentations.auto.apply(ref, params, plugin);
}
}
});
export * from './app';

View File

@@ -1,8 +1,9 @@
#!/usr/bin/env node
/**
* 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 Josh McMenemy <josh.mcmenemy@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as argparse from 'argparse';
@@ -31,11 +32,11 @@ function extractIonNames(ccd: DatabaseCollection<CCD_Schema>) {
function writeIonNamesFile(filePath: string, ionNames: string[]) {
const output = `/**
* 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.
*
* Code-generated ion names params file. Names extracted from CCD components.
*
* @author molstar/chem-comp-dict/create-table cli
* @author molstar/chem-comp-dict/create-ions cli
*/
export const IonNames = new Set(${JSON.stringify(ionNames).replace(/"/g, "'").replace(/,/g, ', ')});

View File

@@ -0,0 +1,77 @@
#!/usr/bin/env node
/**
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as argparse from 'argparse';
import * as path from 'path';
import util from 'util';
import fs from 'fs';
require('util.promisify').shim();
const writeFile = util.promisify(fs.writeFile);
import { DatabaseCollection } from '../../mol-data/db';
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
import { ensureDataAvailable, readCCD } from './util';
function extractSaccharideNames(ccd: DatabaseCollection<CCD_Schema>) {
const saccharideNames: string[] = [];
for (const k in ccd) {
const { chem_comp } = ccd[k];
const type = chem_comp.type.value(0).toUpperCase();
if (type.includes('SACCHARIDE')) {
saccharideNames.push(chem_comp.id.value(0));
}
}
// these are extra saccharides that don't have SACCHARIDE in their type
saccharideNames.push(
'UMQ', // UNDECYL-MALTOSIDE, via GlyFinder
'SQD', // SULFOQUINOVOSYLDIACYLGLYCEROL, via GlyFinder
);
return saccharideNames;
}
function writeSaccharideNamesFile(filePath: string, ionNames: string[]) {
const output = `/**
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated ion names params file. Names extracted from CCD components.
*
* @author molstar/cli/chem-comp-dict/create-saccharides
*/
export const SaccharideNames = new Set(${JSON.stringify(ionNames).replace(/"/g, "'").replace(/,/g, ', ')});
`;
writeFile(filePath, output);
}
async function run(out: string, forceDownload = false) {
await ensureDataAvailable(forceDownload);
const ccd = await readCCD();
const saccharideNames = extractSaccharideNames(ccd);
if (!fs.existsSync(path.dirname(out))) {
fs.mkdirSync(path.dirname(out));
}
writeSaccharideNamesFile(out, saccharideNames);
}
const parser = new argparse.ArgumentParser({
add_help: true,
description: 'Extract and save SaccharideNames from CCD.'
});
parser.add_argument('out', {
help: 'Generated file output path.'
});
parser.add_argument('--forceDownload', '-f', {
action: 'store_true',
help: 'Force download of CCD and PVCD.'
});
interface Args {
out: string,
forceDownload?: boolean,
}
const args: Args = parser.parse_args();
run(args.out, args.forceDownload);

View File

@@ -71,7 +71,7 @@ function classify(name: string, field: CifField): CifWriter.Field {
}
export function convert(path: string, asText = false, hints?: EncodingStrategyHint[], filter?: string) {
return Task.create<Uint8Array>('BinaryCIF', async ctx => {
return Task.create<Uint8Array>('Convert CIF', async ctx => {
const encodingProvider: BinaryEncodingProvider = hints
? CifWriter.createEncodingProviderFromJsonConfig(hints)
: { get: (c, f) => void 0 };

View File

@@ -18,7 +18,7 @@ async function process(srcPath: string, outPath: string, configPath?: string, fi
const config = configPath ? JSON.parse(fs.readFileSync(configPath, 'utf8')) : void 0;
const filter = filterPath ? fs.readFileSync(filterPath, 'utf8') : void 0;
const res = await convert(srcPath, false, config, filter);
const res = await convert(srcPath, srcPath.toLowerCase().indexOf('.bcif') > 0, config, filter);
await write(outPath, res);
}
@@ -38,13 +38,13 @@ function run(args: Args) {
const parser = new argparse.ArgumentParser({
add_help: true,
description: 'Convert any CIF file to a BCIF file'
description: 'Convert any BCIF file to a CIF file or vice versa'
});
parser.add_argument('src', {
help: 'Source CIF path'
help: 'Source file path'
});
parser.add_argument('out', {
help: 'Output BCIF path'
help: 'Output file path'
});
parser.add_argument('-c', '--config', {
help: 'Optional encoding strategy/precision config path',

View File

@@ -161,7 +161,7 @@ const MMCIF_DIC_URL = 'http://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.
const IHM_DIC_PATH = `${DIC_DIR}/ihm-extension.dic`;
const IHM_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/IHM-dictionary/master/ihm-extension.dic';
const MA_DIC_PATH = `${DIC_DIR}/ma-extension.dic`;
const MA_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/MA-dictionary/master/mmcif_ma.dic';
const MA_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/ModelCIF/master/dist/mmcif_ma.dic';
const CIF_CORE_DIC_PATH = `${DIC_DIR}/cif_core.dic`;
const CIF_CORE_DIC_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/cif_core.dic';

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 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 Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -13,15 +13,17 @@ export function getFieldType(type: string, description: string, values?: string[
switch (type) {
// mmCIF
case 'code':
case 'ucode':
case 'line':
case 'uline':
case 'text':
case 'char':
case 'uchar3':
case 'uchar1':
case 'boolean':
return values && values.length ? EnumCol(values, 'str', description) : StrCol(description);
case 'ucode':
case 'uline':
case 'uchar3':
case 'uchar1':
// only force lower-case for enums
return values && values.length ? EnumCol(values.map(x => x.toLowerCase()), 'lstr', description) : StrCol(description);
case 'aliasname':
case 'name':
case 'idname':
@@ -49,6 +51,7 @@ export function getFieldType(type: string, description: string, values?: string[
case 'operation_expression':
case 'point_symmetry':
case '4x3_matrix':
case '3x4_matrix':
case '3x4_matrices':
case 'point_group':
case 'point_group_helical':

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2019 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 Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -10,7 +10,7 @@ import { FieldPath } from '../../../mol-io/reader/cif/schema';
function header(name: string, info: string, moldataImportPath: string) {
return `/**
* Copyright (c) 2017-2020 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.
*
* Code-generated '${name}' schema file. ${info}
*
@@ -35,13 +35,17 @@ function getTypeShorthands(schema: Database, fields?: Filter) {
const { columns } = schema.tables[table];
Object.keys(columns).forEach(columnName => {
if (fields && !fields[table][columnName]) return;
types.add(schema.tables[table].columns[columnName].type);
const col = schema.tables[table].columns[columnName];
if (col.type === 'enum') types.add(col.subType);
types.add(col.type);
});
});
const shorthands: string[] = [];
types.forEach(type => {
switch (type) {
case 'str': shorthands.push('const str = Schema.str;'); break;
case 'ustr': shorthands.push('const ustr = Schema.ustr;'); break;
case 'lstr': shorthands.push('const lstr = Schema.lstr;'); break;
case 'int': shorthands.push('const int = Schema.int;'); break;
case 'float': shorthands.push('const float = Schema.float;'); break;
case 'coord': shorthands.push('const coord = Schema.coord;'); break;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2019 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 Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -29,8 +29,8 @@ export function FloatCol(description: string): FloatCol { return { type: 'float'
export type CoordCol = { type: 'coord' } & BaseCol
export function CoordCol(description: string): CoordCol { return { type: 'coord', description }; }
export type EnumCol = { type: 'enum', subType: 'int' | 'str', values: string[] } & BaseCol
export function EnumCol(values: string[], subType: 'int' | 'str', description: string): EnumCol {
export type EnumCol = { type: 'enum', subType: 'int' | 'str' | 'ustr' | 'lstr', values: string[] } & BaseCol
export function EnumCol(values: string[], subType: 'int' | 'str' | 'ustr' | 'lstr', description: string): EnumCol {
return { type: 'enum', description, values, subType };
}

View File

@@ -55,6 +55,17 @@
</a>
</div>
<script>
function getParam(name, regex) {
var r = new RegExp(name + '=' + '(' + regex + ')[&]?', 'i');
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
}
var debugMode = getParam('debug-mode', '[^&]+').trim() === '1';
if (debugMode) AlphaOrbitalsExample.setDebugMode(debugMode);
var timingMode = getParam('timing-mode', '[^&]+').trim() === '1';
if (timingMode) AlphaOrbitalsExample.setTimingMode(timingMode);
AlphaOrbitalsExample.init('app')
</script>
<!-- __MOLSTAR_ANALYTICS__ -->

View File

@@ -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 David Sehnal <david.sehnal@gmail.com>
*/
@@ -11,7 +11,7 @@ import { SphericalBasisOrder } from '../../extensions/alpha-orbitals/spherical-f
import { BasisAndOrbitals, CreateOrbitalDensityVolume, CreateOrbitalRepresentation3D, CreateOrbitalVolume, StaticBasisAndOrbitals } from '../../extensions/alpha-orbitals/transforms';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { createPluginUI } from '../../mol-plugin-ui';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
import { PluginCommands } from '../../mol-plugin/commands';
@@ -25,6 +25,8 @@ import { DemoMoleculeSDF, DemoOrbitals } from './example-data';
import './index.html';
require('mol-plugin-ui/skin/light.scss');
import { setDebugMode, setTimingMode } from '../../mol-util/debug';
interface DemoInput {
moleculeSdf: string,
basis: Basis,
@@ -80,20 +82,24 @@ export class AlphaOrbitalsExample {
this.plugin.managers.interactivity.setProps({ granularity: 'element' });
if (!canComputeGrid3dOnGPU(this.plugin.canvas3d?.webgl)) {
PluginCommands.Toast.Show(this.plugin, {
title: 'Error',
message: `Browser/device does not support required WebGL extension (OES_texture_float).`
this.plugin.behaviors.canvas3d.initialized.subscribe(init => {
if (!init) return;
if (!canComputeGrid3dOnGPU(this.plugin.canvas3d?.webgl)) {
PluginCommands.Toast.Show(this.plugin, {
title: 'Error',
message: `Browser/device does not support required WebGL extension (OES_texture_float).`
});
return;
}
this.load({
moleculeSdf: DemoMoleculeSDF,
...DemoOrbitals
});
return;
}
this.load({
moleculeSdf: DemoMoleculeSDF,
...DemoOrbitals
mountControls(this, document.getElementById('controls')!);
});
mountControls(this, document.getElementById('controls')!);
}
readonly params = new BehaviorSubject<ParamDefinition.For<Params>>({} as any);
@@ -218,4 +224,6 @@ export class AlphaOrbitalsExample {
}
}
(window as any).AlphaOrbitalsExample = new AlphaOrbitalsExample();
(window as any).AlphaOrbitalsExample = new AlphaOrbitalsExample();
(window as any).AlphaOrbitalsExample.setDebugMode = setDebugMode;
(window as any).AlphaOrbitalsExample.setTimingMode = setTimingMode;

View File

@@ -9,7 +9,7 @@ import { EmptyLoci } from '../../mol-model/loci';
import { StructureSelection } from '../../mol-model/structure';
import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/model-index';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { createPluginUI } from '../../mol-plugin-ui';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
import { PluginCommands } from '../../mol-plugin/commands';
@@ -74,12 +74,20 @@ class BasicWrapper {
toggleSpin() {
if (!this.plugin.canvas3d) return;
const trackball = this.plugin.canvas3d.props.trackball;
PluginCommands.Canvas3D.SetSettings(this.plugin, {
settings: props => {
props.trackball.spin = !props.trackball.spin;
settings: {
trackball: {
...trackball,
animate: trackball.animate.name === 'spin'
? { name: 'off', params: {} }
: { name: 'spin', params: { speed: 1 } }
}
}
});
if (!this.plugin.canvas3d.props.trackball.spin) PluginCommands.Camera.Reset(this.plugin, {});
if (this.plugin.canvas3d.props.trackball.animate.name !== 'spin') {
PluginCommands.Camera.Reset(this.plugin, {});
}
}
private animateModelIndexTargetFps() {

View File

@@ -6,7 +6,7 @@
import { Canvas3DProps } from '../../mol-canvas3d/canvas3d';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { createPluginUI } from '../../mol-plugin-ui';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
import { PluginCommands } from '../../mol-plugin/commands';
@@ -24,7 +24,7 @@ const Canvas3DPresets = {
illustrative: {
canvas3d: <Preset>{
postprocessing: {
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
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) } }
},
renderer: {
@@ -36,7 +36,7 @@ const Canvas3DPresets = {
occlusion: {
canvas3d: <Preset>{
postprocessing: {
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } },
outline: { name: 'off', params: {} }
},
renderer: {

View File

@@ -10,7 +10,7 @@ import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/mod
import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
import { PluginStateObject, PluginStateObject as PSO } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { createPluginUI } from '../../mol-plugin-ui';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
import { CreateVolumeStreamingInfo, InitVolumeStreaming } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
@@ -256,7 +256,16 @@ class MolStarProteopediaWrapper {
toggleSpin() {
if (!this.plugin.canvas3d) return;
const trackball = this.plugin.canvas3d.props.trackball;
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
PluginCommands.Canvas3D.SetSettings(this.plugin, {
settings: {
trackball: {
...trackball,
animate: trackball.animate.name === 'spin'
? { name: 'off', params: {} }
: { name: 'spin', params: { speed: 1 } }
}
}
});
}
viewport = {

View File

@@ -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 David Sehnal <david.sehnal@gmail.com>
*/
@@ -8,6 +8,7 @@ import { sortArray } from '../../mol-data/util';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { Task } from '../../mol-task';
import { isTimingMode } from '../../mol-util/debug';
import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
import { gpuComputeAlphaOrbitalsDensityGridValues } from './gpu/compute';
@@ -19,9 +20,9 @@ export function createSphericalCollocationDensityGrid(
let matrix: Float32Array;
if (canComputeGrid3dOnGPU(webgl)) {
// console.time('gpu');
matrix = await gpuComputeAlphaOrbitalsDensityGridValues(ctx, webgl!, cubeGrid, orbitals);
// console.timeEnd('gpu');
if (isTimingMode) webgl.timer.mark('createSphericalCollocationDensityGrid');
matrix = await gpuComputeAlphaOrbitalsDensityGridValues(ctx, webgl, cubeGrid, orbitals);
if (isTimingMode) webgl.timer.markEnd('createSphericalCollocationDensityGrid');
} else {
throw new Error('Missing OES_texture_float WebGL extension.');
}

View File

@@ -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.
*
* Inspired by https://github.com/dgasmith/gau2grid.
*
@@ -10,12 +10,11 @@ import { sortArray } from '../../mol-data/util';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { Task } from '../../mol-task';
import { isTimingMode } from '../../mol-util/debug';
import { sphericalCollocation } from './collocation';
import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
import { gpuComputeAlphaOrbitalsGridValues } from './gpu/compute';
// setDebugMode(true);
export function createSphericalCollocationGrid(
params: CubeGridComputationParams, orbital: AlphaOrbital, webgl?: WebGLContext
): Task<CubeGrid> {
@@ -24,9 +23,9 @@ export function createSphericalCollocationGrid(
let matrix: Float32Array;
if (canComputeGrid3dOnGPU(webgl)) {
// console.time('gpu');
matrix = await gpuComputeAlphaOrbitalsGridValues(ctx, webgl!, cubeGrid, orbital);
// console.timeEnd('gpu');
if (isTimingMode) webgl.timer.mark('createSphericalCollocationGrid');
matrix = await gpuComputeAlphaOrbitalsGridValues(ctx, webgl, cubeGrid, orbital);
if (isTimingMode) webgl.timer.markEnd('createSphericalCollocationGrid');
} else {
// console.time('cpu');
matrix = await sphericalCollocation(cubeGrid, orbital, ctx);

View File

@@ -43,9 +43,9 @@ export type BilayerPlanesProps = PD.Values<BilayerPlanesParams>
const BilayerRimsParams = {
...Lines.Params,
...SharedParams,
lineSizeAttenuation: PD.Boolean(true),
linesSize: PD.Numeric(0.3, { min: 0.01, max: 50, step: 0.01 }),
dashedLines: PD.Boolean(true),
lineSizeAttenuation: PD.Boolean(false),
linesSize: PD.Numeric(0.5, { min: 0.01, max: 50, step: 0.01 }),
dashedLines: PD.Boolean(false),
};
export type BilayerRimsParams = typeof BilayerRimsParams
export type BilayerRimsProps = PD.Values<BilayerRimsParams>

View File

@@ -32,6 +32,7 @@ import { Color } from '../../mol-util/color';
import { objectForEach } from '../../mol-util/object';
import { readFromFile } from '../../mol-util/data-source';
import { ColorNames } from '../../mol-util/color/names';
import { createBasic } from '../../mol-model-formats/structure/basic/schema';
function getCellPackModelUrl(fileName: string, baseUrl: string) {
return `${baseUrl}/results/${fileName}`;
@@ -310,7 +311,8 @@ async function getCurve(plugin: PluginContext, name: string, ingredient: Ingredi
const cif = getCifCurve(name, transforms, model);
const curveModelTask = Task.create('Curve Model', async ctx => {
const format = MmcifFormat.fromFrame(cif);
const models = await createModels(format.data.db, format, ctx);
const basic = createBasic(format.data.db, true);
const models = await createModels(basic, format, ctx);
return models.representative;
});

View File

@@ -11,149 +11,248 @@ import { Location } from '../../../mol-model/location';
import { CustomProperty } from '../../../mol-model-props/common/custom-property';
import { ColorTheme } from '../../../mol-theme/color';
import { ThemeDataContext } from '../../../mol-theme/theme';
import { Color } from '../../../mol-util/color';
import { Color, ColorMap } from '../../../mol-util/color';
import { getColorMapParams } from '../../../mol-util/color/params';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { TableLegend } from '../../../mol-util/legend';
import { iterableToArray } from '../../../mol-data/util';
import { ObjectKeys } from '../../../mol-util/type-helpers';
const DefaultColor = Color(0xCCCCCC);
const Description = 'Assigns colors to confal pyramids';
const DefaultClassColors = {
A: 0xFFC1C1,
B: 0xC8CFFF,
BII: 0x0059DA,
miB: 0x3BE8FB,
Z: 0x01F60E,
IC: 0xFA5CFB,
OPN: 0xE90000,
SYN: 0xFFFF01,
N: 0xF2F2F2,
};
const ErrorColor = Color(0xFFA10A);
type ConformerClasses = 'A' | 'B' | 'BII' | 'miB' | 'Z' | 'IC' | 'OPN' | 'SYN' | 'N';
const PyramidsColors = ColorMap({
NANT_Upr: DefaultClassColors.N,
NANT_Lwr: DefaultClassColors.N,
AA00_Upr: DefaultClassColors.A,
AA00_Lwr: DefaultClassColors.A,
AA02_Upr: DefaultClassColors.A,
AA02_Lwr: DefaultClassColors.A,
AA03_Upr: DefaultClassColors.A,
AA03_Lwr: DefaultClassColors.A,
AA04_Upr: DefaultClassColors.A,
AA04_Lwr: DefaultClassColors.A,
AA08_Upr: DefaultClassColors.A,
AA08_Lwr: DefaultClassColors.A,
AA09_Upr: DefaultClassColors.A,
AA09_Lwr: DefaultClassColors.A,
AA01_Upr: DefaultClassColors.A,
AA01_Lwr: DefaultClassColors.A,
AA05_Upr: DefaultClassColors.A,
AA05_Lwr: DefaultClassColors.A,
AA06_Upr: DefaultClassColors.A,
AA06_Lwr: DefaultClassColors.A,
AA10_Upr: DefaultClassColors.A,
AA10_Lwr: DefaultClassColors.A,
AA11_Upr: DefaultClassColors.A,
AA11_Lwr: DefaultClassColors.A,
AA07_Upr: DefaultClassColors.A,
AA07_Lwr: DefaultClassColors.A,
AA12_Upr: DefaultClassColors.A,
AA12_Lwr: DefaultClassColors.A,
AA13_Upr: DefaultClassColors.A,
AA13_Lwr: DefaultClassColors.A,
AB01_Upr: DefaultClassColors.A,
AB01_Lwr: DefaultClassColors.B,
AB02_Upr: DefaultClassColors.A,
AB02_Lwr: DefaultClassColors.B,
AB03_Upr: DefaultClassColors.A,
AB03_Lwr: DefaultClassColors.B,
AB04_Upr: DefaultClassColors.A,
AB04_Lwr: DefaultClassColors.B,
AB05_Upr: DefaultClassColors.A,
AB05_Lwr: DefaultClassColors.B,
BA01_Upr: DefaultClassColors.B,
BA01_Lwr: DefaultClassColors.A,
BA05_Upr: DefaultClassColors.B,
BA05_Lwr: DefaultClassColors.A,
BA09_Upr: DefaultClassColors.B,
BA09_Lwr: DefaultClassColors.A,
BA08_Upr: DefaultClassColors.BII,
BA08_Lwr: DefaultClassColors.A,
BA10_Upr: DefaultClassColors.B,
BA10_Lwr: DefaultClassColors.A,
BA13_Upr: DefaultClassColors.BII,
BA13_Lwr: DefaultClassColors.A,
BA16_Upr: DefaultClassColors.BII,
BA16_Lwr: DefaultClassColors.A,
BA17_Upr: DefaultClassColors.BII,
BA17_Lwr: DefaultClassColors.A,
BB00_Upr: DefaultClassColors.B,
BB00_Lwr: DefaultClassColors.B,
BB01_Upr: DefaultClassColors.B,
BB01_Lwr: DefaultClassColors.B,
BB17_Upr: DefaultClassColors.B,
BB17_Lwr: DefaultClassColors.B,
BB02_Upr: DefaultClassColors.B,
BB02_Lwr: DefaultClassColors.B,
BB03_Upr: DefaultClassColors.B,
BB03_Lwr: DefaultClassColors.B,
BB11_Upr: DefaultClassColors.B,
BB11_Lwr: DefaultClassColors.B,
BB16_Upr: DefaultClassColors.B,
BB16_Lwr: DefaultClassColors.B,
BB04_Upr: DefaultClassColors.B,
BB04_Lwr: DefaultClassColors.BII,
BB05_Upr: DefaultClassColors.B,
BB05_Lwr: DefaultClassColors.BII,
BB07_Upr: DefaultClassColors.BII,
BB07_Lwr: DefaultClassColors.BII,
BB08_Upr: DefaultClassColors.BII,
BB08_Lwr: DefaultClassColors.BII,
BB10_Upr: DefaultClassColors.miB,
BB10_Lwr: DefaultClassColors.miB,
BB12_Upr: DefaultClassColors.miB,
BB12_Lwr: DefaultClassColors.miB,
BB13_Upr: DefaultClassColors.miB,
BB13_Lwr: DefaultClassColors.miB,
BB14_Upr: DefaultClassColors.miB,
BB14_Lwr: DefaultClassColors.miB,
BB15_Upr: DefaultClassColors.miB,
BB15_Lwr: DefaultClassColors.miB,
BB20_Upr: DefaultClassColors.miB,
BB20_Lwr: DefaultClassColors.miB,
IC01_Upr: DefaultClassColors.IC,
IC01_Lwr: DefaultClassColors.IC,
IC02_Upr: DefaultClassColors.IC,
IC02_Lwr: DefaultClassColors.IC,
IC03_Upr: DefaultClassColors.IC,
IC03_Lwr: DefaultClassColors.IC,
IC04_Upr: DefaultClassColors.IC,
IC04_Lwr: DefaultClassColors.IC,
IC05_Upr: DefaultClassColors.IC,
IC05_Lwr: DefaultClassColors.IC,
IC06_Upr: DefaultClassColors.IC,
IC06_Lwr: DefaultClassColors.IC,
IC07_Upr: DefaultClassColors.IC,
IC07_Lwr: DefaultClassColors.IC,
OP01_Upr: DefaultClassColors.OPN,
OP01_Lwr: DefaultClassColors.OPN,
OP02_Upr: DefaultClassColors.OPN,
OP02_Lwr: DefaultClassColors.OPN,
OP03_Upr: DefaultClassColors.OPN,
OP03_Lwr: DefaultClassColors.OPN,
OP04_Upr: DefaultClassColors.OPN,
OP04_Lwr: DefaultClassColors.OPN,
OP05_Upr: DefaultClassColors.OPN,
OP05_Lwr: DefaultClassColors.OPN,
OP06_Upr: DefaultClassColors.OPN,
OP06_Lwr: DefaultClassColors.OPN,
OP07_Upr: DefaultClassColors.OPN,
OP07_Lwr: DefaultClassColors.OPN,
OP08_Upr: DefaultClassColors.OPN,
OP08_Lwr: DefaultClassColors.OPN,
OP09_Upr: DefaultClassColors.OPN,
OP09_Lwr: DefaultClassColors.OPN,
OP10_Upr: DefaultClassColors.OPN,
OP10_Lwr: DefaultClassColors.OPN,
OP11_Upr: DefaultClassColors.OPN,
OP11_Lwr: DefaultClassColors.OPN,
OP12_Upr: DefaultClassColors.OPN,
OP12_Lwr: DefaultClassColors.OPN,
OP13_Upr: DefaultClassColors.OPN,
OP13_Lwr: DefaultClassColors.OPN,
OP14_Upr: DefaultClassColors.OPN,
OP14_Lwr: DefaultClassColors.OPN,
OP15_Upr: DefaultClassColors.OPN,
OP15_Lwr: DefaultClassColors.OPN,
OP16_Upr: DefaultClassColors.OPN,
OP16_Lwr: DefaultClassColors.OPN,
OP17_Upr: DefaultClassColors.OPN,
OP17_Lwr: DefaultClassColors.OPN,
OP18_Upr: DefaultClassColors.OPN,
OP18_Lwr: DefaultClassColors.OPN,
OP19_Upr: DefaultClassColors.OPN,
OP19_Lwr: DefaultClassColors.OPN,
OP20_Upr: DefaultClassColors.OPN,
OP20_Lwr: DefaultClassColors.OPN,
OP21_Upr: DefaultClassColors.OPN,
OP21_Lwr: DefaultClassColors.OPN,
OP22_Upr: DefaultClassColors.OPN,
OP22_Lwr: DefaultClassColors.OPN,
OP23_Upr: DefaultClassColors.OPN,
OP23_Lwr: DefaultClassColors.OPN,
OP24_Upr: DefaultClassColors.OPN,
OP24_Lwr: DefaultClassColors.OPN,
OP25_Upr: DefaultClassColors.OPN,
OP25_Lwr: DefaultClassColors.OPN,
OP26_Upr: DefaultClassColors.OPN,
OP26_Lwr: DefaultClassColors.OPN,
OP27_Upr: DefaultClassColors.OPN,
OP27_Lwr: DefaultClassColors.OPN,
OP28_Upr: DefaultClassColors.OPN,
OP28_Lwr: DefaultClassColors.OPN,
OP29_Upr: DefaultClassColors.OPN,
OP29_Lwr: DefaultClassColors.OPN,
OP30_Upr: DefaultClassColors.OPN,
OP30_Lwr: DefaultClassColors.OPN,
OP31_Upr: DefaultClassColors.OPN,
OP31_Lwr: DefaultClassColors.OPN,
OPS1_Upr: DefaultClassColors.OPN,
OPS1_Lwr: DefaultClassColors.OPN,
OP1S_Upr: DefaultClassColors.OPN,
OP1S_Lwr: DefaultClassColors.SYN,
AAS1_Upr: DefaultClassColors.SYN,
AAS1_Lwr: DefaultClassColors.A,
AB1S_Upr: DefaultClassColors.A,
AB1S_Lwr: DefaultClassColors.SYN,
AB2S_Upr: DefaultClassColors.A,
AB2S_Lwr: DefaultClassColors.SYN,
BB1S_Upr: DefaultClassColors.B,
BB1S_Lwr: DefaultClassColors.SYN,
BB2S_Upr: DefaultClassColors.B,
BB2S_Lwr: DefaultClassColors.SYN,
BBS1_Upr: DefaultClassColors.SYN,
BBS1_Lwr: DefaultClassColors.B,
ZZ01_Upr: DefaultClassColors.Z,
ZZ01_Lwr: DefaultClassColors.Z,
ZZ02_Upr: DefaultClassColors.Z,
ZZ02_Lwr: DefaultClassColors.Z,
ZZ1S_Upr: DefaultClassColors.Z,
ZZ1S_Lwr: DefaultClassColors.SYN,
ZZ2S_Upr: DefaultClassColors.Z,
ZZ2S_Lwr: DefaultClassColors.SYN,
ZZS1_Upr: DefaultClassColors.SYN,
ZZS1_Lwr: DefaultClassColors.Z,
ZZS2_Upr: DefaultClassColors.SYN,
ZZS2_Lwr: DefaultClassColors.Z,
});
type PyramidsColors = typeof PyramidsColors;
const ColorMapping: ReadonlyMap<ConformerClasses, Color> = new Map([
['A', Color(0xFFC1C1)],
['B', Color(0xC8CFFF)],
['BII', Color(0x0059DA)],
['miB', Color(0x3BE8FB)],
['Z', Color(0x01F60E)],
['IC', Color(0xFA5CFB)],
['OPN', Color(0xE90000)],
['SYN', Color(0xFFFF01)],
['N', Color(0xF2F2F2)],
]);
export const ConfalPyramidsColorThemeParams = {
colors: PD.MappedStatic('default', {
'default': PD.EmptyGroup(),
'custom': PD.Group(getColorMapParams(PyramidsColors))
}),
};
export type ConfalPyramidsColorThemeParams = typeof ConfalPyramidsColorThemeParams;
const NtCToClasses: ReadonlyMap<string, [ConformerClasses, ConformerClasses]> = new Map([
['NANT', ['N', 'N']],
['AA00', ['A', 'A']],
['AA02', ['A', 'A']],
['AA03', ['A', 'A']],
['AA04', ['A', 'A']],
['AA08', ['A', 'A']],
['AA09', ['A', 'A']],
['AA01', ['A', 'A']],
['AA05', ['A', 'A']],
['AA06', ['A', 'A']],
['AA10', ['A', 'A']],
['AA11', ['A', 'A']],
['AA07', ['A', 'A']],
['AA12', ['A', 'A']],
['AA13', ['A', 'A']],
['AB01', ['A', 'B']],
['AB02', ['A', 'B']],
['AB03', ['A', 'B']],
['AB04', ['A', 'B']],
['AB05', ['A', 'B']],
['BA01', ['B', 'A']],
['BA05', ['B', 'A']],
['BA09', ['B', 'A']],
['BA08', ['BII', 'A']],
['BA10', ['B', 'A']],
['BA13', ['BII', 'A']],
['BA16', ['BII', 'A']],
['BA17', ['BII', 'A']],
['BB00', ['B', 'B']],
['BB01', ['B', 'B']],
['BB17', ['B', 'B']],
['BB02', ['B', 'B']],
['BB03', ['B', 'B']],
['BB11', ['B', 'B']],
['BB16', ['B', 'B']],
['BB04', ['B', 'BII']],
['BB05', ['B', 'BII']],
['BB07', ['BII', 'BII']],
['BB08', ['BII', 'BII']],
['BB10', ['miB', 'miB']],
['BB12', ['miB', 'miB']],
['BB13', ['miB', 'miB']],
['BB14', ['miB', 'miB']],
['BB15', ['miB', 'miB']],
['BB20', ['miB', 'miB']],
['IC01', ['IC', 'IC']],
['IC02', ['IC', 'IC']],
['IC03', ['IC', 'IC']],
['IC04', ['IC', 'IC']],
['IC05', ['IC', 'IC']],
['IC06', ['IC', 'IC']],
['IC07', ['IC', 'IC']],
['OP01', ['OPN', 'OPN']],
['OP02', ['OPN', 'OPN']],
['OP03', ['OPN', 'OPN']],
['OP04', ['OPN', 'OPN']],
['OP05', ['OPN', 'OPN']],
['OP06', ['OPN', 'OPN']],
['OP07', ['OPN', 'OPN']],
['OP08', ['OPN', 'OPN']],
['OP09', ['OPN', 'OPN']],
['OP10', ['OPN', 'OPN']],
['OP11', ['OPN', 'OPN']],
['OP12', ['OPN', 'OPN']],
['OP13', ['OPN', 'OPN']],
['OP14', ['OPN', 'OPN']],
['OP15', ['OPN', 'OPN']],
['OP16', ['OPN', 'OPN']],
['OP17', ['OPN', 'OPN']],
['OP18', ['OPN', 'OPN']],
['OP19', ['OPN', 'OPN']],
['OP20', ['OPN', 'OPN']],
['OP21', ['OPN', 'OPN']],
['OP22', ['OPN', 'OPN']],
['OP23', ['OPN', 'OPN']],
['OP24', ['OPN', 'OPN']],
['OP25', ['OPN', 'OPN']],
['OP26', ['OPN', 'OPN']],
['OP27', ['OPN', 'OPN']],
['OP28', ['OPN', 'OPN']],
['OP29', ['OPN', 'OPN']],
['OP30', ['OPN', 'OPN']],
['OP31', ['OPN', 'OPN']],
['OPS1', ['OPN', 'OPN']],
['OP1S', ['OPN', 'SYN']],
['AAS1', ['SYN', 'A']],
['AB1S', ['A', 'SYN']],
['AB2S', ['A', 'SYN']],
['BB1S', ['B', 'SYN']],
['BB2S', ['B', 'SYN']],
['BBS1', ['SYN', 'B']],
['ZZ01', ['Z', 'Z']],
['ZZ02', ['Z', 'Z']],
['ZZ1S', ['Z', 'SYN']],
['ZZ2S', ['Z', 'SYN']],
['ZZS1', ['SYN', 'Z']],
['ZZS2', ['SYN', 'Z']],
]);
function getConformerColor(ntc: string, useLower: boolean): Color {
const item = NtCToClasses.get(ntc);
if (!item) return ErrorColor;
return ColorMapping.get(useLower ? item[1] : item[0]) ?? ErrorColor;
}
export const ConfalPyramidsColorThemeParams = {};
export type ConfalPyramidsColorThemeParams = typeof ConfalPyramidsColorThemeParams
export function getConfalPyramidsColorThemeParams(ctx: ThemeDataContext) {
return ConfalPyramidsColorThemeParams; // TODO return copy
return PD.clone(ConfalPyramidsColorThemeParams);
}
export function ConfalPyramidsColorTheme(ctx: ThemeDataContext, props: PD.Values<ConfalPyramidsColorThemeParams>): ColorTheme<ConfalPyramidsColorThemeParams> {
const colorMap = props.colors.name === 'default' ? PyramidsColors : props.colors.params;
function color(location: Location, isSecondary: boolean): Color {
if (CPT.isLocation(location)) {
const { pyramid, isLower } = location.data;
return getConformerColor(pyramid.NtC, isLower);
const key = pyramid.NtC + `_${isLower ? 'Lwr' : 'Upr'}` as keyof PyramidsColors;
return colorMap[key] ?? ErrorColor;
}
return DefaultColor;
return ErrorColor;
}
return {
@@ -162,12 +261,7 @@ export function ConfalPyramidsColorTheme(ctx: ThemeDataContext, props: PD.Values
color,
props,
description: Description,
legend: TableLegend(iterableToArray(ColorMapping.entries()).map(([conformer, color]) => {
return [conformer, color] as [string, Color];
}).concat([
['Error', ErrorColor],
['Unknown', DefaultColor]
]))
legend: TableLegend(ObjectKeys(colorMap).map(k => [k.replace('_', ' '), colorMap[k]] as [string, Color]).concat([['Error', ErrorColor]])),
};
}

View File

@@ -123,10 +123,8 @@ function createPyramidsFromCif(model: Model,
for (let i = 0; i < _rowCount; i++) {
const model_num = PDB_model_number.value(i);
if (model_num !== model.modelNum) {
if (model_num !== model.modelNum)
hasMultipleModels = true;
continue; // We are only interested in data for the current model
}
const { _NtC, _confal_score } = getNtCAndConfalScore(id.value(i), i, stepsSummary);

View File

@@ -7,7 +7,7 @@
import { ConfalPyramidsProvider } from './property';
import { ConfalPyramidsTypes as CPT } from './types';
import { OrderedSet, Segmentation } from '../../../mol-data/int';
import { Segmentation } from '../../../mol-data/int';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { ChainIndex, ElementIndex, ResidueIndex, Structure, StructureElement, StructureProperties, Unit } from '../../../mol-model/structure';
@@ -63,15 +63,12 @@ export namespace ConfalPyramidsUtil {
return prop.data.hasMultipleModels;
}
function getPossibleAltIdsIndices(eIFirst: ElementIndex, eILast: ElementIndex, structure: Structure, unit: Unit.Atomic): string[] {
const loc = StructureElement.Location.create(structure, unit, -1 as ElementIndex);
const uIFirst = OrderedSet.indexOf(unit.elements, eIFirst);
const uILast = OrderedSet.indexOf(unit.elements, eILast);
function getPossibleAltIds(residue: Residue, structure: Structure, unit: Unit.Atomic): string[] {
const possibleAltIds: string[] = [];
for (let uI = uIFirst; uI <= uILast; uI++) {
loc.element = unit.elements[uI];
const loc = StructureElement.Location.create(structure, unit, -1 as ElementIndex);
for (let rI = residue.start; rI <= residue.end - 1; rI++) {
loc.element = unit.elements[rI];
const altId = StructureProperties.atom.label_alt_id(loc);
if (altId !== '' && !possibleAltIds.includes(altId)) possibleAltIds.push(altId);
}
@@ -79,10 +76,6 @@ export namespace ConfalPyramidsUtil {
return possibleAltIds;
}
function getPossibleAltIdsResidue(residue: Residue, structure: Structure, unit: Unit.Atomic): string[] {
return getPossibleAltIdsIndices(unit.elements[residue.start], unit.elements[residue.end - 1], structure, unit);
}
class Utility {
protected getPyramidByName(name: string): { pyramid: CPT.Pyramid | undefined, index: number } {
const index = this.data.names.get(name);
@@ -122,19 +115,22 @@ export namespace ConfalPyramidsUtil {
export class UnitWalker extends Utility {
private getAtomIndices(names: string[], residue: Residue): ElementIndex[] {
let rI = residue.start;
const rILast = residue.end - 1;
const indices: ElementIndex[] = [];
for (; rI !== rILast; rI++) {
const eI = this.unit.elements[rI];
const loc = StructureElement.Location.create(this.structure, this.unit, eI);
const loc = StructureElement.Location.create(this.structure, this.unit, -1 as ElementIndex);
for (let rI = residue.start; rI <= residue.end - 1; rI++) {
loc.element = this.unit.elements[rI];
const thisName = StructureProperties.atom.label_atom_id(loc);
if (names.includes(thisName)) indices.push(eI);
if (names.includes(thisName)) indices.push(loc.element);
}
if (indices.length === 0)
throw new Error(`Element ${name} not found on residue ${residue.index}`);
if (indices.length === 0) {
let namesStr = '';
for (const n of names)
namesStr += `${n} `;
throw new Error(`Element [${namesStr}] not found on residue ${residue.index}`);
}
return indices;
}
@@ -257,12 +253,12 @@ export namespace ConfalPyramidsUtil {
}
private step(residue: Residue): { firstAtoms: FirstResidueAtoms[], secondAtoms: SecondResidueAtoms[] } {
const firstPossibleAltIds = getPossibleAltIdsResidue(residue, this.structure, this.unit);
const firstPossibleAltIds = getPossibleAltIds(residue, this.structure, this.unit);
const firstAtoms = this.processFirstResidue(residue, firstPossibleAltIds);
residue = this.residueIt.move();
const secondPossibleAltIds = getPossibleAltIdsResidue(residue, this.structure, this.unit);
const secondPossibleAltIds = getPossibleAltIds(residue, this.structure, this.unit);
const secondAtoms = this.processSecondResidue(residue, secondPossibleAltIds);
return { firstAtoms, secondAtoms };

View File

@@ -0,0 +1,87 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { utf8ByteCount, utf8Write } from '../../mol-io/common/utf8';
import { to_mmCIF, Unit } from '../../mol-model/structure';
import { PluginContext } from '../../mol-plugin/context';
import { Task } from '../../mol-task';
import { getFormattedTime } from '../../mol-util/date';
import { download } from '../../mol-util/download';
import { zip } from '../../mol-util/zip/zip';
export async function exportHierarchy(plugin: PluginContext, options?: { format?: 'cif' | 'bcif' }) {
try {
await plugin.runTask(_exportHierarchy(plugin, options), { useOverlay: true });
} catch (e) {
console.error(e);
plugin.log.error(`Model export failed. See console for details.`);
}
}
function _exportHierarchy(plugin: PluginContext, options?: { format?: 'cif' | 'bcif' }) {
return Task.create('Export', async ctx => {
await ctx.update({ message: 'Exporting...', isIndeterminate: true, canAbort: false });
const format = options?.format ?? 'cif';
const { structures } = plugin.managers.structure.hierarchy.current;
const files: [name: string, data: string | Uint8Array][] = [];
const entryMap = new Map<string, number>();
for (const _s of structures) {
const s = _s.transform?.cell.obj?.data ?? _s.cell.obj?.data;
if (!s) continue;
if (s.models.length > 1) {
plugin.log.warn(`[Export] Skipping ${_s.cell.obj?.label}: Multimodel exports not supported.`);
continue;
}
if (s.units.some(u => !Unit.isAtomic(u))) {
plugin.log.warn(`[Export] Skipping ${_s.cell.obj?.label}: Non-atomic model exports not supported.`);
continue;
}
const name = entryMap.has(s.model.entryId)
? `${s.model.entryId}_${entryMap.get(s.model.entryId)! + 1}.${format}`
: `${s.model.entryId}.${format}`;
entryMap.set(s.model.entryId, (entryMap.get(s.model.entryId) ?? 0) + 1);
await ctx.update({ message: `Exporting ${s.model.entryId}...`, isIndeterminate: true, canAbort: false });
if (s.elementCount > 100000) {
// Give UI chance to update, only needed for larger structures.
await new Promise(res => setTimeout(res, 50));
}
try {
files.push([name, to_mmCIF(s.model.entryId, s, format === 'bcif', { copyAllCategories: true })]);
} catch (e) {
if (format === 'cif' && s.elementCount > 2000000) {
plugin.log.warn(`[Export] The structure might be too big to be exported as Text CIF, consider using the BinaryCIF format instead.`);
}
throw e;
}
}
if (files.length === 1) {
download(new Blob([files[0][1]]), files[0][0]);
} else if (files.length > 1) {
const zipData: Record<string, Uint8Array> = {};
for (const [fn, data] of files) {
if (data instanceof Uint8Array) {
zipData[fn] = data;
} else {
const bytes = new Uint8Array(utf8ByteCount(data));
utf8Write(bytes, 0, data);
zipData[fn] = bytes;
}
}
await ctx.update({ message: `Compressing Data...`, isIndeterminate: true, canAbort: false });
const buffer = await zip(ctx, zipData);
download(new Blob([new Uint8Array(buffer, 0, buffer.byteLength)]), `structures_${getFormattedTime()}.zip`);
}
plugin.log.info(`[Export] Done.`);
});
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { PluginBehavior } from '../../mol-plugin/behavior/behavior';
import { ModelExportUI } from './ui';
export const ModelExport = PluginBehavior.create<{}>({
name: 'extension-model-export',
category: 'misc',
display: {
name: 'Model Export'
},
ctor: class extends PluginBehavior.Handler<{}> {
register(): void {
this.ctx.customStructureControls.set('model-export', ModelExportUI as any);
}
update() {
return false;
}
unregister() {
this.ctx.customStructureControls.delete('model-export');
}
},
params: () => ({})
});

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { useState } from 'react';
import { CollapsableControls, CollapsableState } from '../../mol-plugin-ui/base';
import { Button } from '../../mol-plugin-ui/controls/common';
import { GetAppSvg } from '../../mol-plugin-ui/controls/icons';
import { ParameterControls } from '../../mol-plugin-ui/controls/parameters';
import { useBehavior } from '../../mol-plugin-ui/hooks/use-behavior';
import { PluginContext } from '../../mol-plugin/context';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { exportHierarchy } from './export';
export class ModelExportUI extends CollapsableControls<{}, {}> {
protected defaultState(): CollapsableState {
return {
header: 'Export Models',
isCollapsed: true,
brand: { accent: 'cyan', svg: GetAppSvg }
};
}
protected renderControls(): JSX.Element | null {
return <ExportControls plugin={this.plugin} />;
}
}
const Params = {
format: PD.Select<'cif' | 'bcif'>('cif', [['cif', 'mmCIF'], ['bcif', 'Binary mmCIF']])
};
const DefaultParams = PD.getDefaultValues(Params);
function ExportControls({ plugin }: { plugin: PluginContext }) {
const [params, setParams] = useState(DefaultParams);
const [exporting, setExporting] = useState(false);
useBehavior(plugin.managers.structure.hierarchy.behaviors.selection); // triggers UI update
const isBusy = useBehavior(plugin.behaviors.state.isBusy);
const hierarchy = plugin.managers.structure.hierarchy.current;
let label: string = 'Nothing to Export';
if (hierarchy.structures.length === 1) {
label = 'Export';
} if (hierarchy.structures.length > 1) {
label = 'Export (as ZIP)';
}
const onExport = async () => {
setExporting(true);
try {
await exportHierarchy(plugin, { format: params.format });
} finally {
setExporting(false);
}
};
return <>
<ParameterControls params={Params} values={params} onChangeValues={setParams} isDisabled={isBusy || exporting} />
<Button
onClick={onExport}
style={{ marginTop: 1 }}
disabled={isBusy || hierarchy.structures.length === 0 || exporting}
commit={hierarchy.structures.length ? 'on' : 'off'}
>
{label}
</Button>
</>;
}

View File

@@ -73,7 +73,7 @@ export async function encodeMp4Animation<A extends PluginStateAnimation>(plugin:
await plugin.managers.animation.play(params.animation.definition, params.animation.params);
stoppedAnimation = false;
for (let i = 0; i <= N; i++) {
await loop.tick(i * dt, { isSynchronous: true, manualDraw: true });
await loop.tick(i * dt, { isSynchronous: true, animation: { currentFrame: i, frameCount: N }, manualDraw: true });
const image = params.pass.getImageData(width, height, normalizedViewport);
encoder.addFrameRgba(image.data);

View File

@@ -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 2021-11-25T14:34:23-08:00
// Generated on 2022-04-30T15:35:08-07:00
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
@@ -477,6 +477,8 @@ export type ClustersMembers = {
export type CoreAssembly = {
/** Get PDB entry that includes this assembly. */
readonly entry?: Maybe<CoreEntry>;
/** Get all pairwise polymer interfaces for this PDB assembly. */
readonly interfaces?: Maybe<ReadonlyArray<Maybe<CoreInterface>>>;
readonly pdbx_struct_assembly?: Maybe<PdbxStructAssembly>;
readonly pdbx_struct_assembly_auth_evidence?: Maybe<ReadonlyArray<Maybe<PdbxStructAssemblyAuthEvidence>>>;
readonly pdbx_struct_assembly_gen?: Maybe<ReadonlyArray<Maybe<PdbxStructAssemblyGen>>>;
@@ -657,6 +659,8 @@ export type CoreEntry = {
readonly em_staining?: Maybe<ReadonlyArray<Maybe<EmStaining>>>;
readonly em_vitrification?: Maybe<ReadonlyArray<Maybe<EmVitrification>>>;
readonly entry?: Maybe<Entry>;
/** Get all groups for this PDB entry. */
readonly entry_groups?: Maybe<ReadonlyArray<Maybe<GroupEntry>>>;
readonly exptl?: Maybe<ReadonlyArray<Maybe<Exptl>>>;
readonly exptl_crystal?: Maybe<ReadonlyArray<Maybe<ExptlCrystal>>>;
readonly exptl_crystal_grow?: Maybe<ReadonlyArray<Maybe<ExptlCrystalGrow>>>;
@@ -701,6 +705,7 @@ export type CoreEntry = {
readonly rcsb_associated_holdings?: Maybe<CurrentEntry>;
readonly rcsb_binding_affinity?: Maybe<ReadonlyArray<Maybe<RcsbBindingAffinity>>>;
readonly rcsb_entry_container_identifiers: RcsbEntryContainerIdentifiers;
readonly rcsb_entry_group_membership?: Maybe<ReadonlyArray<Maybe<RcsbEntryGroupMembership>>>;
readonly rcsb_entry_info: RcsbEntryInfo;
readonly rcsb_external_references?: Maybe<ReadonlyArray<Maybe<RcsbExternalReferences>>>;
/**
@@ -724,6 +729,16 @@ export type CoreEntry = {
readonly symmetry?: Maybe<Symmetry>;
};
export type CoreInterface = {
readonly rcsb_id: Scalars['String'];
readonly rcsb_interface_container_identifiers: RcsbInterfaceContainerIdentifiers;
readonly rcsb_interface_info?: Maybe<RcsbInterfaceInfo>;
/** List of operations for each interface partner. */
readonly rcsb_interface_operator: ReadonlyArray<Maybe<ReadonlyArray<Maybe<ReadonlyArray<Maybe<Scalars['String']>>>>>>;
readonly rcsb_interface_partner: ReadonlyArray<Maybe<RcsbInterfacePartner>>;
readonly rcsb_latest_revision?: Maybe<RcsbLatestRevision>;
};
export type CoreNonpolymerEntity = {
/** Get PDB entry that contains this non-polymer entity. */
readonly entry?: Maybe<CoreEntry>;
@@ -839,6 +854,8 @@ export type CorePolymerEntity = {
readonly pdbx_entity_src_syn?: Maybe<ReadonlyArray<Maybe<PdbxEntitySrcSyn>>>;
/** Get all unique Pfam annotations associated with this molecular entity. */
readonly pfams?: Maybe<ReadonlyArray<Maybe<CorePfam>>>;
/** Get all groups for this PDB entity. */
readonly polymer_entity_groups?: Maybe<ReadonlyArray<Maybe<GroupPolymerEntity>>>;
/** Get all unique polymer instances (chains) for this molecular entity. */
readonly polymer_entity_instances?: Maybe<ReadonlyArray<Maybe<CorePolymerEntityInstance>>>;
/** Get a BIRD chemical components described in this molecular entity. */
@@ -875,6 +892,7 @@ export type CorePolymerEntity = {
readonly rcsb_polymer_entity_container_identifiers: RcsbPolymerEntityContainerIdentifiers;
readonly rcsb_polymer_entity_feature?: Maybe<ReadonlyArray<Maybe<RcsbPolymerEntityFeature>>>;
readonly rcsb_polymer_entity_feature_summary?: Maybe<ReadonlyArray<Maybe<RcsbPolymerEntityFeatureSummary>>>;
readonly rcsb_polymer_entity_group_membership?: Maybe<ReadonlyArray<Maybe<RcsbPolymerEntityGroupMembership>>>;
readonly rcsb_polymer_entity_keywords?: Maybe<RcsbPolymerEntityKeywords>;
readonly rcsb_polymer_entity_name_com?: Maybe<ReadonlyArray<Maybe<RcsbPolymerEntityNameCom>>>;
readonly rcsb_polymer_entity_name_sys?: Maybe<ReadonlyArray<Maybe<RcsbPolymerEntityNameSys>>>;
@@ -3186,6 +3204,88 @@ export type GeneName = {
readonly value?: Maybe<Scalars['String']>;
};
export type GroupEntry = {
/** Get provenance associated with this group. */
readonly group_provenance?: Maybe<GroupProvenance>;
readonly rcsb_group_accession_info?: Maybe<RcsbGroupAccessionInfo>;
readonly rcsb_group_container_identifiers: RcsbGroupContainerIdentifiers;
readonly rcsb_group_info: RcsbGroupInfo;
readonly rcsb_group_related?: Maybe<ReadonlyArray<Maybe<RcsbGroupRelated>>>;
readonly rcsb_group_statistics?: Maybe<RcsbGroupStatistics>;
/** A unique textual identifier for a group */
readonly rcsb_id: Scalars['String'];
};
export type GroupMembersAlignmentAlignedRegions = {
/** Aligned region length */
readonly length: Scalars['Int'];
/** Entity seqeunce start position */
readonly query_begin: Scalars['Int'];
/** NCBI sequence start position */
readonly target_begin: Scalars['Int'];
};
export type GroupMembersAlignmentScores = {
readonly query_coverage: Scalars['Int'];
readonly query_length: Scalars['Int'];
readonly target_coverage: Scalars['Int'];
readonly target_length: Scalars['Int'];
};
export type GroupPolymerEntity = {
/** Get provenance associated with this group. */
readonly group_provenance?: Maybe<GroupProvenance>;
readonly rcsb_group_accession_info?: Maybe<RcsbGroupAccessionInfo>;
readonly rcsb_group_container_identifiers: RcsbGroupContainerIdentifiers;
readonly rcsb_group_info: RcsbGroupInfo;
readonly rcsb_group_related?: Maybe<ReadonlyArray<Maybe<RcsbGroupRelated>>>;
readonly rcsb_group_statistics?: Maybe<RcsbGroupStatistics>;
/** A unique textual identifier for a group */
readonly rcsb_id: Scalars['String'];
readonly rcsb_polymer_entity_group_members_rankings?: Maybe<ReadonlyArray<Maybe<RcsbPolymerEntityGroupMembersRankings>>>;
readonly rcsb_polymer_entity_group_sequence_alignment?: Maybe<RcsbPolymerEntityGroupSequenceAlignment>;
};
export type GroupProvenance = {
readonly rcsb_group_aggregation_method?: Maybe<RcsbGroupAggregationMethod>;
readonly rcsb_group_provenance_container_identifiers?: Maybe<RcsbGroupProvenanceContainerIdentifiers>;
/** A unique textual identifier for a group provenance */
readonly rcsb_id?: Maybe<Scalars['String']>;
};
export type InterfacePartnerFeatureAdditionalProperties = {
/**
* The additional property name.
*
* Allowable values:
* TO_BE_DEFINED
*
*/
readonly name?: Maybe<Scalars['String']>;
/** The value(s) of the additional property. */
readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['ObjectScalar']>>>;
};
export type InterfacePartnerFeatureFeaturePositions = {
/** An identifier for the monomer at which this segment of the feature begins. */
readonly beg_seq_id: Scalars['Int'];
/** An identifier for the monomer at which this segment of the feature ends. */
readonly end_seq_id?: Maybe<Scalars['Int']>;
/** The value(s) of the feature over the monomer segment. */
readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['Float']>>>;
};
export type MethodDetails = {
/** A description of special aspects of the clustering process */
readonly description?: Maybe<Scalars['String']>;
/** Defines the name of the description associated with the clustering process */
readonly name?: Maybe<Scalars['String']>;
/** Defines the type of the description associated with the clustering process */
readonly type?: Maybe<Scalars['String']>;
/** Defines the value associated with the clustering process */
readonly value?: Maybe<Scalars['Float']>;
};
export type PdbxAuditRevisionCategory = {
/**
* The category updated in the pdbx_audit_revision_category record.
@@ -6745,6 +6845,16 @@ export type Query = {
readonly entries?: Maybe<ReadonlyArray<Maybe<CoreEntry>>>;
/** Get PDB entry given the PDB id. */
readonly entry?: Maybe<CoreEntry>;
/** Given a group ID get a group object formed by aggregating individual structures that share a degree of similarity */
readonly entry_group?: Maybe<GroupEntry>;
/** Given a list of group IDs get a list of group objects formed by aggregating structures that share a degree of similarity */
readonly entry_groups?: Maybe<ReadonlyArray<Maybe<GroupEntry>>>;
/** Given a group provenance ID get an object that describes aggregation method used to create groups */
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. */
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. */
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. */
@@ -6757,6 +6867,10 @@ export type Query = {
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>;
/** Given a group ID get a group object formed by aggregating polymer entities that share a degree of similarity */
readonly polymer_entity_group?: Maybe<GroupPolymerEntity>;
/** Given a list of group IDs get a list of group objects formed by aggregating polymer entities that share a degree of similarity */
readonly polymer_entity_groups?: Maybe<ReadonlyArray<Maybe<GroupPolymerEntity>>>;
/** Get a PDB polymer entity instance (chain), given the PDB ID and ENTITY INSTANCE ID. Here ENTITY INSTANCE ID identifies structural element in the asymmetric unit, e.g. 'A', 'B', etc. */
readonly polymer_entity_instance?: Maybe<CorePolymerEntityInstance>;
/** Get a list of PDB 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. */
@@ -6831,6 +6945,38 @@ export type QueryEntryArgs = {
};
/** Query root */
export type QueryEntry_GroupArgs = {
group_id: Scalars['String'];
};
/** Query root */
export type QueryEntry_GroupsArgs = {
group_ids: ReadonlyArray<InputMaybe<Scalars['String']>>;
};
/** Query root */
export type QueryGroup_ProvenanceArgs = {
group_provenance_id: Scalars['String'];
};
/** Query root */
export type QueryInterfaceArgs = {
assembly_id: Scalars['String'];
entry_id: Scalars['String'];
interface_id: Scalars['String'];
};
/** Query root */
export type QueryInterfacesArgs = {
interface_ids: ReadonlyArray<Scalars['String']>;
};
/** Query root */
export type QueryNonpolymer_EntitiesArgs = {
entity_ids: ReadonlyArray<Scalars['String']>;
@@ -6870,6 +7016,18 @@ export type QueryPolymer_EntityArgs = {
};
/** Query root */
export type QueryPolymer_Entity_GroupArgs = {
group_id: Scalars['String'];
};
/** Query root */
export type QueryPolymer_Entity_GroupsArgs = {
group_ids: ReadonlyArray<InputMaybe<Scalars['String']>>;
};
/** Query root */
export type QueryPolymer_Entity_InstanceArgs = {
asym_id: Scalars['String'];
@@ -6952,6 +7110,8 @@ export type RcsbAssemblyContainerIdentifiers = {
readonly assembly_id: Scalars['String'];
/** Entry identifier for the container. */
readonly entry_id: Scalars['String'];
/** List of binary interface Ids within the assembly (it points to interface id collection). */
readonly interface_ids?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>;
/**
* A unique identifier for each object in this assembly container formed by
* a dash separated concatenation of entry and assembly identifiers.
@@ -7010,6 +7170,24 @@ export type RcsbAssemblyInfo = {
* This is the total count of non-polymer entity instances generated in the assembly coordinate data.
*/
readonly nonpolymer_entity_instance_count?: Maybe<Scalars['Int']>;
/** Number of heterologous (both binding sites are different) interface entities */
readonly num_heterologous_interface_entities?: Maybe<Scalars['Int']>;
/** Number of heteromeric (both partners are different polymeric entities) interface entities */
readonly num_heteromeric_interface_entities?: Maybe<Scalars['Int']>;
/** Number of homomeric (both partners are the same polymeric entity) interface entities */
readonly num_homomeric_interface_entities?: Maybe<Scalars['Int']>;
/** Number of polymer-polymer interface entities, grouping equivalent interfaces at the entity level (i.e. same entity_ids on either side, with similar but not identical binding sites) */
readonly num_interface_entities?: Maybe<Scalars['Int']>;
/** Number of geometrically equivalent (i.e. same asym_ids on either side) polymer-polymer interfaces in the assembly */
readonly num_interfaces?: Maybe<Scalars['Int']>;
/** Number of isologous (both binding sites are same, i.e. interface is symmetric) interface entities */
readonly num_isologous_interface_entities?: Maybe<Scalars['Int']>;
/** Number of nucleic acid-nucleic acid interface entities */
readonly num_na_interface_entities?: Maybe<Scalars['Int']>;
/** Number of protein-nucleic acid interface entities */
readonly num_prot_na_interface_entities?: Maybe<Scalars['Int']>;
/** Number of protein-protein interface entities */
readonly num_protein_interface_entities?: Maybe<Scalars['Int']>;
/** The assembly non-hydrogen polymer entity atomic coordinate count. */
readonly polymer_atom_count?: Maybe<Scalars['Int']>;
/**
@@ -7085,6 +7263,10 @@ export type RcsbAssemblyInfo = {
* This is the total count of solvent entity instances generated in the assembly coordinate data.
*/
readonly solvent_entity_instance_count?: Maybe<Scalars['Int']>;
/** Total buried surface area calculated as the sum of buried surface areas over all interfaces */
readonly total_assembly_buried_surface_area?: Maybe<Scalars['Float']>;
/** Total number of interfacing residues in the assembly, calculated as the sum of interfacing residues over all interfaces */
readonly total_number_interface_residues?: Maybe<Scalars['Int']>;
/**
* The number of unmodeled polymer monomers in the assembly coordinate data. This is
* the total count of monomers with unreported coordinate data for all polymer
@@ -8590,6 +8772,25 @@ export type RcsbEntryContainerIdentifiers = {
readonly water_entity_ids?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>;
};
export type RcsbEntryGroupMembership = {
/**
* Method used to establish group membership
*
* Allowable values:
* matching_deposit_group_id
*
*/
readonly aggregation_method: Scalars['String'];
/**
* A unique identifier for a group of entries
*
* Examples:
* G_1001001
*
*/
readonly group_id: Scalars['String'];
};
export type RcsbEntryInfo = {
/** The number of assemblies defined for this entry including the deposited assembly. */
readonly assembly_count?: Maybe<Scalars['Int']>;
@@ -8817,6 +9018,220 @@ export type RcsbGenomicLineage = {
readonly name?: Maybe<Scalars['String']>;
};
export type RcsbGroupAccessionInfo = {
/** Identifies the version of the groups solution */
readonly version: Scalars['Int'];
};
export type RcsbGroupAggregationMethod = {
/** The details on a method used to calculate cluster solutions */
readonly method: RcsbGroupAggregationMethodMethod;
readonly similarity_criteria?: Maybe<RcsbGroupAggregationMethodSimilarityCriteria>;
/**
* Specifies the type of similarity criteria used to aggregate members into higher levels in the hierarchy
*
* Allowable values:
* sequence_identity, matching_uniprot_accession, matching_deposit_group_id
*
*/
readonly type: Scalars['String'];
};
export type RcsbGroupAggregationMethodMethod = {
/** Additional details describing the clustering process */
readonly details?: Maybe<ReadonlyArray<Maybe<MethodDetails>>>;
/**
* The name of the software or the method used to calculate cluster solutions
*
* Allowable values:
* mmseqs2, matching_reference_identity
*
*/
readonly name: Scalars['String'];
/**
* The version of the software.
*
* Examples:
* v1.0, 3.1-2, unknown
*
*/
readonly version?: Maybe<Scalars['String']>;
};
export type RcsbGroupAggregationMethodSimilarityCriteria = {
/**
* A function or similarity measure that quantifies the similarity between two members
*
* Allowable values:
* rmsd, sequence_identity
*
*/
readonly similarity_function?: Maybe<Scalars['String']>;
};
export type RcsbGroupContainerIdentifiers = {
/** A unique textual identifier for a group */
readonly group_id: Scalars['String'];
/** Member identifiers representing a group */
readonly group_member_ids: ReadonlyArray<Maybe<Scalars['String']>>;
/**
* A unique group provenance identifier
*
* Allowable values:
* provenance_sequence_identity, provenance_matching_uniprot_accession, provenance_matching_deposit_group_id
*
*/
readonly group_provenance_id: Scalars['String'];
/** Member identifiers representing a higher level in the groping hierarchy that has parent-child relationship */
readonly parent_member_ids?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>;
};
export type RcsbGroupInfo = {
readonly group_description?: Maybe<Scalars['String']>;
readonly group_members_count: Scalars['Int'];
/**
* Granularity of group members identifiers
*
* Allowable values:
* assembly, entry, polymer_entity, polymer_entity_instance
*
*/
readonly group_members_granularity: Scalars['String'];
readonly group_name?: Maybe<Scalars['String']>;
};
export type RcsbGroupProvenanceContainerIdentifiers = {
/**
* A unique group provenance identifier
*
* Allowable values:
* provenance_sequence_identity, provenance_matching_uniprot_accession, provenance_matching_deposit_group_id
*
*/
readonly group_provenance_id: Scalars['String'];
};
export type RcsbGroupRelated = {
/**
* A unique code assigned to a reference related the group
*
* Examples:
* P69905
*
*/
readonly resource_accession_code?: Maybe<Scalars['String']>;
/**
* Defines the type of the resource describing related references
*
* Examples:
* UniProt
*
*/
readonly resource_name?: Maybe<Scalars['String']>;
};
export type RcsbGroupStatistics = {
/** The desired lower limit for the similarity between two members that belong to the same group */
readonly similarity_cutoff?: Maybe<Scalars['Float']>;
/** Similarity score between two most similar group members */
readonly similarity_score_max?: Maybe<Scalars['Float']>;
/** Similarity score between two least similar group members */
readonly similarity_score_min?: Maybe<Scalars['Float']>;
};
export type RcsbInterfaceContainerIdentifiers = {
/** This item references an assembly in pdbx_struct_assembly */
readonly assembly_id: Scalars['String'];
/** Entry identifier for the container. */
readonly entry_id: Scalars['String'];
/**
* Identifier for NCS-equivalent interfaces within the assembly (same entity_ids on both sides)
*
* Examples:
* 1, 2
*
*/
readonly interface_entity_id?: Maybe<Scalars['String']>;
/**
* Identifier for the geometrically equivalent (same asym_ids on either side) interfaces within the assembly
*
* Examples:
* 1, 2
*
*/
readonly interface_id: Scalars['String'];
/**
* Unique identifier for the document
*
* Examples:
* 2UZI-1.A.B?1
*
*/
readonly rcsb_id: Scalars['String'];
};
export type RcsbInterfaceInfo = {
/** Total interface buried surface area */
readonly interface_area?: Maybe<Scalars['Float']>;
/** Allowable values: homo, hetero. */
readonly interface_character?: Maybe<Scalars['String']>;
/** Number of core interface residues, defined as those that bury >90% accessible surface area with respect to the unbound state */
readonly num_core_interface_residues?: Maybe<Scalars['Int']>;
/** Number of interface residues, defined as those with burial fraction > 0 */
readonly num_interface_residues?: Maybe<Scalars['Int']>;
/** Allowable values: Nucleic acid (only), Protein (only), Protein/NA. */
readonly polymer_composition?: Maybe<Scalars['String']>;
/** The Jaccard score (intersection over union) of interface contacts in homomeric interfaces, comparing contact sets left-right vs right-left. High values indicate isologous (symmetric) interfaces, with value=1 if perfectly symmetric (e.g. crystallographic symmetry) */
readonly self_jaccard_contact_score?: Maybe<Scalars['Float']>;
};
export type RcsbInterfacePartner = {
readonly interface_partner_feature?: Maybe<ReadonlyArray<Maybe<RcsbInterfacePartnerInterfacePartnerFeature>>>;
readonly interface_partner_identifier?: Maybe<RcsbInterfacePartnerInterfacePartnerIdentifier>;
};
export type RcsbInterfacePartnerInterfacePartnerFeature = {
readonly additional_properties?: Maybe<ReadonlyArray<Maybe<InterfacePartnerFeatureAdditionalProperties>>>;
/**
* Identifies the version of the feature assignment.
*
* Examples:
* V4_0_2
*
*/
readonly assignment_version?: Maybe<Scalars['String']>;
/** A description for the feature. */
readonly description?: Maybe<Scalars['String']>;
/** An identifier for the feature. */
readonly feature_id?: Maybe<Scalars['String']>;
readonly feature_positions?: Maybe<ReadonlyArray<Maybe<InterfacePartnerFeatureFeaturePositions>>>;
/** A name for the feature. */
readonly name?: Maybe<Scalars['String']>;
/**
* Code identifying the individual, organization or program that assigned the feature.
*
* Examples:
* NACCESS
*
*/
readonly provenance_source?: Maybe<Scalars['String']>;
/**
* A type or category of the feature.
*
* Allowable values:
* ASA_UNBOUND, ASA_BOUND
*
*/
readonly type?: Maybe<Scalars['String']>;
};
export type RcsbInterfacePartnerInterfacePartnerIdentifier = {
/** Instance identifier for this container. */
readonly asym_id: Scalars['String'];
/** Polymer entity identifier for the container. */
readonly entity_id: Scalars['String'];
};
export type RcsbLatestRevision = {
/** The major version number of the latest revision. */
readonly major_revision?: Maybe<Scalars['Int']>;
@@ -9733,6 +10148,7 @@ export type RcsbPolymerEntity = {
*
*/
readonly rcsb_multiple_source_flag?: Maybe<Scalars['String']>;
readonly rcsb_polymer_name_combined?: Maybe<RcsbPolymerEntityRcsbPolymerNameCombined>;
/**
* The number of biological sources for the polymer entity. Multiple source contributions
* may come from the same organism (taxonomy).
@@ -10059,6 +10475,69 @@ export type RcsbPolymerEntityFeatureSummary = {
readonly type?: Maybe<Scalars['String']>;
};
export type RcsbPolymerEntityGroupMembersRankings = {
readonly group_members: ReadonlyArray<Maybe<RcsbPolymerEntityGroupMembersRankingsGroupMembers>>;
/**
* Defines ranking option applicable to group members
*
* Allowable values:
* coverage
*
*/
readonly ranking_criteria_type: Scalars['String'];
};
export type RcsbPolymerEntityGroupMembersRankingsGroupMembers = {
readonly member_id: Scalars['String'];
/** Quantifies the criteria used for ranking */
readonly original_score?: Maybe<Scalars['Float']>;
/** Reflects a relationship between group members such that, for any two members the first is ranked higher (smaller rank value) than the second */
readonly rank: Scalars['Int'];
};
export type RcsbPolymerEntityGroupMembership = {
/**
* Method used to establish group membership
*
* Allowable values:
* sequence_identity, matching_uniprot_accession
*
*/
readonly aggregation_method: Scalars['String'];
/**
* A unique identifier for a group of entities
*
* Examples:
* 1_100, P00003
*
*/
readonly group_id: Scalars['String'];
/** Degree of similarity expressed as a floating-point number */
readonly similarity_cutoff?: Maybe<Scalars['Float']>;
};
export type RcsbPolymerEntityGroupSequenceAlignment = {
/** Abstract reference where group members can be aligned to generate a MSA */
readonly abstract_reference: RcsbPolymerEntityGroupSequenceAlignmentAbstractReference;
/** List of alignments with core_entity canonical sequences */
readonly group_members_alignment: ReadonlyArray<Maybe<RcsbPolymerEntityGroupSequenceAlignmentGroupMembersAlignment>>;
};
export type RcsbPolymerEntityGroupSequenceAlignmentAbstractReference = {
/** Abstract reference length */
readonly length: Scalars['Int'];
/** Sequence that represents the abstract reference */
readonly sequence?: Maybe<Scalars['String']>;
};
export type RcsbPolymerEntityGroupSequenceAlignmentGroupMembersAlignment = {
/** Aligned region */
readonly aligned_regions: ReadonlyArray<Maybe<GroupMembersAlignmentAlignedRegions>>;
readonly member_id?: Maybe<Scalars['String']>;
/** Alignment scores */
readonly scores: GroupMembersAlignmentScores;
};
export type RcsbPolymerEntityInstanceContainerIdentifiers = {
/** Instance identifier for this container. */
readonly asym_id: Scalars['String'];
@@ -10177,6 +10656,13 @@ export type RcsbPolymerEntityRcsbMacromolecularNamesCombined = {
readonly provenance_source?: Maybe<Scalars['String']>;
};
export type RcsbPolymerEntityRcsbPolymerNameCombined = {
/** Protein name annotated by the UniProtKB or macromolecular name assigned by the PDB */
readonly names?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>;
/** Allowable values: PDB Preferred Name, PDB Description, UniProt Name. */
readonly provenance_source?: Maybe<Scalars['String']>;
};
export type RcsbPolymerInstanceAnnotation = {
/** An identifier for the annotation. */
readonly annotation_id?: Maybe<Scalars['String']>;
@@ -10263,7 +10749,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
* 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
*
*/
readonly type?: Maybe<Scalars['String']>;
@@ -11113,11 +11599,11 @@ export type RcsbUniprotAlignments = {
export type RcsbUniprotAlignmentsCoreEntityAlignments = {
/** Aligned region */
readonly aligned_regions?: Maybe<ReadonlyArray<Maybe<CoreEntityAlignmentsAlignedRegions>>>;
readonly aligned_regions: ReadonlyArray<Maybe<CoreEntityAlignmentsAlignedRegions>>;
/** core_entity identifiers */
readonly core_entity_identifiers?: Maybe<CoreEntityAlignmentsCoreEntityIdentifiers>;
/** Alignment scores */
readonly scores?: Maybe<CoreEntityAlignmentsScores>;
readonly scores: CoreEntityAlignmentsScores;
};
export type RcsbUniprotAnnotation = {
@@ -13145,4 +13631,4 @@ export type AssemblySymmetryQueryVariables = Exact<{
}>;
export type AssemblySymmetryQuery = { readonly assembly?: { readonly rcsb_struct_symmetry?: ReadonlyArray<{ readonly kind: string, readonly oligomeric_state: string, readonly stoichiometry: ReadonlyArray<string | null | undefined>, readonly symbol: string, readonly type: string, readonly clusters: ReadonlyArray<{ readonly avg_rmsd?: number | null | undefined, readonly members: ReadonlyArray<{ readonly asym_id: string, readonly pdbx_struct_oper_list_ids?: ReadonlyArray<string | null | undefined> | null | undefined } | null | undefined> } | null | undefined>, readonly rotation_axes?: ReadonlyArray<{ readonly order?: number | null | undefined, readonly start: ReadonlyArray<number | null | undefined>, readonly end: ReadonlyArray<number | null | undefined> } | null | undefined> | null | undefined } | null | undefined> | null | undefined } | null | undefined };
export type AssemblySymmetryQuery = { readonly assembly?: { readonly rcsb_struct_symmetry?: ReadonlyArray<{ readonly kind: string, readonly oligomeric_state: string, readonly stoichiometry: ReadonlyArray<string | null>, readonly symbol: string, readonly type: string, readonly clusters: ReadonlyArray<{ readonly avg_rmsd?: number | null, readonly members: ReadonlyArray<{ readonly asym_id: string, readonly pdbx_struct_oper_list_ids?: ReadonlyArray<string | null> | null } | null> } | null>, readonly rotation_axes?: ReadonlyArray<{ readonly order?: number | null, readonly start: ReadonlyArray<number | null>, readonly end: ReadonlyArray<number | null> } | null> | null } | null> | null } | null };

View File

@@ -55,7 +55,16 @@ function createIntraUnitClashCylinderMesh(ctx: VisualContext, unit: Unit, struct
radius: (edgeIndex: number) => magnitude[edgeIndex] * sizeFactor,
};
return createLinkCylinderMesh(ctx, builderProps, props, mesh);
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
if (boundingSphere) {
m.setBoundingSphere(boundingSphere);
} else if (m.triangleCount > 0) {
const sphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, 1 * sizeFactor);
m.setBoundingSphere(sphere);
}
return m;
}
export const IntraUnitClashParams = {
@@ -169,7 +178,16 @@ function createInterUnitClashCylinderMesh(ctx: VisualContext, structure: Structu
radius: (edgeIndex: number) => edges[edgeIndex].props.magnitude * sizeFactor
};
return createLinkCylinderMesh(ctx, builderProps, props, mesh);
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
if (boundingSphere) {
m.setBoundingSphere(boundingSphere);
} else {
const sphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, 1 * sizeFactor);
m.setBoundingSphere(sphere);
}
return m;
}
export const InterUnitClashParams = {

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { PluginBehavior } from '../../mol-plugin/behavior/behavior';
import { ZenodoImportUI } from './ui';
export const ZenodoImport = PluginBehavior.create<{ }>({
name: 'extension-zenodo-import',
category: 'misc',
display: {
name: 'Zenodo Export'
},
ctor: class extends PluginBehavior.Handler<{ }> {
register(): void {
this.ctx.customImportControls.set('zenodo-import', ZenodoImportUI as any);
}
update() {
return false;
}
unregister() {
this.ctx.customImportControls.delete('zenodo-import');
}
},
params: () => ({ })
});

View File

@@ -0,0 +1,302 @@
/**
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { DownloadFile } from '../../mol-plugin-state/actions/file';
import { DownloadStructure, LoadTrajectory } from '../../mol-plugin-state/actions/structure';
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
import { CoordinatesFormatCategory } from '../../mol-plugin-state/formats/coordinates';
import { TopologyFormatCategory } from '../../mol-plugin-state/formats/topology';
import { TrajectoryFormatCategory } from '../../mol-plugin-state/formats/trajectory';
import { VolumeFormatCategory } from '../../mol-plugin-state/formats/volume';
import { CollapsableControls, CollapsableState } from '../../mol-plugin-ui/base';
import { Button } from '../../mol-plugin-ui/controls/common';
import { OpenInBrowserSvg } from '../../mol-plugin-ui/controls/icons';
import { ParameterControls } from '../../mol-plugin-ui/controls/parameters';
import { PluginContext } from '../../mol-plugin/context';
import { formatBytes } from '../../mol-util';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
type ZenodoFile = {
bucket: string
checksum: string
key: string
links: {
[key: string]: string
self: string
}
size: number
type: string
}
type ZenodoRecord = {
id: number
conceptdoi: string
conceptrecid: string
created: string
doi: string
files: ZenodoFile[]
revision: number
updated: string
metadata: {
title: string
}
}
interface State {
busy?: boolean
recordValues: PD.Values<typeof ZenodoImportParams>
importValues?: PD.Values<ImportParams>
importParams?: ImportParams
record?: ZenodoRecord
files?: ZenodoFile[]
}
const ZenodoImportParams = {
record: PD.Text('', { description: 'Zenodo ID.' })
};
function createImportParams(files: ZenodoFile[], plugin: PluginContext) {
const modelOpts: [string, string][] = [];
const topologyOpts: [string, string][] = [];
const coordinatesOpts: [string, string][] = [];
const volumeOpts: [string, string][] = [];
const compressedOpts: [string, string][] = [];
const structureExts = new Map<string, { format: string, isBinary: boolean }>();
const coordinatesExts = new Map<string, { format: string, isBinary: boolean }>();
const topologyExts = new Map<string, { format: string, isBinary: boolean }>();
const volumeExts = new Map<string, { format: string, isBinary: boolean }>();
for (const { provider: { category, binaryExtensions, stringExtensions }, name } of plugin.dataFormats.list) {
if (category === TrajectoryFormatCategory) {
if (binaryExtensions) for (const e of binaryExtensions) structureExts.set(e, { format: name, isBinary: true });
if (stringExtensions) for (const e of stringExtensions) structureExts.set(e, { format: name, isBinary: false });
} else if (category === VolumeFormatCategory) {
if (binaryExtensions) for (const e of binaryExtensions) volumeExts.set(e, { format: name, isBinary: true });
if (stringExtensions) for (const e of stringExtensions) volumeExts.set(e, { format: name, isBinary: false });
} else if (category === CoordinatesFormatCategory) {
if (binaryExtensions) for (const e of binaryExtensions) coordinatesExts.set(e, { format: name, isBinary: true });
if (stringExtensions) for (const e of stringExtensions) coordinatesExts.set(e, { format: name, isBinary: false });
} else if (category === TopologyFormatCategory) {
if (binaryExtensions) for (const e of binaryExtensions) topologyExts.set(e, { format: name, isBinary: true });
if (stringExtensions) for (const e of stringExtensions) topologyExts.set(e, { format: name, isBinary: false });
}
}
for (const file of files) {
const label = `${file.key} (${formatBytes(file.size)})`;
if (structureExts.has(file.type)) {
const { format, isBinary } = structureExts.get(file.type)!;
modelOpts.push([`${file.links.self}|${format}|${isBinary}`, label]);
topologyOpts.push([`${file.links.self}|${format}|${isBinary}`, label]);
} else if (volumeExts.has(file.type)) {
const { format, isBinary } = volumeExts.get(file.type)!;
volumeOpts.push([`${file.links.self}|${format}|${isBinary}`, label]);
} else if (topologyExts.has(file.type)) {
const { format, isBinary } = topologyExts.get(file.type)!;
topologyOpts.push([`${file.links.self}|${format}|${isBinary}`, label]);
} else if (coordinatesExts.has(file.type)) {
const { format, isBinary } = coordinatesExts.get(file.type)!;
coordinatesOpts.push([`${file.links.self}|${format}|${isBinary}`, label]);
} else if (file.type === 'zip') {
compressedOpts.push([`${file.links.self}|${file.type}|true`, label]);
}
}
const params: PD.Params = {};
let defaultType = '';
if (modelOpts.length) {
defaultType = 'structure';
params.structure = PD.Select(modelOpts[0][0], modelOpts);
}
if (topologyOpts.length && coordinatesOpts.length) {
if (!defaultType) defaultType = 'trajectory';
params.trajectory = PD.Group({
topology: PD.Select(topologyOpts[0][0], topologyOpts),
coordinates: PD.Select(coordinatesOpts[0][0], coordinatesOpts),
}, { isFlat: true });
}
if (volumeOpts.length) {
if (!defaultType) defaultType = 'volume';
params.volume = PD.Select(volumeOpts[0][0], volumeOpts);
}
if (compressedOpts.length) {
if (!defaultType) defaultType = 'compressed';
params.compressed = PD.Select(compressedOpts[0][0], compressedOpts);
}
return {
type: PD.MappedStatic(defaultType, Object.keys(params).length ? params : { '': PD.EmptyGroup() })
};
}
type ImportParams = ReturnType<typeof createImportParams>
export class ZenodoImportUI extends CollapsableControls<{}, State> {
protected defaultState(): State & CollapsableState {
return {
header: 'Zenodo Import',
isCollapsed: true,
brand: { accent: 'cyan', svg: OpenInBrowserSvg },
recordValues: PD.getDefaultValues(ZenodoImportParams),
importValues: undefined,
importParams: undefined,
record: undefined,
files: undefined,
};
}
private recordParamsOnChange = (values: any) => {
this.setState({ recordValues: values });
};
private importParamsOnChange = (values: any) => {
this.setState({ importValues: values });
};
private loadRecord = async () => {
try {
this.setState({ busy: true });
const record: ZenodoRecord = await this.plugin.runTask(this.plugin.fetch({ url: `https://zenodo.org/api/records/${this.state.recordValues.record}`, type: 'json' }));
const importParams = createImportParams(record.files, this.plugin);
this.setState({
record,
files: record.files,
busy: false,
importValues: PD.getDefaultValues(importParams),
importParams
});
} catch (e) {
console.error(e);
this.plugin.log.error(`Failed to load Zenodo record '${this.state.recordValues.record}'`);
this.setState({ busy: false });
}
};
private loadFile = async (values: PD.Values<ImportParams>) => {
try {
this.setState({ busy: true });
const t = values.type;
if (t.name === 'structure') {
const defaultParams = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
const [url, format, isBinary] = t.params.split('|');
await this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'url',
params: {
url,
format: format as any,
isBinary: isBinary === 'true',
options: defaultParams.source.params.options,
}
}
}));
} else if (t.name === 'trajectory') {
const [topologyUrl, topologyFormat, topologyIsBinary] = t.params.topology.split('|');
const [coordinatesUrl, coordinatesFormat, coordinatesIsBinary] = t.params.coordinates.split('|');
await this.plugin.runTask(this.plugin.state.data.applyAction(LoadTrajectory, {
source: {
name: 'url',
params: {
model: {
url: topologyUrl,
format: topologyFormat as any,
isBinary: topologyIsBinary === 'true',
},
coordinates: {
url: coordinatesUrl,
format: coordinatesFormat as any,
isBinary: coordinatesIsBinary === 'true',
},
}
}
}));
} else if (t.name === 'volume') {
const [url, format, isBinary] = t.params.split('|');
await this.plugin.runTask(this.plugin.state.data.applyAction(DownloadDensity, {
source: {
name: 'url',
params: {
url,
format: format as any,
isBinary: isBinary === 'true',
}
}
}));
} else if (t.name === 'compressed') {
const [url, format, isBinary] = t.params.split('|');
await this.plugin.runTask(this.plugin.state.data.applyAction(DownloadFile, {
url,
format: format as any,
isBinary: isBinary === 'true',
visuals: true
}));
}
} catch (e) {
console.error(e);
this.plugin.log.error(`Failed to load Zenodo file`);
} finally {
this.setState({ busy: false });
}
};
private clearRecord = () => {
this.setState({
importValues: undefined,
importParams: undefined,
record: undefined,
files: undefined
});
};
private renderLoadRecord() {
return <div style={{ marginBottom: 10 }}>
<ParameterControls params={ZenodoImportParams} values={this.state.recordValues} onChangeValues={this.recordParamsOnChange} isDisabled={this.state.busy} />
<Button onClick={this.loadRecord} style={{ marginTop: 1 }} disabled={this.state.busy || !this.state.recordValues.record}>
Load Record
</Button>
</div>;
}
private renderRecordInfo(record: ZenodoRecord) {
return <div style={{ marginBottom: 10 }}>
<div className='msp-help-text'>
<div>Record {`${record.id}`}: <i>{`${record.metadata.title}`}</i></div>
</div>
<Button onClick={this.clearRecord} style={{ marginTop: 1 }} disabled={this.state.busy}>
Clear
</Button>
</div>;
}
private renderImportFile(params: ImportParams, values: PD.Values<ImportParams>) {
return values.type.name ? <div style={{ marginBottom: 10 }}>
<ParameterControls params={params} values={this.state.importValues} onChangeValues={this.importParamsOnChange} isDisabled={this.state.busy} />
<Button onClick={() => this.loadFile(values)} style={{ marginTop: 1 }} disabled={this.state.busy}>
Import File
</Button>
</div> : <div className='msp-help-text' style={{ marginBottom: 10 }}>
<div>No supported files</div>
</div>;
}
protected renderControls(): JSX.Element | null {
return <>
{!this.state.record ? this.renderLoadRecord() : null}
{this.state.record ? this.renderRecordInfo(this.state.record) : null}
{this.state.importParams && this.state.importValues ? this.renderImportFile(this.state.importParams, this.state.importValues) : null}
</>;
}
}

View File

@@ -10,6 +10,7 @@ import { Viewport, cameraProject, cameraUnproject } from './camera/util';
import { CameraTransitionManager } from './camera/transition';
import { BehaviorSubject } from 'rxjs';
import { Scene } from '../mol-gl/scene';
import { assertUnreachable } from '../mol-util/type-helpers';
export { ICamera, Camera };
@@ -84,7 +85,7 @@ class Camera implements ICamera {
switch (this.state.mode) {
case 'orthographic': updateOrtho(this); break;
case 'perspective': updatePers(this); break;
default: throw new Error('unknown camera mode');
default: assertUnreachable(this.state.mode);
}
const changed = !Mat4.areEqual(this.projection, this.prevProjection, EPSILON) || !Mat4.areEqual(this.view, this.prevView, EPSILON);

View File

@@ -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>
* @author David Sehnal <david.sehnal@gmail.com>
@@ -30,7 +30,7 @@ import { PickData } from './passes/pick';
import { PickHelper } from './passes/pick';
import { ImagePass, ImageProps } from './passes/image';
import { Sphere3D } from '../mol-math/geometry';
import { isDebugMode } from '../mol-util/debug';
import { isDebugMode, isTimingMode } from '../mol-util/debug';
import { CameraHelperParams } from './helper/camera-helper';
import { produce } from 'immer';
import { HandleHelperParams } from './helper/handle-helper';
@@ -236,7 +236,7 @@ interface Canvas3D {
/** Sets drawPaused = false without starting the built in animation loop */
resume(): void
identify(x: number, y: number): PickData | undefined
mark(loci: Representation.Loci, action: MarkerAction, noDraw?: boolean): void
mark(loci: Representation.Loci, action: MarkerAction): void
getLoci(pickingId: PickingId | undefined): Representation.Loci
notifyDidDraw: boolean,
@@ -345,34 +345,43 @@ namespace Canvas3D {
return { loci, repr };
}
function mark(reprLoci: Representation.Loci, action: MarkerAction, noDraw = false) {
let markBuffer: [reprLoci: Representation.Loci, action: MarkerAction][] = [];
function mark(reprLoci: Representation.Loci, action: MarkerAction) {
// NOTE: might try to optimize a case with opposite actions for the
// same loci. Tho this might end up being more expensive (and error prone)
// then just applying everything "naively".
markBuffer.push([reprLoci, action]);
}
function resolveMarking() {
let changed = false;
for (const [r, l] of markBuffer) {
changed = applyMark(r, l) || changed;
}
markBuffer = [];
if (changed) {
scene.update(void 0, true);
helper.handle.scene.update(void 0, true);
helper.camera.scene.update(void 0, true);
}
return changed;
}
function applyMark(reprLoci: Representation.Loci, action: MarkerAction) {
const { repr, loci } = reprLoci;
let changed = false;
if (repr) {
changed = repr.mark(loci, action);
changed = repr.mark(loci, action) || changed;
} else {
changed = helper.handle.mark(loci, action);
changed = helper.camera.mark(loci, action) || changed;
reprRenderObjects.forEach((_, _repr) => { changed = _repr.mark(loci, action) || changed; });
}
if (changed) {
if (noDraw) {
// Even with `noDraw` make sure changes will be rendered.
// Note that with this calling mark (with or without `noDraw`) multiple times
// during a JS event loop iteration will only result in a single render call.
forceNextRender = true;
} else {
scene.update(void 0, true);
helper.handle.scene.update(void 0, true);
helper.camera.scene.update(void 0, true);
const prevPickDirty = pickHelper.dirty;
draw({ force: true, allowMulti: true });
pickHelper.dirty = prevPickDirty; // marking does not change picking buffers
}
}
changed = helper.handle.mark(loci, action) || changed;
changed = helper.camera.mark(loci, action) || changed;
return changed;
}
function render(force: boolean, allowMulti: boolean) {
function render(force: boolean) {
if (webgl.isContextLost) return false;
let resized = false;
@@ -386,6 +395,8 @@ namespace Canvas3D {
y > gl.drawingBufferHeight || y + height < 0
) return false;
const markingUpdated = resolveMarking();
let didRender = false;
controls.update(currentTime);
const cameraChanged = camera.update();
@@ -393,23 +404,27 @@ namespace Canvas3D {
const shouldRender = force || cameraChanged || resized || forceNextRender;
forceNextRender = false;
const multiSampleChanged = multiSampleHelper.update(shouldRender, p.multiSample);
const multiSampleChanged = multiSampleHelper.update(markingUpdated || shouldRender, p.multiSample);
if (shouldRender || multiSampleChanged) {
if (shouldRender || multiSampleChanged || markingUpdated) {
let cam: Camera | StereoCamera = camera;
if (p.camera.stereo.name === 'on') {
stereoCamera.update();
cam = stereoCamera;
}
if (isTimingMode) webgl.timer.mark('Canvas3D.render');
const ctx = { renderer, camera: cam, scene, helper };
if (MultiSamplePass.isEnabled(p.multiSample)) {
const forceOn = !cameraChanged && allowMulti && !controls.props.spin;
const forceOn = !cameraChanged && markingUpdated && !controls.isAnimating;
multiSampleHelper.render(ctx, p, true, forceOn);
} else {
passes.draw.render(ctx, p, true);
}
pickHelper.dirty = true;
if (isTimingMode) webgl.timer.markEnd('Canvas3D.render');
// if only marking has updated, do not set the flag to dirty
pickHelper.dirty = pickHelper.dirty || shouldRender;
didRender = true;
}
@@ -421,9 +436,9 @@ namespace Canvas3D {
let currentTime = 0;
let drawPaused = false;
function draw(options?: { force?: boolean, allowMulti?: boolean }) {
function draw(options?: { force?: boolean }) {
if (drawPaused) return;
if (render(!!options?.force, !!options?.allowMulti) && notifyDidDraw) {
if (render(!!options?.force) && notifyDidDraw) {
didDraw.next(now() - startTime as now.Timestamp);
}
}
@@ -444,7 +459,7 @@ namespace Canvas3D {
}
draw();
if (!camera.transition.inTransition && !controls.props.spin && !webgl.isContextLost) {
if (!camera.transition.inTransition && !webgl.isContextLost) {
interactionHelper.tick(currentTime);
}
}
@@ -831,6 +846,8 @@ namespace Canvas3D {
dispose: () => {
contextRestoredSub.unsubscribe();
markBuffer = [];
scene.clear();
helper.debug.clear();
controls.dispose();

View File

@@ -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>
* @author David Sehnal <david.sehnal@gmail.com>
@@ -13,7 +13,7 @@ import { Viewport } from '../camera/util';
import { InputObserver, DragInput, WheelInput, PinchInput, ButtonsType, ModifiersKeys, GestureInput } from '../../mol-util/input/input-observer';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Camera } from '../camera';
import { absMax } from '../../mol-math/misc';
import { absMax, degToRad } from '../../mol-math/misc';
import { Binding } from '../../mol-util/binding';
const B = ButtonsType;
@@ -40,8 +40,16 @@ export const TrackballControlsParams = {
zoomSpeed: PD.Numeric(7.0, { min: 1, max: 15, step: 1 }),
panSpeed: PD.Numeric(1.0, { min: 0.1, max: 5, step: 0.1 }),
spin: PD.Boolean(false, { description: 'Spin the 3D scene around the x-axis in view space' }),
spinSpeed: PD.Numeric(1, { min: -20, max: 20, step: 1 }),
animate: PD.MappedStatic('off', {
off: PD.EmptyGroup(),
spin: PD.Group({
speed: PD.Numeric(1, { min: -20, max: 20, step: 1 }),
}, { description: 'Spin the 3D scene around the x-axis in view space' }),
rock: PD.Group({
speed: PD.Numeric(0.3, { min: -5, max: 5, step: 0.1 }),
angle: PD.Numeric(10, { min: 0, max: 90, step: 1 }, { description: 'How many degrees to rotate in each direction.' }),
}, { description: 'Rock the 3D scene around the x-axis in view space' })
}),
staticMoving: PD.Boolean(true, { isHidden: true }),
dynamicDampingFactor: PD.Numeric(0.2, {}, { isHidden: true }),
@@ -72,7 +80,8 @@ export type TrackballControlsProps = PD.Values<typeof TrackballControlsParams>
export { TrackballControls };
interface TrackballControls {
viewport: Viewport
readonly viewport: Viewport
readonly isAnimating: boolean
readonly props: Readonly<TrackballControlsProps>
setProps: (props: Partial<TrackballControlsProps>) => void
@@ -144,6 +153,11 @@ namespace TrackballControls {
);
}
function getRotateFactor() {
const aspectRatio = input.width / input.height;
return p.rotateSpeed * input.pixelRatio * aspectRatio;
}
const rotAxis = Vec3();
const rotQuat = Quat();
const rotEyeDir = Vec3();
@@ -156,8 +170,7 @@ namespace TrackballControls {
const dy = _rotCurr[1] - _rotPrev[1];
Vec3.set(rotMoveDir, dx, dy, 0);
const aspectRatio = input.width / input.height;
const angle = Vec3.magnitude(rotMoveDir) * p.rotateSpeed * input.pixelRatio * aspectRatio;
const angle = Vec3.magnitude(rotMoveDir) * getRotateFactor();
if (angle) {
Vec3.sub(_eye, camera.position, camera.target);
@@ -306,7 +319,10 @@ namespace TrackballControls {
/** Update the object's position, direction and up vectors */
function update(t: number) {
if (lastUpdated === t) return;
if (p.spin && lastUpdated > 0) spin(t - lastUpdated);
if (lastUpdated > 0) {
if (p.animate.name === 'spin') spin(t - lastUpdated);
else if (p.animate.name === 'rock') rock(t - lastUpdated);
}
Vec3.sub(_eye, camera.position, camera.target);
@@ -345,6 +361,7 @@ namespace TrackballControls {
if (!isStart && !_isInteracting) return;
_isInteracting = true;
resetRock(); // start rocking from the center after interactions
const dragRotate = Binding.match(p.bindings.dragRotate, buttons, modifiers);
const dragRotateZ = Binding.match(p.bindings.dragRotateZ, buttons, modifiers);
@@ -434,11 +451,34 @@ namespace TrackballControls {
const _spinSpeed = Vec2.create(0.005, 0);
function spin(deltaT: number) {
if (p.spinSpeed === 0) return;
if (p.animate.name !== 'spin' || p.animate.params.speed === 0 || _isInteracting) return;
const frameSpeed = (p.spinSpeed || 0) / 1000;
const frameSpeed = p.animate.params.speed / 1000;
_spinSpeed[0] = 60 * Math.min(Math.abs(deltaT), 1000 / 8) / 1000 * frameSpeed;
if (!_isInteracting) Vec2.add(_rotCurr, _rotPrev, _spinSpeed);
Vec2.add(_rotCurr, _rotPrev, _spinSpeed);
}
let _rockPhase = 0;
const _rockSpeed = Vec2.create(0.005, 0);
function rock(deltaT: number) {
if (p.animate.name !== 'rock' || p.animate.params.speed === 0 || _isInteracting) return;
const dt = deltaT / 1000 * p.animate.params.speed;
const maxAngle = degToRad(p.animate.params.angle) / getRotateFactor();
const angleA = Math.sin(_rockPhase * Math.PI * 2) * maxAngle;
const angleB = Math.sin((_rockPhase + dt) * Math.PI * 2) * maxAngle;
_rockSpeed[0] = angleB - angleA;
Vec2.add(_rotCurr, _rotPrev, _rockSpeed);
_rockPhase += dt;
if (_rockPhase >= 1) {
_rockPhase = 0;
}
}
function resetRock() {
_rockPhase = 0;
}
function start(t: number) {
@@ -448,9 +488,13 @@ namespace TrackballControls {
return {
viewport,
get isAnimating() { return p.animate.name !== 'off'; },
get props() { return p as Readonly<TrackballControlsProps>; },
setProps: (props: Partial<TrackballControlsProps>) => {
if (props.animate?.name === 'rock' && p.animate.name !== 'rock') {
resetRock(); // start rocking from the center
}
Object.assign(p, props);
},

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020-2021 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>
*/
@@ -17,7 +17,7 @@ import { WebGLContext } from '../../mol-gl/webgl/context';
import { GraphicsRenderVariantsBlended } from '../../mol-gl/webgl/render-item';
import { Sphere3D } from '../../mol-math/geometry';
import { Mat4, Vec3 } from '../../mol-math/linear-algebra';
import { DataLoci, EmptyLoci, Loci } from '../../mol-model/loci';
import { DataLoci, EmptyLoci, isEveryLoci, Loci } from '../../mol-model/loci';
import { Shape } from '../../mol-model/shape';
import { Visual } from '../../mol-repr/visual';
import { ColorNames } from '../../mol-util/color/names';
@@ -113,8 +113,10 @@ export class CameraHelper {
mark(loci: Loci, action: MarkerAction) {
if (!MarkerActions.is(MarkerActions.Highlighting, action)) return false;
if (!isCameraAxesLoci(loci)) return false;
if (loci.data !== this) return false;
if (!isEveryLoci(loci)) {
if (!isCameraAxesLoci(loci)) return false;
if (loci.data !== this) return false;
}
return Visual.mark(this.renderObject, loci, action, this.eachGroup);
}

View File

@@ -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>
*/
@@ -20,7 +20,7 @@ import produce from 'immer';
import { Shape } from '../../mol-model/shape';
import { PickingId } from '../../mol-geo/geometry/picking';
import { Camera } from '../camera';
import { DataLoci, EmptyLoci, Loci } from '../../mol-model/loci';
import { DataLoci, EmptyLoci, isEveryLoci, Loci } from '../../mol-model/loci';
import { MarkerAction, MarkerActions } from '../../mol-util/marker-action';
import { Visual } from '../../mol-repr/visual';
import { Interval } from '../../mol-data/int';
@@ -121,8 +121,10 @@ export class HandleHelper {
mark(loci: Loci, action: MarkerAction) {
if (!MarkerActions.is(MarkerActions.Highlighting, action)) return false;
if (!isHandleLoci(loci)) return false;
if (loci.data !== this) return false;
if (!isEveryLoci(loci)) {
if (!isHandleLoci(loci)) return false;
if (loci.data !== this) return false;
}
return Visual.mark(this.renderObject, loci, action, this.eachGroup);
}

View File

@@ -71,7 +71,7 @@ export class Canvas3dInteractionHelper {
const xyChanged = this.startX !== this.endX || this.startY !== this.endY;
if (e === InputEvent.Drag) {
if (xyChanged && !Representation.Loci.isEmpty(this.prevLoci)) {
if (xyChanged && !this.outsideViewport(this.startX, this.startY)) {
this.events.drag.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers, pageStart: Vec2.create(this.startX, this.startY), pageEnd: Vec2.create(this.endX, this.endY) });
this.startX = this.endX;

View File

@@ -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>
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
@@ -11,47 +11,16 @@ import { Renderer } from '../../mol-gl/renderer';
import { Scene } from '../../mol-gl/scene';
import { Texture } from '../../mol-gl/webgl/texture';
import { Camera, ICamera } from '../camera';
import { QuadSchema, QuadValues } from '../../mol-gl/compute/util';
import { DefineSpec, TextureSpec, UniformSpec, Values } from '../../mol-gl/renderable/schema';
import { ComputeRenderable, createComputeRenderable } from '../../mol-gl/renderable';
import { ShaderCode } from '../../mol-gl/shader-code';
import { createComputeRenderItem } from '../../mol-gl/webgl/render-item';
import { ValueCell } from '../../mol-util';
import { Vec2 } from '../../mol-math/linear-algebra';
import { Helper } from '../helper/helper';
import { quad_vert } from '../../mol-gl/shader/quad.vert';
import { depthMerge_frag } from '../../mol-gl/shader/depth-merge.frag';
import { StereoCamera } from '../camera/stereo';
import { WboitPass } from './wboit';
import { AntialiasingPass, PostprocessingPass, PostprocessingProps } from './postprocessing';
import { MarkingPass, MarkingProps } from './marking';
import { CopyRenderable, createCopyRenderable } from '../../mol-gl/compute/util';
const DepthMergeSchema = {
...QuadSchema,
tDepthPrimitives: TextureSpec('texture', 'depth', 'ushort', 'nearest'),
tDepthVolumes: TextureSpec('texture', 'depth', 'ushort', 'nearest'),
uTexSize: UniformSpec('v2'),
dPackedDepth: DefineSpec('boolean'),
};
const DepthMergeShaderCode = ShaderCode('depth-merge', quad_vert, depthMerge_frag);
type DepthMergeRenderable = ComputeRenderable<Values<typeof DepthMergeSchema>>
function getDepthMergeRenderable(ctx: WebGLContext, depthTexturePrimitives: Texture, depthTextureVolumes: Texture, packedDepth: boolean): DepthMergeRenderable {
const values: Values<typeof DepthMergeSchema> = {
...QuadValues,
tDepthPrimitives: ValueCell.create(depthTexturePrimitives),
tDepthVolumes: ValueCell.create(depthTextureVolumes),
uTexSize: ValueCell.create(Vec2.create(depthTexturePrimitives.getWidth(), depthTexturePrimitives.getHeight())),
dPackedDepth: ValueCell.create(packedDepth),
};
const schema = { ...DepthMergeSchema };
const renderItem = createComputeRenderItem(ctx, 'triangles', DepthMergeShaderCode, schema, values);
return createComputeRenderable(renderItem, values);
}
import { isTimingMode } from '../../mol-util/debug';
type Props = {
postprocessing: PostprocessingProps
@@ -70,16 +39,13 @@ export class DrawPass {
private readonly drawTarget: RenderTarget;
readonly colorTarget: RenderTarget;
readonly depthTexture: Texture;
readonly depthTexturePrimitives: Texture;
readonly depthTextureTransparent: Texture;
readonly depthTextureOpaque: Texture;
readonly packedDepth: boolean;
private depthTarget: RenderTarget;
private depthTargetPrimitives: RenderTarget | null;
private depthTargetVolumes: RenderTarget | null;
private depthTextureVolumes: Texture;
private depthMerge: DepthMergeRenderable;
private depthTargetTransparent: RenderTarget;
private depthTargetOpaque: RenderTarget | null;
private copyFboTarget: CopyRenderable;
private copyFboPostprocessing: CopyRenderable;
@@ -101,19 +67,15 @@ export class DrawPass {
this.colorTarget = webgl.createRenderTarget(width, height, true, 'uint8', 'linear');
this.packedDepth = !extensions.depthTexture;
this.depthTarget = webgl.createRenderTarget(width, height);
this.depthTexture = this.depthTarget.texture;
this.depthTargetTransparent = webgl.createRenderTarget(width, height);
this.depthTextureTransparent = this.depthTargetTransparent.texture;
this.depthTargetPrimitives = this.packedDepth ? webgl.createRenderTarget(width, height) : null;
this.depthTargetVolumes = this.packedDepth ? webgl.createRenderTarget(width, height) : null;
this.depthTargetOpaque = this.packedDepth ? webgl.createRenderTarget(width, height) : null;
this.depthTexturePrimitives = this.depthTargetPrimitives ? this.depthTargetPrimitives.texture : resources.texture('image-depth', 'depth', isWebGL2 ? 'float' : 'ushort', 'nearest');
this.depthTextureVolumes = this.depthTargetVolumes ? this.depthTargetVolumes.texture : resources.texture('image-depth', 'depth', isWebGL2 ? 'float' : 'ushort', 'nearest');
this.depthTextureOpaque = this.depthTargetOpaque ? this.depthTargetOpaque.texture : resources.texture('image-depth', 'depth', isWebGL2 ? 'float' : 'ushort', 'nearest');
if (!this.packedDepth) {
this.depthTexturePrimitives.define(width, height);
this.depthTextureVolumes.define(width, height);
this.depthTextureOpaque.define(width, height);
}
this.depthMerge = getDepthMergeRenderable(webgl, this.depthTexturePrimitives, this.depthTextureVolumes, this.packedDepth);
this.wboit = enableWboit ? new WboitPass(webgl, width, height) : undefined;
this.marking = new MarkingPass(webgl, width, height);
@@ -134,22 +96,14 @@ export class DrawPass {
if (width !== w || height !== h) {
this.colorTarget.setSize(width, height);
this.depthTarget.setSize(width, height);
this.depthTargetTransparent.setSize(width, height);
if (this.depthTargetPrimitives) {
this.depthTargetPrimitives.setSize(width, height);
if (this.depthTargetOpaque) {
this.depthTargetOpaque.setSize(width, height);
} else {
this.depthTexturePrimitives.define(width, height);
this.depthTextureOpaque.define(width, height);
}
if (this.depthTargetVolumes) {
this.depthTargetVolumes.setSize(width, height);
} else {
this.depthTextureVolumes.define(width, height);
}
ValueCell.update(this.depthMerge.values.uTexSize, Vec2.set(this.depthMerge.values.uTexSize.ref.value, width, height));
ValueCell.update(this.copyFboTarget.values.uTexSize, Vec2.set(this.copyFboTarget.values.uTexSize.ref.value, width, height));
ValueCell.update(this.copyFboPostprocessing.values.uTexSize, Vec2.set(this.copyFboPostprocessing.values.uTexSize.ref.value, width, height));
@@ -163,20 +117,6 @@ export class DrawPass {
}
}
private _depthMerge() {
const { state, gl } = this.webgl;
this.depthMerge.update();
this.depthTarget.bind();
state.disable(gl.BLEND);
state.disable(gl.DEPTH_TEST);
state.disable(gl.CULL_FACE);
state.depthMask(false);
state.clearColor(1, 1, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
this.depthMerge.render();
}
private _renderWboit(renderer: Renderer, camera: ICamera, scene: Scene, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
if (!this.wboit?.supported) throw new Error('expected wboit to be supported');
@@ -184,38 +124,41 @@ export class DrawPass {
renderer.clear(true);
// render opaque primitives
this.depthTexturePrimitives.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
this.depthTextureOpaque.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
this.colorTarget.bind();
renderer.clearDepth();
renderer.renderWboitOpaque(scene.primitives, camera, null);
// render opaque volumes
this.depthTextureVolumes.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
this.colorTarget.bind();
renderer.clearDepth();
renderer.renderWboitOpaque(scene.volumes, camera, this.depthTexturePrimitives);
// merge depth of opaque primitives and volumes
this._depthMerge();
if (PostprocessingPass.isEnabled(postprocessingProps)) {
if (PostprocessingPass.isOutlineEnabled(postprocessingProps)) {
this.depthTargetTransparent.bind();
renderer.clearDepth(true);
if (scene.opacityAverage < 1) {
renderer.renderDepthTransparent(scene.primitives, camera, this.depthTextureOpaque);
}
}
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps);
}
// render transparent primitives and volumes
this.wboit.bind();
renderer.renderWboitTransparent(scene.primitives, camera, this.depthTexture);
renderer.renderWboitTransparent(scene.volumes, camera, this.depthTexture);
if (scene.opacityAverage < 1 || scene.volumes.renderables.length > 0) {
this.wboit.bind();
if (scene.opacityAverage < 1) {
renderer.renderWboitTransparent(scene.primitives, camera, this.depthTextureOpaque);
}
if (scene.volumes.renderables.length > 0) {
renderer.renderWboitTransparent(scene.volumes, camera, this.depthTextureOpaque);
}
// evaluate wboit
if (PostprocessingPass.isEnabled(postprocessingProps)) {
this.depthTexturePrimitives.attachFramebuffer(this.postprocessing.target.framebuffer, 'depth');
this.postprocessing.target.bind();
} else {
this.depthTexturePrimitives.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
this.colorTarget.bind();
// evaluate wboit
if (PostprocessingPass.isEnabled(postprocessingProps)) {
this.postprocessing.target.bind();
} else {
this.colorTarget.bind();
}
this.wboit.render();
}
this.wboit.render();
}
private _renderBlended(renderer: Renderer, camera: ICamera, scene: Scene, toDrawingBuffer: boolean, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
@@ -224,7 +167,7 @@ export class DrawPass {
} else {
this.colorTarget.bind();
if (!this.packedDepth) {
this.depthTexturePrimitives.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
this.depthTextureOpaque.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
}
}
@@ -234,47 +177,62 @@ export class DrawPass {
if (!toDrawingBuffer) {
// do a depth pass if not rendering to drawing buffer and
// extensions.depthTexture is unsupported (i.e. depthTarget is set)
if (this.depthTargetPrimitives) {
this.depthTargetPrimitives.bind();
renderer.clear(false);
// TODO: this should only render opaque
renderer.renderDepth(scene.primitives, camera, null);
if (this.depthTargetOpaque) {
this.depthTargetOpaque.bind();
renderer.clearDepth(true);
renderer.renderDepthOpaque(scene.primitives, camera, null);
this.colorTarget.bind();
}
// do direct-volume rendering
if (!this.packedDepth) {
this.depthTextureVolumes.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
renderer.clearDepth(); // from previous frame
}
renderer.renderBlendedVolumeOpaque(scene.volumes, camera, this.depthTexturePrimitives);
// do volume depth pass if extensions.depthTexture is unsupported (i.e. depthTarget is set)
if (this.depthTargetVolumes) {
this.depthTargetVolumes.bind();
renderer.clear(false);
renderer.renderDepth(scene.volumes, camera, this.depthTexturePrimitives);
this.colorTarget.bind();
}
// merge depths from primitive and volume rendering
this._depthMerge();
this.colorTarget.bind();
if (PostprocessingPass.isEnabled(postprocessingProps)) {
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps);
}
renderer.renderBlendedVolumeTransparent(scene.volumes, camera, this.depthTexturePrimitives);
if (!this.packedDepth) {
this.depthTextureOpaque.detachFramebuffer(this.postprocessing.target.framebuffer, 'depth');
} else {
this.colorTarget.depthRenderbuffer?.detachFramebuffer(this.postprocessing.target.framebuffer);
}
const target = PostprocessingPass.isEnabled(postprocessingProps)
? this.postprocessing.target : this.colorTarget;
if (!this.packedDepth) {
this.depthTexturePrimitives.attachFramebuffer(target.framebuffer, 'depth');
if (PostprocessingPass.isOutlineEnabled(postprocessingProps)) {
this.depthTargetTransparent.bind();
renderer.clearDepth(true);
if (scene.opacityAverage < 1) {
renderer.renderDepthTransparent(scene.primitives, camera, this.depthTextureOpaque);
}
}
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps);
if (!this.packedDepth) {
this.depthTextureOpaque.attachFramebuffer(this.postprocessing.target.framebuffer, 'depth');
} else {
this.colorTarget.depthRenderbuffer?.attachFramebuffer(this.postprocessing.target.framebuffer);
}
}
if (scene.volumes.renderables.length > 0) {
const target = PostprocessingPass.isEnabled(postprocessingProps)
? this.postprocessing.target : this.colorTarget;
if (!this.packedDepth) {
this.depthTextureOpaque.detachFramebuffer(target.framebuffer, 'depth');
} else {
this.colorTarget.depthRenderbuffer?.detachFramebuffer(target.framebuffer);
}
target.bind();
renderer.renderBlendedVolume(scene.volumes, camera, this.depthTextureOpaque);
if (!this.packedDepth) {
this.depthTextureOpaque.attachFramebuffer(target.framebuffer, 'depth');
} else {
this.colorTarget.depthRenderbuffer?.attachFramebuffer(target.framebuffer);
}
target.bind();
}
target.bind();
}
renderer.renderBlendedTransparent(scene.primitives, camera, null);
if (scene.opacityAverage < 1) {
renderer.renderBlendedTransparent(scene.primitives, camera, null);
}
}
private _render(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, props: Props) {
@@ -307,19 +265,21 @@ export class DrawPass {
}
if (markingEnabled) {
const markingDepthTest = props.marking.ghostEdgeStrength < 1;
if (markingDepthTest) {
this.marking.depthTarget.bind();
renderer.clear(false);
renderer.renderMarkingDepth(scene.primitives, camera, null);
if (scene.markerAverage > 0) {
const markingDepthTest = props.marking.ghostEdgeStrength < 1;
if (markingDepthTest && scene.markerAverage !== 1) {
this.marking.depthTarget.bind();
renderer.clear(false, true);
renderer.renderMarkingDepth(scene.primitives, camera, null);
}
this.marking.maskTarget.bind();
renderer.clear(false, true);
renderer.renderMarkingMask(scene.primitives, camera, markingDepthTest ? this.marking.depthTarget.texture : null);
this.marking.update(props.marking);
this.marking.render(camera.viewport, postprocessingEnabled ? this.postprocessing.target : this.colorTarget);
}
this.marking.maskTarget.bind();
renderer.clear(false);
renderer.renderMarkingMask(scene.primitives, camera, markingDepthTest ? this.marking.depthTarget.texture : null);
this.marking.update(props.marking);
this.marking.render(camera.viewport, postprocessingEnabled ? this.postprocessing.target : this.colorTarget);
}
if (helper.debug.isEnabled) {
@@ -352,6 +312,7 @@ export class DrawPass {
}
render(ctx: RenderContext, props: Props, toDrawingBuffer: boolean) {
if (isTimingMode) this.webgl.timer.mark('DrawPass.render');
const { renderer, camera, scene, helper } = ctx;
renderer.setTransparentBackground(props.transparentBackground);
renderer.setDrawingBufferSize(this.colorTarget.getWidth(), this.colorTarget.getHeight());
@@ -363,6 +324,7 @@ export class DrawPass {
} else {
this._render(renderer, camera, scene, helper, toDrawingBuffer, props);
}
if (isTimingMode) this.webgl.timer.markEnd('DrawPass.render');
}
getColorTarget(postprocessingProps: PostprocessingProps): RenderTarget {

View File

@@ -18,6 +18,7 @@ import { quad_vert } from '../../mol-gl/shader/quad.vert';
import { fxaa_frag } from '../../mol-gl/shader/fxaa.frag';
import { Viewport } from '../camera/util';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { isTimingMode } from '../../mol-util/debug';
export const FxaaParams = {
edgeThresholdMin: PD.Numeric(0.0312, { min: 0.0312, max: 0.0833, step: 0.0001 }, { description: 'Trims the algorithm from processing darks.' }),
@@ -83,6 +84,7 @@ export class FxaaPass {
}
render(viewport: Viewport, target: RenderTarget | undefined) {
if (isTimingMode) this.webgl.timer.mark('FxaaPass.render');
if (target) {
target.bind();
} else {
@@ -90,6 +92,7 @@ export class FxaaPass {
}
this.updateState(viewport);
this.renderable.render();
if (isTimingMode) this.webgl.timer.markEnd('FxaaPass.render');
}
}

View File

@@ -20,6 +20,7 @@ import { Viewport } from '../camera/util';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { Color } from '../../mol-util/color';
import { edge_frag } from '../../mol-gl/shader/marking/edge.frag';
import { isTimingMode } from '../../mol-util/debug';
export const MarkingParams = {
enabled: PD.Boolean(true),
@@ -117,6 +118,7 @@ export class MarkingPass {
}
render(viewport: Viewport, target: RenderTarget | undefined) {
if (isTimingMode) this.webgl.timer.mark('MarkingPass.render');
this.edgesTarget.bind();
this.setEdgeState(viewport);
this.edge.render();
@@ -128,6 +130,7 @@ export class MarkingPass {
}
this.setOverlayState(viewport);
this.overlay.render();
if (isTimingMode) this.webgl.timer.markEnd('MarkingPass.render');
}
}

View File

@@ -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,6 +25,7 @@ import { StereoCamera } from '../camera/stereo';
import { quad_vert } from '../../mol-gl/shader/quad.vert';
import { compose_frag } from '../../mol-gl/shader/compose.frag';
import { MarkingProps } from './marking';
import { isTimingMode } from '../../mol-util/debug';
const ComposeSchema = {
...QuadSchema,
@@ -126,6 +127,7 @@ export class MultiSamplePass {
const { camera } = ctx;
const { compose, composeTarget, drawPass, webgl } = this;
const { gl, state } = webgl;
if (isTimingMode) webgl.timer.mark('MultiSamplePass.renderMultiSample');
// based on the Multisample Anti-Aliasing Render Pass
// contributed to three.js by bhouston / http://clara.io/
@@ -157,6 +159,14 @@ export class MultiSamplePass {
ValueCell.update(compose.values.uWeight, sampleWeight);
// render scene
if (i === 0) {
drawPass.postprocessing.setOcclusionOffset(0, 0);
} else {
drawPass.postprocessing.setOcclusionOffset(
offset[0] / width,
offset[1] / height
);
}
drawPass.render(ctx, props, false);
// compose rendered scene with compose target
@@ -175,6 +185,8 @@ export class MultiSamplePass {
compose.render();
}
drawPass.postprocessing.setOcclusionOffset(0, 0);
ValueCell.update(compose.values.uWeight, 1.0);
ValueCell.update(compose.values.tColor, composeTarget.texture);
compose.update();
@@ -188,12 +200,14 @@ export class MultiSamplePass {
camera.viewOffset.enabled = false;
camera.update();
if (isTimingMode) webgl.timer.markEnd('MultiSamplePass.renderMultiSample');
}
private renderTemporalMultiSample(sampleIndex: number, ctx: RenderContext, props: Props, toDrawingBuffer: boolean) {
const { camera } = ctx;
const { compose, composeTarget, holdTarget, drawPass, webgl } = this;
const { gl, state } = webgl;
if (isTimingMode) webgl.timer.mark('MultiSamplePass.renderTemporalMultiSample');
// based on the Multisample Anti-Aliasing Render Pass
// contributed to three.js by bhouston / http://clara.io/
@@ -236,6 +250,14 @@ export class MultiSamplePass {
camera.update();
// render scene
if (sampleIndex === 0) {
drawPass.postprocessing.setOcclusionOffset(0, 0);
} else {
drawPass.postprocessing.setOcclusionOffset(
offset[0] / width,
offset[1] / height
);
}
drawPass.render(ctx, props, false);
// compose rendered scene with compose target
@@ -258,6 +280,8 @@ export class MultiSamplePass {
}
}
drawPass.postprocessing.setOcclusionOffset(0, 0);
this.bindOutputTarget(toDrawingBuffer);
gl.viewport(x, y, width, height);
gl.scissor(x, y, width, height);
@@ -281,6 +305,7 @@ export class MultiSamplePass {
camera.viewOffset.enabled = false;
camera.update();
if (isTimingMode) webgl.timer.markEnd('MultiSamplePass.renderTemporalMultiSample');
return sampleIndex >= offsetList.length ? -2 : sampleIndex;
}
@@ -291,23 +316,23 @@ const JitterVectors = [
[0, 0]
],
[
[4, 4], [-4, -4]
[0, 0], [-4, -4]
],
[
[-2, -6], [6, -2], [-6, 2], [2, 6]
[0, 0], [6, -2], [-6, 2], [2, 6]
],
[
[1, -3], [-1, 3], [5, 1], [-3, -5],
[0, 0], [-1, 3], [5, 1], [-3, -5],
[-5, 5], [-7, -1], [3, 7], [7, -7]
],
[
[1, 1], [-1, -3], [-3, 2], [4, -1],
[0, 0], [-1, -3], [-3, 2], [4, -1],
[-5, -2], [2, 5], [5, 3], [3, -5],
[-2, 6], [0, -7], [-4, -6], [-6, 4],
[-8, 0], [7, -4], [6, 7], [-7, -8]
],
[
[-4, -7], [-7, -5], [-3, -5], [-5, -4],
[0, 0], [-7, -5], [-3, -5], [-5, -4],
[-1, -4], [-2, -2], [-6, -1], [-4, 0],
[-7, 1], [-1, 2], [-6, 3], [-3, 3],
[-7, 6], [-3, 6], [-5, 7], [-1, 7],

View File

@@ -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>
*/
@@ -7,11 +7,15 @@
import { PickingId } from '../../mol-geo/geometry/picking';
import { PickType, Renderer } from '../../mol-gl/renderer';
import { Scene } from '../../mol-gl/scene';
import { isWebGL2 } from '../../mol-gl/webgl/compat';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { GraphicsRenderVariant } from '../../mol-gl/webgl/render-item';
import { Framebuffer } from '../../mol-gl/webgl/framebuffer';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { Renderbuffer } from '../../mol-gl/webgl/renderbuffer';
import { Texture } from '../../mol-gl/webgl/texture';
import { Vec3 } from '../../mol-math/linear-algebra';
import { spiral2d } from '../../mol-math/misc';
import { isTimingMode } from '../../mol-util/debug';
import { unpackRGBToInt, unpackRGBAToDepth } from '../../mol-util/number-packing';
import { Camera, ICamera } from '../camera';
import { StereoCamera } from '../camera/stereo';
@@ -25,10 +29,24 @@ const NullId = Math.pow(2, 24) - 2;
export type PickData = { id: PickingId, position: Vec3 }
export class PickPass {
readonly objectPickTarget: RenderTarget;
readonly instancePickTarget: RenderTarget;
readonly groupPickTarget: RenderTarget;
readonly depthPickTarget: RenderTarget;
private readonly objectPickTarget: RenderTarget;
private readonly instancePickTarget: RenderTarget;
private readonly groupPickTarget: RenderTarget;
private readonly depthPickTarget: RenderTarget;
private readonly framebuffer: Framebuffer;
private readonly objectPickTexture: Texture;
private readonly instancePickTexture: Texture;
private readonly groupPickTexture: Texture;
private readonly depthPickTexture: Texture;
private readonly objectPickFramebuffer: Framebuffer;
private readonly instancePickFramebuffer: Framebuffer;
private readonly groupPickFramebuffer: Framebuffer;
private readonly depthPickFramebuffer: Framebuffer;
private readonly depthRenderbuffer: Renderbuffer;
private pickWidth: number;
private pickHeight: number;
@@ -38,10 +56,89 @@ export class PickPass {
this.pickWidth = Math.ceil(drawPass.colorTarget.getWidth() * pickScale);
this.pickHeight = Math.ceil(drawPass.colorTarget.getHeight() * pickScale);
this.objectPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.instancePickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.groupPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.depthPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
const { resources, extensions: { drawBuffers }, gl } = webgl;
if (drawBuffers) {
this.objectPickTexture = resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
this.objectPickTexture.define(this.pickWidth, this.pickHeight);
this.instancePickTexture = resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
this.instancePickTexture.define(this.pickWidth, this.pickHeight);
this.groupPickTexture = resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
this.groupPickTexture.define(this.pickWidth, this.pickHeight);
this.depthPickTexture = resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
this.depthPickTexture.define(this.pickWidth, this.pickHeight);
this.framebuffer = resources.framebuffer();
this.objectPickFramebuffer = resources.framebuffer();
this.instancePickFramebuffer = resources.framebuffer();
this.groupPickFramebuffer = resources.framebuffer();
this.depthPickFramebuffer = resources.framebuffer();
this.framebuffer.bind();
drawBuffers!.drawBuffers([
drawBuffers!.COLOR_ATTACHMENT0,
drawBuffers!.COLOR_ATTACHMENT1,
drawBuffers!.COLOR_ATTACHMENT2,
drawBuffers!.COLOR_ATTACHMENT3,
]);
this.objectPickTexture.attachFramebuffer(this.framebuffer, 'color0');
this.instancePickTexture.attachFramebuffer(this.framebuffer, 'color1');
this.groupPickTexture.attachFramebuffer(this.framebuffer, 'color2');
this.depthPickTexture.attachFramebuffer(this.framebuffer, 'color3');
this.depthRenderbuffer = isWebGL2(gl)
? resources.renderbuffer('depth32f', 'depth', this.pickWidth, this.pickHeight)
: resources.renderbuffer('depth16', 'depth', this.pickWidth, this.pickHeight);
this.depthRenderbuffer.attachFramebuffer(this.framebuffer);
this.objectPickTexture.attachFramebuffer(this.objectPickFramebuffer, 'color0');
this.instancePickTexture.attachFramebuffer(this.instancePickFramebuffer, 'color0');
this.groupPickTexture.attachFramebuffer(this.groupPickFramebuffer, 'color0');
this.depthPickTexture.attachFramebuffer(this.depthPickFramebuffer, 'color0');
} else {
this.objectPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.instancePickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.groupPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.depthPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
}
}
bindObject() {
if (this.webgl.extensions.drawBuffers) {
this.objectPickFramebuffer.bind();
} else {
this.objectPickTarget.bind();
}
}
bindInstance() {
if (this.webgl.extensions.drawBuffers) {
this.instancePickFramebuffer.bind();
} else {
this.instancePickTarget.bind();
}
}
bindGroup() {
if (this.webgl.extensions.drawBuffers) {
this.groupPickFramebuffer.bind();
} else {
this.groupPickTarget.bind();
}
}
bindDepth() {
if (this.webgl.extensions.drawBuffers) {
this.depthPickFramebuffer.bind();
} else {
this.depthPickTarget.bind();
}
}
get drawingBufferHeight() {
@@ -57,21 +154,30 @@ export class PickPass {
this.pickWidth = pickWidth;
this.pickHeight = pickHeight;
this.objectPickTarget.setSize(this.pickWidth, this.pickHeight);
this.instancePickTarget.setSize(this.pickWidth, this.pickHeight);
this.groupPickTarget.setSize(this.pickWidth, this.pickHeight);
this.depthPickTarget.setSize(this.pickWidth, this.pickHeight);
if (this.webgl.extensions.drawBuffers) {
this.objectPickTexture.define(this.pickWidth, this.pickHeight);
this.instancePickTexture.define(this.pickWidth, this.pickHeight);
this.groupPickTexture.define(this.pickWidth, this.pickHeight);
this.depthPickTexture.define(this.pickWidth, this.pickHeight);
this.depthRenderbuffer.setSize(this.pickWidth, this.pickHeight);
} else {
this.objectPickTarget.setSize(this.pickWidth, this.pickHeight);
this.instancePickTarget.setSize(this.pickWidth, this.pickHeight);
this.groupPickTarget.setSize(this.pickWidth, this.pickHeight);
this.depthPickTarget.setSize(this.pickWidth, this.pickHeight);
}
}
}
private renderVariant(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, variant: GraphicsRenderVariant, pickType: number) {
const depth = this.drawPass.depthTexturePrimitives;
private renderVariant(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, variant: 'pick' | 'depth', pickType: number) {
renderer.clear(false);
renderer.update(camera);
renderer.renderPick(scene.primitives, camera, variant, null, pickType);
renderer.renderPick(scene.volumes, camera, variant, depth, pickType);
renderer.renderPick(helper.handle.scene, camera, variant, null, pickType);
if (helper.handle.isEnabled) {
renderer.renderPick(helper.handle.scene, camera, variant, null, pickType);
}
if (helper.camera.isEnabled) {
helper.camera.update(camera);
@@ -81,18 +187,23 @@ export class PickPass {
}
render(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper) {
this.objectPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Object);
if (this.webgl.extensions.drawBuffers) {
this.framebuffer.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.None);
} else {
this.objectPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Object);
this.instancePickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Instance);
this.instancePickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Instance);
this.groupPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Group);
// printTexture(this.webgl, this.groupPickTarget.texture, { id: 'group' })
this.groupPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Group);
// printTexture(this.webgl, this.groupPickTarget.texture, { id: 'group' })
this.depthPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'depth', PickType.None);
this.depthPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'depth', PickType.None);
}
}
}
@@ -147,19 +258,21 @@ export class PickHelper {
}
private syncBuffers() {
if (isTimingMode) this.webgl.timer.mark('PickHelper.syncBuffers');
const { pickX, pickY, pickWidth, pickHeight } = this;
this.pickPass.objectPickTarget.bind();
this.pickPass.bindObject();
this.webgl.readPixels(pickX, pickY, pickWidth, pickHeight, this.objectBuffer);
this.pickPass.instancePickTarget.bind();
this.pickPass.bindInstance();
this.webgl.readPixels(pickX, pickY, pickWidth, pickHeight, this.instanceBuffer);
this.pickPass.groupPickTarget.bind();
this.pickPass.bindGroup();
this.webgl.readPixels(pickX, pickY, pickWidth, pickHeight, this.groupBuffer);
this.pickPass.depthPickTarget.bind();
this.pickPass.bindDepth();
this.webgl.readPixels(pickX, pickY, pickWidth, pickHeight, this.depthBuffer);
if (isTimingMode) this.webgl.timer.markEnd('PickHelper.syncBuffers');
}
private getBufferIdx(x: number, y: number): number {
@@ -178,11 +291,12 @@ export class PickHelper {
}
private render(camera: Camera | StereoCamera) {
if (isTimingMode) this.webgl.timer.mark('PickHelper.render');
const { pickX, pickY, pickWidth, pickHeight, halfPickWidth } = this;
const { renderer, scene, helper } = this;
renderer.setTransparentBackground(false);
renderer.setDrawingBufferSize(this.pickPass.objectPickTarget.getWidth(), this.pickPass.objectPickTarget.getHeight());
renderer.setDrawingBufferSize(pickWidth, pickHeight);
renderer.setPixelRatio(this.pickScale);
if (StereoCamera.is(camera)) {
@@ -197,6 +311,7 @@ export class PickHelper {
}
this.dirty = false;
if (isTimingMode) this.webgl.timer.markEnd('PickHelper.render');
}
private identifyInternal(x: number, y: number, camera: Camera | StereoCamera): PickData | undefined {
@@ -217,8 +332,10 @@ export class PickHelper {
) return;
if (this.dirty) {
if (isTimingMode) this.webgl.timer.mark('PickHelper.identify');
this.render(camera);
this.syncBuffers();
if (isTimingMode) this.webgl.timer.markEnd('PickHelper.identify');
}
const xv = x - viewport.x;
@@ -240,6 +357,7 @@ export class PickHelper {
if (groupId === -1 || groupId === NullId) return;
const z = this.getDepth(xp, yp);
// console.log('z', z);
const position = Vec3.create(x, viewport.height - y, z);
if (StereoCamera.is(camera)) {
const halfWidth = Math.floor(viewport.width / 2);
@@ -254,7 +372,7 @@ export class PickHelper {
cameraUnproject(position, position, viewport, camera.inverseProjectionView);
}
// console.log({ { objectId, instanceId, groupId }, position} );
// console.log({ id: { objectId, instanceId, groupId }, position });
return { id: { objectId, instanceId, groupId }, position };
}

View File

@@ -1,11 +1,11 @@
/**
* 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>
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
*/
import { QuadSchema, QuadValues } from '../../mol-gl/compute/util';
import { CopyRenderable, createCopyRenderable, QuadSchema, QuadValues } from '../../mol-gl/compute/util';
import { TextureSpec, Values, UniformSpec, DefineSpec } from '../../mol-gl/renderable/schema';
import { ShaderCode } from '../../mol-gl/shader-code';
import { WebGLContext } from '../../mol-gl/webgl/context';
@@ -27,10 +27,12 @@ import { Framebuffer } from '../../mol-gl/webgl/framebuffer';
import { Color } from '../../mol-util/color';
import { FxaaParams, FxaaPass } from './fxaa';
import { SmaaParams, SmaaPass } from './smaa';
import { isTimingMode } from '../../mol-util/debug';
const OutlinesSchema = {
...QuadSchema,
tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
tDepthOpaque: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
tDepthTransparent: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
uTexSize: UniformSpec('v2'),
dOrthographic: DefineSpec('number'),
@@ -41,11 +43,15 @@ const OutlinesSchema = {
};
type OutlinesRenderable = ComputeRenderable<Values<typeof OutlinesSchema>>
function getOutlinesRenderable(ctx: WebGLContext, depthTexture: Texture): OutlinesRenderable {
function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, depthTextureTransparent: Texture): OutlinesRenderable {
const width = depthTextureOpaque.getWidth();
const height = depthTextureOpaque.getHeight();
const values: Values<typeof OutlinesSchema> = {
...QuadValues,
tDepth: ValueCell.create(depthTexture),
uTexSize: ValueCell.create(Vec2.create(depthTexture.getWidth(), depthTexture.getHeight())),
tDepthOpaque: ValueCell.create(depthTextureOpaque),
tDepthTransparent: ValueCell.create(depthTextureTransparent),
uTexSize: ValueCell.create(Vec2.create(width, height)),
dOrthographic: ValueCell.create(0),
uNear: ValueCell.create(1),
@@ -183,7 +189,8 @@ const PostprocessingSchema = {
...QuadSchema,
tSsaoDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
tColor: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
tDepthOpaque: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
tDepthTransparent: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
tOutlines: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
uTexSize: UniformSpec('v2'),
@@ -199,6 +206,7 @@ const PostprocessingSchema = {
uMaxPossibleViewZDiff: UniformSpec('f'),
dOcclusionEnable: DefineSpec('boolean'),
uOcclusionOffset: UniformSpec('v2'),
dOutlineEnable: DefineSpec('boolean'),
dOutlineScale: DefineSpec('number'),
@@ -206,12 +214,13 @@ const PostprocessingSchema = {
};
type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>>
function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTexture: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture): PostprocessingRenderable {
function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture): PostprocessingRenderable {
const values: Values<typeof PostprocessingSchema> = {
...QuadValues,
tSsaoDepth: ValueCell.create(ssaoDepthTexture),
tColor: ValueCell.create(colorTexture),
tDepth: ValueCell.create(depthTexture),
tDepthOpaque: ValueCell.create(depthTextureOpaque),
tDepthTransparent: ValueCell.create(depthTextureTransparent),
tOutlines: ValueCell.create(outlinesTexture),
uTexSize: ValueCell.create(Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())),
@@ -227,6 +236,7 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
uMaxPossibleViewZDiff: ValueCell.create(0.5),
dOcclusionEnable: ValueCell.create(true),
uOcclusionOffset: ValueCell.create(Vec2.create(0, 0)),
dOutlineEnable: ValueCell.create(false),
dOutlineScale: ValueCell.create(1),
@@ -244,9 +254,10 @@ export const PostprocessingParams = {
occlusion: PD.MappedStatic('on', {
on: PD.Group({
samples: PD.Numeric(32, { min: 1, max: 256, step: 1 }),
radius: PD.Numeric(5, { min: 0, max: 10, step: 0.1 }, { description: 'Final radius is 2^x.' }),
radius: PD.Numeric(5, { min: 0, max: 10, step: 0.1 }, { description: 'Final occlusion radius is 2^x' }),
bias: PD.Numeric(0.8, { min: 0, max: 3, step: 0.1 }),
blurKernelSize: PD.Numeric(15, { min: 1, max: 25, step: 2 }),
resolutionScale: PD.Numeric(1, { min: 0.1, max: 1, step: 0.05 }, { description: 'Adjust resolution of occlusion calculation' }),
}),
off: PD.Group({})
}, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }),
@@ -271,6 +282,10 @@ export class PostprocessingPass {
return props.occlusion.name === 'on' || props.outline.name === 'on';
}
static isOutlineEnabled(props: PostprocessingProps) {
return props.outline.name === 'on';
}
readonly target: RenderTarget;
private readonly outlinesTarget: RenderTarget;
@@ -281,6 +296,9 @@ export class PostprocessingPass {
private readonly ssaoBlurFirstPassFramebuffer: Framebuffer;
private readonly ssaoBlurSecondPassFramebuffer: Framebuffer;
private readonly downsampledDepthTarget: RenderTarget;
private readonly downsampleDepthRenderable: CopyRenderable;
private readonly ssaoDepthTexture: Texture;
private readonly ssaoDepthBlurProxyTexture: Texture;
@@ -290,30 +308,31 @@ export class PostprocessingPass {
private nSamples: number;
private blurKernelSize: number;
private downsampleFactor: number;
private readonly renderable: PostprocessingRenderable;
private ssaoScale: number;
private calcSsaoScale() {
// downscale ssao for high pixel-ratios
return Math.min(1, 1 / this.webgl.pixelRatio);
return Math.min(1, 1 / this.webgl.pixelRatio) * this.downsampleFactor;
}
constructor(private webgl: WebGLContext, drawPass: DrawPass) {
this.ssaoScale = this.calcSsaoScale();
const { colorTarget, depthTexture } = drawPass;
constructor(private webgl: WebGLContext, private drawPass: DrawPass) {
const { colorTarget, depthTextureTransparent, depthTextureOpaque } = drawPass;
const width = colorTarget.getWidth();
const height = colorTarget.getHeight();
this.nSamples = 1;
this.blurKernelSize = 1;
this.downsampleFactor = 1;
this.ssaoScale = this.calcSsaoScale();
// needs to be linear for anti-aliasing pass
this.target = webgl.createRenderTarget(width, height, false, 'uint8', 'linear');
this.outlinesTarget = webgl.createRenderTarget(width, height, false);
this.outlinesRenderable = getOutlinesRenderable(webgl, depthTexture);
this.outlinesRenderable = getOutlinesRenderable(webgl, depthTextureOpaque, depthTextureTransparent);
this.randomHemisphereVector = [];
for (let i = 0; i < 256; i++) {
@@ -332,20 +351,23 @@ export class PostprocessingPass {
const sw = Math.floor(width * this.ssaoScale);
const sh = Math.floor(height * this.ssaoScale);
this.ssaoDepthTexture = webgl.resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
this.downsampledDepthTarget = webgl.createRenderTarget(sw, sh, false, 'uint8', 'linear');
this.downsampleDepthRenderable = createCopyRenderable(webgl, depthTextureOpaque);
this.ssaoDepthTexture = webgl.resources.texture('image-uint8', 'rgba', 'ubyte', 'linear');
this.ssaoDepthTexture.define(sw, sh);
this.ssaoDepthTexture.attachFramebuffer(this.ssaoFramebuffer, 'color0');
this.ssaoDepthBlurProxyTexture = webgl.resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
this.ssaoDepthBlurProxyTexture = webgl.resources.texture('image-uint8', 'rgba', 'ubyte', 'linear');
this.ssaoDepthBlurProxyTexture.define(sw, sh);
this.ssaoDepthBlurProxyTexture.attachFramebuffer(this.ssaoBlurFirstPassFramebuffer, 'color0');
this.ssaoDepthTexture.attachFramebuffer(this.ssaoBlurSecondPassFramebuffer, 'color0');
this.ssaoRenderable = getSsaoRenderable(webgl, depthTexture);
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, depthTexture, this.outlinesTarget.texture, this.ssaoDepthTexture);
this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.outlinesTarget.texture, this.ssaoDepthTexture);
}
setSize(width: number, height: number) {
@@ -359,11 +381,13 @@ export class PostprocessingPass {
const sh = Math.floor(height * this.ssaoScale);
this.target.setSize(width, height);
this.outlinesTarget.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.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));
ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurSecondPassRenderable.values.uTexSize.ref.value, sw, sh));
@@ -434,6 +458,30 @@ export class PostprocessingPass {
ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize);
}
if (this.downsampleFactor !== props.occlusion.params.resolutionScale) {
needsUpdateSsao = true;
this.downsampleFactor = props.occlusion.params.resolutionScale;
this.ssaoScale = this.calcSsaoScale();
const sw = Math.floor(w * this.ssaoScale);
const sh = Math.floor(h * this.ssaoScale);
this.downsampledDepthTarget.setSize(sw, sh);
this.ssaoDepthTexture.define(sw, sh);
this.ssaoDepthBlurProxyTexture.define(sw, sh);
if (this.ssaoScale === 1) {
ValueCell.update(this.ssaoRenderable.values.tDepth, this.drawPass.depthTextureTransparent);
} else {
ValueCell.update(this.ssaoRenderable.values.tDepth, this.downsampledDepthTarget.texture);
}
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));
ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurSecondPassRenderable.values.uTexSize.ref.value, sw, sh));
}
}
if (props.outline.name === 'on') {
@@ -494,7 +542,15 @@ export class PostprocessingPass {
gl.scissor(x, y, width, height);
}
private occlusionOffset: [x: number, y: number] = [0, 0];
setOcclusionOffset(x: number, y: number) {
this.occlusionOffset[0] = x;
this.occlusionOffset[1] = y;
ValueCell.update(this.renderable.values.uOcclusionOffset, Vec2.set(this.renderable.values.uOcclusionOffset.ref.value, x, y));
}
render(camera: ICamera, toDrawingBuffer: boolean, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps) {
if (isTimingMode) this.webgl.timer.mark('PostprocessingPass.render');
this.updateState(camera, transparentBackground, backgroundColor, props);
if (props.outline.name === 'on') {
@@ -502,14 +558,13 @@ export class PostprocessingPass {
this.outlinesRenderable.render();
}
if (props.occlusion.name === 'on') {
const { x, y, width, height } = camera.viewport;
const sx = Math.floor(x * this.ssaoScale);
const sy = Math.floor(y * this.ssaoScale);
const sw = Math.ceil(width * this.ssaoScale);
const sh = Math.ceil(height * this.ssaoScale);
this.webgl.gl.viewport(sx, sy, sw, sh);
this.webgl.gl.scissor(sx, sy, sw, sh);
// 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) {
if (this.ssaoScale < 1) {
this.downsampledDepthTarget.bind();
this.downsampleDepthRenderable.render();
}
this.ssaoFramebuffer.bind();
this.ssaoRenderable.render();
@@ -519,9 +574,6 @@ export class PostprocessingPass {
this.ssaoBlurSecondPassFramebuffer.bind();
this.ssaoBlurSecondPassRenderable.render();
this.webgl.gl.viewport(x, y, width, height);
this.webgl.gl.scissor(x, y, width, height);
}
if (toDrawingBuffer) {
@@ -535,6 +587,7 @@ export class PostprocessingPass {
gl.clear(gl.COLOR_BUFFER_BIT);
this.renderable.render();
if (isTimingMode) this.webgl.timer.markEnd('PostprocessingPass.render');
}
}

View File

@@ -22,7 +22,7 @@ import { weights_frag } from '../../mol-gl/shader/smaa/weights.frag';
import { edges_vert } from '../../mol-gl/shader/smaa/edges.vert';
import { edges_frag } from '../../mol-gl/shader/smaa/edges.frag';
import { Viewport } from '../camera/util';
import { isDebugMode } from '../../mol-util/debug';
import { isDebugMode, isTimingMode } from '../../mol-util/debug';
export const SmaaParams = {
edgeThreshold: PD.Numeric(0.1, { min: 0.05, max: 0.15, step: 0.01 }),
@@ -120,6 +120,7 @@ export class SmaaPass {
}
render(viewport: Viewport, target: RenderTarget | undefined) {
if (isTimingMode) this.webgl.timer.mark('SmaaPass.render');
this.edgesTarget.bind();
this.updateState(viewport);
this.edgesRenderable.render();
@@ -135,8 +136,8 @@ export class SmaaPass {
}
this.updateState(viewport);
this.blendRenderable.render();
if (isTimingMode) this.webgl.timer.markEnd('SmaaPass.render');
}
}
//

View File

@@ -17,7 +17,7 @@ import { quad_vert } from '../../mol-gl/shader/quad.vert';
import { evaluateWboit_frag } from '../../mol-gl/shader/evaluate-wboit.frag';
import { Framebuffer } from '../../mol-gl/webgl/framebuffer';
import { Vec2 } from '../../mol-math/linear-algebra';
import { isDebugMode } from '../../mol-util/debug';
import { isDebugMode, isTimingMode } from '../../mol-util/debug';
const EvaluateWboitSchema = {
...QuadSchema,
@@ -71,6 +71,7 @@ export class WboitPass {
}
render() {
if (isTimingMode) this.webgl.timer.mark('WboitPass.render');
const { state, gl } = this.webgl;
state.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
@@ -78,6 +79,7 @@ export class WboitPass {
this.renderable.update();
this.renderable.render();
if (isTimingMode) this.webgl.timer.markEnd('WboitPass.render');
}
setSize(width: number, height: number) {

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 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>
@@ -61,6 +61,29 @@ describe('column', () => {
});
});
describe('string column', () => {
const xs = ['A', 'b', null, undefined];
const xsArr = xs.map(x => x ?? '');
const xsLC = xs.map(x => (x ?? '').toLowerCase());
const arr = Column.ofArray({ array: xs as any, schema: Column.Schema.str });
const arrLC = Column.ofArray({ array: xs as any, schema: Column.Schema.Str({ transform: 'lowercase' }) });
const aliasedLC = Column.ofArray({ array: xs as any, schema: Column.Schema.Aliased<'a' | 'b'>(Column.Schema.lstr) });
it('value', () => {
for (let i = 0; i < xs.length; i++) {
expect(arr.value(i)).toBe(xs[i] ?? '');
expect(arrLC.value(i)).toBe(xsLC[i] ?? '');
expect(aliasedLC.value(i)).toBe(xsLC[i]);
}
});
it('array', () => {
expect(arr.toArray()).toEqual(xsArr);
expect(arrLC.toArray()).toEqual(xsLC);
expect(aliasedLC.toArray()).toEqual(xsLC);
});
});
describe('table', () => {
const schema = {
x: Column.Schema.int,

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2019 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>
@@ -25,38 +25,39 @@ interface Column<T> {
namespace Column {
export type ArrayCtor<T> = { new(size: number): ArrayLike<T> }
export type Schema<T = any> = Schema.Str | Schema.Int | Schema.Float | Schema.Coordinate | Schema.Aliased<T> | Schema.Tensor | Schema.List<number|string>
export type Schema<T = any> = Schema.Str | Schema.Int | Schema.Float | Schema.Coordinate | Schema.Aliased<T> | Schema.Tensor | Schema.List<number | string>
export namespace Schema {
// T also serves as a default value for undefined columns
type Base<T extends string> = { valueType: T }
export type Str = { '@type': 'str', T: string } & Base<'str'>
export type Str = { '@type': 'str', T: string, transform?: 'uppercase' | 'lowercase' } & Base<'str'>
export type Int = { '@type': 'int', T: number } & Base<'int'>
export type Float = { '@type': 'float', T: number } & Base<'float'>
export type Coordinate = { '@type': 'coord', T: number } & Base<'float'>
export type Tensor = { '@type': 'tensor', T: Tensors.Data, space: Tensors.Space, baseType: Int | Float } & Base<'tensor'>
export type Aliased<T> = { '@type': 'aliased', T: T } & Base<T extends string ? 'str' : 'int'>
export type List<T extends number|string> = { '@type': 'list', T: T[], separator: string, itemParse: (x: string) => T } & Base<'list'>
export type Aliased<T> = { '@type': 'aliased', T: T, transform?: T extends string ? 'uppercase' | 'lowercase' : never } & Base<T extends string ? 'str' : 'int'>
export type List<T extends number | string> = { '@type': 'list', T: T[], separator: string, itemParse: (x: string) => T } & Base<'list'>
export const str: Str = { '@type': 'str', T: '', valueType: 'str' };
export const ustr: Str = { '@type': 'str', T: '', valueType: 'str', transform: 'uppercase' };
export const lstr: Str = { '@type': 'str', T: '', valueType: 'str', transform: 'lowercase' };
export const int: Int = { '@type': 'int', T: 0, valueType: 'int' };
export const coord: Coordinate = { '@type': 'coord', T: 0, valueType: 'float' };
export const float: Float = { '@type': 'float', T: 0, valueType: 'float' };
export function Str(defaultValue = ''): Str { return { '@type': 'str', T: defaultValue, valueType: 'str' }; };
export function Str(options?: { defaultValue?: string, transform?: 'uppercase' | 'lowercase' }): Str { return { '@type': 'str', T: options?.defaultValue ?? '', transform: options?.transform, valueType: 'str' }; };
export function Int(defaultValue = 0): Int { return { '@type': 'int', T: defaultValue, valueType: 'int' }; };
export function Float(defaultValue = 0): Float { return { '@type': 'float', T: defaultValue, valueType: 'float' }; };
export function Tensor(space: Tensors.Space, baseType: Int | Float = float): Tensor { return { '@type': 'tensor', T: space.create(), space, valueType: 'tensor', baseType }; }
export function Vector(dim: number, baseType: Int | Float = float): Tensor { return Tensor(Tensors.Vector(dim, baseType['@type'] === 'int' ? Int32Array : Float64Array), baseType); }
export function Matrix(rows: number, cols: number, baseType: Int | Float = float): Tensor { return Tensor(Tensors.ColumnMajorMatrix(rows, cols, baseType['@type'] === 'int' ? Int32Array : Float64Array), baseType); }
export function Aliased<T>(t: Str | Int, defaultValue?: T): Aliased<T> {
if (typeof defaultValue !== 'undefined') return { ...t, T: defaultValue } as any as Aliased<T>;
export function Aliased<T>(t: Str | Int): Aliased<T> {
return t as any as Aliased<T>;
}
export function List<T extends number|string>(separator: string, itemParse: (x: string) => T, defaultValue: T[] = []): List<T> {
export function List<T extends number | string>(separator: string, itemParse: (x: string) => T, defaultValue: T[] = []): List<T> {
return { '@type': 'list', T: defaultValue, separator, itemParse, valueType: 'list' };
}
}
@@ -287,8 +288,13 @@ function lambdaColumn<T extends Column.Schema>({ value, valueKind, areValuesEqua
function arrayColumn<T extends Column.Schema>({ array, schema, valueKind }: Column.ArraySpec<T>): Column<T['T']> {
const rowCount = array.length;
const defaultValue = schema.T;
const value: Column<T['T']>['value'] = schema.valueType === 'str'
? row => { const v = array[row]; return typeof v === 'string' ? v : '' + v; }
? (schema as Column.Schema.Str).transform === 'lowercase'
? row => { const v = array[row]; return typeof v === 'string' ? v.toLowerCase() : `${v ?? defaultValue}`.toLowerCase(); }
: (schema as Column.Schema.Str).transform === 'uppercase'
? row => { const v = array[row]; return typeof v === 'string' ? v.toUpperCase() : `${v ?? defaultValue}`.toUpperCase(); }
: row => { const v = array[row]; return typeof v === 'string' ? v : `${v ?? defaultValue}`; }
: row => array[row];
const isTyped = ColumnHelpers.isTypedArray(array);
@@ -300,15 +306,35 @@ function arrayColumn<T extends Column.Schema>({ array, schema, valueKind }: Colu
value,
valueKind: valueKind ? valueKind : row => Column.ValueKind.Present,
toArray: schema.valueType === 'str'
? params => {
const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);
const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
for (let i = 0, _i = end - start; i < _i; i++) {
const v = array[start + i];
ret[i] = typeof v === 'string' ? v : '' + v;
? (schema as Column.Schema.Str).transform === 'lowercase'
? params => {
const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);
const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
for (let i = 0, _i = end - start; i < _i; i++) {
const v = array[start + i];
ret[i] = typeof v === 'string' ? v.toLowerCase() : `${v ?? defaultValue}`.toLowerCase();
}
return ret;
}
return ret;
}
: (schema as Column.Schema.Str).transform === 'uppercase'
? params => {
const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);
const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
for (let i = 0, _i = end - start; i < _i; i++) {
const v = array[start + i];
ret[i] = typeof v === 'string' ? v.toUpperCase() : `${v ?? defaultValue}`.toUpperCase();
}
return ret;
}
: params => {
const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);
const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
for (let i = 0, _i = end - start; i < _i; i++) {
const v = array[start + i];
ret[i] = typeof v === 'string' ? v : `${v ?? defaultValue}`;
}
return ret;
}
: isTyped
? params => ColumnHelpers.typedArrayWindow(array, params) as any as ReadonlyArray<T>
: params => {

View File

@@ -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>
* @author David Sehnal <david.sehnal@gmail.com>
@@ -11,11 +11,13 @@ import { Color } from '../../mol-util/color';
import { Vec2, Vec3, Vec4 } from '../../mol-math/linear-algebra';
import { LocationIterator } from '../util/location-iterator';
import { NullLocation } from '../../mol-model/location';
import { LocationColor, ColorTheme } from '../../mol-theme/color';
import { Geometry } from './geometry';
import { LocationColor, ColorTheme, ColorVolume } from '../../mol-theme/color';
import { createNullTexture, Texture } from '../../mol-gl/webgl/texture';
export type ColorType = 'uniform' | 'instance' | 'group' | 'groupInstance' | 'vertex' | 'vertexInstance' | 'volume' | 'volumeInstance' | 'direct'
export type ColorTypeLocation = 'uniform' | 'instance' | 'group' | 'groupInstance' | 'vertex' | 'vertexInstance';
export type ColorTypeGrid = 'volume' | 'volumeInstance';
export type ColorTypeDirect = 'direct';
export type ColorType = ColorTypeLocation | ColorTypeGrid | ColorTypeDirect;
export type ColorData = {
uColor: ValueCell<Vec3>,
@@ -29,7 +31,7 @@ export type ColorData = {
dUsePalette: ValueCell<boolean>,
}
export function createColors(locationIt: LocationIterator, positionIt: LocationIterator, colorTheme: ColorTheme<any>, colorData?: ColorData): ColorData {
export function createColors(locationIt: LocationIterator, positionIt: LocationIterator, colorTheme: ColorTheme<any, any>, colorData?: ColorData): ColorData {
const data = _createColors(locationIt, positionIt, colorTheme, colorData);
if (colorTheme.palette) {
ValueCell.updateIfChanged(data.dUsePalette, true);
@@ -40,16 +42,19 @@ export function createColors(locationIt: LocationIterator, positionIt: LocationI
return data;
}
function _createColors(locationIt: LocationIterator, positionIt: LocationIterator, colorTheme: ColorTheme<any>, colorData?: ColorData): ColorData {
switch (Geometry.getGranularity(locationIt, colorTheme.granularity)) {
function _createColors(locationIt: LocationIterator, positionIt: LocationIterator, colorTheme: ColorTheme<any, any>, colorData?: ColorData): ColorData {
switch (colorTheme.granularity) {
case 'uniform': return createUniformColor(locationIt, colorTheme.color, colorData);
case 'instance': return createInstanceColor(locationIt, colorTheme.color, colorData);
case 'instance':
return locationIt.nonInstanceable
? createGroupColor(locationIt, colorTheme.color, colorData)
: createInstanceColor(locationIt, colorTheme.color, colorData);
case 'group': return createGroupColor(locationIt, colorTheme.color, colorData);
case 'groupInstance': return createGroupInstanceColor(locationIt, colorTheme.color, colorData);
case 'vertex': return createVertexColor(positionIt, colorTheme.color, colorData);
case 'vertexInstance': return createVertexInstanceColor(positionIt, colorTheme.color, colorData);
case 'volume': return createGridColor((colorTheme as any).grid, 'volume', colorData);
case 'volumeInstance': return createGridColor((colorTheme as any).grid, 'volumeInstance', colorData);
case 'volume': return createGridColor(colorTheme.grid, 'volume', colorData);
case 'volumeInstance': return createGridColor(colorTheme.grid, 'volumeInstance', colorData);
case 'direct': return createDirectColor(colorData);
}
}
@@ -207,12 +212,6 @@ function createVertexInstanceColor(locationIt: LocationIterator, color: Location
//
interface ColorVolume {
colors: Texture
dimension: Vec3
transform: Vec4
}
export function createGridColor(grid: ColorVolume, type: ColorType, colorData?: ColorData): ColorData {
const { colors, dimension, transform } = grid;
const width = colors.getWidth();

View File

@@ -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>
*/
@@ -157,6 +157,7 @@ export namespace Cylinders {
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
};
@@ -241,6 +242,7 @@ export namespace Cylinders {
uDoubleSided: ValueCell.create(props.doubleSided),
dIgnoreLight: ValueCell.create(props.ignoreLight),
dXrayShaded: ValueCell.create(props.xrayShaded),
dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
uBumpFrequency: ValueCell.create(props.bumpFrequency),
uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
};
@@ -258,6 +260,7 @@ export namespace Cylinders {
ValueCell.updateIfChanged(values.uDoubleSided, props.doubleSided);
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2020 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>
*/
@@ -165,7 +165,7 @@ export namespace Lines {
export const Params = {
...BaseGeometry.Params,
sizeFactor: PD.Numeric(3, { min: 0, max: 10, step: 0.1 }),
sizeFactor: PD.Numeric(2, { min: 0, max: 10, step: 0.1 }),
lineSizeAttenuation: PD.Boolean(false),
};
export type Params = typeof Params

View File

@@ -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>
*/
@@ -34,13 +34,15 @@ export function calcMeshColorSmoothing(input: ColorSmoothingInput, resolution: n
const isInstanceType = colorType.endsWith('Instance');
const box = Box3D.fromSphere3D(Box3D(), isInstanceType ? input.boundingSphere : input.invariantBoundingSphere);
const pad = 1 + resolution;
const expandedBox = Box3D.expand(Box3D(), box, Vec3.create(pad, pad, pad));
const scaleFactor = 1 / resolution;
const scaledBox = Box3D.scale(Box3D(), box, scaleFactor);
const scaledBox = Box3D.scale(Box3D(), expandedBox, scaleFactor);
const gridDim = Box3D.size(Vec3(), scaledBox);
Vec3.ceil(gridDim, gridDim);
Vec3.add(gridDim, gridDim, Vec3.create(2, 2, 2));
const { min } = box;
const { min } = expandedBox;
const [xn, yn] = gridDim;
const { width, height } = getVolumeTexture2dLayout(gridDim);

View File

@@ -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>
* @author David Sehnal <david.sehnal@gmail.com>
@@ -625,6 +625,7 @@ export namespace Mesh {
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
};
@@ -700,6 +701,7 @@ export namespace Mesh {
dFlipSided: ValueCell.create(props.flipSided),
dIgnoreLight: ValueCell.create(props.ignoreLight),
dXrayShaded: ValueCell.create(props.xrayShaded),
dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
uBumpFrequency: ValueCell.create(props.bumpFrequency),
uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
@@ -720,6 +722,7 @@ export namespace Mesh {
ValueCell.updateIfChanged(values.dFlipSided, props.flipSided);
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
}

View File

@@ -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>
*/
@@ -129,6 +129,7 @@ export namespace Spheres {
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
};
@@ -208,6 +209,7 @@ export namespace Spheres {
uDoubleSided: ValueCell.create(props.doubleSided),
dIgnoreLight: ValueCell.create(props.ignoreLight),
dXrayShaded: ValueCell.create(props.xrayShaded),
dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
uBumpFrequency: ValueCell.create(props.bumpFrequency),
uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
};
@@ -225,6 +227,7 @@ export namespace Spheres {
ValueCell.updateIfChanged(values.uDoubleSided, props.doubleSided);
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
}

View File

@@ -8,6 +8,7 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { ChunkedArray } from '../../../mol-data/util';
import { Text } from './text';
import { getFontAtlas } from './font-atlas';
import { assertUnreachable } from '../../../mol-util/type-helpers';
const quadIndices = new Uint16Array([
0, 1, 2,
@@ -237,7 +238,7 @@ export namespace TextBuilder {
yBaseCenter = yTop;
break;
default:
throw new Error('unsupported attachment');
assertUnreachable(attachment);
}
caAdd2(mappings, xTip, yTip); // tip
caAdd2(mappings, xBaseA, yBaseA); // base A

View File

@@ -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>
*/
@@ -20,6 +20,7 @@ import { accumulate_frag } from '../../../mol-gl/shader/compute/color-smoothing/
import { accumulate_vert } from '../../../mol-gl/shader/compute/color-smoothing/accumulate.vert';
import { isWebGL2 } from '../../../mol-gl/webgl/compat';
import { TextureMeshValues } from '../../../mol-gl/renderable/texture-mesh';
import { isTimingMode } from '../../../mol-util/debug';
export const ColorAccumulateSchema = {
drawCount: ValueSpec('number'),
@@ -255,17 +256,20 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
const { drawBuffers } = webgl.extensions;
if (!drawBuffers) throw new Error('need WebGL draw buffers');
if (isTimingMode) webgl.timer.mark('calcTextureMeshColorSmoothing');
const { gl, resources, state, extensions: { colorBufferHalfFloat, textureHalfFloat } } = webgl;
const isInstanceType = input.colorType.endsWith('Instance');
const box = Box3D.fromSphere3D(Box3D(), isInstanceType ? input.boundingSphere : input.invariantBoundingSphere);
const pad = 1 + resolution;
const expandedBox = Box3D.expand(Box3D(), box, Vec3.create(pad, pad, pad));
const scaleFactor = 1 / resolution;
const scaledBox = Box3D.scale(Box3D(), box, scaleFactor);
const scaledBox = Box3D.scale(Box3D(), expandedBox, scaleFactor);
const gridDim = Box3D.size(Vec3(), scaledBox);
Vec3.ceil(gridDim, gridDim);
Vec3.add(gridDim, gridDim, Vec3.create(2, 2, 2));
const { min } = box;
const { min } = expandedBox;
const [dx, dy, dz] = gridDim;
const { texDimX: width, texDimY: height, texCols } = getTexture2dSize(gridDim);
@@ -308,7 +312,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
accumulateTexture.attachFramebuffer(framebuffer, 0);
countTexture.attachFramebuffer(framebuffer, 1);
const accumulateRenderable = getAccumulateRenderable(webgl, input, box, resolution, stride);
const accumulateRenderable = getAccumulateRenderable(webgl, input, expandedBox, resolution, stride);
state.currentRenderItemId = -1;
framebuffer.bind();
@@ -319,6 +323,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
const { uCurrentSlice, uCurrentX, uCurrentY } = accumulateRenderable.values;
if (isTimingMode) webgl.timer.mark('ColorAccumulate.render');
setAccumulateDefaults(webgl);
gl.viewport(0, 0, width, height);
gl.scissor(0, 0, width, height);
@@ -347,6 +352,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
accumulateTexture.detachFramebuffer(framebuffer, 0);
countTexture.detachFramebuffer(framebuffer, 1);
drawBuffers.drawBuffers([gl.COLOR_ATTACHMENT0, gl.NONE]);
if (isTimingMode) webgl.timer.markEnd('ColorAccumulate.render');
// const accImage = new Float32Array(width * height * 4);
// accumulateTexture.attachFramebuffer(framebuffer, 0);
@@ -362,6 +368,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
// normalize
if (isTimingMode) webgl.timer.mark('ColorNormalize.render');
if (!texture) texture = resources.texture('image-uint8', 'rgba', 'ubyte', 'linear');
texture.define(width, height);
@@ -374,6 +381,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
gl.scissor(0, 0, width, height);
gl.clear(gl.COLOR_BUFFER_BIT);
normalizeRenderable.render();
if (isTimingMode) webgl.timer.markEnd('ColorNormalize.render');
// const normImage = new Uint8Array(width * height * 4);
// texture.attachFramebuffer(framebuffer, 0);
@@ -383,6 +391,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
const gridTransform = Vec4.create(min[0], min[1], min[2], scaleFactor);
const type = isInstanceType ? 'volumeInstance' : 'volume';
if (isTimingMode) webgl.timer.markEnd('calcTextureMeshColorSmoothing');
return { texture, gridDim, gridTexDim: Vec2.create(width, height), gridTransform, type };
}

View File

@@ -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>
*/
@@ -24,6 +24,7 @@ import { Vec2, 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';
export interface TextureMesh {
readonly kind: 'texture-mesh',
@@ -113,6 +114,7 @@ export namespace TextureMesh {
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
};
@@ -125,8 +127,8 @@ export namespace TextureMesh {
createValuesSimple,
updateValues,
updateBoundingSphere,
createRenderableState: BaseGeometry.createRenderableState,
updateRenderableState: BaseGeometry.updateRenderableState,
createRenderableState,
updateRenderableState,
createPositionIterator: () => LocationIterator(1, 1, 1, () => NullLocation)
};
@@ -172,6 +174,7 @@ export namespace TextureMesh {
dFlipSided: ValueCell.create(props.flipSided),
dIgnoreLight: ValueCell.create(props.ignoreLight),
dXrayShaded: ValueCell.create(props.xrayShaded),
dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
uBumpFrequency: ValueCell.create(props.bumpFrequency),
uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
@@ -192,6 +195,7 @@ export namespace TextureMesh {
ValueCell.updateIfChanged(values.dFlipSided, props.flipSided);
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
}
@@ -208,4 +212,16 @@ export namespace TextureMesh {
ValueCell.update(values.uInvariantBoundingSphere, Vec4.fromSphere(values.uInvariantBoundingSphere.ref.value, invariantBoundingSphere));
}
}
function createRenderableState(props: PD.Values<Params>): RenderableState {
const state = BaseGeometry.createRenderableState(props);
updateRenderableState(state, props);
return state;
}
function updateRenderableState(state: RenderableState, props: PD.Values<Params>) {
BaseGeometry.updateRenderableState(state, props);
state.opaque = state.opaque && !props.xrayShaded;
state.writeDepth = state.opaque;
}
}

View File

@@ -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>
*/
@@ -29,6 +29,7 @@ export function applyTransparencyValue(array: Uint8Array, start: number, end: nu
}
export function getTransparencyAverage(array: Uint8Array, count: number): number {
if (count === 0 || array.length < count) return 0;
let sum = 0;
for (let i = 0; i < count; ++i) {
sum += array[i];

View File

@@ -31,7 +31,7 @@ describe('renderer', () => {
expect(ctx.gl.drawingBufferHeight).toBe(32);
expect(ctx.stats.resourceCounts.attribute).toBe(0);
expect(ctx.stats.resourceCounts.texture).toBe(0);
expect(ctx.stats.resourceCounts.texture).toBe(1);
expect(ctx.stats.resourceCounts.vertexArray).toBe(0);
expect(ctx.stats.resourceCounts.program).toBe(0);
expect(ctx.stats.resourceCounts.shader).toBe(0);
@@ -52,7 +52,7 @@ describe('renderer', () => {
scene.add(points);
scene.commit();
expect(ctx.stats.resourceCounts.attribute).toBe(ctx.isWebGL2 ? 4 : 5);
expect(ctx.stats.resourceCounts.texture).toBe(8);
expect(ctx.stats.resourceCounts.texture).toBe(9);
expect(ctx.stats.resourceCounts.vertexArray).toBe(ctx.extensions.vertexArrayObject ? 5 : 0);
expect(ctx.stats.resourceCounts.program).toBe(5);
expect(ctx.stats.resourceCounts.shader).toBe(10);
@@ -60,7 +60,7 @@ describe('renderer', () => {
scene.remove(points);
scene.commit();
expect(ctx.stats.resourceCounts.attribute).toBe(0);
expect(ctx.stats.resourceCounts.texture).toBe(0);
expect(ctx.stats.resourceCounts.texture).toBe(1);
expect(ctx.stats.resourceCounts.vertexArray).toBe(0);
expect(ctx.stats.resourceCounts.program).toBe(5);
expect(ctx.stats.resourceCounts.shader).toBe(10);

View File

@@ -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 David Sehnal <david.sehnal@gmail.com>
*/
@@ -18,8 +18,9 @@ import { createComputeRenderItem } from '../webgl/render-item';
import { createComputeRenderable } from '../renderable';
import { isLittleEndian } from '../../mol-util/is-little-endian';
import { RuntimeContext } from '../../mol-task';
import { isTimingMode } from '../../mol-util/debug';
export function canComputeGrid3dOnGPU(webgl?: WebGLContext) {
export function canComputeGrid3dOnGPU(webgl?: WebGLContext): webgl is WebGLContext {
return !!webgl?.extensions.textureFloat;
}
@@ -159,7 +160,8 @@ export function createGrid3dComputeRenderable<S extends RenderableSchema, P, CS>
const array = new Uint8Array(uWidth * uWidth * 4);
if (spec.cumulative) {
const { gl } = webgl;
const { gl, state } = webgl;
if (isTimingMode) webgl.timer.mark('Grid3dCompute.renderCumulative');
const states = spec.cumulative.states(params);
@@ -167,7 +169,7 @@ export function createGrid3dComputeRenderable<S extends RenderableSchema, P, CS>
tex[1].define(uWidth, uWidth);
resetGl(webgl, uWidth);
gl.clearColor(0, 0, 0, 0);
state.clearColor(0, 0, 0, 0);
tex[0].attachFramebuffer(framebuffer, 'color0');
gl.clear(gl.COLOR_BUFFER_BIT);
@@ -175,12 +177,13 @@ export function createGrid3dComputeRenderable<S extends RenderableSchema, P, CS>
tex[1].attachFramebuffer(framebuffer, 'color0');
gl.clear(gl.COLOR_BUFFER_BIT);
if (spec.cumulative.yieldPeriod) {
if (spec.cumulative.yieldPeriod && !isTimingMode) {
await ctx.update({ message: 'Computing...', isIndeterminate: false, current: 0, max: states.length });
}
const yieldPeriod = Math.max(1, spec.cumulative.yieldPeriod ?? 1 | 0);
if (isTimingMode) webgl.timer.mark('Grid3dCompute.renderBatch');
for (let i = 0; i < states.length; i++) {
ValueCell.update(cells.tCumulativeSum, tex[(i + 1) % 2]);
tex[i % 2].attachFramebuffer(framebuffer, 'color0');
@@ -191,23 +194,31 @@ export function createGrid3dComputeRenderable<S extends RenderableSchema, P, CS>
if (spec.cumulative.yieldPeriod && i !== states.length - 1) {
if (i % yieldPeriod === yieldPeriod - 1) {
webgl.readPixels(0, 0, 1, 1, array);
webgl.waitForGpuCommandsCompleteSync();
if (isTimingMode) webgl.timer.markEnd('Grid3dCompute.renderBatch');
if (isTimingMode) webgl.timer.mark('Grid3dCompute.renderBatch');
}
if (ctx.shouldUpdate) {
if (ctx.shouldUpdate && !isTimingMode) {
await ctx.update({ current: i + 1 });
}
}
}
if (isTimingMode) webgl.timer.markEnd('Grid3dCompute.renderBatch');
if (isTimingMode) webgl.timer.markEnd('Grid3dCompute.renderCumulative');
} else {
if (isTimingMode) webgl.timer.mark('Grid3dCompute.render');
tex[0].define(uWidth, uWidth);
tex[0].attachFramebuffer(framebuffer, 'color0');
framebuffer.bind();
resetGl(webgl, uWidth);
renderable.update();
renderable.render();
if (isTimingMode) webgl.timer.markEnd('Grid3dCompute.render');
}
if (isTimingMode) webgl.timer.mark('Grid3dCompute.readPixels');
webgl.readPixels(0, 0, uWidth, uWidth, array);
if (isTimingMode) webgl.timer.markEnd('Grid3dCompute.readPixels');
return new Float32Array(array.buffer, array.byteOffset, nx * ny * nz);
};
}

View File

@@ -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>
*/
@@ -19,6 +19,7 @@ import { isPowerOfTwo } from '../../../mol-math/misc';
import { quad_vert } from '../../../mol-gl/shader/quad.vert';
import { reduction_frag } from '../../../mol-gl/shader/histogram-pyramid/reduction.frag';
import { isWebGL2 } from '../../webgl/compat';
import { isTimingMode } from '../../../mol-util/debug';
const HistopyramidReductionSchema = {
...QuadSchema,
@@ -120,6 +121,7 @@ export interface HistogramPyramid {
}
export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture, scale: Vec2, gridTexDim: Vec3): HistogramPyramid {
if (isTimingMode) ctx.timer.mark('createHistogramPyramid');
const { gl } = ctx;
const w = inputTexture.getWidth();
const h = inputTexture.getHeight();
@@ -193,6 +195,7 @@ export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture,
}
gl.finish();
if (isTimingMode) ctx.timer.markEnd('createHistogramPyramid');
// printTexture(ctx, pyramidTex, 2)

View File

@@ -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>
*/
@@ -16,6 +16,7 @@ import { QuadSchema, QuadValues } from '../util';
import { quad_vert } from '../../../mol-gl/shader/quad.vert';
import { sum_frag } from '../../../mol-gl/shader/histogram-pyramid/sum.frag';
import { isWebGL2 } from '../../webgl/compat';
import { isTimingMode } from '../../../mol-util/debug';
const HistopyramidSumSchema = {
...QuadSchema,
@@ -66,6 +67,7 @@ const sumBytes = new Uint8Array(4);
const sumInts = new Int32Array(4);
export function getHistopyramidSum(ctx: WebGLContext, pyramidTopTexture: Texture) {
if (isTimingMode) ctx.timer.mark('getHistopyramidSum');
const { gl, resources } = ctx;
const renderable = getHistopyramidSumRenderable(ctx, pyramidTopTexture);
@@ -93,6 +95,7 @@ export function getHistopyramidSum(ctx: WebGLContext, pyramidTopTexture: Texture
ctx.readPixels(0, 0, 1, 1, isWebGL2(gl) ? sumInts : sumBytes);
ctx.unbindFramebuffer();
if (isTimingMode) ctx.timer.markEnd('getHistopyramidSum');
return isWebGL2(gl)
? sumInts[0]

View File

@@ -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>
*/
@@ -16,6 +16,7 @@ import { QuadSchema, QuadValues } from '../util';
import { getTriCount } from './tables';
import { quad_vert } from '../../../mol-gl/shader/quad.vert';
import { activeVoxels_frag } from '../../../mol-gl/shader/marching-cubes/active-voxels.frag';
import { isTimingMode } from '../../../mol-util/debug';
const ActiveVoxelsSchema = {
...QuadSchema,
@@ -83,6 +84,7 @@ function setRenderingDefaults(ctx: WebGLContext) {
}
export function calcActiveVoxels(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, isoValue: number, gridScale: Vec2) {
if (isTimingMode) ctx.timer.mark('calcActiveVoxels');
const { gl, resources } = ctx;
const width = volumeData.getWidth();
const height = volumeData.getHeight();
@@ -115,6 +117,7 @@ export function calcActiveVoxels(ctx: WebGLContext, volumeData: Texture, gridDim
// console.log('at', readTexture(ctx, activeVoxelsTex));
gl.finish();
if (isTimingMode) ctx.timer.markEnd('calcActiveVoxels');
return activeVoxelsTex;
}

View File

@@ -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>
*/
@@ -19,6 +19,7 @@ import { quad_vert } from '../../../mol-gl/shader/quad.vert';
import { isosurface_frag } from '../../../mol-gl/shader/marching-cubes/isosurface.frag';
import { calcActiveVoxels } from './active-voxels';
import { isWebGL2 } from '../../webgl/compat';
import { isTimingMode } from '../../../mol-util/debug';
const IsosurfaceSchema = {
...QuadSchema,
@@ -122,6 +123,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
const { drawBuffers } = ctx.extensions;
if (!drawBuffers) throw new Error('need WebGL draw buffers');
if (isTimingMode) ctx.timer.mark('createIsosurfaceBuffers');
const { gl, resources, extensions } = ctx;
const { pyramidTex, height, levels, scale, count } = histogramPyramid;
const width = pyramidTex.getWidth();
@@ -192,6 +194,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
renderable.render();
gl.finish();
if (isTimingMode) ctx.timer.markEnd('createIsosurfaceBuffers');
return { vertexTexture, groupTexture, normalTexture, vertexCount: count };
}
@@ -208,20 +211,11 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
* Implementation based on http://www.miaumiau.cat/2016/10/stream-compaction-in-webgl/
*/
export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
// console.time('calcActiveVoxels');
if (isTimingMode) ctx.timer.mark('extractIsosurface');
const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale);
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('calcActiveVoxels');
// console.time('createHistogramPyramid');
const compacted = createHistogramPyramid(ctx, activeVoxelsTex, gridTexScale, gridTexDim);
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('createHistogramPyramid');
// console.time('createIsosurfaceBuffers');
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, invert, packedGroup, axisOrder, vertexTexture, groupTexture, normalTexture);
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('createIsosurfaceBuffers');
if (isTimingMode) ctx.timer.markEnd('extractIsosurface');
return gv;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020-2021 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>
*/
@@ -26,6 +26,7 @@ export const CylindersSchema = {
uDoubleSided: UniformSpec('b'),
dIgnoreLight: DefineSpec('boolean'),
dXrayShaded: DefineSpec('boolean'),
dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
uBumpFrequency: UniformSpec('f'),
uBumpAmplitude: UniformSpec('f'),
};

View File

@@ -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>
*/
@@ -22,6 +22,7 @@ export const MeshSchema = {
dFlipSided: DefineSpec('boolean'),
dIgnoreLight: DefineSpec('boolean'),
dXrayShaded: DefineSpec('boolean'),
dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
uBumpFrequency: UniformSpec('f'),
uBumpAmplitude: UniformSpec('f'),
meta: ValueSpec('unknown')

View File

@@ -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>
*/
@@ -153,7 +153,7 @@ export const GlobalUniformSchema = {
uXrayEdgeFalloff: UniformSpec('f'),
uRenderWboit: UniformSpec('b'),
uRenderMask: UniformSpec('i'),
uMarkingDepthTest: UniformSpec('b'),
uMarkingType: UniformSpec('i'),
uPickType: UniformSpec('i'),

View File

@@ -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>
*/
@@ -23,6 +23,7 @@ export const SpheresSchema = {
uDoubleSided: UniformSpec('b'),
dIgnoreLight: DefineSpec('boolean'),
dXrayShaded: DefineSpec('boolean'),
dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
uBumpFrequency: UniformSpec('f'),
uBumpAmplitude: UniformSpec('f'),
};

View File

@@ -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>
*/
@@ -23,6 +23,7 @@ export const TextureMeshSchema = {
dFlipSided: DefineSpec('boolean'),
dIgnoreLight: DefineSpec('boolean'),
dXrayShaded: DefineSpec('boolean'),
dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
uBumpFrequency: UniformSpec('f'),
uBumpAmplitude: UniformSpec('f'),
meta: ValueSpec('unknown')

View File

@@ -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>
*/
@@ -16,9 +16,10 @@ import { GlobalUniformValues } from './renderable/schema';
import { GraphicsRenderVariant } from './webgl/render-item';
import { ParamDefinition as PD } from '../mol-util/param-definition';
import { degToRad } from '../mol-math/misc';
import { createNullTexture, Texture, Textures } from './webgl/texture';
import { Texture, Textures } from './webgl/texture';
import { arrayMapUpsert } from '../mol-util/array';
import { clamp } from '../mol-math/interpolate';
import { isTimingMode } from '../mol-util/debug';
export interface RendererStats {
programCount: number
@@ -53,19 +54,20 @@ interface Renderer {
readonly stats: RendererStats
readonly props: Readonly<RendererProps>
clear: (toBackgroundColor: boolean) => void
clearDepth: () => void
clear: (toBackgroundColor: boolean, ignoreTransparentBackground?: boolean) => void
clearDepth: (packed?: boolean) => void
update: (camera: ICamera) => void
renderPick: (group: Scene.Group, camera: ICamera, variant: GraphicsRenderVariant, depthTexture: Texture | null, pickType: PickType) => void
renderPick: (group: Scene.Group, camera: ICamera, variant: 'pick' | 'depth', depthTexture: Texture | null, pickType: PickType) => void
renderDepth: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderDepthOpaque: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderDepthTransparent: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderMarkingDepth: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderMarkingMask: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderBlended: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderBlendedOpaque: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderBlendedTransparent: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderBlendedVolumeOpaque: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderBlendedVolumeTransparent: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderBlendedVolume: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderWboitOpaque: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
renderWboitTransparent: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
@@ -135,6 +137,18 @@ function getLight(props: RendererProps['light'], light?: Light): Light {
}
namespace Renderer {
const enum Flag {
None = 0,
BlendedFront = 1,
BlendedBack = 2
}
const enum Mask {
All = 0,
Opaque = 1,
Transparent = 2,
}
export function create(ctx: WebGLContext, props: Partial<RendererProps> = {}): Renderer {
const { gl, state, stats } = ctx;
const p = PD.merge(RendererParams, PD.getDefaultValues(RendererParams), props);
@@ -146,9 +160,11 @@ namespace Renderer {
let transparentBackground = false;
const nullDepthTexture = createNullTexture(gl);
const emptyDepthTexture = ctx.resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
emptyDepthTexture.define(1, 1);
emptyDepthTexture.load({ array: new Uint8Array([255, 255, 255, 255]), width: 1, height: 1 });
const sharedTexturesList: Textures = [
['tDepth', nullDepthTexture]
['tDepth', emptyDepthTexture]
];
const view = Mat4();
@@ -191,7 +207,7 @@ namespace Renderer {
uFogFar: ValueCell.create(10000),
uFogColor: ValueCell.create(bgColor),
uRenderWboit: ValueCell.create(false),
uRenderMask: ValueCell.create(0),
uMarkingDepthTest: ValueCell.create(false),
uPickType: ValueCell.create(PickType.None),
uMarkingType: ValueCell.create(MarkingType.None),
@@ -220,7 +236,7 @@ namespace Renderer {
let globalUniformsNeedUpdate = true;
const renderObject = (r: GraphicsRenderable, variant: GraphicsRenderVariant) => {
const renderObject = (r: GraphicsRenderable, variant: GraphicsRenderVariant, flag: Flag) => {
if (r.state.disposed || !r.state.visible || (!r.state.pickable && variant === 'pick')) {
return;
}
@@ -259,6 +275,24 @@ namespace Renderer {
state.disable(gl.DEPTH_TEST);
state.depthMask(false);
}
} else if (flag === Flag.BlendedFront) {
state.enable(gl.CULL_FACE);
if (r.values.dFlipSided?.ref.value) {
state.frontFace(gl.CW);
state.cullFace(gl.FRONT);
} else {
state.frontFace(gl.CCW);
state.cullFace(gl.BACK);
}
} else if (flag === Flag.BlendedBack) {
state.enable(gl.CULL_FACE);
if (r.values.dFlipSided?.ref.value) {
state.frontFace(gl.CW);
state.cullFace(gl.BACK);
} else {
state.frontFace(gl.CCW);
state.cullFace(gl.FRONT);
}
} else {
if (r.values.uDoubleSided) {
if (r.values.uDoubleSided.ref.value || r.values.hasReflection.ref.value) {
@@ -271,14 +305,9 @@ namespace Renderer {
state.disable(gl.CULL_FACE);
}
if (r.values.dFlipSided) {
if (r.values.dFlipSided.ref.value) {
state.frontFace(gl.CW);
state.cullFace(gl.FRONT);
} else {
state.frontFace(gl.CCW);
state.cullFace(gl.BACK);
}
if (r.values.dFlipSided?.ref.value) {
state.frontFace(gl.CW);
state.cullFace(gl.FRONT);
} else {
// webgl default
state.frontFace(gl.CCW);
@@ -308,8 +337,8 @@ namespace Renderer {
ValueCell.updateIfChanged(globalUniforms.uTransparentBackground, transparentBackground);
};
const updateInternal = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null, renderWboit: boolean, markingDepthTest: boolean) => {
arrayMapUpsert(sharedTexturesList, 'tDepth', depthTexture || nullDepthTexture);
const updateInternal = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null, renderMask: Mask, markingDepthTest: boolean) => {
arrayMapUpsert(sharedTexturesList, 'tDepth', depthTexture || emptyDepthTexture);
ValueCell.update(globalUniforms.uModel, group.view);
ValueCell.update(globalUniforms.uModelView, Mat4.mul(modelView, group.view, camera.view));
@@ -317,7 +346,7 @@ namespace Renderer {
ValueCell.update(globalUniforms.uModelViewProjection, Mat4.mul(modelViewProjection, modelView, camera.projection));
ValueCell.update(globalUniforms.uInvModelViewProjection, Mat4.invert(invModelViewProjection, modelViewProjection));
ValueCell.updateIfChanged(globalUniforms.uRenderWboit, renderWboit);
ValueCell.updateIfChanged(globalUniforms.uRenderMask, renderMask);
ValueCell.updateIfChanged(globalUniforms.uMarkingDepthTest, markingDepthTest);
state.enable(gl.SCISSOR_TEST);
@@ -332,40 +361,81 @@ namespace Renderer {
};
const renderPick = (group: Scene.Group, camera: ICamera, variant: GraphicsRenderVariant, depthTexture: Texture | null, pickType: PickType) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderPick');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, false);
updateInternal(group, camera, depthTexture, Mask.All, false);
ValueCell.updateIfChanged(globalUniforms.uPickType, pickType);
const { renderables } = group;
for (let i = 0, il = renderables.length; i < il; ++i) {
if (!renderables[i].state.colorOnly) {
renderObject(renderables[i], variant);
renderObject(renderables[i], variant, Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderPick');
};
const renderDepth = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderDepth');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, false);
updateInternal(group, camera, depthTexture, Mask.All, false);
const { renderables } = group;
for (let i = 0, il = renderables.length; i < il; ++i) {
renderObject(renderables[i], 'depth');
renderObject(renderables[i], 'depth', Flag.None);
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderDepth');
};
const renderMarkingDepth = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
const renderDepthOpaque = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderDepthOpaque');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, false);
updateInternal(group, camera, depthTexture, Mask.Opaque, false);
const { renderables } = group;
for (let i = 0, il = renderables.length; i < il; ++i) {
const r = renderables[i];
if (r.state.opaque && r.values.transparencyAverage.ref.value !== 1 && !r.values.dXrayShaded?.ref.value) {
renderObject(r, 'depth', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderDepthOpaque');
};
const renderDepthTransparent = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderDepthTransparent');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, Mask.Transparent, false);
const { renderables } = group;
for (let i = 0, il = renderables.length; i < il; ++i) {
const r = renderables[i];
if (!r.state.opaque || r.values.transparencyAverage.ref.value > 0 || r.values.dXrayShaded?.ref.value) {
renderObject(r, 'depth', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderDepthTransparent');
};
const renderMarkingDepth = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderMarkingDepth');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, Mask.All, false);
ValueCell.updateIfChanged(globalUniforms.uMarkingType, MarkingType.Depth);
const { renderables } = group;
@@ -373,17 +443,19 @@ namespace Renderer {
const r = renderables[i];
if (r.values.markerAverage.ref.value !== 1) {
renderObject(renderables[i], 'marking');
renderObject(renderables[i], 'marking', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderMarkingDepth');
};
const renderMarkingMask = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderMarkingMask');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, !!depthTexture);
updateInternal(group, camera, depthTexture, Mask.All, !!depthTexture);
ValueCell.updateIfChanged(globalUniforms.uMarkingType, MarkingType.Mask);
const { renderables } = group;
@@ -391,9 +463,10 @@ namespace Renderer {
const r = renderables[i];
if (r.values.markerAverage.ref.value > 0) {
renderObject(renderables[i], 'marking');
renderObject(renderables[i], 'marking', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderMarkingMask');
};
const renderBlended = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
@@ -402,25 +475,30 @@ namespace Renderer {
};
const renderBlendedOpaque = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderBlendedOpaque');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, false);
updateInternal(group, camera, depthTexture, Mask.Opaque, false);
const { renderables } = group;
for (let i = 0, il = renderables.length; i < il; ++i) {
const r = renderables[i];
if (r.state.opaque) {
renderObject(r, 'colorBlended');
renderObject(r, 'colorBlended', Flag.None);
} else if (r.values.uDoubleSided?.ref.value && r.values.dTransparentBackfaces?.ref.value === 'opaque') {
renderObject(r, 'colorBlended', Flag.BlendedBack);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderBlendedOpaque');
};
const renderBlendedTransparent = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderBlendedTransparent');
state.enable(gl.DEPTH_TEST);
updateInternal(group, camera, depthTexture, false, false);
updateInternal(group, camera, depthTexture, Mask.Transparent, false);
const { renderables } = group;
@@ -435,63 +513,52 @@ namespace Renderer {
for (let i = 0, il = renderables.length; i < il; ++i) {
const r = renderables[i];
if (!r.state.opaque && r.state.writeDepth) {
renderObject(r, 'colorBlended');
renderObject(r, 'colorBlended', Flag.None);
}
}
state.depthMask(false);
for (let i = 0, il = renderables.length; i < il; ++i) {
const r = renderables[i];
if (!r.state.opaque && !r.state.writeDepth) {
renderObject(r, 'colorBlended');
if ((!r.state.opaque && !r.state.writeDepth) || r.values.transparencyAverage.ref.value > 0) {
if (r.values.uDoubleSided?.ref.value) {
// render frontfaces and backfaces separately to avoid artefacts
if (r.values.dTransparentBackfaces?.ref.value !== 'opaque') {
renderObject(r, 'colorBlended', Flag.BlendedBack);
}
renderObject(r, 'colorBlended', Flag.BlendedFront);
} else {
renderObject(r, 'colorBlended', Flag.None);
}
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderBlendedTransparent');
};
const renderBlendedVolumeOpaque = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
const renderBlendedVolume = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderBlendedVolume');
state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
state.enable(gl.BLEND);
updateInternal(group, camera, depthTexture, false, false);
updateInternal(group, camera, depthTexture, Mask.Transparent, false);
const { renderables } = group;
for (let i = 0, il = renderables.length; i < il; ++i) {
const r = renderables[i];
// TODO: simplify, handle in renderable.state???
// uAlpha is updated in "render" so we need to recompute it here
const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if (alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && !r.values.dXrayShaded?.ref.value) {
renderObject(r, 'colorBlended');
}
}
};
const renderBlendedVolumeTransparent = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
state.enable(gl.BLEND);
updateInternal(group, camera, depthTexture, false, false);
const { renderables } = group;
for (let i = 0, il = renderables.length; i < il; ++i) {
const r = renderables[i];
// TODO: simplify, handle in renderable.state???
// uAlpha is updated in "render" so we need to recompute it here
const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || r.values.dXrayShaded?.ref.value) {
renderObject(r, 'colorBlended');
if (r.values.dGeometryType.ref.value === 'directVolume') {
renderObject(r, 'colorBlended', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderBlendedVolume');
};
const renderWboitOpaque = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderWboitOpaque');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
updateInternal(group, camera, depthTexture, false, false);
updateInternal(group, camera, depthTexture, Mask.Opaque, false);
const { renderables } = group;
for (let i = 0, il = renderables.length; i < il; ++i) {
@@ -500,14 +567,16 @@ namespace Renderer {
// TODO: simplify, handle in renderable.state???
// uAlpha is updated in "render" so we need to recompute it here
const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if (alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && r.values.dGeometryType.ref.value !== 'directVolume' && r.values.dPointStyle?.ref.value !== 'fuzzy' && !r.values.dXrayShaded?.ref.value) {
renderObject(r, 'colorWboit');
if ((alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && r.values.dGeometryType.ref.value !== 'directVolume' && r.values.dPointStyle?.ref.value !== 'fuzzy' && !r.values.dXrayShaded?.ref.value) || r.values.dTransparentBackfaces?.ref.value === 'opaque') {
renderObject(r, 'colorWboit', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderWboitOpaque');
};
const renderWboitTransparent = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
updateInternal(group, camera, depthTexture, true, false);
if (isTimingMode) ctx.timer.mark('Renderer.renderWboitTransparent');
updateInternal(group, camera, depthTexture, Mask.Transparent, false);
const { renderables } = group;
for (let i = 0, il = renderables.length; i < il; ++i) {
@@ -517,19 +586,20 @@ namespace Renderer {
// uAlpha is updated in "render" so we need to recompute it here
const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || r.values.dGeometryType.ref.value === 'directVolume' || r.values.dPointStyle?.ref.value === 'fuzzy' || !!r.values.uBackgroundColor || r.values.dXrayShaded?.ref.value) {
renderObject(r, 'colorWboit');
renderObject(r, 'colorWboit', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderWboitTransparent');
};
return {
clear: (toBackgroundColor: boolean) => {
clear: (toBackgroundColor: boolean, ignoreTransparentBackground?: boolean) => {
state.enable(gl.SCISSOR_TEST);
state.enable(gl.DEPTH_TEST);
state.colorMask(true, true, true, true);
state.depthMask(true);
if (transparentBackground) {
if (transparentBackground && !ignoreTransparentBackground) {
state.clearColor(0, 0, 0, 0);
} else if (toBackgroundColor) {
state.clearColor(bgColor[0], bgColor[1], bgColor[2], 1);
@@ -538,23 +608,31 @@ namespace Renderer {
}
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
},
clearDepth: () => {
clearDepth: (packed = false) => {
state.enable(gl.SCISSOR_TEST);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
gl.clear(gl.DEPTH_BUFFER_BIT);
if (packed) {
state.colorMask(true, true, true, true);
state.clearColor(1, 1, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
} else {
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
gl.clear(gl.DEPTH_BUFFER_BIT);
}
},
update,
renderPick,
renderDepth,
renderDepthOpaque,
renderDepthTransparent,
renderMarkingDepth,
renderMarkingMask,
renderBlended,
renderBlendedOpaque,
renderBlendedTransparent,
renderBlendedVolumeOpaque,
renderBlendedVolumeTransparent,
renderBlendedVolume,
renderWboitOpaque,
renderWboitTransparent,

View File

@@ -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>
* @author David Sehnal <david.sehnal@gmail.com>
@@ -16,6 +16,7 @@ import { BoundaryHelper } from '../mol-math/geometry/boundary-helper';
import { hash1 } from '../mol-data/util';
import { GraphicsRenderable } from './renderable';
import { GraphicsRenderVariants } from './webgl/render-item';
import { clamp } from '../mol-math/interpolate';
const boundaryHelper = new BoundaryHelper('98');
@@ -79,6 +80,8 @@ interface Scene extends Object3D {
has: (o: GraphicsRenderObject) => boolean
clear: () => void
forEach: (callbackFn: (value: GraphicsRenderable, key: GraphicsRenderObject) => void) => void
readonly markerAverage: number
readonly opacityAverage: number
}
namespace Scene {
@@ -98,6 +101,9 @@ namespace Scene {
let boundingSphereDirty = true;
let boundingSphereVisibleDirty = true;
let markerAverage = 0;
let opacityAverage = 0;
const object3d = Object3D.create();
const { view, position, direction, up } = object3d;
@@ -154,6 +160,7 @@ namespace Scene {
}
renderables.sort(renderableSort);
opacityAverage = calculateOpacityAverage();
return true;
}
@@ -175,12 +182,42 @@ namespace Scene {
const newVisibleHash = computeVisibleHash();
if (newVisibleHash !== visibleHash) {
boundingSphereVisibleDirty = true;
opacityAverage = calculateOpacityAverage();
return true;
} else {
return false;
}
}
function calculateMarkerAverage() {
if (primitives.length === 0) return 0;
let count = 0;
let markerAverage = 0;
for (let i = 0, il = primitives.length; i < il; ++i) {
if (!primitives[i].state.visible) continue;
markerAverage += primitives[i].values.markerAverage.ref.value;
count += 1;
}
return count > 0 ? markerAverage / count : 0;
}
function calculateOpacityAverage() {
if (primitives.length === 0) return 0;
let count = 0;
let opacityAverage = 0;
for (let i = 0, il = primitives.length; i < il; ++i) {
const p = primitives[i];
if (!p.state.visible) continue;
// TODO: simplify, handle in renderable.state???
// uAlpha is updated in "render" so we need to recompute it here
const alpha = clamp(p.values.alpha.ref.value * p.state.alphaFactor, 0, 1);
const xray = p.values.dXrayShaded?.ref.value ? 0.5 : 1;
opacityAverage += (1 - p.values.transparencyAverage.ref.value) * alpha * xray;
count += 1;
}
return count > 0 ? opacityAverage / count : 0;
}
return {
view, position, direction, up,
@@ -206,6 +243,8 @@ namespace Scene {
} else {
syncVisibility();
}
markerAverage = calculateMarkerAverage();
opacityAverage = calculateOpacityAverage();
},
add: (o: GraphicsRenderObject) => commitQueue.add(o),
remove: (o: GraphicsRenderObject) => commitQueue.remove(o),
@@ -219,6 +258,8 @@ namespace Scene {
renderables[i].dispose();
}
renderables.length = 0;
primitives.length = 0;
volumes.length = 0;
renderableMap.clear();
boundingSphereDirty = true;
boundingSphereVisibleDirty = true;
@@ -243,7 +284,13 @@ namespace Scene {
visibleHash = computeVisibleHash();
}
return boundingSphereVisible;
}
},
get markerAverage() {
return markerAverage;
},
get opacityAverage() {
return opacityAverage;
},
};
}
}

View File

@@ -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>
*/
@@ -202,6 +202,7 @@ export const DirectVolumeShaderCode = ShaderCode('direct-volume', directVolume_v
import { image_vert } from './shader/image.vert';
import { image_frag } from './shader/image.frag';
import { assertUnreachable } from '../mol-util/type-helpers';
export const ImageShaderCode = ShaderCode('image', image_vert, image_frag, { drawBuffers: 'optional' }, {}, ignoreDefineUnlit);
//
@@ -228,13 +229,25 @@ function getDefinesCode(defines: ShaderDefines, ignore?: IgnoreDefine) {
} else if (typeof v === 'boolean') {
if (v) lines.push(`#define ${name}`);
} else {
throw new Error('unknown define type');
assertUnreachable(v);
}
}
}
return lines.join('\n') + '\n';
}
function getGlsl100VertPrefix(extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) {
const prefix: string[] = [];
if (shaderExtensions.drawBuffers) {
if (extensions.drawBuffers) {
prefix.push('#define requiredDrawBuffers');
} else if (shaderExtensions.drawBuffers === 'required') {
throw new Error(`required 'GL_EXT_draw_buffers' extension not available`);
}
}
return prefix.join('\n') + '\n';
}
function getGlsl100FragPrefix(extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) {
const prefix: string[] = [
'#extension GL_OES_standard_derivatives : enable'
@@ -270,7 +283,7 @@ function getGlsl100FragPrefix(extensions: WebGLExtensions, shaderExtensions: Sha
return prefix.join('\n') + '\n';
}
const glsl300VertPrefix = `#version 300 es
const glsl300VertPrefixCommon = `
#define attribute in
#define varying out
#define texture2D texture
@@ -287,24 +300,42 @@ const glsl300FragPrefixCommon = `
#define depthTextureSupport
`;
function getGlsl300VertPrefix(extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) {
const prefix = [
'#version 300 es',
];
if (shaderExtensions.drawBuffers) {
if (extensions.drawBuffers) {
prefix.push('#define requiredDrawBuffers');
}
}
prefix.push(glsl300VertPrefixCommon);
return prefix.join('\n') + '\n';
}
function getGlsl300FragPrefix(gl: WebGL2RenderingContext, extensions: WebGLExtensions, shaderExtensions: ShaderExtensions, outTypes: FragOutTypes) {
const prefix = [
'#version 300 es',
`layout(location = 0) out highp ${outTypes[0] || 'vec4'} out_FragData0;`
];
if (shaderExtensions.fragDepth) {
prefix.push('#define enabledFragDepth');
if (extensions.fragDepth) {
prefix.push('#define enabledFragDepth');
}
}
if (shaderExtensions.drawBuffers) {
prefix.push('#define requiredDrawBuffers');
const maxDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS) as number;
for (let i = 1, il = maxDrawBuffers; i < il; ++i) {
prefix.push(`layout(location = ${i}) out highp ${outTypes[i] || 'vec4'} out_FragData${i};`);
if (extensions.drawBuffers) {
prefix.push('#define requiredDrawBuffers');
const maxDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS) as number;
for (let i = 1, il = maxDrawBuffers; i < il; ++i) {
prefix.push(`layout(location = ${i}) out highp ${outTypes[i] || 'vec4'} out_FragData${i};`);
}
}
}
if (shaderExtensions.shaderTextureLod) {
prefix.push('#define enabledShaderTextureLod');
if (extensions.shaderTextureLod) {
prefix.push('#define enabledShaderTextureLod');
}
}
prefix.push(glsl300FragPrefixCommon);
return prefix.join('\n') + '\n';
@@ -317,7 +348,9 @@ function transformGlsl300Frag(frag: string) {
export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtensions, defines: ShaderDefines, shaders: ShaderCode): ShaderCode {
const vertHeader = getDefinesCode(defines, shaders.ignoreDefine);
const fragHeader = getDefinesCode(defines, shaders.ignoreDefine);
const vertPrefix = isWebGL2(gl) ? glsl300VertPrefix : '';
const vertPrefix = isWebGL2(gl)
? getGlsl300VertPrefix(extensions, shaders.extensions)
: getGlsl100VertPrefix(extensions, shaders.extensions);
const fragPrefix = isWebGL2(gl)
? getGlsl300FragPrefix(gl, extensions, shaders.extensions, shaders.outTypes)
: getGlsl100FragPrefix(extensions, shaders.extensions);

View File

@@ -5,5 +5,9 @@ if (interior) {
} else {
gl_FragColor.rgb *= 1.0 - uInteriorDarkening;
}
#ifdef dTransparentBackfaces_opaque
gl_FragColor.a = 1.0;
#endif
}
`;

View File

@@ -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 Alexander Rose <alexander.rose@weirdbyte.de>
*
@@ -8,61 +8,65 @@
*/
export const apply_light_color = `
#ifdef bumpEnabled
if (uBumpFrequency > 0.0 && uBumpAmplitude > 0.0) {
vec3 bumpNormal = perturbNormal(-vViewPosition, normal, fbm(vModelPosition * uBumpFrequency), (uBumpAmplitude * bumpiness) / uBumpFrequency);
#ifdef enabledFragDepth
if (!isNaN(bumpNormal.x) && !isNaN(bumpNormal.y) && !isNaN(bumpNormal.z)) {
normal = bumpNormal;
}
#else
normal = bumpNormal;
#endif
}
#endif
vec4 color = material;
ReflectedLight reflectedLight = ReflectedLight(vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
PhysicalMaterial physicalMaterial;
physicalMaterial.diffuseColor = color.rgb * (1.0 - metalness);
#ifdef enabledFragDepth
physicalMaterial.roughness = min(max(roughness, 0.0525), 1.0);
#ifdef dIgnoreLight
gl_FragColor = material;
#else
vec3 dxy = max(abs(dFdx(normal)), abs(dFdy(normal)));
float geometryRoughness = max(max(dxy.x, dxy.y), dxy.z);
physicalMaterial.roughness = min(max(roughness, 0.0525) + geometryRoughness, 1.0);
#ifdef bumpEnabled
if (uBumpFrequency > 0.0 && uBumpAmplitude > 0.0) {
vec3 bumpNormal = perturbNormal(-vViewPosition, normal, fbm(vModelPosition * uBumpFrequency), (uBumpAmplitude * bumpiness) / uBumpFrequency);
#ifdef enabledFragDepth
if (!isNaN(bumpNormal.x) && !isNaN(bumpNormal.y) && !isNaN(bumpNormal.z)) {
normal = bumpNormal;
}
#else
normal = bumpNormal;
#endif
}
#endif
vec4 color = material;
ReflectedLight reflectedLight = ReflectedLight(vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
PhysicalMaterial physicalMaterial;
physicalMaterial.diffuseColor = color.rgb * (1.0 - metalness);
#ifdef enabledFragDepth
physicalMaterial.roughness = min(max(roughness, 0.0525), 1.0);
#else
vec3 dxy = max(abs(dFdx(normal)), abs(dFdy(normal)));
float geometryRoughness = max(max(dxy.x, dxy.y), dxy.z);
physicalMaterial.roughness = min(max(roughness, 0.0525) + geometryRoughness, 1.0);
#endif
physicalMaterial.specularColor = mix(vec3(0.04), color.rgb, metalness);
physicalMaterial.specularF90 = 1.0;
GeometricContext geometry;
geometry.position = -vViewPosition;
geometry.normal = normal;
geometry.viewDir = normalize(vViewPosition);
IncidentLight directLight;
#pragma unroll_loop_start
for (int i = 0; i < dLightCount; ++i) {
directLight.direction = uLightDirection[i];
directLight.color = uLightColor[i] * PI; // * PI for punctual light
RE_Direct_Physical(directLight, geometry, physicalMaterial, reflectedLight);
}
#pragma unroll_loop_end
vec3 irradiance = uAmbientColor * PI; // * PI for punctual light
RE_IndirectDiffuse_Physical(irradiance, geometry, physicalMaterial, reflectedLight);
// indirect specular only metals
vec3 radiance = uAmbientColor * metalness;
vec3 iblIrradiance = uAmbientColor * metalness;
vec3 clearcoatRadiance = vec3(0.0);
RE_IndirectSpecular_Physical(radiance, iblIrradiance, clearcoatRadiance, geometry, physicalMaterial, reflectedLight);
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular;
gl_FragColor = vec4(outgoingLight, color.a);
#endif
physicalMaterial.specularColor = mix(vec3(0.04), color.rgb, metalness);
physicalMaterial.specularF90 = 1.0;
GeometricContext geometry;
geometry.position = -vViewPosition;
geometry.normal = normal;
geometry.viewDir = normalize(vViewPosition);
IncidentLight directLight;
#pragma unroll_loop_start
for (int i = 0; i < dLightCount; ++i) {
directLight.direction = uLightDirection[i];
directLight.color = uLightColor[i] * PI; // * PI for punctual light
RE_Direct_Physical(directLight, geometry, physicalMaterial, reflectedLight);
}
#pragma unroll_loop_end
vec3 irradiance = uAmbientColor * PI; // * PI for punctual light
RE_IndirectDiffuse_Physical(irradiance, geometry, physicalMaterial, reflectedLight);
// indirect specular only metals
vec3 radiance = uAmbientColor * metalness;
vec3 iblIrradiance = uAmbientColor * metalness;
vec3 clearcoatRadiance = vec3(0.0);
RE_IndirectSpecular_Physical(radiance, iblIrradiance, clearcoatRadiance, geometry, physicalMaterial, reflectedLight);
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular;
gl_FragColor = vec4(outgoingLight, color.a);
#ifdef dXrayShaded
gl_FragColor.a *= 1.0 - pow(abs(dot(normal, vec3(0.0, 0.0, 1.0))), uXrayEdgeFalloff);

View File

@@ -56,13 +56,19 @@ export const assign_color_varying = `
vSubstance.rgb = mix(vec3(uMetalness, uRoughness, uBumpiness), vSubstance.rgb, vSubstance.a);
#endif
#elif defined(dRenderVariant_pick)
if (uPickType == 1) {
vColor = vec4(packIntToRGB(float(uObjectId)), 1.0);
} else if (uPickType == 2) {
vColor = vec4(packIntToRGB(aInstance), 1.0);
} else {
vColor = vec4(packIntToRGB(group), 1.0);
}
#ifdef requiredDrawBuffers
vObject = vec4(packIntToRGB(float(uObjectId)), 1.0);
vInstance = vec4(packIntToRGB(aInstance), 1.0);
vGroup = vec4(packIntToRGB(group), 1.0);
#else
if (uPickType == 1) {
vColor = vec4(packIntToRGB(float(uObjectId)), 1.0);
} else if (uPickType == 2) {
vColor = vec4(packIntToRGB(aInstance), 1.0);
} else {
vColor = vec4(packIntToRGB(group), 1.0);
}
#endif
#endif
#ifdef dTransparency

View File

@@ -28,14 +28,35 @@ export const assign_material_color = `
roughness = mix(roughness, vSubstance.g, vSubstance.a);
bumpiness = mix(bumpiness, vSubstance.b, vSubstance.a);
#endif
#elif defined(dRenderVariant_pick)
vec4 material = vColor;
#elif defined(dRenderVariant_depth)
#ifdef enabledFragDepth
vec4 material = packDepthToRGBA(gl_FragDepthEXT);
if (fragmentDepth > getDepth(gl_FragCoord.xy / uDrawingBufferSize)) {
discard;
}
#ifndef dXrayShaded
#if defined(dTransparency)
float dta = 1.0 - vTransparency;
if (vTransparency < 0.2) dta = 1.0; // hard cutoff looks better
if (uRenderMask == MaskTransparent && uAlpha * dta == 1.0) {
discard;
} else if (uRenderMask == MaskOpaque && uAlpha * dta < 1.0) {
discard;
}
#else
if (uRenderMask == MaskTransparent && uAlpha == 1.0) {
discard;
} else if (uRenderMask == MaskOpaque && uAlpha < 1.0) {
discard;
}
#endif
#else
vec4 material = packDepthToRGBA(gl_FragCoord.z);
if (uRenderMask == MaskOpaque) {
discard;
}
#endif
vec4 material = packDepthToRGBA(fragmentDepth);
#elif defined(dRenderVariant_marking)
vec4 material;
if(uMarkingType == 1) {
@@ -51,7 +72,7 @@ export const assign_material_color = `
discard;
float depthTest = 1.0;
if (uMarkingDepthTest) {
depthTest = (fragmentDepth >= getDepth(gl_FragCoord.xy / uDrawingBufferSize)) ? 1.0 : 0.0;
depthTest = (fragmentDepth >= getDepthPacked(gl_FragCoord.xy / uDrawingBufferSize)) ? 1.0 : 0.0;
}
bool isHighlight = intMod(marker, 2.0) > 0.1;
float viewZ = depthToViewZ(uIsOrtho, fragmentDepth, uNear, uFar);
@@ -62,47 +83,41 @@ export const assign_material_color = `
}
#endif
// apply screendoor transparency
#if defined(dTransparency)
// apply per-group transparency
#if defined(dTransparency) && (defined(dRenderVariant_pick) || defined(dRenderVariant_color))
float ta = 1.0 - vTransparency;
#if defined(dRenderVariant_colorWboit)
if (vTransparency < 0.2) ta = 1.0; // hard cutoff looks better with wboit
#endif
if (vTransparency < 0.2) ta = 1.0; // hard cutoff looks better
#if defined(dRenderVariant_pick)
if (ta < uPickingAlphaThreshold)
discard; // ignore so the element below can be picked
#else
#elif defined(dRenderVariant_color)
material.a *= ta;
#if defined(dRenderVariant_colorBlended)
float at = 0.0;
// shift by view-offset during multi-sample rendering to allow for blending
vec2 coord = gl_FragCoord.xy + uViewOffset * 0.25;
const mat4 thresholdMatrix = mat4(
1.0 / 17.0, 9.0 / 17.0, 3.0 / 17.0, 11.0 / 17.0,
13.0 / 17.0, 5.0 / 17.0, 15.0 / 17.0, 7.0 / 17.0,
4.0 / 17.0, 12.0 / 17.0, 2.0 / 17.0, 10.0 / 17.0,
16.0 / 17.0, 8.0 / 17.0, 14.0 / 17.0, 6.0 / 17.0
);
int ci = int(intMod(coord.x, 4.0));
int ri = int(intMod(coord.y, 4.0));
#if __VERSION__ == 100
vec4 i = vec4(float(ci * 4 + ri));
vec4 v = thresholdMatrix[0] * vec4(equal(i, vec4(0.0, 1.0, 2.0, 3.0))) +
thresholdMatrix[1] * vec4(equal(i, vec4(4.0, 5.0, 6.0, 7.0))) +
thresholdMatrix[2] * vec4(equal(i, vec4(8.0, 9.0, 10.0, 11.0))) +
thresholdMatrix[3] * vec4(equal(i, vec4(12.0, 13.0, 14.0, 15.0)));
at = v.x + v.y + v.z + v.w;
#else
at = thresholdMatrix[ci][ri];
#if defined(dTransparentBackfaces_off)
if ((uRenderMask == MaskOpaque && material.a < 1.0) ||
(uRenderMask == MaskTransparent && material.a == 1.0) ||
(interior && material.a < 1.0)
) {
discard;
}
#elif defined(dTransparentBackfaces_on)
if ((uRenderMask == MaskOpaque && material.a < 1.0) ||
(uRenderMask == MaskTransparent && material.a == 1.0)
) {
discard;
}
#elif defined(dTransparentBackfaces_opaque)
if (interior) {
material.a = 1.0;
} else if (
(uRenderMask == MaskOpaque && material.a < 1.0) ||
(uRenderMask == MaskTransparent && material.a == 1.0)
) {
discard;
}
#endif
if (ta < 0.99 && (ta < 0.01 || ta < at)) {
discard;
}
#elif defined(dRenderVariant_colorWboit)
material.a *= ta;
#endif
#endif
#endif

View File

@@ -2,6 +2,12 @@ export const check_picking_alpha = `
float viewZ = depthToViewZ(uIsOrtho, fragmentDepth, uNear, uFar);
float fogFactor = smoothstep(uFogNear, uFogFar, abs(viewZ));
float alpha = (1.0 - fogFactor) * uAlpha;
if (uAlpha < uPickingAlphaThreshold || alpha < 0.1)
discard; // ignore so the element below can be picked
// if not opaque enough ignore so the element below can be picked
if (uAlpha < uPickingAlphaThreshold || alpha < 0.1) {
#ifdef dTransparentBackfaces_opaque
if (!interior) discard;
#else
discard;
#endif
}
`;

View File

@@ -28,9 +28,21 @@ uniform float uBumpiness;
#endif
#elif defined(dRenderVariant_pick)
#if __VERSION__ == 100
varying vec4 vColor;
#ifdef requiredDrawBuffers
varying vec4 vObject;
varying vec4 vInstance;
varying vec4 vGroup;
#else
varying vec4 vColor;
#endif
#else
flat in vec4 vColor;
#ifdef requiredDrawBuffers
flat in vec4 vObject;
flat in vec4 vInstance;
flat in vec4 vGroup;
#else
flat in vec4 vColor;
#endif
#endif
#endif

View File

@@ -19,6 +19,8 @@ uniform float uBumpiness;
uniform vec3 uColorGridDim;
uniform vec4 uColorGridTransform;
uniform sampler2D tColorGrid;
#elif defined(dColorType_direct)
varying vec4 vColor;
#endif
#ifdef dUsePalette
@@ -54,9 +56,21 @@ uniform float uBumpiness;
#endif
#elif defined(dRenderVariant_pick)
#if __VERSION__ == 100
varying vec4 vColor;
#ifdef requiredDrawBuffers
varying vec4 vObject;
varying vec4 vInstance;
varying vec4 vGroup;
#else
varying vec4 vColor;
#endif
#else
flat out vec4 vColor;
#ifdef requiredDrawBuffers
flat out vec4 vObject;
flat out vec4 vInstance;
flat out vec4 vGroup;
#else
flat out vec4 vColor;
#endif
#endif
#endif

View File

@@ -64,17 +64,24 @@ uniform float uXrayEdgeFalloff;
uniform mat4 uProjection;
uniform bool uRenderWboit;
uniform int uRenderMask;
uniform bool uMarkingDepthTest;
uniform sampler2D tDepth;
uniform vec2 uDrawingBufferSize;
float getDepth(const in vec2 coords) {
// always packed due to merged depth from primitives and volumes
float getDepthPacked(const in vec2 coords) {
return unpackRGBAToDepth(texture2D(tDepth, coords));
}
float getDepth(const in vec2 coords) {
#ifdef depthTextureSupport
return texture2D(tDepth, coords).r;
#else
return unpackRGBAToDepth(texture2D(tDepth, coords));
#endif
}
float calcDepth(const in vec3 pos) {
vec2 clipZW = pos.z * uProjection[2].zw + uProjection[3].zw;
return 0.5 + 0.5 * clipZW.x / clipZW.y;

View File

@@ -17,6 +17,10 @@ export const common = `
#define dColorType_varying
#endif
#define MaskAll 0
#define MaskOpaque 1
#define MaskTransparent 2
//
#define PI 3.14159265

View File

@@ -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>
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
@@ -7,13 +7,16 @@
export const wboit_write = `
#if defined(dRenderVariant_colorWboit)
if (!uRenderWboit) {
if (uRenderMask == MaskOpaque) {
if (preFogAlpha < 1.0) {
discard;
}
} else if (uRenderWboit) {
} else if (uRenderMask == MaskTransparent) {
// the 'fragmentDepth > 0.99' check is to handle precision issues with packed depth
if (preFogAlpha != 1.0 && !interior && (fragmentDepth < getDepth(gl_FragCoord.xy / uDrawingBufferSize) || fragmentDepth > 0.99)) {
if (preFogAlpha != 1.0 && (fragmentDepth < getDepth(gl_FragCoord.xy / uDrawingBufferSize) || fragmentDepth > 0.99)) {
#ifdef dTransparentBackfaces_off
if (interior) discard;
#endif
float alpha = gl_FragColor.a;
float wboitWeight = alpha * clamp(pow(1.0 - fragmentDepth, 2.0), 0.01, 1.0);
gl_FragColor = vec4(gl_FragColor.rgb * alpha * wboitWeight, alpha);

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020-2021 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>
*/
@@ -121,19 +121,22 @@ void main() {
#if defined(dRenderVariant_pick)
#include check_picking_alpha
gl_FragColor = material;
#ifdef requiredDrawBuffers
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
#else
gl_FragColor = vColor;
#endif
#elif defined(dRenderVariant_depth)
gl_FragColor = material;
#elif defined(dRenderVariant_marking)
gl_FragColor = material;
#elif defined(dRenderVariant_color)
#ifdef dIgnoreLight
gl_FragColor = material;
#else
mat3 normalMatrix = transpose3(inverse3(mat3(uView)));
vec3 normal = normalize(normalMatrix * -normalize(intersection.yzw));
#include apply_light_color
#endif
mat3 normalMatrix = transpose3(inverse3(mat3(uView)));
vec3 normal = normalize(normalMatrix * -normalize(intersection.yzw));
#include apply_light_color
#include apply_interior_color
#include apply_marker_color

View File

@@ -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 Alexander Rose <alexander.rose@weirdbyte.de>
* @author Michael Krone <michael.krone@uni-tuebingen.de>
@@ -68,16 +68,10 @@ uniform float uFogFar;
uniform vec3 uFogColor;
uniform float uAlpha;
uniform float uPickingAlphaThreshold;
uniform bool uTransparentBackground;
uniform float uXrayEdgeFalloff;
uniform float uInteriorDarkening;
uniform bool uInteriorColorFlag;
uniform vec3 uInteriorColor;
uniform bool uRenderWboit;
uniform bool uDoubleSided;
uniform int uRenderMask;
uniform float uNear;
uniform float uFar;
@@ -146,12 +140,7 @@ float transferFunction(float value) {
float getDepth(const in vec2 coords) {
#ifdef depthTextureSupport
if (!uRenderWboit) {
// in case of opaque volumes (and depth texture support)
return texture2D(tDepth, coords).r;
} else {
return unpackRGBAToDepth(texture2D(tDepth, coords));
}
return texture2D(tDepth, coords).r;
#else
return unpackRGBAToDepth(texture2D(tDepth, coords));
#endif
@@ -166,9 +155,7 @@ vec3 v3m4(vec3 p, mat4 m) {
float preFogAlphaBlended = 0.0;
vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) {
#if !defined(dIgnoreLight)
mat3 normalMatrix = transpose3(inverse3(mat3(uModelView * vTransform)));
#endif
mat3 normalMatrix = transpose3(inverse3(mat3(uModelView * vTransform)));
mat4 cartnToUnit = uCartnToUnit * inverse4(vTransform);
#if defined(dClipVariant_pixel) && dClipObjectCount != 0
mat4 modelTransform = uModel * vTransform * uTransform;
@@ -363,7 +350,6 @@ void main() {
float fragmentDepth = calcDepth((uModelView * vec4(start, 1.0)).xyz);
float preFogAlpha = clamp(preFogAlphaBlended, 0.0, 1.0);
bool interior = false;
#include wboit_write
}
`;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020-2021 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>
*/
@@ -99,18 +99,25 @@ void main() {
if (imageData.a > 0.9) imageData.a = 1.0;
float fragmentDepth = gl_FragCoord.z;
bool interior = false;
#if defined(dRenderVariant_pick)
if (imageData.a < 0.3)
discard;
if (uPickType == 1) {
#ifdef requiredDrawBuffers
gl_FragColor = vec4(packIntToRGB(float(uObjectId)), 1.0);
} else if (uPickType == 2) {
gl_FragColor = vec4(packIntToRGB(vInstance), 1.0);
} else {
gl_FragColor = vec4(texture2D(tGroupTex, vUv).rgb, 1.0);
}
gl_FragData[1] = vec4(packIntToRGB(vInstance), 1.0);
gl_FragData[2] = vec4(texture2D(tGroupTex, vUv).rgb, 1.0);
gl_FragData[3] = packDepthToRGBA(gl_FragCoord.z);
#else
gl_FragColor = vColor;
if (uPickType == 1) {
gl_FragColor = vec4(packIntToRGB(float(uObjectId)), 1.0);
} else if (uPickType == 2) {
gl_FragColor = vec4(packIntToRGB(vInstance), 1.0);
} else {
gl_FragColor = vec4(texture2D(tGroupTex, vUv).rgb, 1.0);
}
#endif
#elif defined(dRenderVariant_depth)
if (imageData.a < 0.05)
discard;
@@ -131,7 +138,7 @@ void main() {
discard;
float depthTest = 1.0;
if (uMarkingDepthTest) {
depthTest = (fragmentDepth >= getDepth(gl_FragCoord.xy / uDrawingBufferSize)) ? 1.0 : 0.0;
depthTest = (fragmentDepth >= getDepthPacked(gl_FragCoord.xy / uDrawingBufferSize)) ? 1.0 : 0.0;
}
bool isHighlight = intMod(marker, 2.0) > 0.1;
gl_FragColor = vec4(0.0, depthTest, isHighlight ? 1.0 : 0.0, 1.0);

View File

@@ -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>
*/
@@ -16,13 +16,19 @@ precision highp int;
void main(){
#include clip_pixel
bool interior = false;
float fragmentDepth = gl_FragCoord.z;
#include assign_material_color
#if defined(dRenderVariant_pick)
#include check_picking_alpha
gl_FragColor = material;
#ifdef requiredDrawBuffers
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
#else
gl_FragColor = vColor;
#endif
#elif defined(dRenderVariant_depth)
gl_FragColor = material;
#elif defined(dRenderVariant_marking)

View File

@@ -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>
*/
@@ -37,23 +37,26 @@ void main() {
#if defined(dRenderVariant_pick)
#include check_picking_alpha
gl_FragColor = material;
#ifdef requiredDrawBuffers
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
#else
gl_FragColor = vColor;
#endif
#elif defined(dRenderVariant_depth)
gl_FragColor = material;
#elif defined(dRenderVariant_marking)
gl_FragColor = material;
#elif defined(dRenderVariant_color)
#ifdef dIgnoreLight
gl_FragColor = material;
#if defined(dFlatShaded)
vec3 normal = -faceNormal;
#else
#if defined(dFlatShaded)
vec3 normal = -faceNormal;
#else
vec3 normal = -normalize(vNormal);
if (uDoubleSided) normal *= float(frontFacing) * 2.0 - 1.0;
#endif
#include apply_light_color
vec3 normal = -normalize(vNormal);
if (uDoubleSided) normal *= float(frontFacing) * 2.0 - 1.0;
#endif
#include apply_light_color
#include apply_interior_color
#include apply_marker_color

View File

@@ -1,7 +1,8 @@
/**
* 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 Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
@author Alexander Rose <alexander.rose@weirdbyte.de>
*/
export const outlines_frag = `
@@ -9,7 +10,8 @@ precision highp float;
precision highp int;
precision highp sampler2D;
uniform sampler2D tDepth;
uniform sampler2D tDepthOpaque;
uniform sampler2D tDepthTransparent;
uniform vec2 uTexSize;
uniform float uNear;
@@ -27,8 +29,16 @@ float getViewZ(const in float depth) {
#endif
}
float getDepth(const in vec2 coords) {
return unpackRGBAToDepth(texture2D(tDepth, coords));
float getDepthOpaque(const in vec2 coords) {
#ifdef depthTextureSupport
return texture2D(tDepthOpaque, coords).r;
#else
return unpackRGBAToDepth(texture2D(tDepthOpaque, coords));
#endif
}
float getDepthTransparent(const in vec2 coords) {
return unpackRGBAToDepth(texture2D(tDepthTransparent, coords));
}
bool isBackground(const in float depth) {
@@ -41,8 +51,11 @@ void main(void) {
vec2 coords = gl_FragCoord.xy / uTexSize;
vec2 invTexSize = 1.0 / uTexSize;
float selfDepth = getDepth(coords);
float selfViewZ = isBackground(selfDepth) ? backgroundViewZ : getViewZ(getDepth(coords));
float selfDepthOpaque = getDepthOpaque(coords);
float selfViewZOpaque = isBackground(selfDepthOpaque) ? backgroundViewZ : getViewZ(selfDepthOpaque);
float selfDepthTransparent = getDepthTransparent(coords);
float selfViewZTransparent = isBackground(selfDepthTransparent) ? backgroundViewZ : getViewZ(selfDepthTransparent);
float outline = 1.0;
float bestDepth = 1.0;
@@ -50,12 +63,22 @@ void main(void) {
for (int y = -1; y <= 1; y++) {
for (int x = -1; x <= 1; x++) {
vec2 sampleCoords = coords + vec2(float(x), float(y)) * invTexSize;
float sampleDepth = getDepth(sampleCoords);
float sampleViewZ = isBackground(sampleDepth) ? backgroundViewZ : getViewZ(sampleDepth);
if (abs(selfViewZ - sampleViewZ) > uMaxPossibleViewZDiff && selfDepth > sampleDepth && sampleDepth <= bestDepth) {
float sampleDepthOpaque = getDepthOpaque(sampleCoords);
float sampleDepthTransparent = getDepthTransparent(sampleCoords);
float sampleViewZOpaque = isBackground(sampleDepthOpaque) ? backgroundViewZ : getViewZ(sampleDepthOpaque);
if (abs(selfViewZOpaque - sampleViewZOpaque) > uMaxPossibleViewZDiff && selfDepthOpaque > sampleDepthOpaque && sampleDepthOpaque <= bestDepth) {
outline = 0.0;
bestDepth = sampleDepth;
bestDepth = sampleDepthOpaque;
}
if (sampleDepthTransparent < sampleDepthOpaque) {
float sampleViewZTransparent = isBackground(sampleDepthTransparent) ? backgroundViewZ : getViewZ(sampleDepthTransparent);
if (abs(selfViewZTransparent - sampleViewZTransparent) > uMaxPossibleViewZDiff && selfDepthTransparent > sampleDepthTransparent && sampleDepthTransparent <= bestDepth) {
outline = 0.0;
bestDepth = sampleDepthTransparent;
}
}
}
}

View File

@@ -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>
*/
@@ -20,7 +20,6 @@ void main(){
#include clip_pixel
float fragmentDepth = gl_FragCoord.z;
bool interior = false;
#include assign_material_color
#if defined(dPointStyle_circle)
@@ -34,7 +33,14 @@ void main(){
#if defined(dRenderVariant_pick)
#include check_picking_alpha
gl_FragColor = material;
#ifdef requiredDrawBuffers
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
#else
gl_FragColor = vColor;
#endif
#elif defined(dRenderVariant_depth)
gl_FragColor = material;
#elif defined(dRenderVariant_marking)

View File

@@ -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>
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
@@ -12,7 +12,8 @@ precision highp sampler2D;
uniform sampler2D tSsaoDepth;
uniform sampler2D tColor;
uniform sampler2D tDepth;
uniform sampler2D tDepthOpaque;
uniform sampler2D tDepthTransparent;
uniform sampler2D tOutlines;
uniform vec2 uTexSize;
@@ -24,8 +25,7 @@ uniform vec3 uFogColor;
uniform vec3 uOutlineColor;
uniform bool uTransparentBackground;
uniform float uOcclusionBias;
uniform float uOcclusionRadius;
uniform vec2 uOcclusionOffset;
uniform float uMaxPossibleViewZDiff;
@@ -41,19 +41,27 @@ float getViewZ(const in float depth) {
#endif
}
float getDepth(const in vec2 coords) {
return unpackRGBAToDepth(texture2D(tDepth, coords));
float getDepthOpaque(const in vec2 coords) {
#ifdef depthTextureSupport
return texture2D(tDepthOpaque, coords).r;
#else
return unpackRGBAToDepth(texture2D(tDepthOpaque, coords));
#endif
}
float getDepthTransparent(const in vec2 coords) {
return unpackRGBAToDepth(texture2D(tDepthTransparent, coords));
}
bool isBackground(const in float depth) {
return depth == 1.0;
}
float getOutline(const in vec2 coords, out float closestTexel) {
float getOutline(const in vec2 coords, const in float opaqueDepth, out float closestTexel) {
float backgroundViewZ = uFar + 3.0 * uMaxPossibleViewZDiff;
vec2 invTexSize = 1.0 / uTexSize;
float selfDepth = getDepth(coords);
float selfDepth = min(opaqueDepth, getDepthTransparent(coords));
float selfViewZ = isBackground(selfDepth) ? backgroundViewZ : getViewZ(selfDepth);
float outline = 1.0;
@@ -69,14 +77,15 @@ float getOutline(const in vec2 coords, out float closestTexel) {
vec4 sampleOutlineCombined = texture2D(tOutlines, sampleCoords);
float sampleOutline = sampleOutlineCombined.r;
float sampleOutlineDepth = unpackRGToUnitInterval(sampleOutlineCombined.gb);
float sampleOutlineViewZ = isBackground(sampleOutlineDepth) ? backgroundViewZ : getViewZ(sampleOutlineDepth);
if (sampleOutline == 0.0 && sampleOutlineDepth < closestTexel && abs(selfViewZ - sampleOutlineDepth) > uMaxPossibleViewZDiff) {
if (sampleOutline == 0.0 && sampleOutlineDepth < closestTexel && abs(selfViewZ - sampleOutlineViewZ) > uMaxPossibleViewZDiff) {
outline = 0.0;
closestTexel = sampleOutlineDepth;
}
}
}
return outline;
return closestTexel < opaqueDepth ? outline : 1.0;
}
float getSsao(vec2 coords) {
@@ -96,13 +105,13 @@ void main(void) {
float viewDist;
float fogFactor;
float opaqueDepth = getDepthOpaque(coords);
#ifdef dOcclusionEnable
float depth = getDepth(coords);
if (!isBackground(depth)) {
viewDist = abs(getViewZ(depth));
if (!isBackground(opaqueDepth)) {
viewDist = abs(getViewZ(opaqueDepth));
fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
float occlusionFactor = getSsao(coords);
float occlusionFactor = getSsao(coords + uOcclusionOffset);
if (!uTransparentBackground) {
color.rgb = mix(mix(occlusionColor, uFogColor, fogFactor), color.rgb, occlusionFactor);
} else {
@@ -114,16 +123,15 @@ void main(void) {
// outline needs to be handled after occlusion to keep them clean
#ifdef dOutlineEnable
float closestTexel;
float outline = getOutline(coords, closestTexel);
float outline = getOutline(coords, opaqueDepth, closestTexel);
if (outline == 0.0) {
color.rgb = mix(uOutlineColor, color.rgb, outline);
viewDist = abs(getViewZ(closestTexel));
fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
if (!uTransparentBackground) {
color.rgb = mix(color.rgb, uFogColor, fogFactor);
color.rgb = mix(uOutlineColor, uFogColor, fogFactor);
} else {
color.a = 1.0 - fogFactor;
color.rgb = mix(uOutlineColor, color.rgb, fogFactor);
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More