diff --git a/CHANGELOG.md b/CHANGELOG.md index d53ee991029192f9a794aa57824c2eee4fa43560..157d61aa382d346e011f12f3495d62b0b3966121 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ Note that since we don't clearly distinguish between a public and private interf ## [Unreleased] - Add an `includeTransparent` parameter to hide/show outlines of components that are transparent +- Better guard against issue (black fringes) with bumpiness in impostors + +## [v3.26.0] - 2022-12-04 + +- Support for ``powerPreference`` webgl attribute. Add ``PluginConfig.General.PowerPreference`` and ``power-preference`` Viewer GET param. +- Excluded common protein caps `NME` and `ACE` from the ligand selection query +- Add screen-space shadow post-processing effect +- Add "Structure Molecular Surface" visual +- Add `external-volume` theme (coloring of arbitrary geometries by user-selected volume) + ## [v3.25.1] - 2022-11-20 - Fix edge-case in `Structure.eachUnitPair` with single-element units diff --git a/package-lock.json b/package-lock.json index 56c21ea56aba76d56ba0af9b0737e7f62d022224..a0702acc416d6b0154f572f3becd240936a5bd1a 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/package.json b/package.json index 130d63d20e01683b702950f588107d0f9035775f..e85b86797ab0ad7a498116237720fb2c9637ffde 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "molstar", - "version": "3.25.1", + "version": "3.26.0", "description": "A comprehensive macromolecular library.", "homepage": "https://github.com/molstar/molstar#readme", "repository": { @@ -92,57 +92,58 @@ "Panagiotis Tourlas <panagiot_tourlov@hotmail.com>", "Adam Midlik <midlik@gmail.com>", "Koya Sakuma <koya.sakuma.work@gmail.com>", - "Gianluca Tomasello <giagitom@gmail.com>" + "Gianluca Tomasello <giagitom@gmail.com>", + "Jason Pattle <jpattle@exscientia.co.uk>" ], "license": "MIT", "devDependencies": { "@graphql-codegen/add": "^3.2.1", - "@graphql-codegen/cli": "^2.13.11", + "@graphql-codegen/cli": "^2.15.0", "@graphql-codegen/time": "^3.2.1", - "@graphql-codegen/typescript": "^2.8.1", + "@graphql-codegen/typescript": "^2.8.3", "@graphql-codegen/typescript-graphql-files-modules": "^2.2.1", "@graphql-codegen/typescript-graphql-request": "^4.5.8", - "@graphql-codegen/typescript-operations": "^2.5.6", + "@graphql-codegen/typescript-operations": "^2.5.8", "@types/cors": "^2.8.12", - "@types/gl": "^6.0.1", - "@types/jest": "^29.2.2", - "@types/react": "^18.0.25", - "@types/react-dom": "^18.0.8", - "@typescript-eslint/eslint-plugin": "^5.42.1", - "@typescript-eslint/parser": "^5.42.1", + "@types/gl": "^6.0.2", + "@types/jest": "^29.2.3", + "@types/react": "^18.0.26", + "@types/react-dom": "^18.0.9", + "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/parser": "^5.45.0", "benchmark": "^2.1.4", - "concurrently": "^7.5.0", + "concurrently": "^7.6.0", "cpx2": "^4.2.0", "crypto-browserify": "^3.12.0", "css-loader": "^6.7.2", - "eslint": "^8.27.0", + "eslint": "^8.29.0", "extra-watch-webpack-plugin": "^1.0.3", "file-loader": "^6.2.0", - "fs-extra": "^10.1.0", + "fs-extra": "^11.1.0", "graphql": "^16.6.0", "http-server": "^14.1.1", "jest": "^29.3.1", - "mini-css-extract-plugin": "^2.6.1", + "mini-css-extract-plugin": "^2.7.1", "path-browserify": "^1.0.1", "raw-loader": "^4.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.56.1", "sass-loader": "^13.2.0", - "simple-git": "^3.15.0", + "simple-git": "^3.15.1", "stream-browserify": "^3.0.0", "style-loader": "^3.3.1", "ts-jest": "^29.0.3", - "typescript": "^4.8.4", + "typescript": "^4.9.3", "webpack": "^5.75.0", - "webpack-cli": "^4.10.0" + "webpack-cli": "^5.0.0" }, "dependencies": { "@types/argparse": "^2.0.10", "@types/benchmark": "^2.1.2", "@types/compression": "1.7.2", "@types/express": "^4.17.14", - "@types/node": "^16.18.3", + "@types/node": "^16.18.4", "@types/node-fetch": "^2.6.2", "@types/swagger-ui-dist": "3.30.1", "argparse": "^2.0.1", @@ -154,7 +155,7 @@ "immer": "^9.0.16", "immutable": "^4.1.0", "node-fetch": "^2.6.7", - "rxjs": "^7.5.7", + "rxjs": "^7.6.0", "swagger-ui-dist": "^4.15.5", "tslib": "^2.4.1", "util.promisify": "^1.1.1", diff --git a/src/apps/docking-viewer/viewport.tsx b/src/apps/docking-viewer/viewport.tsx index 94beb975db096a0629f208833bc3c5ada126d081..98a5479d8cb7ddb8396219361ac0c96fedc1f56d 100644 --- a/src/apps/docking-viewer/viewport.tsx +++ b/src/apps/docking-viewer/viewport.tsx @@ -31,7 +31,8 @@ function shinyStyle(plugin: PluginContext) { postprocessing: { ...plugin.canvas3d!.props.postprocessing, occlusion: { name: 'off', params: {} }, - outline: { name: 'off', params: {} } + shadow: { name: 'off', params: {} }, + outline: { name: 'off', params: {} }, } } }); } @@ -48,7 +49,7 @@ function occlusionStyle(plugin: PluginContext) { blurKernelSize: 15, radius: 5, samples: 32, - resolutionScale: 1 + resolutionScale: 1, } }, outline: { name: 'on', params: { scale: 1.0, @@ -56,6 +57,7 @@ function occlusionStyle(plugin: PluginContext) { color: Color(0x0000), includeTransparent: true, } } + shadow: { name: 'off', params: {} }, } } }); } diff --git a/src/apps/viewer/app.ts b/src/apps/viewer/app.ts index 93920c9d94511f926731d070b237c4ca0012c379..3d488ae366147da4cb8ae7c88d1716c322e41da5 100644 --- a/src/apps/viewer/app.ts +++ b/src/apps/viewer/app.ts @@ -91,6 +91,7 @@ const DefaultViewerOptions = { enableDpoit: PluginConfig.General.EnableDpoit.defaultValue, preferWebgl1: PluginConfig.General.PreferWebGl1.defaultValue, allowMajorPerformanceCaveat: PluginConfig.General.AllowMajorPerformanceCaveat.defaultValue, + powerPreference: PluginConfig.General.PowerPreference.defaultValue, viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue, viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue, @@ -163,6 +164,7 @@ export class Viewer { [PluginConfig.General.EnableDpoit, o.enableDpoit], [PluginConfig.General.PreferWebGl1, o.preferWebgl1], [PluginConfig.General.AllowMajorPerformanceCaveat, o.allowMajorPerformanceCaveat], + [PluginConfig.General.PowerPreference, o.powerPreference], [PluginConfig.Viewport.ShowExpand, o.viewportShowExpand], [PluginConfig.Viewport.ShowControls, o.viewportShowControls], [PluginConfig.Viewport.ShowSettings, o.viewportShowSettings], diff --git a/src/apps/viewer/index.html b/src/apps/viewer/index.html index 71d41ff6787f13b3ac4a0f40a3d57a1a0fd25cad..9918dd47d8ca700c3e4b2c4d2c9f454eb8e5a53a 100644 --- a/src/apps/viewer/index.html +++ b/src/apps/viewer/index.html @@ -63,6 +63,7 @@ var enableDpoit = getParam('enable-dpoit', '[^&]+').trim() === '1'; var preferWebgl1 = getParam('prefer-webgl1', '[^&]+').trim() === '1' || void 0; var allowMajorPerformanceCaveat = getParam('allow-major-performance-caveat', '[^&]+').trim() === '1'; + var powerPreference = getParam('power-preference', '[^&]+').trim().toLowerCase(); molstar.Viewer.create('app', { layoutShowControls: !hideControls, @@ -80,6 +81,7 @@ enableDpoit: enableDpoit ? true : void 0, preferWebgl1: preferWebgl1, allowMajorPerformanceCaveat: allowMajorPerformanceCaveat, + powerPreference: powerPreference || 'high-performance', }).then(viewer => { var snapshotId = getParam('snapshot-id', '[^&]+').trim(); if (snapshotId) viewer.setRemoteSnapshot(snapshotId); diff --git a/src/examples/lighting/index.ts b/src/examples/lighting/index.ts index 47018a13b30d86570820a85afeb298ed00b9b88a..0cc1048ef7843c78080a383bd8927ea3ba88a2a4 100644 --- a/src/examples/lighting/index.ts +++ b/src/examples/lighting/index.ts @@ -25,7 +25,8 @@ const Canvas3DPresets = { canvas3d: <Preset>{ postprocessing: { occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } }, - outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000), includeTransparent: true, } } + outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000), includeTransparent: true, } }, + shadow: { name: 'off', params: {} }, }, renderer: { ambientIntensity: 1.0, @@ -37,7 +38,8 @@ const Canvas3DPresets = { canvas3d: <Preset>{ postprocessing: { occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } }, - outline: { name: 'off', params: {} } + outline: { name: 'off', params: {} }, + shadow: { name: 'off', params: {} }, }, renderer: { ambientIntensity: 0.4, @@ -50,7 +52,8 @@ const Canvas3DPresets = { canvas3d: <Preset>{ postprocessing: { occlusion: { name: 'off', params: {} }, - outline: { name: 'off', params: {} } + outline: { name: 'off', params: {} }, + shadow: { name: 'off', params: {} }, }, renderer: { ambientIntensity: 0.4, diff --git a/src/extensions/cellpack/model.ts b/src/extensions/cellpack/model.ts index 38a74bbd09c4a19503a9aa2f4549f763ff62ebdd..91ea9c33315343732112fe22b80829545b5edc90 100644 --- a/src/extensions/cellpack/model.ts +++ b/src/extensions/cellpack/model.ts @@ -606,6 +606,15 @@ export const LoadCellPackModel = StateAction.build({ resolutionScale: 1, } }, + shadow: { + name: 'on', + params: { + bias: 0.6, + maxDistance: 80, + steps: 3, + tolerance: 1.0, + } + }, outline: { name: 'on', params: { diff --git a/src/extensions/rcsb/graphql/types.ts b/src/extensions/rcsb/graphql/types.ts index 58fc86f4e00d4ef5bf0743dbc2e23756466d3edf..8c1f2b1bba986faa172403928d30f4e1e0dc93f0 100644 --- a/src/extensions/rcsb/graphql/types.ts +++ b/src/extensions/rcsb/graphql/types.ts @@ -4,7 +4,7 @@ export type InputMaybe<T> = Maybe<T>; export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] }; export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> }; export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> }; -// Generated on 2022-08-20T16:36:05-07:00 +// Generated on 2022-12-03T21:55:37-08:00 /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { @@ -343,6 +343,14 @@ export type Citation = { * */ readonly journal_abbrev?: Maybe<Scalars['String']>; + /** + * Full name of the cited journal; relevant for journal articles. + * + * Examples: + * Journal of Molecular Biology + * + */ + readonly journal_full?: Maybe<Scalars['String']>; /** * The American Society for Testing and Materials (ASTM) code * assigned to the journal cited (also referred to as the CODEN @@ -550,6 +558,7 @@ export type CoreBranchedEntityInstance = { readonly rcsb_id: Scalars['String']; readonly rcsb_latest_revision?: Maybe<RcsbLatestRevision>; readonly rcsb_ligand_neighbors?: Maybe<ReadonlyArray<Maybe<RcsbLigandNeighbors>>>; + readonly struct_asym?: Maybe<StructAsym>; }; export type CoreChemComp = { @@ -661,6 +670,7 @@ export type CoreEntry = { readonly exptl?: Maybe<ReadonlyArray<Maybe<Exptl>>>; readonly exptl_crystal?: Maybe<ReadonlyArray<Maybe<ExptlCrystal>>>; readonly exptl_crystal_grow?: Maybe<ReadonlyArray<Maybe<ExptlCrystalGrow>>>; + readonly ma_data?: Maybe<ReadonlyArray<Maybe<MaData>>>; /** Get all non-polymer (non-solvent) entities for this PDB entry. */ readonly nonpolymer_entities?: Maybe<ReadonlyArray<Maybe<CoreNonpolymerEntity>>>; readonly pdbx_SG_project?: Maybe<ReadonlyArray<Maybe<PdbxSgProject>>>; @@ -701,6 +711,7 @@ export type CoreEntry = { /** The list of content types associated with this entry. */ readonly rcsb_associated_holdings?: Maybe<CurrentEntry>; readonly rcsb_binding_affinity?: Maybe<ReadonlyArray<Maybe<RcsbBindingAffinity>>>; + readonly rcsb_comp_model_provenance?: Maybe<RcsbCompModelProvenance>; readonly rcsb_entry_container_identifiers: RcsbEntryContainerIdentifiers; readonly rcsb_entry_group_membership?: Maybe<ReadonlyArray<Maybe<RcsbEntryGroupMembership>>>; readonly rcsb_entry_info: RcsbEntryInfo; @@ -713,6 +724,7 @@ export type CoreEntry = { * */ readonly rcsb_id: Scalars['String']; + readonly rcsb_ma_qa_metric_global?: Maybe<ReadonlyArray<Maybe<RcsbMaQaMetricGlobal>>>; readonly rcsb_primary_citation?: Maybe<RcsbPrimaryCitation>; readonly refine?: Maybe<ReadonlyArray<Maybe<Refine>>>; readonly refine_analyze?: Maybe<ReadonlyArray<Maybe<RefineAnalyze>>>; @@ -786,6 +798,7 @@ export type CoreNonpolymerEntityInstance = { readonly rcsb_nonpolymer_instance_validation_score?: Maybe<ReadonlyArray<Maybe<RcsbNonpolymerInstanceValidationScore>>>; readonly rcsb_nonpolymer_struct_conn?: Maybe<ReadonlyArray<Maybe<RcsbNonpolymerStructConn>>>; readonly rcsb_target_neighbors?: Maybe<ReadonlyArray<Maybe<RcsbTargetNeighbors>>>; + readonly struct_asym?: Maybe<StructAsym>; }; export type CorePfam = { @@ -919,6 +932,7 @@ export type CorePolymerEntityInstance = { readonly rcsb_polymer_instance_feature?: Maybe<ReadonlyArray<Maybe<RcsbPolymerInstanceFeature>>>; readonly rcsb_polymer_instance_feature_summary?: Maybe<ReadonlyArray<Maybe<RcsbPolymerInstanceFeatureSummary>>>; readonly rcsb_polymer_struct_conn?: Maybe<ReadonlyArray<Maybe<RcsbPolymerStructConn>>>; + readonly struct_asym?: Maybe<StructAsym>; }; export type CorePubmed = { @@ -1284,9 +1298,9 @@ export type Em2dCrystalEntity = { readonly id: Scalars['String']; /** pointer to _em_image_processing.id in the EM_IMAGE_PROCESSING category. */ readonly image_processing_id: Scalars['String']; - /** Unit-cell length a in Angstroms. */ + /** Unit-cell length a in angstroms. */ readonly length_a?: Maybe<Scalars['Float']>; - /** Unit-cell length b in Angstroms. */ + /** Unit-cell length b in angstroms. */ readonly length_b?: Maybe<Scalars['Float']>; /** Thickness of 2D crystal */ readonly length_c?: Maybe<Scalars['Float']>; @@ -1317,11 +1331,11 @@ export type Em3dCrystalEntity = { readonly id: Scalars['String']; /** pointer to _em_image_processing.id in the EM_IMAGE_PROCESSING category. */ readonly image_processing_id: Scalars['String']; - /** Unit-cell length a in Angstroms. */ + /** Unit-cell length a in angstroms. */ readonly length_a?: Maybe<Scalars['Float']>; - /** Unit-cell length b in Angstroms. */ + /** Unit-cell length b in angstroms. */ readonly length_b?: Maybe<Scalars['Float']>; - /** Unit-cell length c in Angstroms. */ + /** Unit-cell length c in angstroms. */ readonly length_c?: Maybe<Scalars['Float']>; /** * Space group name. @@ -1482,7 +1496,7 @@ export type Em3dReconstruction = { */ readonly refinement_type?: Maybe<Scalars['String']>; /** - * The final resolution (in Angstroms)of the 3D reconstruction. + * The final resolution (in angstroms)of the 3D reconstruction. * * Examples: * null, null @@ -1558,7 +1572,7 @@ export type EmDiffractionShell = { */ readonly fourier_space_coverage?: Maybe<Scalars['Float']>; /** - * High resolution limit for this shell (Angstroms) + * High resolution limit for this shell (angstroms) * * Examples: * null @@ -1568,7 +1582,7 @@ export type EmDiffractionShell = { /** Unique identifier for the category em_diffraction_shell */ readonly id: Scalars['String']; /** - * Low resolution limit for this shell (Angstroms) + * Low resolution limit for this shell (angstroms) * * Examples: * null @@ -1614,7 +1628,7 @@ export type EmDiffractionStats = { */ readonly fourier_space_coverage?: Maybe<Scalars['Float']>; /** - * High resolution limit of the structure factor data, in Angstroms + * High resolution limit of the structure factor data, in angstroms * * Examples: * null @@ -1998,12 +2012,12 @@ export type EmImaging = { /** The magnification indicated by the microscope readout. */ readonly nominal_magnification?: Maybe<Scalars['Int']>; /** - * The specimen temperature maximum (degrees Kelvin) for the duration + * The specimen temperature maximum (kelvin) for the duration * of imaging. */ readonly recording_temperature_maximum?: Maybe<Scalars['Float']>; /** - * The specimen temperature minimum (degrees Kelvin) for the duration + * The specimen temperature minimum (kelvin) for the duration * of imaging. */ readonly recording_temperature_minimum?: Maybe<Scalars['Float']>; @@ -2028,7 +2042,7 @@ export type EmImaging = { /** Foreign key to the EM_SPECIMEN category */ readonly specimen_id?: Maybe<Scalars['String']>; /** - * The mean specimen stage temperature (degrees Kelvin) during imaging + * The mean specimen stage temperature (in kelvin) during imaging * in the microscope. */ readonly temperature?: Maybe<Scalars['Float']>; @@ -2215,7 +2229,7 @@ export type EmStaining = { }; export type EmVitrification = { - /** The temperature (in degrees Kelvin) of the sample just prior to vitrification. */ + /** The temperature (in kelvin) of the sample just prior to vitrification. */ readonly chamber_temperature?: Maybe<Scalars['Float']>; /** * This is the name of the cryogen. @@ -2259,7 +2273,7 @@ export type EmVitrification = { /** This data item is a pointer to _em_specimen.id */ readonly specimen_id: Scalars['String']; /** - * The vitrification temperature (in degrees Kelvin), e.g., + * The vitrification temperature (in kelvin), e.g., * temperature of the plunge instrument cryogen bath. */ readonly temp?: Maybe<Scalars['Float']>; @@ -2364,6 +2378,14 @@ export type EntityPoly = { * */ readonly pdbx_seq_one_letter_code_can?: Maybe<Scalars['String']>; + /** + * Evidence for the assignment of the polymer sequence. + * + * Allowable values: + * depositor provided, derived from coordinates + * + */ + readonly pdbx_sequence_evidence_code?: Maybe<Scalars['String']>; /** * The PDB strand/chain id(s) corresponding to this polymer entity. * @@ -3005,6 +3027,8 @@ export type Entry = { * identifier. */ readonly id: Scalars['String']; + /** An identifier for the model collection associated with the entry. */ + readonly ma_collection_id?: Maybe<Scalars['String']>; }; export type Exptl = { @@ -3263,6 +3287,29 @@ export type InterfacePartnerFeatureFeaturePositions = { readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['Float']>>>; }; +export type MaData = { + /** + * The type of data held in the dataset. + * + * Allowable values: + * coevolution MSA, input structure, model coordinates, other, polymeric template library, spatial restraints, target, target-template alignment, template structure + * + */ + readonly content_type?: Maybe<Scalars['String']>; + /** Details for other content types. */ + readonly content_type_other_details?: Maybe<Scalars['String']>; + /** A unique identifier for the data. */ + readonly id: Scalars['Int']; + /** + * An author-given name for the content held in the dataset. + * + * Examples: + * NMR NOE Distances, Target Template Alignment, Coevolution Data + * + */ + readonly name?: Maybe<Scalars['String']>; +}; + export type MethodDetails = { /** A description of special aspects of the clustering process */ readonly description?: Maybe<Scalars['String']>; @@ -4199,7 +4246,7 @@ export type PdbxNmrExptlSampleConditions = { */ readonly pressure_units?: Maybe<Scalars['String']>; /** - * The temperature (in Kelvin) at which NMR data were + * The temperature (in kelvin) at which NMR data were * collected. */ readonly temperature?: Maybe<Scalars['String']>; @@ -4453,7 +4500,7 @@ export type PdbxPrdAudit = { * An identifier for the wwPDB site creating or modifying the molecule. * * Allowable values: - * BMRB, PDBC, PDBJ, PDBe, RCSB + * BMRB, PDBC, PDBE, PDBJ, RCSB * */ readonly processing_site?: Maybe<Scalars['String']>; @@ -6817,7 +6864,7 @@ export type Query = { readonly assemblies?: Maybe<ReadonlyArray<Maybe<CoreAssembly>>>; /** Get an assembly given the PDB ID and ASSEMBLY ID. Here ASSEMBLY ID is '1', '2', '3', etc. or 'deposited' for deposited coordinates. */ readonly assembly?: Maybe<CoreAssembly>; - /** Get a list of PDB branched entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. */ + /** Get a list of PDB branched entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. Note that the ENTRY ID part must be upper case. */ readonly branched_entities?: Maybe<ReadonlyArray<Maybe<CoreBranchedEntity>>>; /** Get a PDB branched entity, given the PDB ID and ENTITY ID. Here ENTITY ID is a '1', '2', '3', etc. */ readonly branched_entity?: Maybe<CoreBranchedEntity>; @@ -6841,9 +6888,9 @@ export type Query = { readonly group_provenance?: Maybe<GroupProvenance>; /** Get a pairwise polymeric interface given the PDB ID, ASSEMBLY ID and INTERFACE ID. */ readonly interface?: Maybe<CoreInterface>; - /** Get a list of pairwise polymeric interfaces given a list of INTERFACE IDs. Here INTERFACE ID is a compound identifier that includes entry_id, assembly_id and interface_id e.g. 1XXX-1.1. */ + /** Get a list of pairwise polymeric interfaces given a list of INTERFACE IDs. Here INTERFACE ID is a compound identifier that includes entry_id, assembly_id and interface_id e.g. 1XXX-1.1. Note that the ENTRY ID part must be upper case. */ readonly interfaces?: Maybe<ReadonlyArray<Maybe<CoreInterface>>>; - /** Get a list of PDB non-polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. */ + /** Get a list of PDB non-polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. Note that the ENTRY ID part must be upper case. */ readonly nonpolymer_entities?: Maybe<ReadonlyArray<Maybe<CoreNonpolymerEntity>>>; /** Get a PDB non-polymer entity, given the PDB ID and ENTITY ID. Here ENTITY ID is a '1', '2', '3', etc. */ readonly nonpolymer_entity?: Maybe<CoreNonpolymerEntity>; @@ -6851,7 +6898,7 @@ export type Query = { readonly nonpolymer_entity_instance?: Maybe<CoreNonpolymerEntityInstance>; /** Get a list of PDB non-polymer entity instances (chains), given the list of ENTITY INSTANCE IDs. Here ENTITY INSTANCE ID identifies structural element in the asymmetric unit, e.g. 'A', 'B', etc. */ readonly nonpolymer_entity_instances?: Maybe<ReadonlyArray<Maybe<CoreNonpolymerEntityInstance>>>; - /** Get a list of PDB polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. */ + /** Get a list of PDB polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. Note that the ENTRY ID part must be upper case. */ readonly polymer_entities?: Maybe<ReadonlyArray<Maybe<CorePolymerEntity>>>; /** Get a PDB polymer entity, given the PDB ID and ENTITY ID. Here ENTITY ID is a '1', '2', '3', etc. */ readonly polymer_entity?: Maybe<CorePolymerEntity>; @@ -8421,6 +8468,29 @@ export type RcsbClusterMembership = { readonly identity?: Maybe<Scalars['Int']>; }; +export type RcsbCompModelProvenance = { + /** + * Entry identifier corresponding to the computed structure model. + * + * Examples: + * AF-P60325-F1, ma-bak-cepc-0019 + * + */ + readonly entry_id: Scalars['String']; + /** + * Source database for the computed structure model. + * + * Allowable values: + * AlphaFoldDB, ModelArchive + * + */ + readonly source_db?: Maybe<Scalars['String']>; + /** Source filename for the computed structure model. */ + readonly source_filename?: Maybe<Scalars['String']>; + /** Source URL for computed structure model file. */ + readonly source_url?: Maybe<Scalars['String']>; +}; + export type RcsbEntityHostOrganism = { /** * The beginning polymer sequence position for the polymer section corresponding @@ -8657,7 +8727,7 @@ export type RcsbEntitySourceOrganism = { * A code indicating the provenance of the source organism details for the entity * * Allowable values: - * PDB Primary Data + * PDB Primary Data, UniProt * */ readonly provenance_source?: Maybe<Scalars['String']>; @@ -8731,7 +8801,7 @@ export type RcsbEntryContainerIdentifiers = { * Entry identifier for the container. * * Examples: - * 1KIP, 4HHB + * 4HHB, AF_AFP60325F1, MA_MABAKCEPC0019 * */ readonly entry_id: Scalars['String']; @@ -8879,6 +8949,15 @@ export type RcsbEntryInfo = { * */ readonly na_polymer_entity_types?: Maybe<Scalars['String']>; + /** + * This data item identifies secondary structure + * features of nucleic acids in the entry. + * + * Allowable values: + * a-form double helix, b-form double helix, bulge loop, double helix, four-way junction, hairpin loop, internal loop, mismatched base pair, other right-handed double helix, parallel strands, quadruple helix, tetraloop, three-way junction, triple helix, two-way junction, z-form double helix + * + */ + readonly ndb_struct_conf_na_feature_combined?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>; /** Bound nonpolymer components in this entry. */ readonly nonpolymer_bound_components?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>; /** The number of distinct non-polymer entities in the structure entry exclusive of solvent. */ @@ -8955,6 +9034,21 @@ export type RcsbEntryInfo = { readonly software_programs_combined?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>; /** The number of distinct solvent entities per deposited structure model. */ readonly solvent_entity_count?: Maybe<Scalars['Int']>; + /** + * Indicates if the structure was determined using experimental or computational methods. + * + * Allowable values: + * computational, experimental + * + */ + readonly structure_determination_methodology: Scalars['String']; + /** + * Indicates the priority of the value in _rcsb_entry_info.structure_determination_methodology. + * The lower the number the higher the priority. + * Priority values for "experimental" structures is currently set to 10 and + * the values for "computational" structures is set to 100. + */ + readonly structure_determination_methodology_priority?: Maybe<Scalars['Int']>; }; export type RcsbEntryInfoDiffrnResolutionHigh = { @@ -9294,6 +9388,49 @@ export type RcsbLigandNeighbors = { readonly seq_id?: Maybe<Scalars['Int']>; }; +export type RcsbMaQaMetricGlobal = { + readonly ma_qa_metric_global?: Maybe<ReadonlyArray<Maybe<RcsbMaQaMetricGlobalMaQaMetricGlobal>>>; + /** The model identifier. */ + readonly model_id: Scalars['Int']; +}; + +export type RcsbMaQaMetricGlobalMaQaMetricGlobal = { + /** + * Description of the global QA metric. + * + * Examples: + * confidence score predicting accuracy according to the CA-only Local Distance Difference Test (lDDT-CA) in [0,100] + * + */ + readonly description?: Maybe<Scalars['String']>; + /** + * Name of the global QA metric. + * + * Examples: + * pLDDT + * + */ + readonly name: Scalars['String']; + /** + * The type of global QA metric. + * + * Allowable values: + * PAE, contact probability, distance, energy, ipTM, normalized score, other, pLDDT, pLDDT all-atom, pLDDT all-atom in [0,1], pLDDT in [0,1], pTM, zscore + * + */ + readonly type: Scalars['String']; + /** Details for other type of global QA metric. */ + readonly type_other_details?: Maybe<Scalars['String']>; + /** + * Value of the global QA metric. + * + * Examples: + * null + * + */ + readonly value: Scalars['Float']; +}; + export type RcsbMembraneLineage = { /** Hierarchy depth. */ readonly depth?: Maybe<Scalars['Int']>; @@ -10332,7 +10469,7 @@ export type RcsbPolymerEntityContainerIdentifiersReferenceSequenceIdentifiers = * Source of the reference database assignment * * Allowable values: - * PDB, RCSB, SIFTS + * PDB, RCSB, SIFTS, UniProt * */ readonly provenance_source?: Maybe<Scalars['String']>; @@ -10737,7 +10874,7 @@ export type RcsbPolymerInstanceFeature = { * A type or category of the feature. * * Allowable values: - * ANGLE_OUTLIER, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SCOP, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ, ASA + * ANGLE_OUTLIER, BEND, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, HELX_LH_PP_P, HELX_RH_3T_P, HELX_RH_AL_P, HELX_RH_PI_P, MA_QA_METRIC_LOCAL_TYPE_CONTACT_PROBABILITY, MA_QA_METRIC_LOCAL_TYPE_DISTANCE, MA_QA_METRIC_LOCAL_TYPE_ENERGY, MA_QA_METRIC_LOCAL_TYPE_IPTM, MA_QA_METRIC_LOCAL_TYPE_NORMALIZED_SCORE, MA_QA_METRIC_LOCAL_TYPE_OTHER, MA_QA_METRIC_LOCAL_TYPE_PAE, MA_QA_METRIC_LOCAL_TYPE_PLDDT, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM_[0,1], MA_QA_METRIC_LOCAL_TYPE_PLDDT_[0,1], MA_QA_METRIC_LOCAL_TYPE_PTM, MA_QA_METRIC_LOCAL_TYPE_ZSCORE, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SCOP, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, STRN, TURN_TY1_P, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ, ASA * */ readonly type?: Maybe<Scalars['String']>; @@ -10748,7 +10885,7 @@ export type RcsbPolymerInstanceFeatureAdditionalProperties = { * The additional property name. * * Allowable values: - * CATH_DOMAIN_ID, CATH_NAME, ECOD_DOMAIN_ID, ECOD_FAMILY_NAME, OMEGA_ANGLE, PARTNER_ASYM_ID, PARTNER_BOND_DISTANCE, PARTNER_COMP_ID, SCOP2_DOMAIN_ID, SCOP2_FAMILY_ID, SCOP2_FAMILY_NAME, SCOP2_SUPERFAMILY_ID, SCOP2_SUPERFAMILY_NAME, SCOP_DOMAIN_ID, SCOP_NAME, SCOP_SUN_ID, SHEET_SENSE + * CATH_DOMAIN_ID, CATH_NAME, ECOD_DOMAIN_ID, ECOD_FAMILY_NAME, MODELCIF_MODEL_ID, OMEGA_ANGLE, PARTNER_ASYM_ID, PARTNER_BOND_DISTANCE, PARTNER_COMP_ID, SCOP2_DOMAIN_ID, SCOP2_FAMILY_ID, SCOP2_FAMILY_NAME, SCOP2_SUPERFAMILY_ID, SCOP2_SUPERFAMILY_NAME, SCOP_DOMAIN_ID, SCOP_NAME, SCOP_SUN_ID, SHEET_SENSE * */ readonly name?: Maybe<Scalars['String']>; @@ -10818,7 +10955,7 @@ export type RcsbPolymerInstanceFeatureSummary = { * Type or category of the feature. * * Allowable values: - * ANGLE_OUTLIER, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SAbDab Antibody Heavy Chain Subclass, SAbDab Antibody Light Chain Subclass, SAbDab Antibody Light Chain Type, SCOP, SCOP2 Family, SCOP2 Superfamily, SCOP2B Superfamily, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ + * ANGLE_OUTLIER, BEND, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, HELX_LH_PP_P, HELX_RH_3T_P, HELX_RH_AL_P, HELX_RH_PI_P, MA_QA_METRIC_LOCAL_TYPE_CONTACT_PROBABILITY, MA_QA_METRIC_LOCAL_TYPE_DISTANCE, MA_QA_METRIC_LOCAL_TYPE_ENERGY, MA_QA_METRIC_LOCAL_TYPE_IPTM, MA_QA_METRIC_LOCAL_TYPE_NORMALIZED_SCORE, MA_QA_METRIC_LOCAL_TYPE_OTHER, MA_QA_METRIC_LOCAL_TYPE_PAE, MA_QA_METRIC_LOCAL_TYPE_PLDDT, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM_[0,1], MA_QA_METRIC_LOCAL_TYPE_PLDDT_[0,1], MA_QA_METRIC_LOCAL_TYPE_PTM, MA_QA_METRIC_LOCAL_TYPE_ZSCORE, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SCOP, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, STRN, TURN_TY1_P, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ * */ readonly type?: Maybe<Scalars['String']>; @@ -13377,6 +13514,11 @@ export type ReflnsShell = { }; export type Software = { + /** + * This data item is a pointer to _citation.id in the CITATION + * category. + */ + readonly citation_id?: Maybe<Scalars['String']>; /** * The classification of the program according to its * major function. @@ -13527,6 +13669,37 @@ export type Struct = { readonly title?: Maybe<Scalars['String']>; }; +export type StructAsym = { + /** + * This data item is a pointer to _atom_site.pdbx_PDB_strand_id the + * ATOM_SITE category. + * + * Examples: + * 1ABC + * + */ + readonly pdbx_PDB_id?: Maybe<Scalars['String']>; + /** + * This data item is a pointer to _atom_site.ndb_alias_strand_id the + * ATOM_SITE category. + */ + readonly pdbx_alt_id?: Maybe<Scalars['String']>; + /** + * This data item gives the order of the structural elements in the + * ATOM_SITE category. + */ + readonly pdbx_order?: Maybe<Scalars['Int']>; + /** + * This data item describes the general type of the structural elements + * in the ATOM_SITE category. + * + * Allowable values: + * ATOMN, ATOMP, ATOMS, HETAC, HETAD, HETAI, HETAIN, HETAS, HETIC + * + */ + readonly pdbx_type?: Maybe<Scalars['String']>; +}; + export type StructKeywords = { /** * Terms characterizing the macromolecular structure. diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index ed05d3a357ba32df5d8d88e57981a2b654d5c205..b65f42eb74df809aabf86620e4d5cbd07f911673 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -120,6 +120,7 @@ interface Canvas3DContext { namespace Canvas3DContext { export const DefaultAttribs = { + powerPreference: 'high-performance' as WebGLContextAttributes['powerPreference'], failIfMajorPerformanceCaveat: false, /** true by default to avoid issues with Safari (Jan 2021) */ antialias: true, @@ -140,8 +141,9 @@ namespace Canvas3DContext { if (a.enableWboit && a.enableDpoit) throw new Error('Multiple transparency methods not allowed.'); - const { failIfMajorPerformanceCaveat, antialias, preserveDrawingBuffer, pixelScale, preferWebGl1 } = a; + const { powerPreference, failIfMajorPerformanceCaveat, antialias, preserveDrawingBuffer, pixelScale, preferWebGl1 } = a; const gl = getGLContext(canvas, { + powerPreference, failIfMajorPerformanceCaveat, antialias, preserveDrawingBuffer, diff --git a/src/mol-canvas3d/passes/draw.ts b/src/mol-canvas3d/passes/draw.ts index 34282e8408d16a0c59251178c6ab14843914d707..1f6c5549bc2169e74b09f6246446930781db242b 100644 --- a/src/mol-canvas3d/passes/draw.ts +++ b/src/mol-canvas3d/passes/draw.ts @@ -150,7 +150,7 @@ export class DrawPass { } } - this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps); + this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps, renderer.light); } this.depthTextureOpaque.detachFramebuffer(this.colorTarget.framebuffer, 'depth'); @@ -204,7 +204,7 @@ export class DrawPass { } } - this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps); + this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps, renderer.light); } // render transparent primitives and volumes @@ -268,7 +268,7 @@ export class DrawPass { } } - this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps); + this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps, renderer.light); if (!this.packedDepth) { this.depthTextureOpaque.attachFramebuffer(this.postprocessing.target.framebuffer, 'depth'); diff --git a/src/mol-canvas3d/passes/postprocessing.ts b/src/mol-canvas3d/passes/postprocessing.ts index 5a113fe762843104c027771124a5a627164f0225..e1f086d1ba9e2c7988eaf7bcfca847867948efa6 100644 --- a/src/mol-canvas3d/passes/postprocessing.ts +++ b/src/mol-canvas3d/passes/postprocessing.ts @@ -3,6 +3,7 @@ * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz> + * @author Ludovic Autin <ludovic.autin@gmail.com> */ import { CopyRenderable, createCopyRenderable, QuadSchema, QuadValues } from '../../mol-gl/compute/util'; @@ -30,6 +31,8 @@ import { SmaaParams, SmaaPass } from './smaa'; import { isTimingMode } from '../../mol-util/debug'; import { BackgroundParams, BackgroundPass } from './background'; import { AssetManager } from '../../mol-util/assets'; +import { Light } from '../../mol-gl/renderer'; +import { shadows_frag } from '../../mol-gl/shader/shadows.frag'; const OutlinesSchema = { ...QuadSchema, @@ -73,6 +76,64 @@ function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, d return createComputeRenderable(renderItem, values); } +const ShadowsSchema = { + ...QuadSchema, + tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), + uTexSize: UniformSpec('v2'), + + uProjection: UniformSpec('m4'), + uInvProjection: UniformSpec('m4'), + uBounds: UniformSpec('v4'), + + dOrthographic: DefineSpec('number'), + uNear: UniformSpec('f'), + uFar: UniformSpec('f'), + + dSteps: DefineSpec('number'), + uMaxDistance: UniformSpec('f'), + uTolerance: UniformSpec('f'), + uBias: UniformSpec('f'), + + uLightDirection: UniformSpec('v3[]'), + uLightColor: UniformSpec('v3[]'), + dLightCount: DefineSpec('number'), +}; +type ShadowsRenderable = ComputeRenderable<Values<typeof ShadowsSchema>> + +function getShadowsRenderable(ctx: WebGLContext, depthTexture: Texture): ShadowsRenderable { + const width = depthTexture.getWidth(); + const height = depthTexture.getHeight(); + + const values: Values<typeof ShadowsSchema> = { + ...QuadValues, + tDepth: ValueCell.create(depthTexture), + uTexSize: ValueCell.create(Vec2.create(width, height)), + + uProjection: ValueCell.create(Mat4.identity()), + uInvProjection: ValueCell.create(Mat4.identity()), + uBounds: ValueCell.create(Vec4()), + + dOrthographic: ValueCell.create(0), + uNear: ValueCell.create(1), + uFar: ValueCell.create(10000), + + dSteps: ValueCell.create(1), + uMaxDistance: ValueCell.create(3.0), + uTolerance: ValueCell.create(1.0), + uBias: ValueCell.create(0.6), + + uLightDirection: ValueCell.create([]), + uLightColor: ValueCell.create([]), + dLightCount: ValueCell.create(0), + }; + + const schema = { ...ShadowsSchema }; + const shaderCode = ShaderCode('shadows', quad_vert, shadows_frag); + const renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values); + + return createComputeRenderable(renderItem, values); +} + const SsaoSchema = { ...QuadSchema, tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), @@ -208,6 +269,7 @@ const PostprocessingSchema = { tColor: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tDepthOpaque: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tDepthTransparent: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), + tShadows: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tOutlines: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), uTexSize: UniformSpec('v2'), @@ -225,6 +287,8 @@ const PostprocessingSchema = { dOcclusionEnable: DefineSpec('boolean'), uOcclusionOffset: UniformSpec('v2'), + dShadowEnable: DefineSpec('boolean'), + dOutlineEnable: DefineSpec('boolean'), dOutlineScale: DefineSpec('number'), uOutlineThreshold: UniformSpec('f'), @@ -233,13 +297,15 @@ const PostprocessingSchema = { }; type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>> -function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture, transparentOutline: boolean): PostprocessingRenderable { + +function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, shadowsTexture: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture, transparentOutline: boolean): PostprocessingRenderable { const values: Values<typeof PostprocessingSchema> = { ...QuadValues, tSsaoDepth: ValueCell.create(ssaoDepthTexture), tColor: ValueCell.create(colorTexture), tDepthOpaque: ValueCell.create(depthTextureOpaque), tDepthTransparent: ValueCell.create(depthTextureTransparent), + tShadows: ValueCell.create(shadowsTexture), tOutlines: ValueCell.create(outlinesTexture), uTexSize: ValueCell.create(Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())), @@ -257,6 +323,8 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d dOcclusionEnable: ValueCell.create(true), uOcclusionOffset: ValueCell.create(Vec2.create(0, 0)), + dShadowEnable: ValueCell.create(false), + dOutlineEnable: ValueCell.create(false), dOutlineScale: ValueCell.create(1), uOutlineThreshold: ValueCell.create(0.33), @@ -282,6 +350,15 @@ export const PostprocessingParams = { }), off: PD.Group({}) }, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }), + shadow: PD.MappedStatic('off', { + on: PD.Group({ + steps: PD.Numeric(1, { min: 1, max: 64, step: 1 }), + bias: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }), + maxDistance: PD.Numeric(3, { min: 0, max: 256, step: 1 }), + tolerance: PD.Numeric(1.0, { min: 0.0, max: 10.0, step: 0.1 }), + }), + off: PD.Group({}) + }, { cycle: true, description: 'Simplistic shadows' }), outline: PD.MappedStatic('off', { on: PD.Group({ scale: PD.Numeric(1, { min: 1, max: 5, step: 1 }), @@ -298,11 +375,12 @@ export const PostprocessingParams = { }, { options: [['fxaa', 'FXAA'], ['smaa', 'SMAA'], ['off', 'Off']], description: 'Smooth pixel edges' }), background: PD.Group(BackgroundParams, { isFlat: true }), }; + export type PostprocessingProps = PD.Values<typeof PostprocessingParams> export class PostprocessingPass { static isEnabled(props: PostprocessingProps) { - return props.occlusion.name === 'on' || props.outline.name === 'on' || props.background.variant.name !== 'off'; + return props.occlusion.name === 'on' || props.shadow.name === 'on' || props.outline.name === 'on' || props.background.variant.name !== 'off'; } static isOutlineEnabled(props: PostprocessingProps) { @@ -314,6 +392,9 @@ export class PostprocessingPass { private readonly outlinesTarget: RenderTarget; private readonly outlinesRenderable: OutlinesRenderable; + private readonly shadowsTarget: RenderTarget; + private readonly shadowsRenderable: ShadowsRenderable; + private readonly ssaoFramebuffer: Framebuffer; private readonly ssaoBlurFirstPassFramebuffer: Framebuffer; private readonly ssaoBlurSecondPassFramebuffer: Framebuffer; @@ -359,6 +440,9 @@ export class PostprocessingPass { this.outlinesTarget = webgl.createRenderTarget(width, height, false); this.outlinesRenderable = getOutlinesRenderable(webgl, depthTextureOpaque, depthTextureTransparent, true); + this.shadowsTarget = webgl.createRenderTarget(width, height, false); + this.shadowsRenderable = getShadowsRenderable(webgl, depthTextureOpaque); + this.ssaoFramebuffer = webgl.resources.framebuffer(); this.ssaoBlurFirstPassFramebuffer = webgl.resources.framebuffer(); this.ssaoBlurSecondPassFramebuffer = webgl.resources.framebuffer(); @@ -382,7 +466,7 @@ export class PostprocessingPass { this.ssaoRenderable = getSsaoRenderable(webgl, this.downsampleFactor === 1 ? depthTextureOpaque : this.downsampledDepthTarget.texture); this.ssaoBlurFirstPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthTexture, 'horizontal'); this.ssaoBlurSecondPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthBlurProxyTexture, 'vertical'); - this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.outlinesTarget.texture, this.ssaoDepthTexture, true); + this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.shadowsTarget.texture, this.outlinesTarget.texture, this.ssaoDepthTexture, true); this.background = new BackgroundPass(webgl, assetManager, width, height); } @@ -398,12 +482,14 @@ export class PostprocessingPass { const sh = Math.floor(height * this.ssaoScale); this.target.setSize(width, height); this.outlinesTarget.setSize(width, height); + this.shadowsTarget.setSize(width, height); this.downsampledDepthTarget.setSize(sw, sh); this.ssaoDepthTexture.define(sw, sh); this.ssaoDepthBlurProxyTexture.define(sw, sh); ValueCell.update(this.renderable.values.uTexSize, Vec2.set(this.renderable.values.uTexSize.ref.value, width, height)); ValueCell.update(this.outlinesRenderable.values.uTexSize, Vec2.set(this.outlinesRenderable.values.uTexSize.ref.value, width, height)); + ValueCell.update(this.shadowsRenderable.values.uTexSize, Vec2.set(this.shadowsRenderable.values.uTexSize.ref.value, width, height)); ValueCell.update(this.downsampleDepthRenderable.values.uTexSize, Vec2.set(this.downsampleDepthRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoRenderable.values.uTexSize, Vec2.set(this.ssaoRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurFirstPassRenderable.values.uTexSize.ref.value, sw, sh)); @@ -413,7 +499,8 @@ export class PostprocessingPass { } } - private updateState(camera: ICamera, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps) { + private updateState(camera: ICamera, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps, light: Light) { + let needsUpdateShadows = false; let needsUpdateMain = false; let needsUpdateSsao = false; let needsUpdateSsaoBlur = false; @@ -421,18 +508,20 @@ export class PostprocessingPass { const orthographic = camera.state.mode === 'orthographic' ? 1 : 0; const outlinesEnabled = props.outline.name === 'on'; + const shadowsEnabled = props.shadow.name === 'on'; const occlusionEnabled = props.occlusion.name === 'on'; const invProjection = Mat4.identity(); Mat4.invert(invProjection, camera.projection); + const [w, h] = this.renderable.values.uTexSize.ref.value; + const v = camera.viewport; + if (props.occlusion.name === 'on') { ValueCell.update(this.ssaoRenderable.values.uProjection, camera.projection); ValueCell.update(this.ssaoRenderable.values.uInvProjection, invProjection); - const [w, h] = this.renderable.values.uTexSize.ref.value; const b = this.ssaoRenderable.values.uBounds; - const v = camera.viewport; const s = this.ssaoScale; Vec4.set(b.ref.value, Math.floor(v.x * s) / (w * s), @@ -504,6 +593,38 @@ export class PostprocessingPass { } } + if (props.shadow.name === 'on') { + ValueCell.update(this.shadowsRenderable.values.uProjection, camera.projection); + ValueCell.update(this.shadowsRenderable.values.uInvProjection, invProjection); + + Vec4.set(this.shadowsRenderable.values.uBounds.ref.value, + v.x / w, + v.y / h, + (v.x + v.width) / w, + (v.y + v.height) / h + ); + ValueCell.update(this.shadowsRenderable.values.uBounds, this.shadowsRenderable.values.uBounds.ref.value); + + ValueCell.updateIfChanged(this.shadowsRenderable.values.uNear, camera.near); + ValueCell.updateIfChanged(this.shadowsRenderable.values.uFar, camera.far); + ValueCell.updateIfChanged(this.shadowsRenderable.values.dOrthographic, orthographic); + + ValueCell.updateIfChanged(this.shadowsRenderable.values.uMaxDistance, props.shadow.params.maxDistance); + ValueCell.updateIfChanged(this.shadowsRenderable.values.uTolerance, props.shadow.params.tolerance); + ValueCell.updateIfChanged(this.shadowsRenderable.values.uBias, props.shadow.params.bias); + if (this.shadowsRenderable.values.dSteps.ref.value !== props.shadow.params.steps) { + ValueCell.update(this.shadowsRenderable.values.dSteps, props.shadow.params.steps); + needsUpdateShadows = true; + } + + ValueCell.update(this.shadowsRenderable.values.uLightDirection, light.direction); + ValueCell.update(this.shadowsRenderable.values.uLightColor, light.color); + if (this.shadowsRenderable.values.dLightCount.ref.value !== light.count) { + ValueCell.update(this.shadowsRenderable.values.dLightCount, light.count); + needsUpdateShadows = true; + } + } + if (props.outline.name === 'on') { let { threshold, includeTransparent } = props.outline.params; const transparentOutline = includeTransparent ?? true; @@ -536,8 +657,11 @@ export class PostprocessingPass { ValueCell.updateIfChanged(this.renderable.values.uTransparentBackground, transparentBackground); if (this.renderable.values.dOrthographic.ref.value !== orthographic) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOrthographic, orthographic); + if (this.renderable.values.dOutlineEnable.ref.value !== outlinesEnabled) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOutlineEnable, outlinesEnabled); + if (this.renderable.values.dShadowEnable.ref.value !== shadowsEnabled) { needsUpdateMain = true; } + ValueCell.updateIfChanged(this.renderable.values.dShadowEnable, shadowsEnabled); if (this.renderable.values.dOcclusionEnable.ref.value !== occlusionEnabled) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, occlusionEnabled); @@ -545,6 +669,10 @@ export class PostprocessingPass { this.outlinesRenderable.update(); } + if (needsUpdateShadows) { + this.shadowsRenderable.update(); + } + if (needsUpdateSsao) { this.ssaoRenderable.update(); } @@ -582,15 +710,20 @@ export class PostprocessingPass { this.transparentBackground = value; } - render(camera: ICamera, toDrawingBuffer: boolean, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps) { + render(camera: ICamera, toDrawingBuffer: boolean, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps, light: Light) { if (isTimingMode) this.webgl.timer.mark('PostprocessingPass.render'); - this.updateState(camera, transparentBackground, backgroundColor, props); + this.updateState(camera, transparentBackground, backgroundColor, props, light); if (props.outline.name === 'on') { this.outlinesTarget.bind(); this.outlinesRenderable.render(); } + if (props.shadow.name === 'on') { + this.shadowsTarget.bind(); + this.shadowsRenderable.render(); + } + // don't render occlusion if offset is given, // which will reuse the existing occlusion if (props.occlusion.name === 'on' && this.occlusionOffset[0] === 0 && this.occlusionOffset[1] === 0) { diff --git a/src/mol-geo/geometry/texture-mesh/texture-mesh.ts b/src/mol-geo/geometry/texture-mesh/texture-mesh.ts index 0a246b3e0e29a1b49e1dfec9ef18accccbf7c01b..585a9284319c2500d79e57635191eb07b68bd7f4 100644 --- a/src/mol-geo/geometry/texture-mesh/texture-mesh.ts +++ b/src/mol-geo/geometry/texture-mesh/texture-mesh.ts @@ -7,7 +7,7 @@ import { ValueCell } from '../../../mol-util'; import { Sphere3D } from '../../../mol-math/geometry'; import { ParamDefinition as PD } from '../../../mol-util/param-definition'; -import { LocationIterator } from '../../../mol-geo/util/location-iterator'; +import { LocationIterator, PositionLocation } from '../../../mol-geo/util/location-iterator'; import { TransformData } from '../transform-data'; import { createColors } from '../color-data'; import { createMarkers } from '../marker-data'; @@ -20,11 +20,12 @@ import { createEmptyTransparency } from '../transparency-data'; import { TextureMeshValues } from '../../../mol-gl/renderable/texture-mesh'; import { calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util'; import { createNullTexture, Texture } from '../../../mol-gl/webgl/texture'; -import { Vec2, Vec4 } from '../../../mol-math/linear-algebra'; +import { Vec2, Vec3, Vec4 } from '../../../mol-math/linear-algebra'; import { createEmptyClipping } from '../clipping-data'; import { NullLocation } from '../../../mol-model/location'; import { createEmptySubstance } from '../substance-data'; import { RenderableState } from '../../../mol-gl/renderable'; +import { WebGLContext } from '../../../mol-gl/webgl/context'; export interface TextureMesh { readonly kind: 'texture-mesh', @@ -43,7 +44,10 @@ export interface TextureMesh { readonly boundingSphere: Sphere3D - readonly meta: { [k: string]: unknown } + readonly meta: { + webgl?: WebGLContext + [k: string]: unknown + } } export namespace TextureMesh { @@ -131,9 +135,42 @@ export namespace TextureMesh { updateBoundingSphere, createRenderableState, updateRenderableState, - createPositionIterator: () => LocationIterator(1, 1, 1, () => NullLocation) + createPositionIterator, }; + const TextureMeshName = 'texture-mesh'; + + function createPositionIterator(textureMesh: TextureMesh, transform: TransformData): LocationIterator { + const webgl = textureMesh.meta.webgl; + if (!webgl) return LocationIterator(1, 1, 1, () => NullLocation); + + if (!webgl.namedFramebuffers[TextureMeshName]) { + webgl.namedFramebuffers[TextureMeshName] = webgl.resources.framebuffer(); + } + const framebuffer = webgl.namedFramebuffers[TextureMeshName]; + const [width, height] = textureMesh.geoTextureDim.ref.value; + const vertices = new Float32Array(width * height * 4); + framebuffer.bind(); + textureMesh.vertexTexture.ref.value.attachFramebuffer(framebuffer, 0); + webgl.readPixels(0, 0, width, height, vertices); + + const groupCount = textureMesh.vertexCount; + const instanceCount = transform.instanceCount.ref.value; + const location = PositionLocation(); + const p = location.position; + const v = vertices; + const m = transform.aTransform.ref.value; + const getLocation = (groupIndex: number, instanceIndex: number) => { + if (instanceIndex < 0) { + Vec3.fromArray(p, v, groupIndex * 4); + } else { + Vec3.transformMat4Offset(p, v, m, 0, groupIndex * 4, instanceIndex * 16); + } + return location; + }; + return LocationIterator(groupCount, instanceCount, 1, getLocation); + } + function createValues(textureMesh: TextureMesh, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: PD.Values<Params>): TextureMeshValues { const { instanceCount, groupCount } = locationIt; const positionIt = Utils.createPositionIterator(textureMesh, transform); diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index 086f6db4086bed82767ccb56c8d8bb7bec60f58a..c41bf3283e32076853c8e4923fa59702b0364b87 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -54,6 +54,7 @@ export const enum MarkingType { interface Renderer { readonly stats: RendererStats readonly props: Readonly<RendererProps> + readonly light: Readonly<Light> clear: (toBackgroundColor: boolean, ignoreTransparentBackground?: boolean) => void clearDepth: (packed?: boolean) => void @@ -103,13 +104,13 @@ export const RendererParams = { xrayEdgeFalloff: PD.Numeric(1, { min: 0.0, max: 3.0, step: 0.1 }), light: PD.ObjectList({ - inclination: PD.Numeric(180, { min: 0, max: 180, step: 1 }), - azimuth: PD.Numeric(0, { min: 0, max: 360, step: 1 }), + inclination: PD.Numeric(150, { min: 0, max: 180, step: 1 }), + azimuth: PD.Numeric(320, { min: 0, max: 360, step: 1 }), color: PD.Color(Color.fromNormalizedRgb(1.0, 1.0, 1.0)), intensity: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }), }, o => Color.toHexString(o.color), { defaultValue: [{ - inclination: 180, - azimuth: 0, + inclination: 150, + azimuth: 320, color: Color.fromNormalizedRgb(1.0, 1.0, 1.0), intensity: 0.6 }] }), @@ -118,7 +119,7 @@ export const RendererParams = { }; export type RendererProps = PD.Values<typeof RendererParams> -type Light = { +export type Light = { count: number direction: number[] color: number[] @@ -827,6 +828,9 @@ namespace Renderer { instancedDrawCount: stats.instancedDrawCount, }; }, + get light(): Light { + return light; + }, dispose: () => { // TODO } diff --git a/src/mol-gl/shader/chunks/apply-light-color.glsl.ts b/src/mol-gl/shader/chunks/apply-light-color.glsl.ts index bddbf634b013296a098601b85406adb334e5450e..ff2036d50cdc38547483552017dae5c90274bbcc 100644 --- a/src/mol-gl/shader/chunks/apply-light-color.glsl.ts +++ b/src/mol-gl/shader/chunks/apply-light-color.glsl.ts @@ -12,7 +12,7 @@ export const apply_light_color = ` gl_FragColor = material; #else #ifdef bumpEnabled - if (uBumpFrequency > 0.0 && uBumpAmplitude > 0.0) { + if (uBumpFrequency > 0.0 && uBumpAmplitude > 0.0 && bumpiness > 0.0) { normal = perturbNormal(-vViewPosition, normal, fbm(vModelPosition * uBumpFrequency), (uBumpAmplitude * bumpiness) / uBumpFrequency); } #endif diff --git a/src/mol-gl/shader/direct-volume.frag.ts b/src/mol-gl/shader/direct-volume.frag.ts index 1b15f590f999549bfda4c25efda6a566a891ccbb..f64cf9b3c7fa93f1604f9fa53ed6c24284465c34 100644 --- a/src/mol-gl/shader/direct-volume.frag.ts +++ b/src/mol-gl/shader/direct-volume.frag.ts @@ -270,16 +270,16 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) { #elif defined(dColorType_groupInstance) material.rgb = readFromTexture(tColor, vInstance * float(uGroupCount) + group, uColorTexDim).rgb; #elif defined(dColorType_vertex) - material.rgb = texture3dFrom1dTrilinear(tColor, isoPos, uGridDim, uColorTexDim, 0.0).rgb; + material.rgb = texture3dFrom1dTrilinear(tColor, unitPos, uGridDim, uColorTexDim, 0.0).rgb; #elif defined(dColorType_vertexInstance) - material.rgb = texture3dFrom1dTrilinear(tColor, isoPos, uGridDim, uColorTexDim, vInstance * float(uVertexCount)).rgb; + material.rgb = texture3dFrom1dTrilinear(tColor, unitPos, uGridDim, uColorTexDim, vInstance * float(uVertexCount)).rgb; #endif #ifdef dOverpaint #if defined(dOverpaintType_groupInstance) overpaint = readFromTexture(tOverpaint, vInstance * float(uGroupCount) + group, uOverpaintTexDim); #elif defined(dOverpaintType_vertexInstance) - overpaint = texture3dFrom1dTrilinear(tOverpaint, isoPos, uGridDim, uOverpaintTexDim, vInstance * float(uVertexCount)); + overpaint = texture3dFrom1dTrilinear(tOverpaint, unitPos, uGridDim, uOverpaintTexDim, vInstance * float(uVertexCount)); #endif material.rgb = mix(material.rgb, overpaint.rgb, overpaint.a); diff --git a/src/mol-gl/shader/postprocessing.frag.ts b/src/mol-gl/shader/postprocessing.frag.ts index db622f416aef822a557cae32b21fd4c4fad37c79..80e9712225c6589c8e7a39eca283a7f075be7f02 100644 --- a/src/mol-gl/shader/postprocessing.frag.ts +++ b/src/mol-gl/shader/postprocessing.frag.ts @@ -14,6 +14,7 @@ uniform sampler2D tSsaoDepth; uniform sampler2D tColor; uniform sampler2D tDepthOpaque; uniform sampler2D tDepthTransparent; +uniform sampler2D tShadows; uniform sampler2D tOutlines; uniform vec2 uTexSize; @@ -124,7 +125,20 @@ void main(void) { } #endif - // outline needs to be handled after occlusion to keep them clean + #ifdef dShadowEnable + if (!isBackground(opaqueDepth)) { + viewDist = abs(getViewZ(opaqueDepth)); + fogFactor = smoothstep(uFogNear, uFogFar, viewDist); + vec4 shadow = texture2D(tShadows, coords); + if (!uTransparentBackground) { + color.rgb = mix(mix(vec3(0), uFogColor, fogFactor), color.rgb, shadow.a); + } else { + color.rgb = mix(vec3(0) * (1.0 - fogFactor), color.rgb, shadow.a); + } + } + #endif + + // outline needs to be handled after occlusion and shadow to keep them clean #ifdef dOutlineEnable float closestTexel; float outline = getOutline(coords, opaqueDepth, closestTexel); diff --git a/src/mol-gl/shader/shadows.frag.ts b/src/mol-gl/shader/shadows.frag.ts new file mode 100644 index 0000000000000000000000000000000000000000..3bdb662601b7f2188a76f1e96a6dc429b4f6fbd7 --- /dev/null +++ b/src/mol-gl/shader/shadows.frag.ts @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Ludovic Autin <ludovic.autin@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +export const shadows_frag = ` +precision highp float; +precision highp int; +precision highp sampler2D; + +#include common + +uniform sampler2D tDepth; +uniform vec2 uTexSize; +uniform vec4 uBounds; + +uniform float uNear; +uniform float uFar; + +#if dLightCount != 0 + uniform vec3 uLightDirection[dLightCount]; + uniform vec3 uLightColor[dLightCount]; +#endif + +uniform mat4 uProjection; +uniform mat4 uInvProjection; + +uniform float uMaxDistance; +uniform float uTolerance; +uniform float uBias; + +bool isBackground(const in float depth) { + return depth == 1.0; +} + +bool outsideBounds(const in vec2 p) { + return p.x < uBounds.x || p.y < uBounds.y || p.x > uBounds.z || p.y > uBounds.w; +} + +float getViewZ(const in float depth) { + #if dOrthographic == 1 + return orthographicDepthToViewZ(depth, uNear, uFar); + #else + return perspectiveDepthToViewZ(depth, uNear, uFar); + #endif +} + +float getDepth(const in vec2 coords) { + #ifdef depthTextureSupport + return texture2D(tDepth, coords).r; + #else + return unpackRGBAToDepth(texture2D(tDepth, coords)); + #endif +} + +float screenFade(const in vec2 coords) { + vec2 c = (coords - uBounds.xy) / (uBounds.zw - uBounds.xy); + vec2 fade = max(12.0 * abs(c - 0.5) - 5.0, vec2(0.0)); + return saturate(1.0 - dot(fade, fade)); +} + +// based on https://panoskarabelas.com/posts/screen_space_shadows/ +float screenSpaceShadow(const in vec3 position, const in vec3 lightDirection, const in float stepLength) { + // Ray position and direction (in view-space) + vec3 rayPos = position; + vec3 rayDir = -lightDirection; + + // Compute ray step + vec3 rayStep = rayDir * stepLength; + + // Ray march towards the light + float occlusion = 0.0; + vec4 rayCoords = vec4(0.0); + for (int i = 0; i < dSteps; ++i) { + // Step the ray + rayPos += rayStep; + + rayCoords = uProjection * vec4(rayPos, 1.0); + rayCoords.xyz = (rayCoords.xyz / rayCoords.w) * 0.5 + 0.5; + + if (outsideBounds(rayCoords.xy)) + return 1.0; + + // Compute the difference between the ray's and the camera's depth + float depth = getDepth(rayCoords.xy); + float viewZ = getViewZ(depth); + float zDelta = rayPos.z - viewZ; + + if (zDelta < uTolerance) { + occlusion = 1.0; + + // Fade out as we approach the edges of the screen + occlusion *= screenFade(rayCoords.xy); + + break; + } + } + + return 1.0 - (uBias * occlusion); +} + +void main(void) { + vec2 invTexSize = 1.0 / uTexSize; + vec2 selfCoords = gl_FragCoord.xy * invTexSize; + + float selfDepth = getDepth(selfCoords); + + if (isBackground(selfDepth)) { + gl_FragColor = vec4(0.0); + return; + } + + vec3 selfViewPos = screenSpaceToViewSpace(vec3(selfCoords, selfDepth), uInvProjection); + float stepLength = uMaxDistance / float(dSteps); + + float o = 1.0; + #if dLightCount != 0 + float sh[dLightCount]; + #pragma unroll_loop_start + for (int i = 0; i < dLightCount; ++i) { + sh[i] = screenSpaceShadow(selfViewPos, uLightDirection[i], stepLength); + o = min(o, sh[i]); + } + #pragma unroll_loop_end + #endif + + gl_FragColor = vec4(o); +} +`; \ No newline at end of file diff --git a/src/mol-io/reader/cif/schema/bird.ts b/src/mol-io/reader/cif/schema/bird.ts index 882751de4acff8ebed74b3e426dbc4f59ee924d0..8b3b3ef27158a6ebefce47d1495e48c4bf474eb6 100644 --- a/src/mol-io/reader/cif/schema/bird.ts +++ b/src/mol-io/reader/cif/schema/bird.ts @@ -1,7 +1,7 @@ /** * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * - * Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.362, IHM 1.17, MA 1.4.3. + * Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.363, IHM 1.17, MA 1.4.3. * * @author molstar/ciftools package */ diff --git a/src/mol-io/reader/cif/schema/ccd.ts b/src/mol-io/reader/cif/schema/ccd.ts index abc49e51dc51aaf171cb31f71ae68ca4197c3d2b..6a06351d09c29e5cf5c3749e9033342516df6a1d 100644 --- a/src/mol-io/reader/cif/schema/ccd.ts +++ b/src/mol-io/reader/cif/schema/ccd.ts @@ -1,7 +1,7 @@ /** * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * - * Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.362, IHM 1.17, MA 1.4.3. + * Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.363, IHM 1.17, MA 1.4.3. * * @author molstar/ciftools package */ diff --git a/src/mol-io/reader/cif/schema/mmcif.ts b/src/mol-io/reader/cif/schema/mmcif.ts index e39a178b6efb373b97f356c6f95dd134a97f6367..668c396895218173bbbe3d07ef127bb657a19a0f 100644 --- a/src/mol-io/reader/cif/schema/mmcif.ts +++ b/src/mol-io/reader/cif/schema/mmcif.ts @@ -1,7 +1,7 @@ /** * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * - * Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.362, IHM 1.17, MA 1.4.3. + * Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.363, IHM 1.17, MA 1.4.3. * * @author molstar/ciftools package */ diff --git a/src/mol-model/structure/model/types.ts b/src/mol-model/structure/model/types.ts index 216a92baa9b50480ab8c61d29f01f53db6d2ef66..9795bdb628d3948ed0a74b01d8239125366eafdd 100644 --- a/src/mol-model/structure/model/types.ts +++ b/src/mol-model/structure/model/types.ts @@ -285,6 +285,10 @@ export const AminoAcidNamesD = new Set([ ]); export const AminoAcidNames = SetUtils.unionMany(AminoAcidNamesL, AminoAcidNamesD); +export const CommonProteinCaps = new Set([ + 'NME', 'ACE' +]); + export const RnaBaseNames = new Set([ 'A', 'C', 'T', 'G', 'I', 'U', 'N' // unknown RNA base from CCD diff --git a/src/mol-model/structure/model/types/saccharides.ts b/src/mol-model/structure/model/types/saccharides.ts index 1aaa87e85bbdf3bc43fba445cee666c4045e30dd..4d33a55e2ebba997604276967e96c7a668d0f109 100644 --- a/src/mol-model/structure/model/types/saccharides.ts +++ b/src/mol-model/structure/model/types/saccharides.ts @@ -6,4 +6,4 @@ * @author molstar/cli/chem-comp-dict/create-saccharides */ -export const SaccharideNames = new Set(['145', '147', '149', '289', '291', '293', '445', '475', '491', '510', '604', '045', '05L', '07E', '07Y', '08U', '09X', '0AT', '0BD', '0H0', '0HX', '0LP', '0MK', '0NZ', '0TS', '0UB', '0V4', '0WK', '0XY', '0YT', '10M', '12E', '14T', '15L', '16F', '16G', '16O', '17T', '18D', '18O', '18T', '1AR', '1BW', '1CF', '1FT', '1GL', '1GN', '1JB', '1LL', '1NA', '1S3', '1S4', '1SD', '1X4', '20S', '20X', '22O', '22S', '23V', '24S', '25E', '26M', '26O', '26Q', '26R', '26V', '26W', '26Y', '27C', '2DG', '2DR', '2F8', '2FG', '2FL', '2FP', '2GL', '2GS', '2H5', '2HA', '2M4', '2M5', '2M8', '2OS', '2WP', '2WS', '32O', '34V', '38J', '3BU', '3CM', '3DO', '3DY', '3FM', '3GR', '3HD', '3J3', '3J4', '3LJ', '3LR', '3MF', '3MG', '3MK', '3R3', '3S6', '3SA', '3YW', '40J', '42D', '44S', '46D', '46M', '46Z', '48Z', '49A', '49S', '49T', '49V', '4AM', '4CQ', '4GC', '4GL', '4GP', '4JA', '4N2', '4NN', '4QY', '4R1', '4RS', '4SG', '4U0', '4U1', '4U2', '4UZ', '4V5', '50A', '51N', '56N', '57S', '5DI', '5GF', '5GO', '5II', '5KQ', '5KS', '5KT', '5KV', '5L2', '5L3', '5LS', '5LT', '5MM', '5N6', '5QP', '5RP', '5SA', '5SP', '5TH', '5TJ', '5TK', '5TM', '61J', '62I', '64K', '66O', '6BG', '6C2', '6DM', '6GB', '6GP', '6GR', '6K3', '6KH', '6KL', '6KS', '6KU', '6KW', '6LA', '6LS', '6LW', '6MJ', '6MN', '6PG', '6PY', '6PZ', '6S2', '6SA', '6UD', '6Y6', '6YR', '6ZC', '73E', '79J', '7CV', '7D1', '7GP', '7JZ', '7K2', '7K3', '7NU', '7SA', '83Y', '89Y', '8B7', '8B9', '8EX', '8GA', '8GG', '8GP', '8LM', '8LR', '8OQ', '8PK', '8S0', '8YV', '95Z', '96O', '9AM', '9C1', '9CD', '9GP', '9KJ', '9MR', '9OK', '9PG', '9QG', '9QZ', '9S7', '9SG', '9SJ', '9SM', '9SP', '9T1', '9T7', '9VP', '9WJ', '9WN', '9WZ', '9YW', 'A0K', 'A1Q', 'A2G', 'A5C', 'A6P', 'AAL', 'AAO', 'ABC', 'ABD', 'ABE', 'ABF', 'ABL', 'AC1', 'ACG', 'ACR', 'ACX', 'ADA', 'ADG', 'ADR', 'AF1', 'AFD', 'AFL', 'AFO', 'AFP', 'AFR', 'AGC', 'AGH', 'AGL', 'AGR', 'AH2', 'AH8', 'AHG', 'AHM', 'AHR', 'AIG', 'ALL', 'ALX', 'AMG', 'AMN', 'AMU', 'AMV', 'ANA', 'AOG', 'AOS', 'AQA', 'ARA', 'ARB', 'ARE', 'ARI', 'ARW', 'ASC', 'ASG', 'ASO', 'AXP', 'AXR', 'AY9', 'AZC', 'B0D', 'B16', 'B1H', 'B1N', 'B2G', 'B4G', 'B6D', 'B7G', 'B8D', 'B9D', 'BBK', 'BBV', 'BCD', 'BCW', 'BDF', 'BDG', 'BDP', 'BDR', 'BDZ', 'BEM', 'BFN', 'BFP', 'BG6', 'BG8', 'BGC', 'BGL', 'BGN', 'BGP', 'BGS', 'BHG', 'BM3', 'BM7', 'BMA', 'BMX', 'BND', 'BNG', 'BNX', 'BO1', 'BOG', 'BQY', 'BRI', 'BS7', 'BTG', 'BTU', 'BW3', 'BWG', 'BXF', 'BXP', 'BXX', 'BXY', 'BZD', 'C3B', 'C3G', 'C3X', 'C4B', 'C4W', 'C4X', 'C5X', 'CAP', 'CBF', 'CBI', 'CBK', 'CDR', 'CE5', 'CE6', 'CE8', 'CEG', 'CEX', 'CEY', 'CEZ', 'CGF', 'CJB', 'CKB', 'CKP', 'CNP', 'CR1', 'CR6', 'CRA', 'CT3', 'CTO', 'CTR', 'CTT', 'D0N', 'D1M', 'D5E', 'D6G', 'DAF', 'DAG', 'DAN', 'DDA', 'DDB', 'DDL', 'DEG', 'DEL', 'DFR', 'DFX', 'DG0', 'DGC', 'DGD', 'DGM', 'DGO', 'DGS', 'DGU', 'DIG', 'DJB', 'DJE', 'DK4', 'DKX', 'DKZ', 'DL6', 'DLD', 'DLF', 'DLG', 'DMU', 'DNO', 'DO8', 'DOM', 'DP5', 'DPC', 'DQQ', 'DQR', 'DR2', 'DR3', 'DR4', 'DR5', 'DRI', 'DSR', 'DT6', 'DVC', 'DYM', 'E3M', 'E4P', 'E5G', 'EAG', 'EBG', 'EBQ', 'EEN', 'EEQ', 'EGA', 'EJT', 'EMP', 'EMZ', 'EPG', 'EQP', 'EQV', 'ERE', 'ERI', 'ETT', 'EUS', 'F1P', 'F1X', 'F55', 'F58', 'F6P', 'F8X', 'FBP', 'FCA', 'FCB', 'FCT', 'FDP', 'FDQ', 'FFC', 'FFX', 'FIF', 'FIX', 'FK9', 'FKD', 'FMF', 'FMO', 'FNG', 'FNY', 'FRU', 'FSA', 'FSI', 'FSM', 'FSR', 'FSW', 'FU4', 'FUB', 'FUC', 'FUD', 'FUF', 'FUL', 'FUY', 'FVQ', 'FX1', 'FYJ', 'G0S', 'G16', 'G1P', 'G20', 'G28', 'G2F', 'G3F', 'G3I', 'G4D', 'G4S', 'G6D', 'G6P', 'G6S', 'G7P', 'G8Z', 'GAA', 'GAC', 'GAD', 'GAF', 'GAL', 'GAT', 'GBH', 'GC1', 'GC4', 'GC9', 'GCB', 'GCD', 'GCN', 'GCO', 'GCS', 'GCT', 'GCU', 'GCV', 'GCW', 'GDA', 'GDL', 'GE1', 'GE3', 'GFP', 'GIV', 'GL0', 'GL1', 'GL2', 'GL4', 'GL5', 'GL6', 'GL7', 'GL9', 'GLA', 'GLB', 'GLC', 'GLD', 'GLF', 'GLG', 'GLO', 'GLP', 'GLS', 'GLT', 'GLW', 'GM0', 'GMB', 'GMH', 'GMT', 'GMZ', 'GN1', 'GN4', 'GNS', 'GNX', 'GP0', 'GP1', 'GP4', 'GPH', 'GPK', 'GPM', 'GPO', 'GPQ', 'GPU', 'GPV', 'GPW', 'GQ1', 'GRF', 'GRX', 'GS1', 'GS4', 'GS9', 'GSA', 'GSD', 'GTE', 'GTH', 'GTK', 'GTM', 'GTR', 'GU0', 'GU1', 'GU2', 'GU3', 'GU4', 'GU5', 'GU6', 'GU8', 'GU9', 'GUF', 'GUL', 'GUP', 'GUZ', 'GXL', 'GXV', 'GYE', 'GYG', 'GYP', 'GYU', 'GYV', 'GZL', 'H1M', 'H1S', 'H2P', 'H3S', 'H53', 'H6Q', 'H6Z', 'HBZ', 'HD4', 'HDL', 'HMS', 'HNV', 'HNW', 'HSG', 'HSH', 'HSJ', 'HSQ', 'HSR', 'HSU', 'HSX', 'HSY', 'HSZ', 'HTG', 'HTM', 'I57', 'IAB', 'IDC', 'IDF', 'IDG', 'IDR', 'IDS', 'IDT', 'IDU', 'IDX', 'IDY', 'IEM', 'IN1', 'IPT', 'ISD', 'ISL', 'ISX', 'IXD', 'J5B', 'JFZ', 'JHM', 'JLT', 'JRV', 'JS2', 'JSV', 'JV4', 'JVA', 'JVS', 'JZR', 'K5B', 'K99', 'KBA', 'KBG', 'KD5', 'KDA', 'KDB', 'KDD', 'KDE', 'KDF', 'KDM', 'KDN', 'KDO', 'KDR', 'KFN', 'KG1', 'KGM', 'KHP', 'KME', 'KO1', 'KO2', 'KOT', 'KTU', 'L1L', 'L6S', 'L6T', 'LAG', 'LAH', 'LAI', 'LAK', 'LAO', 'LAT', 'LB2', 'LBS', 'LBT', 'LCN', 'LDY', 'LEC', 'LER', 'LFC', 'LFR', 'LGC', 'LGU', 'LKA', 'LKS', 'LM2', 'LMO', 'LMT', 'LMU', 'LNV', 'LOG', 'LOX', 'LPK', 'LRH', 'LSM', 'LTG', 'LTM', 'LVO', 'LVZ', 'LXB', 'LXC', 'LXZ', 'LZ0', 'M1F', 'M1P', 'M2F', 'M3M', 'M3N', 'M55', 'M6D', 'M6P', 'M7B', 'M7P', 'M8C', 'MA1', 'MA2', 'MA3', 'MA8', 'MAB', 'MAF', 'MAG', 'MAL', 'MAN', 'MAT', 'MAV', 'MAW', 'MBE', 'MBF', 'MBG', 'MCU', 'MDA', 'MDP', 'MFA', 'MFB', 'MFU', 'MG5', 'MGA', 'MGC', 'MGL', 'MGS', 'MJJ', 'MLB', 'MLR', 'MMA', 'MMN', 'MN0', 'MNA', 'MQG', 'MQT', 'MRH', 'MRP', 'MSX', 'MTT', 'MUB', 'MUG', 'MUR', 'MVP', 'MXY', 'MXZ', 'MYG', 'N1L', 'N9S', 'NA1', 'NAA', 'NAG', 'NBG', 'NBX', 'NBY', 'NDG', 'NED', 'NFG', 'NG1', 'NG6', 'NGA', 'NGB', 'NGC', 'NGE', 'NGF', 'NGK', 'NGL', 'NGR', 'NGS', 'NGY', 'NGZ', 'NHF', 'NLC', 'NM6', 'NM9', 'NNG', 'NPF', 'NSQ', 'NT1', 'NTF', 'NTO', 'NTP', 'NXD', 'NYT', 'O1G', 'OAK', 'OEL', 'OI7', 'OPM', 'ORP', 'OSU', 'OTG', 'OTN', 'OTU', 'OX2', 'P53', 'P6P', 'P8E', 'PA1', 'PA5', 'PAV', 'PDX', 'PH5', 'PKM', 'PNA', 'PNG', 'PNJ', 'PNW', 'PPC', 'PRP', 'PSG', 'PSJ', 'PSV', 'PTQ', 'PUF', 'PZU', 'QDK', 'QIF', 'QKH', 'QPS', 'QV4', 'R1P', 'R1X', 'R2B', 'R2G', 'R5P', 'RAA', 'RAE', 'RAF', 'RAM', 'RAO', 'RAT', 'RB5', 'RBL', 'RCD', 'RDP', 'REL', 'RER', 'RF5', 'RG1', 'RGG', 'RHA', 'RHC', 'RI2', 'RIB', 'RIP', 'RM4', 'RNS', 'RNT', 'ROB', 'ROR', 'RP3', 'RP5', 'RP6', 'RPA', 'RR7', 'RRJ', 'RRY', 'RST', 'RTG', 'RTV', 'RUB', 'RUG', 'RUU', 'RV7', 'RVG', 'RVM', 'RWI', 'RY7', 'RZM', 'S6P', 'S7P', 'S81', 'SA0', 'SCG', 'SCR', 'SDD', 'SDY', 'SEJ', 'SF6', 'SF9', 'SFJ', 'SFU', 'SG4', 'SG5', 'SG6', 'SG7', 'SGA', 'SGC', 'SGD', 'SGN', 'SGS', 'SHB', 'SHD', 'SHG', 'SI3', 'SIA', 'SID', 'SIO', 'SIZ', 'SLB', 'SLM', 'SLT', 'SMD', 'SN5', 'SNG', 'SOE', 'SOG', 'SOL', 'SOR', 'SR1', 'SSG', 'SSH', 'STW', 'STZ', 'SUC', 'SUP', 'SUS', 'SWE', 'SZZ', 'T68', 'T6D', 'T6P', 'T6T', 'TA6', 'TAG', 'TCB', 'TCG', 'TDG', 'TEU', 'TF0', 'TFU', 'TGA', 'TGK', 'TGR', 'TGY', 'TH1', 'TM5', 'TM6', 'TM9', 'TMR', 'TMX', 'TNX', 'TOA', 'TOC', 'TQY', 'TRE', 'TRV', 'TS8', 'TT7', 'TTV', 'TTZ', 'TU4', 'TUG', 'TUJ', 'TUP', 'TUR', 'TVD', 'TVG', 'TVM', 'TVS', 'TVV', 'TVY', 'TW7', 'TWA', 'TWD', 'TWG', 'TWJ', 'TWY', 'TXB', 'TYV', 'U1Y', 'U2A', 'U2D', 'U63', 'U8V', 'U97', 'U9A', 'U9D', 'U9G', 'U9J', 'U9M', 'UAP', 'UCD', 'UDC', 'UEA', 'V3M', 'V3P', 'V71', 'VG1', 'VJ1', 'VJ4', 'VKN', 'VTB', 'W9T', 'WIA', 'WOO', 'WUN', 'WZ1', 'WZ2', 'WZ4', 'X0X', 'X1P', 'X1X', 'X2F', 'X2Y', 'X34', 'X4S', 'X5S', 'X6X', 'X6Y', 'XBP', 'XDP', 'XDX', 'XGP', 'XIL', 'XKJ', 'XLF', 'XLS', 'XMM', 'XS2', 'XUL', 'XXM', 'XXR', 'XXX', 'XYB', 'XYF', 'XYL', 'XYP', 'XYS', 'XYT', 'XYZ', 'YDR', 'YIO', 'YJM', 'YKR', 'YO5', 'YX0', 'YX1', 'YYB', 'YYH', 'YYJ', 'YYK', 'YYM', 'YYQ', 'YYR', 'YZ0', 'YZT', 'Z0F', 'Z15', 'Z16', 'Z2D', 'Z2T', 'Z3K', 'Z3L', 'Z3Q', 'Z3U', 'Z4K', 'Z4R', 'Z4S', 'Z4U', 'Z4V', 'Z4W', 'Z4Y', 'Z57', 'Z5J', 'Z5L', 'Z61', 'Z6H', 'Z6J', 'Z6W', 'Z8H', 'Z8T', 'Z9D', 'Z9E', 'Z9H', 'Z9K', 'Z9L', 'Z9M', 'Z9N', 'Z9W', 'ZB0', 'ZB1', 'ZB2', 'ZB3', 'ZCD', 'ZCZ', 'ZD0', 'ZDC', 'ZDM', 'ZDO', 'ZEE', 'ZEL', 'ZGE', 'ZMR', 'UMQ', 'SQD']); +export const SaccharideNames = new Set(['145', '147', '149', '289', '291', '293', '445', '475', '491', '510', '604', '045', '05L', '07E', '07Y', '08U', '09X', '0AT', '0BD', '0H0', '0HX', '0LP', '0MK', '0NZ', '0TS', '0UB', '0V4', '0WK', '0XY', '0YT', '10M', '12E', '14T', '15L', '16F', '16G', '16O', '17T', '18D', '18O', '18T', '1AR', '1BW', '1CF', '1FT', '1GL', '1GN', '1JB', '1LL', '1NA', '1S3', '1S4', '1SD', '1X4', '20S', '20X', '22O', '22S', '23V', '24S', '25E', '26M', '26O', '26Q', '26R', '26V', '26W', '26Y', '27C', '2DG', '2DR', '2F8', '2FG', '2FL', '2FP', '2GL', '2GS', '2H5', '2HA', '2M4', '2M5', '2M8', '2OS', '2WP', '2WS', '32O', '34V', '38J', '3BU', '3CM', '3DO', '3DY', '3FM', '3GR', '3HD', '3J3', '3J4', '3LJ', '3LR', '3MF', '3MG', '3MK', '3R3', '3S6', '3SA', '3YW', '40J', '42D', '44S', '46D', '46M', '46Z', '48Z', '49A', '49S', '49T', '49V', '4AM', '4CQ', '4GC', '4GL', '4GP', '4JA', '4N2', '4NN', '4QY', '4R1', '4RS', '4SG', '4U0', '4U1', '4U2', '4UZ', '4V5', '50A', '51N', '56N', '57S', '5DI', '5GF', '5GO', '5II', '5KQ', '5KS', '5KT', '5KV', '5L2', '5L3', '5LS', '5LT', '5MM', '5N6', '5QP', '5RP', '5SA', '5SP', '5TH', '5TJ', '5TK', '5TM', '61J', '62I', '64K', '66O', '6BG', '6C2', '6DM', '6GB', '6GP', '6GR', '6K3', '6KH', '6KL', '6KS', '6KU', '6KW', '6LA', '6LS', '6LW', '6MJ', '6MN', '6PG', '6PY', '6PZ', '6S2', '6SA', '6UD', '6Y6', '6YR', '6ZC', '73E', '79J', '7CV', '7D1', '7GP', '7JZ', '7K2', '7K3', '7NU', '7SA', '83Y', '89Y', '8B7', '8B9', '8EX', '8GA', '8GG', '8GP', '8I4', '8LM', '8LR', '8OQ', '8PK', '8S0', '8YV', '95Z', '96O', '98U', '9AM', '9C1', '9CD', '9GP', '9KJ', '9MR', '9OK', '9PG', '9QG', '9QZ', '9S7', '9SG', '9SJ', '9SM', '9SP', '9T1', '9T7', '9VP', '9WJ', '9WN', '9WZ', '9YW', 'A0K', 'A1Q', 'A2G', 'A5C', 'A6P', 'AAL', 'AAO', 'ABC', 'ABD', 'ABE', 'ABF', 'ABL', 'AC1', 'ACG', 'ACR', 'ACX', 'ADA', 'ADG', 'ADR', 'AF1', 'AFD', 'AFL', 'AFO', 'AFP', 'AFR', 'AGC', 'AGH', 'AGL', 'AGR', 'AH2', 'AH8', 'AHG', 'AHM', 'AHR', 'AIG', 'ALL', 'ALX', 'AMG', 'AMN', 'AMU', 'AMV', 'ANA', 'AOG', 'AOS', 'AQA', 'ARA', 'ARB', 'ARE', 'ARI', 'ARW', 'ASC', 'ASG', 'ASO', 'AXP', 'AXR', 'AY9', 'AZC', 'B0D', 'B16', 'B1H', 'B1N', 'B2G', 'B4G', 'B6D', 'B7G', 'B8D', 'B9D', 'BBK', 'BBV', 'BCD', 'BCW', 'BDF', 'BDG', 'BDP', 'BDR', 'BDZ', 'BEM', 'BFN', 'BFP', 'BG6', 'BG8', 'BGC', 'BGL', 'BGN', 'BGP', 'BGS', 'BHG', 'BM3', 'BM7', 'BMA', 'BMX', 'BND', 'BNG', 'BNX', 'BO1', 'BOG', 'BQY', 'BRI', 'BS7', 'BTG', 'BTU', 'BW3', 'BWG', 'BXF', 'BXP', 'BXX', 'BXY', 'BZD', 'C3B', 'C3G', 'C3X', 'C4B', 'C4W', 'C4X', 'C5X', 'CAP', 'CBF', 'CBI', 'CBK', 'CDR', 'CE5', 'CE6', 'CE8', 'CEG', 'CEX', 'CEY', 'CEZ', 'CGF', 'CJB', 'CKB', 'CKP', 'CNP', 'CR1', 'CR6', 'CRA', 'CT3', 'CTO', 'CTR', 'CTT', 'D0N', 'D1M', 'D5E', 'D6G', 'DAF', 'DAG', 'DAN', 'DDA', 'DDB', 'DDL', 'DEG', 'DEL', 'DFR', 'DFX', 'DG0', 'DGC', 'DGD', 'DGM', 'DGO', 'DGS', 'DGU', 'DIG', 'DJB', 'DJE', 'DK4', 'DKX', 'DKZ', 'DL6', 'DLD', 'DLF', 'DLG', 'DMU', 'DNO', 'DO8', 'DOM', 'DP5', 'DPC', 'DQQ', 'DQR', 'DR2', 'DR3', 'DR4', 'DR5', 'DRI', 'DSR', 'DT6', 'DVC', 'DYM', 'E3M', 'E4P', 'E5G', 'EAG', 'EBG', 'EBQ', 'EEN', 'EEQ', 'EGA', 'EJT', 'EMP', 'EMZ', 'EPG', 'EQP', 'EQV', 'ERE', 'ERI', 'ETT', 'EUS', 'F1P', 'F1X', 'F55', 'F58', 'F6P', 'F8X', 'FBP', 'FCA', 'FCB', 'FCT', 'FDP', 'FDQ', 'FFC', 'FFX', 'FIF', 'FIX', 'FK9', 'FKD', 'FMF', 'FMO', 'FNG', 'FNY', 'FRU', 'FSA', 'FSI', 'FSM', 'FSR', 'FSW', 'FU4', 'FUB', 'FUC', 'FUD', 'FUF', 'FUL', 'FUY', 'FVQ', 'FX1', 'FYJ', 'G0S', 'G16', 'G1P', 'G20', 'G28', 'G2F', 'G3F', 'G3I', 'G4D', 'G4S', 'G6D', 'G6P', 'G6S', 'G7P', 'G8Z', 'GAA', 'GAC', 'GAD', 'GAF', 'GAL', 'GAT', 'GBH', 'GC1', 'GC4', 'GC9', 'GCB', 'GCD', 'GCN', 'GCO', 'GCS', 'GCT', 'GCU', 'GCV', 'GCW', 'GDA', 'GDL', 'GE1', 'GE3', 'GFP', 'GIV', 'GL0', 'GL1', 'GL2', 'GL4', 'GL5', 'GL6', 'GL7', 'GL9', 'GLA', 'GLB', 'GLC', 'GLD', 'GLF', 'GLG', 'GLO', 'GLP', 'GLS', 'GLT', 'GLW', 'GM0', 'GMB', 'GMH', 'GMT', 'GMZ', 'GN1', 'GN4', 'GNS', 'GNX', 'GP0', 'GP1', 'GP4', 'GPH', 'GPK', 'GPM', 'GPO', 'GPQ', 'GPU', 'GPV', 'GPW', 'GQ1', 'GRF', 'GRX', 'GS1', 'GS4', 'GS9', 'GSA', 'GSD', 'GTE', 'GTH', 'GTK', 'GTM', 'GTR', 'GU0', 'GU1', 'GU2', 'GU3', 'GU4', 'GU5', 'GU6', 'GU8', 'GU9', 'GUF', 'GUL', 'GUP', 'GUZ', 'GXL', 'GXV', 'GYE', 'GYG', 'GYP', 'GYU', 'GYV', 'GZL', 'H1M', 'H1S', 'H2P', 'H3S', 'H53', 'H6Q', 'H6Z', 'HBZ', 'HD4', 'HDL', 'HMS', 'HNV', 'HNW', 'HSG', 'HSH', 'HSJ', 'HSQ', 'HSR', 'HSU', 'HSX', 'HSY', 'HSZ', 'HTG', 'HTM', 'HVC', 'I57', 'IAB', 'IDC', 'IDF', 'IDG', 'IDR', 'IDS', 'IDT', 'IDU', 'IDX', 'IDY', 'IEM', 'IN1', 'IPT', 'ISD', 'ISL', 'ISX', 'IXD', 'J5B', 'JFZ', 'JHM', 'JLT', 'JRV', 'JS2', 'JSV', 'JV4', 'JVA', 'JVS', 'JZR', 'K5B', 'K99', 'KBA', 'KBG', 'KD5', 'KDA', 'KDB', 'KDD', 'KDE', 'KDF', 'KDM', 'KDN', 'KDO', 'KDR', 'KFN', 'KG1', 'KGM', 'KHP', 'KME', 'KO1', 'KO2', 'KOT', 'KTU', 'L1L', 'L6S', 'L6T', 'LAG', 'LAH', 'LAI', 'LAK', 'LAO', 'LAT', 'LB2', 'LBS', 'LBT', 'LCN', 'LDY', 'LEC', 'LER', 'LFC', 'LFR', 'LGC', 'LGU', 'LKA', 'LKS', 'LM2', 'LMO', 'LMT', 'LMU', 'LNV', 'LOG', 'LOX', 'LPK', 'LRH', 'LSM', 'LTG', 'LTM', 'LVO', 'LVZ', 'LXB', 'LXC', 'LXZ', 'LZ0', 'M1F', 'M1P', 'M2F', 'M3M', 'M3N', 'M55', 'M6D', 'M6P', 'M7B', 'M7P', 'M8C', 'MA1', 'MA2', 'MA3', 'MA8', 'MAB', 'MAF', 'MAG', 'MAL', 'MAN', 'MAT', 'MAV', 'MAW', 'MBE', 'MBF', 'MBG', 'MCU', 'MDA', 'MDP', 'MFA', 'MFB', 'MFU', 'MG5', 'MGA', 'MGC', 'MGL', 'MGS', 'MJJ', 'MLB', 'MLR', 'MMA', 'MMN', 'MN0', 'MNA', 'MQG', 'MQT', 'MRH', 'MRP', 'MSX', 'MTT', 'MUB', 'MUG', 'MUR', 'MVP', 'MXY', 'MXZ', 'MYG', 'N1L', 'N3U', 'N9S', 'NA1', 'NAA', 'NAG', 'NBG', 'NBX', 'NBY', 'NDG', 'NED', 'NFG', 'NG1', 'NG6', 'NGA', 'NGB', 'NGC', 'NGE', 'NGF', 'NGK', 'NGL', 'NGR', 'NGS', 'NGY', 'NGZ', 'NHF', 'NLC', 'NM6', 'NM9', 'NNG', 'NPF', 'NSQ', 'NT1', 'NTF', 'NTO', 'NTP', 'NXD', 'NYT', 'O1G', 'OAK', 'OEL', 'OI7', 'OPM', 'ORP', 'OSU', 'OTG', 'OTN', 'OTU', 'OX2', 'P53', 'P6P', 'P8E', 'PA1', 'PA5', 'PAV', 'PDX', 'PH5', 'PKM', 'PNA', 'PNG', 'PNJ', 'PNW', 'PPC', 'PRP', 'PSG', 'PSJ', 'PSV', 'PTQ', 'PUF', 'PZU', 'QDK', 'QIF', 'QKH', 'QPS', 'QV4', 'R1P', 'R1X', 'R2B', 'R2G', 'R5P', 'RAA', 'RAE', 'RAF', 'RAM', 'RAO', 'RAT', 'RB5', 'RBL', 'RCD', 'RDP', 'REL', 'RER', 'RF5', 'RG1', 'RGG', 'RHA', 'RHC', 'RI2', 'RIB', 'RIP', 'RM4', 'RNS', 'RNT', 'ROB', 'ROR', 'RP3', 'RP5', 'RP6', 'RPA', 'RR7', 'RRJ', 'RRY', 'RST', 'RTG', 'RTV', 'RUB', 'RUG', 'RUU', 'RV7', 'RVG', 'RVM', 'RWI', 'RY7', 'RZM', 'S6P', 'S7P', 'S81', 'SA0', 'SCG', 'SCR', 'SDD', 'SDY', 'SEJ', 'SF6', 'SF9', 'SFJ', 'SFU', 'SG4', 'SG5', 'SG6', 'SG7', 'SGA', 'SGC', 'SGD', 'SGN', 'SGS', 'SHB', 'SHD', 'SHG', 'SI3', 'SIA', 'SID', 'SIO', 'SIZ', 'SLB', 'SLM', 'SLT', 'SMD', 'SN5', 'SNG', 'SOE', 'SOG', 'SOL', 'SOR', 'SR1', 'SSG', 'SSH', 'STW', 'STZ', 'SUC', 'SUP', 'SUS', 'SWE', 'SZZ', 'T68', 'T6D', 'T6P', 'T6T', 'TA6', 'TAG', 'TCB', 'TCG', 'TDG', 'TEU', 'TF0', 'TFU', 'TGA', 'TGK', 'TGR', 'TGY', 'TH1', 'TM5', 'TM6', 'TM9', 'TMR', 'TMX', 'TNX', 'TOA', 'TOC', 'TQY', 'TRE', 'TRV', 'TS8', 'TT7', 'TTV', 'TTZ', 'TU4', 'TUG', 'TUJ', 'TUP', 'TUR', 'TVD', 'TVG', 'TVM', 'TVS', 'TVV', 'TVY', 'TW7', 'TWA', 'TWD', 'TWG', 'TWJ', 'TWY', 'TXB', 'TYV', 'U1Y', 'U2A', 'U2D', 'U63', 'U8V', 'U97', 'U9A', 'U9D', 'U9G', 'U9J', 'U9M', 'UAP', 'UBH', 'UBO', 'UCD', 'UDC', 'UEA', 'V3M', 'V3P', 'V71', 'VG1', 'VJ1', 'VJ4', 'VKN', 'VTB', 'W9T', 'WIA', 'WOO', 'WUN', 'WZ1', 'WZ2', 'WZ4', 'X0X', 'X1P', 'X1X', 'X2F', 'X2Y', 'X34', 'X4S', 'X5S', 'X6X', 'X6Y', 'XBP', 'XDP', 'XDX', 'XGP', 'XIL', 'XKJ', 'XLF', 'XLS', 'XMM', 'XS2', 'XUL', 'XXM', 'XXR', 'XXX', 'XYB', 'XYF', 'XYL', 'XYP', 'XYS', 'XYT', 'XYZ', 'YDR', 'YIO', 'YJM', 'YKR', 'YO5', 'YX0', 'YX1', 'YYB', 'YYH', 'YYJ', 'YYK', 'YYM', 'YYQ', 'YYR', 'YZ0', 'YZT', 'Z0F', 'Z15', 'Z16', 'Z2D', 'Z2T', 'Z3K', 'Z3L', 'Z3Q', 'Z3U', 'Z4K', 'Z4R', 'Z4S', 'Z4U', 'Z4V', 'Z4W', 'Z4Y', 'Z57', 'Z5J', 'Z5L', 'Z61', 'Z6H', 'Z6J', 'Z6W', 'Z8H', 'Z8T', 'Z9D', 'Z9E', 'Z9H', 'Z9K', 'Z9L', 'Z9M', 'Z9N', 'Z9W', 'ZB0', 'ZB1', 'ZB2', 'ZB3', 'ZCD', 'ZCZ', 'ZD0', 'ZDC', 'ZDM', 'ZDO', 'ZEE', 'ZEL', 'ZGE', 'ZMR', 'UMQ', 'SQD']); diff --git a/src/mol-plugin-state/helpers/structure-selection-query.ts b/src/mol-plugin-state/helpers/structure-selection-query.ts index 8f7edc975b02a2b3b3f4f6df2ec026f7ca552b65..169781fa6360b7c858963a574d27c5e18d5d0165 100644 --- a/src/mol-plugin-state/helpers/structure-selection-query.ts +++ b/src/mol-plugin-state/helpers/structure-selection-query.ts @@ -7,7 +7,7 @@ import { CustomProperty } from '../../mol-model-props/common/custom-property'; import { QueryContext, Structure, StructureQuery, StructureSelection, StructureProperties, StructureElement } from '../../mol-model/structure'; -import { BondType, NucleicBackboneAtoms, ProteinBackboneAtoms, SecondaryStructureType, AminoAcidNamesL, RnaBaseNames, DnaBaseNames, WaterNames, ElementSymbol, PolymerNames } from '../../mol-model/structure/model/types'; +import { BondType, NucleicBackboneAtoms, ProteinBackboneAtoms, SecondaryStructureType, AminoAcidNamesL, RnaBaseNames, DnaBaseNames, WaterNames, ElementSymbol, PolymerNames, CommonProteinCaps } from '../../mol-model/structure/model/types'; import { PluginContext } from '../../mol-plugin/context'; import { MolScriptBuilder as MS } from '../../mol-script/language/builder'; import { Expression } from '../../mol-script/language/expression'; @@ -350,14 +350,23 @@ const ligand = StructureSelectionQuery('Ligand', MS.struct.modifier.union([ ]) ]), ]), - by: MS.struct.modifier.union([ + by: MS.struct.combinator.merge([ + MS.struct.modifier.union([ + MS.struct.generator.atomGroups({ + 'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']), + 'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']), + 'residue-test': MS.core.set.has([ + MS.set(...SetUtils.toArray(PolymerNames)), MS.ammp('label_comp_id') + ]) + }), + ]), MS.struct.generator.atomGroups({ - 'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']), 'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']), 'residue-test': MS.core.set.has([ - MS.set(...SetUtils.toArray(PolymerNames)), MS.ammp('label_comp_id') - ]) - }) + MS.set(...SetUtils.toArray(CommonProteinCaps)), + MS.ammp('label_comp_id'), + ]), + }), ]) }) ]), { category: StructureSelectionCategory.Type }); diff --git a/src/mol-plugin-ui/controls/parameters.tsx b/src/mol-plugin-ui/controls/parameters.tsx index 4a59801972ee5f62b538f035d5bd5560cb676646..1d7cf96da53279b4e1a714ba289b82eb079ddd9d 100644 --- a/src/mol-plugin-ui/controls/parameters.tsx +++ b/src/mol-plugin-ui/controls/parameters.tsx @@ -18,7 +18,7 @@ import { getPrecision } from '../../mol-util/number'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { ParamMapping } from '../../mol-util/param-mapping'; import { camelCaseToWords } from '../../mol-util/string'; -import { PluginUIComponent } from '../base'; +import { PluginReactContext, PluginUIComponent } from '../base'; import { PluginUIContext } from '../context'; import { ActionMenu } from './action-menu'; import { ColorOptions, ColorValueOption, CombinedColorControl } from './color'; @@ -505,10 +505,12 @@ export class ValueRefControl extends React.PureComponent<ParamProps<PD.ValueRef< toggle = () => this.setState({ showOptions: !this.state.showOptions }); - items = memoizeLatest((param: PD.ValueRef) => ActionMenu.createItemsFromSelectOptions(param.getOptions())); + private get items() { + return ActionMenu.createItemsFromSelectOptions(this.props.param.getOptions(this.context)); + } renderControl() { - const items = this.items(this.props.param); + const items = this.items; const current = this.props.value.ref ? ActionMenu.findItem(items, this.props.value.ref) : void 0; const label = current ? current.label @@ -521,7 +523,7 @@ export class ValueRefControl extends React.PureComponent<ParamProps<PD.ValueRef< renderAddOn() { if (!this.state.showOptions) return null; - const items = this.items(this.props.param); + const items = this.items; const current = ActionMenu.findItem(items, this.props.value.ref); return <ActionMenu items={items} current={current} onSelect={this.onSelect} />; @@ -539,6 +541,7 @@ export class ValueRefControl extends React.PureComponent<ParamProps<PD.ValueRef< }); } } +ValueRefControl.contextType = PluginReactContext; export class IntervalControl extends React.PureComponent<ParamProps<PD.Interval>, { isExpanded: boolean }> { state = { isExpanded: false }; diff --git a/src/mol-plugin-ui/structure/quick-styles.tsx b/src/mol-plugin-ui/structure/quick-styles.tsx index 49bbb19a17267277e2785270521f55b6155030ff..27bda32a3ba4376210c13b00bc3345ef35bca922 100644 --- a/src/mol-plugin-ui/structure/quick-styles.tsx +++ b/src/mol-plugin-ui/structure/quick-styles.tsx @@ -62,6 +62,7 @@ export class QuickStyles extends PurePluginUIComponent { name: 'on', params: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1 } }, + shadow: { name: 'off', params: {} }, } }); } @@ -86,6 +87,7 @@ export class QuickStyles extends PurePluginUIComponent { ? pp.occlusion.params : { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1 } }, + shadow: { name: 'off', params: {} }, } }); } diff --git a/src/mol-plugin-ui/viewport/simple-settings.tsx b/src/mol-plugin-ui/viewport/simple-settings.tsx index a3f7eb6d939a26fb0db47839521823779989c94f..ddf7fcf54304c5503f428ec8b31c42e488a832e8 100644 --- a/src/mol-plugin-ui/viewport/simple-settings.tsx +++ b/src/mol-plugin-ui/viewport/simple-settings.tsx @@ -59,6 +59,7 @@ const SimpleSettingsParams = { }, { pivot: 'color' }), lighting: PD.Group({ occlusion: Canvas3DParams.postprocessing.params.occlusion, + shadow: Canvas3DParams.postprocessing.params.shadow, outline: Canvas3DParams.postprocessing.params.outline, fog: Canvas3DParams.cameraFog, }, { isFlat: true }), @@ -114,6 +115,7 @@ const SimpleSettingsMapping = ParamMapping({ }, lighting: { occlusion: canvas.postprocessing.occlusion, + shadow: canvas.postprocessing.shadow, outline: canvas.postprocessing.outline, fog: canvas.cameraFog, }, @@ -129,6 +131,7 @@ const SimpleSettingsMapping = ParamMapping({ canvas.transparentBackground = s.background.transparent; canvas.renderer.backgroundColor = s.background.color; canvas.postprocessing.occlusion = s.lighting.occlusion; + canvas.postprocessing.shadow = s.lighting.shadow; canvas.postprocessing.outline = s.lighting.outline; canvas.postprocessing.background = s.background.style; canvas.cameraFog = s.lighting.fog; diff --git a/src/mol-plugin/config.ts b/src/mol-plugin/config.ts index 8d097a20047244701bc05f203d6764ecc7ef274c..11ccf25798e2e9c5fe07f8a93a249ae6d530db10 100644 --- a/src/mol-plugin/config.ts +++ b/src/mol-plugin/config.ts @@ -37,6 +37,7 @@ export const PluginConfig = { // TODO: check back in a few weeks to see if it was fixed PreferWebGl1: item('plugin-config.prefer-webgl1', PluginFeatureDetection.preferWebGl1), AllowMajorPerformanceCaveat: item('plugin-config.allow-major-performance-caveat', false), + PowerPreference: item<WebGLContextAttributes['powerPreference']>('plugin-config.power-preference', 'high-performance'), }, State: { DefaultServer: item('plugin-state.server', 'https://webchem.ncbr.muni.cz/molstar-state'), diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts index fd315a57e306cd784e6d3286fafd8fcf2e26a1a6..92fd7bfaa2724b7ecdbeeb0c88274b3d3727e6b9 100644 --- a/src/mol-plugin/context.ts +++ b/src/mol-plugin/context.ts @@ -267,7 +267,8 @@ export class PluginContext { const enableDpoit = this.config.get(PluginConfig.General.EnableDpoit) || false; const preferWebGl1 = this.config.get(PluginConfig.General.PreferWebGl1) || false; const failIfMajorPerformanceCaveat = !(this.config.get(PluginConfig.General.AllowMajorPerformanceCaveat) ?? false); - (this.canvas3dContext as Canvas3DContext) = Canvas3DContext.fromCanvas(canvas, this.managers.asset, { antialias, preserveDrawingBuffer, pixelScale, pickScale, pickPadding, enableWboit, enableDpoit, preferWebGl1, failIfMajorPerformanceCaveat }); + const powerPreference = this.config.get(PluginConfig.General.PowerPreference) || 'high-performance'; + (this.canvas3dContext as Canvas3DContext) = Canvas3DContext.fromCanvas(canvas, this.managers.asset, { antialias, preserveDrawingBuffer, pixelScale, pickScale, pickPadding, enableWboit, enableDpoit, preferWebGl1, failIfMajorPerformanceCaveat, powerPreference }); } (this.canvas3d as Canvas3D) = Canvas3D.create(this.canvas3dContext!); this.canvas3dInit.next(true); diff --git a/src/mol-repr/representation.ts b/src/mol-repr/representation.ts index 33b452e766d5d80467d38d2582cfdcbce22f9462..ef534488d887eace73375402f9c1dacddfc631fd 100644 --- a/src/mol-repr/representation.ts +++ b/src/mol-repr/representation.ts @@ -140,7 +140,7 @@ export class RepresentationRegistry<D, S extends Representation.State> { // export { Representation }; -interface Representation<D, P extends PD.Params = {}, S extends Representation.State = Representation.State> { +interface Representation<D, P extends PD.Params = PD.Params, S extends Representation.State = Representation.State> { readonly label: string readonly updated: Subject<number> /** Number of addressable groups in all visuals of the representation */ @@ -236,7 +236,7 @@ namespace Representation { } export const StateBuilder: StateBuilder<State> = { create: createState, update: updateState }; - export type Any = Representation<any, any, any> + export type Any<P extends PD.Params = PD.Params, S extends State = State> = Representation<any, P, S> export const Empty: Any = { label: '', groupCount: 0, renderObjects: [], geometryVersion: -1, props: {}, params: {}, updated: new Subject(), state: createState(), theme: Theme.createEmpty(), createOrUpdate: () => Task.constant('', undefined), @@ -248,7 +248,7 @@ namespace Representation { destroy: () => {} }; - export type Def<D, P extends PD.Params = {}, S extends State = State> = { [k: string]: RepresentationFactory<D, P, S> } + export type Def<D, P extends PD.Params = PD.Params, S extends State = State> = { [k: string]: RepresentationFactory<D, P, S> } export class GeometryState { private curr = new Set<number>(); @@ -272,7 +272,7 @@ namespace Representation { } } - export function createMulti<D, P extends PD.Params = {}, S extends State = State>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<D, P>, stateBuilder: StateBuilder<S>, reprDefs: Def<D, P>): Representation<D, P, S> { + export function createMulti<D, P extends PD.Params = PD.Params, S extends State = State>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<D, P>, stateBuilder: StateBuilder<S>, reprDefs: Def<D, P>): Representation<D, P, S> { let version = 0; const updated = new Subject<number>(); const geometryState = new GeometryState(); diff --git a/src/mol-repr/structure/representation/molecular-surface.ts b/src/mol-repr/structure/representation/molecular-surface.ts index d8ad8d08611f8e044727692b3060105d399311bd..e5d51cdb91d248931182ef3d0e3303aa5dcf685b 100644 --- a/src/mol-repr/structure/representation/molecular-surface.ts +++ b/src/mol-repr/structure/representation/molecular-surface.ts @@ -1,13 +1,13 @@ /** - * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { MolecularSurfaceMeshVisual, MolecularSurfaceMeshParams } from '../visual/molecular-surface-mesh'; +import { MolecularSurfaceMeshVisual, MolecularSurfaceMeshParams, StructureMolecularSurfaceMeshVisual } from '../visual/molecular-surface-mesh'; import { UnitsRepresentation } from '../units-representation'; import { ParamDefinition as PD } from '../../../mol-util/param-definition'; -import { StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../representation'; +import { ComplexRepresentation, StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../representation'; import { Representation, RepresentationParamsGetter, RepresentationContext } from '../../../mol-repr/representation'; import { ThemeRegistryContext } from '../../../mol-theme/theme'; import { Structure } from '../../../mol-model/structure'; @@ -16,6 +16,7 @@ import { BaseGeometry } from '../../../mol-geo/geometry/base'; const MolecularSurfaceVisuals = { 'molecular-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, MolecularSurfaceMeshParams>) => UnitsRepresentation('Molecular surface mesh', ctx, getParams, MolecularSurfaceMeshVisual), + 'structure-molecular-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, MolecularSurfaceMeshParams>) => ComplexRepresentation('Structure Molecular surface mesh', ctx, getParams, StructureMolecularSurfaceMeshVisual), 'molecular-surface-wireframe': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, MolecularSurfaceWireframeParams>) => UnitsRepresentation('Molecular surface wireframe', ctx, getParams, MolecularSurfaceWireframeVisual), }; diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts index 85da9b6064cf3e6d59dd19a88ccc118a92fbb152..b8223d3a42185024d59922bd4976c790e9be0321 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts @@ -247,6 +247,7 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit, const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, densityTextureData.maxRadius); const surface = TextureMesh.create(gv.vertexCount, groupCount, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh); (surface.meta as GaussianSurfaceMeta).resolution = densityTextureData.resolution; + surface.meta.webgl = ctx.webgl; return surface; } @@ -321,6 +322,7 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str const boundingSphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, densityTextureData.maxRadius); const surface = TextureMesh.create(gv.vertexCount, groupCount, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh); (surface.meta as GaussianSurfaceMeta).resolution = densityTextureData.resolution; + surface.meta.webgl = ctx.webgl; return surface; } diff --git a/src/mol-repr/structure/visual/molecular-surface-mesh.ts b/src/mol-repr/structure/visual/molecular-surface-mesh.ts index 72e1a972c6f5c04d0eac95cc39527cab2406c5a5..d30c6d4ee499bb239587182177d6916da47f471f 100644 --- a/src/mol-repr/structure/visual/molecular-surface-mesh.ts +++ b/src/mol-repr/structure/visual/molecular-surface-mesh.ts @@ -11,9 +11,9 @@ import { VisualContext } from '../../visual'; import { Unit, Structure } from '../../../mol-model/structure'; import { Theme } from '../../../mol-theme/theme'; import { Mesh } from '../../../mol-geo/geometry/mesh/mesh'; -import { computeUnitMolecularSurface } from './util/molecular-surface'; +import { computeStructureMolecularSurface, computeUnitMolecularSurface } from './util/molecular-surface'; import { computeMarchingCubesMesh } from '../../../mol-geo/util/marching-cubes/algorithm'; -import { ElementIterator, getElementLoci, eachElement } from './util/element'; +import { ElementIterator, getElementLoci, eachElement, getSerialElementLoci, eachSerialElement } from './util/element'; import { VisualUpdateState } from '../../util'; import { CommonSurfaceParams } from './util/common'; import { Sphere3D } from '../../../mol-math/geometry'; @@ -23,6 +23,7 @@ import { WebGLContext } from '../../../mol-gl/webgl/context'; import { applyMeshColorSmoothing } from '../../../mol-geo/geometry/mesh/color-smoothing'; import { ColorSmoothingParams, getColorSmoothingProps } from '../../../mol-geo/geometry/base'; import { ValueCell } from '../../../mol-util'; +import { ComplexMeshVisual, ComplexVisual } from '../complex-visual'; export const MolecularSurfaceMeshParams = { ...UnitsMeshParams, @@ -104,4 +105,72 @@ export function MolecularSurfaceMeshVisual(materialId: number): UnitsVisual<Mole (geometry.meta as MolecularSurfaceMeta).colorTexture?.destroy(); } }, materialId); +} + +// + +async function createStructureMolecularSurfaceMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: MolecularSurfaceMeshProps, mesh?: Mesh): Promise<Mesh> { + const { transform, field, idField, resolution, maxRadius } = await computeStructureMolecularSurface(structure, theme.size, props).runInContext(ctx.runtime); + + const params = { + isoLevel: props.probeRadius, + scalarField: field, + idField + }; + const surface = await computeMarchingCubesMesh(params, mesh).runAsChild(ctx.runtime); + + if (props.includeParent) { + const iterations = Math.ceil(2 / props.resolution); + Mesh.smoothEdges(surface, { iterations, maxNewEdgeLength: Math.sqrt(2) }); + } + + Mesh.transform(surface, transform); + if (ctx.webgl && !ctx.webgl.isWebGL2) { + Mesh.uniformTriangleGroup(surface); + ValueCell.updateIfChanged(surface.varyingGroup, false); + } else { + ValueCell.updateIfChanged(surface.varyingGroup, true); + } + + const sphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, maxRadius); + surface.setBoundingSphere(sphere); + (surface.meta as MolecularSurfaceMeta).resolution = resolution; + + return surface; +} + +export function StructureMolecularSurfaceMeshVisual(materialId: number): ComplexVisual<MolecularSurfaceMeshParams> { + return ComplexMeshVisual<MolecularSurfaceMeshParams>({ + defaultProps: PD.getDefaultValues(MolecularSurfaceMeshParams), + createGeometry: createStructureMolecularSurfaceMesh, + createLocationIterator: ElementIterator.fromStructure, + getLoci: getSerialElementLoci, + eachLocation: eachSerialElement, + setUpdateState: (state: VisualUpdateState, newProps: PD.Values<MolecularSurfaceMeshParams>, currentProps: PD.Values<MolecularSurfaceMeshParams>) => { + if (newProps.resolution !== currentProps.resolution) state.createGeometry = true; + if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true; + if (newProps.probePositions !== currentProps.probePositions) state.createGeometry = true; + if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true; + if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true; + if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true; + + if (newProps.smoothColors.name !== currentProps.smoothColors.name) { + state.updateColor = true; + } else if (newProps.smoothColors.name === 'on' && currentProps.smoothColors.name === 'on') { + if (newProps.smoothColors.params.resolutionFactor !== currentProps.smoothColors.params.resolutionFactor) state.updateColor = true; + if (newProps.smoothColors.params.sampleStride !== currentProps.smoothColors.params.sampleStride) state.updateColor = true; + } + }, + processValues: (values: MeshValues, geometry: Mesh, props: PD.Values<MolecularSurfaceMeshParams>, theme: Theme, webgl?: WebGLContext) => { + const { resolution, colorTexture } = geometry.meta as MolecularSurfaceMeta; + const csp = getColorSmoothingProps(props.smoothColors, theme.color.preferSmoothing, resolution); + if (csp) { + applyMeshColorSmoothing(values, csp.resolution, csp.stride, webgl, colorTexture); + (geometry.meta as MolecularSurfaceMeta).colorTexture = values.tColorGrid.ref.value; + } + }, + dispose: (geometry: Mesh) => { + (geometry.meta as MolecularSurfaceMeta).colorTexture?.destroy(); + } + }, materialId); } \ No newline at end of file diff --git a/src/mol-repr/structure/visual/util/common.ts b/src/mol-repr/structure/visual/util/common.ts index c0eaf6269e1784f4c86a86eb958959c1c541c6da..50d3f2659866cf41cfea42ed9147cb4a90dcc6b4 100644 --- a/src/mol-repr/structure/visual/util/common.ts +++ b/src/mol-repr/structure/visual/util/common.ts @@ -151,7 +151,7 @@ function squaredDistance(x: number, y: number, z: number, center: Vec3) { } /** marks `indices` for filtering/ignoring in `id` when not in `elements` */ -function filterId(id: AssignableArrayLike<number>, elements: SortedArray, indices: SortedArray) { +function filterUnitId(id: AssignableArrayLike<number>, elements: SortedArray, indices: SortedArray) { let start = 0; const end = elements.length; for (let i = 0, il = indices.length; i < il; ++i) { @@ -168,24 +168,25 @@ function filterId(id: AssignableArrayLike<number>, elements: SortedArray, indice export function getUnitConformationAndRadius(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: CommonSurfaceProps) { const { ignoreHydrogens, traceOnly, includeParent } = props; const rootUnit = includeParent ? structure.root.unitMap.get(unit.id) : unit; + const differentRoot = includeParent && rootUnit !== unit; const { x, y, z } = getConformation(rootUnit); const { elements } = rootUnit; const { center, radius: sphereRadius } = unit.boundary.sphere; - const extraRadius = (2 + 1.5) * 2; // TODO should be twice (the max vdW/sphere radius plus the probe radius) + const extraRadius = (4 + 1.5) * 2; // TODO should be twice (the max vdW/sphere radius plus the probe radius) const radiusSq = (sphereRadius + extraRadius) * (sphereRadius + extraRadius); let indices: SortedArray<ElementIndex>; let id: AssignableArrayLike<number>; - if (ignoreHydrogens || traceOnly || (includeParent && rootUnit !== unit)) { - const _indices = []; - const _id = []; + if (ignoreHydrogens || traceOnly || differentRoot) { + const _indices: number[] = []; + const _id: number[] = []; for (let i = 0, il = elements.length; i < il; ++i) { const eI = elements[i]; if (ignoreHydrogens && isHydrogen(rootUnit, eI)) continue; if (traceOnly && !isTrace(rootUnit, eI)) continue; - if (includeParent && squaredDistance(x[eI], y[eI], z[eI], center) > radiusSq) continue; + if (differentRoot && squaredDistance(x[eI], y[eI], z[eI], center) > radiusSq) continue; _indices.push(eI); _id.push(i); @@ -198,11 +199,11 @@ export function getUnitConformationAndRadius(structure: Structure, unit: Unit, s } if (includeParent && rootUnit !== unit) { - filterId(id, unit.elements, indices); + filterUnitId(id, unit.elements, indices); } const position = { indices, x, y, z, id }; - const boundary = unit === rootUnit ? unit.boundary : getBoundary(position); + const boundary = differentRoot ? getBoundary(position) : unit.boundary; const l = StructureElement.Location.create(structure, rootUnit); const radius = (index: number) => { @@ -213,25 +214,36 @@ export function getUnitConformationAndRadius(structure: Structure, unit: Unit, s return { position, boundary, radius }; } -export function getStructureConformationAndRadius(structure: Structure, sizeTheme: SizeTheme<any>, ignoreHydrogens: boolean, traceOnly: boolean) { - const l = StructureElement.Location.create(structure); +export function getStructureConformationAndRadius(structure: Structure, sizeTheme: SizeTheme<any>, props: CommonSurfaceProps) { + const { ignoreHydrogens, traceOnly, includeParent } = props; + const differentRoot = includeParent && !!structure.parent; + const l = StructureElement.Location.create(structure.root); + + const { center, radius: sphereRadius } = structure.boundary.sphere; + const extraRadius = (4 + 1.5) * 2; // TODO should be twice (the max vdW/sphere radius plus the probe radius) + const radiusSq = (sphereRadius + extraRadius) * (sphereRadius + extraRadius); let xs: ArrayLike<number>; let ys: ArrayLike<number>; let zs: ArrayLike<number>; let rs: ArrayLike<number>; - let id: ArrayLike<number>; + let id: AssignableArrayLike<number>; + let indices: OrderedSet<number>; + + if (ignoreHydrogens || traceOnly || differentRoot) { + const { getSerialIndex } = structure.serialMapping; + const units = differentRoot ? structure.root.units : structure.units; - if (ignoreHydrogens || traceOnly) { const _xs: number[] = []; const _ys: number[] = []; const _zs: number[] = []; const _rs: number[] = []; const _id: number[] = []; - for (let i = 0, m = 0, il = structure.units.length; i < il; ++i) { - const unit = structure.units[i]; + for (let i = 0, il = units.length; i < il; ++i) { + const unit = units[i]; const { elements } = unit; const { x, y, z } = unit.conformation; + const childUnit = structure.unitMap.get(unit.id); l.unit = unit; for (let j = 0, jl = elements.length; j < jl; ++j) { @@ -239,17 +251,30 @@ export function getStructureConformationAndRadius(structure: Structure, sizeThem if (ignoreHydrogens && isHydrogen(unit, eI)) continue; if (traceOnly && !isTrace(unit, eI)) continue; - _xs.push(x(eI)); - _ys.push(y(eI)); - _zs.push(z(eI)); + const _x = x(eI), _y = y(eI), _z = z(eI); + if (differentRoot && squaredDistance(_x, _y, _z, center) > radiusSq) continue; + + _xs.push(_x); + _ys.push(_y); + _zs.push(_z); l.element = eI; _rs.push(sizeTheme.size(l)); - _id.push(m + j); + + if (differentRoot) { + const idx = childUnit ? SortedArray.indexOf(childUnit.elements, eI) : -1; + if (idx === -1) { + _id.push(-2); // mark for filtering/ignoring when not in `elements` + } else { + _id.push(getSerialIndex(childUnit, eI)); + } + } else { + _id.push(getSerialIndex(unit, eI)); + } } - m += elements.length; } xs = _xs, ys = _ys, zs = _zs, rs = _rs; id = _id; + indices = OrderedSet.ofRange(0, id.length); } else { const { elementCount } = structure; const _xs = new Float32Array(elementCount); @@ -275,12 +300,14 @@ export function getStructureConformationAndRadius(structure: Structure, sizeThem } xs = _xs, ys = _ys, zs = _zs, rs = _rs; id = fillSerial(new Uint32Array(elementCount)); + indices = OrderedSet.ofRange(0, id.length); } - const position = { indices: OrderedSet.ofRange(0, id.length), x: xs, y: ys, z: zs, id }; + const position = { indices, x: xs, y: ys, z: zs, id }; + const boundary = differentRoot ? getBoundary(position) : structure.boundary; const radius = (index: number) => rs[index]; - return { position, radius }; + return { position, boundary, radius }; } const _H = AtomicNumbers['H']; diff --git a/src/mol-repr/structure/visual/util/gaussian.ts b/src/mol-repr/structure/visual/util/gaussian.ts index c286a869d2ef6310f3bcee27a07a21ec0c5508a9..9ed5b158765458283336dcb1464947e9c62bdb15 100644 --- a/src/mol-repr/structure/visual/util/gaussian.ts +++ b/src/mol-repr/structure/visual/util/gaussian.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -34,56 +34,51 @@ export function getTextureMaxCells(webgl: WebGLContext, structure?: Structure) { // export function computeUnitGaussianDensity(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: GaussianDensityProps) { - const { box } = unit.lookup3d.boundary; - const p = ensureReasonableResolution(box, props); - const { position, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, p); + const { position, boundary, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, props); + const p = ensureReasonableResolution(boundary.box, props); return Task.create('Gaussian Density', async ctx => { - return await GaussianDensityCPU(ctx, position, box, radius, p); + return await GaussianDensityCPU(ctx, position, boundary.box, radius, p); }); } export function computeUnitGaussianDensityTexture(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) { - const { box } = unit.lookup3d.boundary; - const p = ensureReasonableResolution(box, props, getTextureMaxCells(webgl, structure)); - const { position, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, p); + const { position, boundary, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, props); + const p = ensureReasonableResolution(boundary.box, props, getTextureMaxCells(webgl, structure)); return Task.create('Gaussian Density', async ctx => { - return GaussianDensityTexture(webgl, position, box, radius, p, texture); + return GaussianDensityTexture(webgl, position, boundary.box, radius, p, texture); }); } export function computeUnitGaussianDensityTexture2d(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, powerOfTwo: boolean, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) { - const { box } = unit.lookup3d.boundary; - const p = ensureReasonableResolution(box, props, getTextureMaxCells(webgl, structure)); - const { position, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, p); + const { position, boundary, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, props); + const p = ensureReasonableResolution(boundary.box, props, getTextureMaxCells(webgl, structure)); return Task.create('Gaussian Density', async ctx => { - return GaussianDensityTexture2d(webgl, position, box, radius, powerOfTwo, p, texture); + return GaussianDensityTexture2d(webgl, position, boundary.box, radius, powerOfTwo, p, texture); }); } // export function computeStructureGaussianDensity(structure: Structure, sizeTheme: SizeTheme<any>, props: GaussianDensityProps) { - const { box } = structure.lookup3d.boundary; - const p = ensureReasonableResolution(box, props); - const { position, radius } = getStructureConformationAndRadius(structure, sizeTheme, props.ignoreHydrogens, props.traceOnly); + const { position, boundary, radius } = getStructureConformationAndRadius(structure, sizeTheme, props); + const p = ensureReasonableResolution(boundary.box, props); return Task.create('Gaussian Density', async ctx => { - return await GaussianDensityCPU(ctx, position, box, radius, p); + return await GaussianDensityCPU(ctx, position, boundary.box, radius, p); }); } export function computeStructureGaussianDensityTexture(structure: Structure, sizeTheme: SizeTheme<any>, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) { - const { box } = structure.lookup3d.boundary; - const p = ensureReasonableResolution(box, props, getTextureMaxCells(webgl)); - const { position, radius } = getStructureConformationAndRadius(structure, sizeTheme, props.ignoreHydrogens, props.traceOnly); + const { position, boundary, radius } = getStructureConformationAndRadius(structure, sizeTheme, props); + const p = ensureReasonableResolution(boundary.box, props); return Task.create('Gaussian Density', async ctx => { - return GaussianDensityTexture(webgl, position, box, radius, p, texture); + return GaussianDensityTexture(webgl, position, boundary.box, radius, p, texture); }); } export function computeStructureGaussianDensityTexture2d(structure: Structure, sizeTheme: SizeTheme<any>, powerOfTwo: boolean, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) { const { box } = structure.lookup3d.boundary; - const p = ensureReasonableResolution(box, props, getTextureMaxCells(webgl)); - const { position, radius } = getStructureConformationAndRadius(structure, sizeTheme, props.ignoreHydrogens, props.traceOnly); + const { position, boundary, radius } = getStructureConformationAndRadius(structure, sizeTheme, props); + const p = ensureReasonableResolution(boundary.box, props); return Task.create('Gaussian Density', async ctx => { return GaussianDensityTexture2d(webgl, position, box, radius, powerOfTwo, p, texture); }); diff --git a/src/mol-repr/structure/visual/util/molecular-surface.ts b/src/mol-repr/structure/visual/util/molecular-surface.ts index 66927958de06d524e34a0a5dd1048154eee0cf0a..15c576128875fb040b689b3ed18b17388c266ece 100644 --- a/src/mol-repr/structure/visual/util/molecular-surface.ts +++ b/src/mol-repr/structure/visual/util/molecular-surface.ts @@ -1,12 +1,12 @@ /** - * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { Unit, Structure } from '../../../../mol-model/structure'; import { Task, RuntimeContext } from '../../../../mol-task'; -import { getUnitConformationAndRadius, CommonSurfaceProps, ensureReasonableResolution } from './common'; +import { getUnitConformationAndRadius, CommonSurfaceProps, ensureReasonableResolution, getStructureConformationAndRadius } from './common'; import { PositionData, DensityData, Box3D } from '../../../../mol-math/geometry'; import { MolecularSurfaceCalculationProps, calcMolecularSurface } from '../../../../mol-math/geometry/molecular-surface'; import { OrderedSet } from '../../../../mol-data/int'; @@ -15,7 +15,7 @@ import { SizeTheme } from '../../../../mol-theme/size'; export type MolecularSurfaceProps = MolecularSurfaceCalculationProps & CommonSurfaceProps -function getPositionDataAndMaxRadius(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: MolecularSurfaceProps) { +function getUnitPositionDataAndMaxRadius(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: MolecularSurfaceProps) { const { probeRadius } = props; const { position, boundary, radius } = getUnitConformationAndRadius(structure, unit, sizeTheme, props); const { indices } = position; @@ -34,11 +34,38 @@ function getPositionDataAndMaxRadius(structure: Structure, unit: Unit, sizeTheme } export function computeUnitMolecularSurface(structure: Structure, unit: Unit, sizeTheme: SizeTheme<any>, props: MolecularSurfaceProps) { - const { box } = unit.lookup3d.boundary; - const p = ensureReasonableResolution(box, props); - const { position, boundary, maxRadius } = getPositionDataAndMaxRadius(structure, unit, sizeTheme, p); + const { position, boundary, maxRadius } = getUnitPositionDataAndMaxRadius(structure, unit, sizeTheme, props); + const p = ensureReasonableResolution(boundary.box, props); return Task.create('Molecular Surface', async ctx => { - return await MolecularSurface(ctx, position, boundary, maxRadius, box, p); + return await MolecularSurface(ctx, position, boundary, maxRadius, boundary.box, p); + }); +} + +// + +function getStructurePositionDataAndMaxRadius(structure: Structure, sizeTheme: SizeTheme<any>, props: MolecularSurfaceProps) { + const { probeRadius } = props; + const { position, boundary, radius } = getStructureConformationAndRadius(structure, sizeTheme, props); + const { indices } = position; + const n = OrderedSet.size(indices); + const radii = new Float32Array(OrderedSet.end(indices)); + + let maxRadius = 0; + for (let i = 0; i < n; ++i) { + const j = OrderedSet.getAt(indices, i); + const r = radius(j); + if (maxRadius < r) maxRadius = r; + radii[j] = r + probeRadius; + } + + return { position: { ...position, radius: radii }, boundary, maxRadius }; +} + +export function computeStructureMolecularSurface(structure: Structure, sizeTheme: SizeTheme<any>, props: MolecularSurfaceProps) { + const { position, boundary, maxRadius } = getStructurePositionDataAndMaxRadius(structure, sizeTheme, props); + const p = ensureReasonableResolution(boundary.box, props); + return Task.create('Molecular Surface', async ctx => { + return await MolecularSurface(ctx, position, boundary, maxRadius, boundary.box, p); }); } diff --git a/src/mol-repr/volume/isosurface.ts b/src/mol-repr/volume/isosurface.ts index e99c46d855e6991d2c794735e01916f9fa4192b9..e2f36b0c20fb663c393e05c3b74698767de30e79 100644 --- a/src/mol-repr/volume/isosurface.ts +++ b/src/mol-repr/volume/isosurface.ts @@ -201,6 +201,7 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol const groupCount = volume.grid.cells.data.length; const surface = TextureMesh.create(gv.vertexCount, groupCount, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh); + surface.meta.webgl = ctx.webgl; return surface; } diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts index 84af7dad2d2a34f23cfcb4f270fc068dda79f949..160d0ba066e5b65d8a6079e0c2daf12e026d4b01 100644 --- a/src/mol-theme/color.ts +++ b/src/mol-theme/color.ts @@ -40,6 +40,7 @@ import { VolumeValueColorThemeProvider } from './color/volume-value'; import { Vec3, Vec4 } from '../mol-math/linear-algebra'; import { ModelIndexColorThemeProvider } from './color/model-index'; import { StructureIndexColorThemeProvider } from './color/structure-index'; +import { ExternalVolumeColorThemeProvider } from './color/external-volume'; export type LocationColor = (location: Location, isSecondary: boolean) => Color @@ -152,6 +153,7 @@ namespace ColorTheme { 'unit-index': UnitIndexColorThemeProvider, 'uniform': UniformColorThemeProvider, 'volume-value': VolumeValueColorThemeProvider, + 'external-volume': ExternalVolumeColorThemeProvider, }; type _BuiltIn = typeof BuiltIn export type BuiltIn = keyof _BuiltIn diff --git a/src/mol-theme/color/external-volume.ts b/src/mol-theme/color/external-volume.ts new file mode 100644 index 0000000000000000000000000000000000000000..43fce54d962f8ff4e86de8049bdf650f794ce0cd --- /dev/null +++ b/src/mol-theme/color/external-volume.ts @@ -0,0 +1,159 @@ +/** + * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Color, ColorScale } from '../../mol-util/color'; +import { Location } from '../../mol-model/location'; +import { ColorTheme } from '../color'; +import { ParamDefinition as PD } from '../../mol-util/param-definition'; +import { ThemeDataContext } from '../theme'; +import { Grid, Volume } from '../../mol-model/volume'; +import { type PluginContext } from '../../mol-plugin/context'; +import { isPositionLocation } from '../../mol-geo/util/location-iterator'; +import { Mat4, Vec3 } from '../../mol-math/linear-algebra'; +import { lerp } from '../../mol-math/interpolate'; + +const Description = `Assigns a color based volume value at a given vertex.`; + +export const ExternalVolumeColorThemeParams = { + volume: PD.ValueRef<Volume>( + (ctx: PluginContext) => { + const volumes = ctx.state.data.selectQ(q => q.root.subtree().filter(c => Volume.is(c.obj?.data))); + return volumes.map(v => [v.transform.ref, v.obj?.label ?? '<unknown>'] as [string, string]); + }, + (ref, getData) => getData(ref), + ), + coloring: PD.MappedStatic('absolute-value', { + 'absolute-value': PD.Group({ + domain: PD.MappedStatic('auto', { + custom: PD.Interval([-1, 1]), + auto: PD.Group({ + symmetric: PD.Boolean(false, { description: 'If true the automatic range is determined as [-|max|, |max|].' }) + }) + }), + list: PD.ColorList('red-white-blue', { presetKind: 'scale' }) + }), + 'relative-value': PD.Group({ + domain: PD.MappedStatic('auto', { + custom: PD.Interval([-1, 1]), + auto: PD.Group({ + symmetric: PD.Boolean(false, { description: 'If true the automatic range is determined as [-|max|, |max|].' }) + }) + }), + list: PD.ColorList('red-white-blue', { presetKind: 'scale' }) + }) + }), + defaultColor: PD.Color(Color(0xcccccc)), +}; +export type ExternalVolumeColorThemeParams = typeof ExternalVolumeColorThemeParams + +export function ExternalVolumeColorTheme(ctx: ThemeDataContext, props: PD.Values<ExternalVolumeColorThemeParams>): ColorTheme<ExternalVolumeColorThemeParams> { + let volume: Volume | undefined; + try { + volume = props.volume.getValue(); + } catch { + // .getValue() is resolved during state reconciliation => would throw from UI + } + + // NOTE: this will currently be slow for with GPU/texture meshes due to slow iteration + // TODO: create texture to be able to do the sampling on the GPU + + let color; + if (volume) { + const coloring = props.coloring.params; + const { stats } = volume.grid; + const domain: [number, number] = coloring.domain.name === 'custom' ? coloring.domain.params : [stats.min, stats.max]; + + const isRelative = props.coloring.name === 'relative-value'; + if (coloring.domain.name === 'auto' && isRelative) { + domain[0] = (domain[0] - stats.mean) / stats.sigma; + domain[1] = (domain[1] - stats.mean) / stats.sigma; + } + + if (props.coloring.params.domain.name === 'auto' && props.coloring.params.domain.params.symmetric) { + const max = Math.max(Math.abs(domain[0]), Math.abs(domain[1])); + domain[0] = -max; + domain[1] = max; + } + + const scale = ColorScale.create({ domain, listOrName: coloring.list.colors }); + + const cartnToGrid = Grid.getGridToCartesianTransform(volume.grid); + Mat4.invert(cartnToGrid, cartnToGrid); + const gridCoords = Vec3(); + + const { dimensions, get } = volume.grid.cells.space; + const data = volume.grid.cells.data; + + const [mi, mj, mk] = dimensions; + + color = (location: Location): Color => { + if (!isPositionLocation(location)) { + return props.defaultColor; + } + + Vec3.copy(gridCoords, location.position); + Vec3.transformMat4(gridCoords, gridCoords, cartnToGrid); + + const i = Math.floor(gridCoords[0]); + const j = Math.floor(gridCoords[1]); + const k = Math.floor(gridCoords[2]); + + if (i < 0 || i >= mi || j < 0 || j >= mj || k < 0 || k >= mk) { + return props.defaultColor; + } + + const u = gridCoords[0] - i; + const v = gridCoords[1] - j; + const w = gridCoords[2] - k; + + // Tri-linear interpolation for the value + const ii = Math.min(i + 1, mi - 1); + const jj = Math.min(j + 1, mj - 1); + const kk = Math.min(k + 1, mk - 1); + + let a = get(data, i, j, k); + let b = get(data, ii, j, k); + let c = get(data, i, jj, k); + let d = get(data, ii, jj, k); + const x = lerp(lerp(a, b, u), lerp(c, d, u), v); + + a = get(data, i, j, kk); + b = get(data, ii, j, kk); + c = get(data, i, jj, kk); + d = get(data, ii, jj, kk); + const y = lerp(lerp(a, b, u), lerp(c, d, u), v); + + let value = lerp(x, y, w); + if (isRelative) { + value = (value - stats.mean) / stats.sigma; + } + + return scale.color(value); + }; + } else { + color = () => props.defaultColor; + } + + return { + factory: ExternalVolumeColorTheme, + granularity: 'vertex', + preferSmoothing: true, + color, + props, + description: Description, + // TODO: figure out how to do legend for this + }; +} + +export const ExternalVolumeColorThemeProvider: ColorTheme.Provider<ExternalVolumeColorThemeParams, 'external-volume'> = { + name: 'external-volume', + label: 'External Volume', + category: ColorTheme.Category.Misc, + factory: ExternalVolumeColorTheme, + getParams: () => ExternalVolumeColorThemeParams, + defaultValues: PD.getDefaultValues(ExternalVolumeColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => true, +}; \ No newline at end of file diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index a9697f5f454d63753f657bba63ff2ab32771eb3c..5516f909767c683b15f454206eae413ea082d4c0 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -290,9 +290,9 @@ export namespace ParamDefinition { // getValue needs to be assigned by a runtime because it might not be serializable export interface ValueRef<T = any> extends Base<{ ref: string, getValue: () => T }> { type: 'value-ref', - resolveRef: (ref: string) => T, + resolveRef: (ref: string, getData: (ref: string) => any) => T, // a provider because the list changes over time - getOptions: () => Select<string>['options'], + getOptions: (ctx: any) => Select<string>['options'], } export function ValueRef<T>(getOptions: ValueRef['getOptions'], resolveRef: ValueRef<T>['resolveRef'], info?: Info & { defaultRef?: string }) { return setInfo<ValueRef<T>>({ type: 'value-ref', defaultValue: { ref: info?.defaultRef ?? '', getValue: unsetGetValue as any }, getOptions, resolveRef }, info); @@ -365,8 +365,8 @@ export namespace ParamDefinition { return d as Values<T>; } - function _resolveRef(resolve: (ref: string) => any, ref: string) { - return () => resolve(ref); + function _resolveRef(resolve: (ref: string, getData: (ref: string) => any) => any, ref: string, getData: (ref: string) => any) { + return () => resolve(ref, getData); } function resolveRefValue(p: Any, value: any, getData: (ref: string) => any) { @@ -375,11 +375,11 @@ export namespace ParamDefinition { if (p.type === 'value-ref') { const v = value as ValueRef['defaultValue']; if (!v.ref) v.getValue = () => { throw new Error('Unset ref in ValueRef value.'); }; - else v.getValue = _resolveRef(p.resolveRef, v.ref); + else v.getValue = _resolveRef(p.resolveRef, v.ref, getData); } else if (p.type === 'data-ref') { const v = value as ValueRef['defaultValue']; if (!v.ref) v.getValue = () => { throw new Error('Unset ref in ValueRef value.'); }; - else v.getValue = _resolveRef(getData, v.ref); + else v.getValue = _resolveRef(getData, v.ref, getData); } else if (p.type === 'group') { resolveRefs(p.params, value, getData); } else if (p.type === 'mapped') {