mirror of
https://github.com/molstar/molstar.git
synced 2026-06-04 21:34:23 +08:00
Compare commits
32 Commits
v3.0.0-dev
...
v3.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
805f772696 | ||
|
|
308bbc1ea0 | ||
|
|
4a248b5591 | ||
|
|
704a9a111d | ||
|
|
a6befc5509 | ||
|
|
9e7aa4226d | ||
|
|
7a25699c23 | ||
|
|
901ae7f6d6 | ||
|
|
c57a4cdf6e | ||
|
|
18573e17f0 | ||
|
|
5bc7ffa8a7 | ||
|
|
430cc83259 | ||
|
|
3cd3afb775 | ||
|
|
93215b6beb | ||
|
|
e4f630dbef | ||
|
|
ccaf18af04 | ||
|
|
2b72098f95 | ||
|
|
b32546bea7 | ||
|
|
b9b0413e9f | ||
|
|
1d29b4627f | ||
|
|
bd44c76709 | ||
|
|
06b4761f2b | ||
|
|
daa3d1dbaa | ||
|
|
5490d5ceb5 | ||
|
|
cf3c1cfcce | ||
|
|
be2607ae84 | ||
|
|
e2966241e8 | ||
|
|
447792b1ef | ||
|
|
1cbcb5c530 | ||
|
|
f8d32d1d8d | ||
|
|
8c556c2849 | ||
|
|
98050875c7 |
2
.github/workflows/node.yml
vendored
2
.github/workflows/node.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14
|
||||
node-version: 17
|
||||
- run: npm ci
|
||||
- run: sudo apt-get install xvfb
|
||||
- name: Lint
|
||||
|
||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -6,6 +6,22 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v3.0.0-dev.5] - 2021-12-16
|
||||
|
||||
- Fix initial camera reset not triggering for some entries.
|
||||
|
||||
## [v3.0.0-dev.4] - 2021-12-14
|
||||
|
||||
- Add ``bumpiness`` (per-object and per-group), ``bumpFrequency`` & ``bumpAmplitude`` (per-object) render parameters (#299)
|
||||
- Change ``label`` representation defaults: Use text border instead of rectangle background
|
||||
- Add outline color option to renderer
|
||||
- Fix false positives in Model.isFromPdbArchive
|
||||
- Add drag and drop support for loading any file, including multiple at once
|
||||
- If there are session files (.molx or .molj) among the dropped files, only the first session will be loaded
|
||||
- Add drag and drop overlay
|
||||
- Safari 15.1 - 15.3 WebGL 2 support workaround
|
||||
- [Breaking] Move ``react`` and ``react-dom`` to ``peerDependencies``. This might break some builds.
|
||||
|
||||
## [v3.0.0-dev.3] - 2021-12-4
|
||||
|
||||
- Fix OBJ and USDZ export
|
||||
|
||||
28
package-lock.json
generated
28
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.0.0-dev.3",
|
||||
"version": "3.0.0-dev.5",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "molstar",
|
||||
"version": "3.0.0-dev.3",
|
||||
"version": "3.0.0-dev.5",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/argparse": "^2.0.10",
|
||||
@@ -27,8 +27,6 @@
|
||||
"immer": "^9.0.7",
|
||||
"immutable": "^3.8.2",
|
||||
"node-fetch": "^2.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"rxjs": "^7.4.0",
|
||||
"swagger-ui-dist": "^4.1.1",
|
||||
"tslib": "^2.3.1",
|
||||
@@ -85,6 +83,10 @@
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"gl": "^4.9.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
@@ -11292,6 +11294,7 @@
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -11304,6 +11307,7 @@
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@@ -11864,6 +11868,7 @@
|
||||
"version": "0.20.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
|
||||
"integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -12522,9 +12527,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-ui-dist": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.1.tgz",
|
||||
"integrity": "sha512-xvPMEpOCbd5S9Z1pJT/L/K/C2yAX89ZWJDxEECkVW1dENsKFLbu7sRY7b6UBqLXuTUfdM5owlgPrpwr24CRonA=="
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.3.tgz",
|
||||
"integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ=="
|
||||
},
|
||||
"node_modules/swap-case": {
|
||||
"version": "2.0.2",
|
||||
@@ -22606,6 +22611,7 @@
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -22615,6 +22621,7 @@
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@@ -23039,6 +23046,7 @@
|
||||
"version": "0.20.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
|
||||
"integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -23553,9 +23561,9 @@
|
||||
}
|
||||
},
|
||||
"swagger-ui-dist": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.1.tgz",
|
||||
"integrity": "sha512-xvPMEpOCbd5S9Z1pJT/L/K/C2yAX89ZWJDxEECkVW1dENsKFLbu7sRY7b6UBqLXuTUfdM5owlgPrpwr24CRonA=="
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.3.tgz",
|
||||
"integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ=="
|
||||
},
|
||||
"swap-case": {
|
||||
"version": "2.0.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.0.0-dev.3",
|
||||
"version": "3.0.0-dev.5",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -146,14 +146,16 @@
|
||||
"immer": "^9.0.7",
|
||||
"immutable": "^3.8.2",
|
||||
"node-fetch": "^2.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"rxjs": "^7.4.0",
|
||||
"swagger-ui-dist": "^4.1.1",
|
||||
"tslib": "^2.3.1",
|
||||
"util.promisify": "^1.1.1",
|
||||
"xhr2": "^0.2.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"gl": "^4.9.2"
|
||||
}
|
||||
|
||||
@@ -7,6 +7,23 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function removeDir(dirPath) {
|
||||
for (const ent of fs.readdirSync(dirPath)) {
|
||||
const entryPath = path.join(dirPath, ent);
|
||||
remove(entryPath);
|
||||
}
|
||||
|
||||
fs.rmdirSync(dirPath);
|
||||
}
|
||||
|
||||
function remove(entryPath) {
|
||||
const st = fs.statSync(entryPath);
|
||||
if (st.isDirectory())
|
||||
removeDir(entryPath);
|
||||
else
|
||||
fs.unlinkSync(entryPath);
|
||||
}
|
||||
|
||||
const toClean = [
|
||||
path.resolve(__dirname, '../build'),
|
||||
path.resolve(__dirname, '../lib'),
|
||||
@@ -14,6 +31,11 @@ const toClean = [
|
||||
];
|
||||
|
||||
toClean.forEach(ph => {
|
||||
if (fs.existsSync(ph))
|
||||
fs.rm(ph, { recursive: true }, err => { if (err) console.warn(`Failed to delete ${ph}: ${err}`); });
|
||||
if (fs.existsSync(ph)) {
|
||||
try {
|
||||
remove(ph);
|
||||
} catch (err) {
|
||||
console.warn(`Cleanup failed: ${err}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,6 +14,9 @@ const buildDir = path.resolve(__dirname, '../build/');
|
||||
const deployDir = path.resolve(buildDir, 'deploy/');
|
||||
const localPath = path.resolve(deployDir, 'molstar.github.io/');
|
||||
|
||||
const analyticsTag = /<!-- __MOLSTAR_ANALYTICS__ -->/g;
|
||||
const analyticsCode = `<!-- Cloudflare Web Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "c414cbae2d284ea995171a81e4a3e721"}'></script><!-- End Cloudflare Web Analytics -->`;
|
||||
|
||||
function log(command, stdout, stderr) {
|
||||
if (command) {
|
||||
console.log('\n###', command);
|
||||
@@ -22,11 +25,18 @@ function log(command, stdout, stderr) {
|
||||
}
|
||||
}
|
||||
|
||||
function addAnalytics(path) {
|
||||
const data = fs.readFileSync(path, 'utf8');
|
||||
const result = data.replace(analyticsTag, analyticsCode);
|
||||
fs.writeFileSync(path, result, 'utf8');
|
||||
}
|
||||
|
||||
function copyViewer() {
|
||||
console.log('\n###', 'copy viewer files');
|
||||
const viewerBuildPath = path.resolve(buildDir, '../build/viewer/');
|
||||
const viewerDeployPath = path.resolve(localPath, 'viewer/');
|
||||
fse.copySync(viewerBuildPath, viewerDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(viewerDeployPath, 'index.html'));
|
||||
}
|
||||
|
||||
if (!fs.existsSync(localPath)) {
|
||||
|
||||
@@ -51,7 +51,8 @@ function occlusionStyle(plugin: PluginContext) {
|
||||
} },
|
||||
outline: { name: 'on', params: {
|
||||
scale: 1.0,
|
||||
threshold: 0.33
|
||||
threshold: 0.33,
|
||||
color: Color(0x0000),
|
||||
} }
|
||||
}
|
||||
} });
|
||||
|
||||
@@ -91,5 +91,6 @@
|
||||
var emdb = getParam('emdb', '[^&]+').trim();
|
||||
if (emdb) viewer.loadEmdb(emdb);
|
||||
</script>
|
||||
<!-- __MOLSTAR_ANALYTICS__ -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -11,6 +11,7 @@ import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import './index.html';
|
||||
require('mol-plugin-ui/skin/light.scss');
|
||||
|
||||
@@ -26,7 +27,7 @@ const Canvas3DPresets = {
|
||||
},
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.1 } }
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.1, color: Color(0x000000) } }
|
||||
},
|
||||
renderer: {
|
||||
style: { name: 'flat', params: {} }
|
||||
|
||||
@@ -125,17 +125,20 @@ export class Mp4Controls extends PluginComponent {
|
||||
this.subscribe(this.plugin.canvas3d?.resized!, () => this.syncInfo());
|
||||
this.subscribe(this.plugin.helpers.viewportScreenshot?.events.previewed!, () => this.syncInfo());
|
||||
|
||||
this.subscribe(this.plugin.behaviors.state.isBusy, b => {
|
||||
const anim = this.current;
|
||||
if (!b && anim) {
|
||||
this.behaviors.canApply.next(anim.anim.canApply?.(this.plugin) ?? { canApply: true });
|
||||
}
|
||||
});
|
||||
this.subscribe(this.plugin.behaviors.state.isBusy, b => this.updateCanApply(b));
|
||||
this.subscribe(this.plugin.managers.snapshot.events.changed, b => this.updateCanApply(b));
|
||||
|
||||
this.sync();
|
||||
this.syncInfo();
|
||||
}
|
||||
|
||||
private updateCanApply(b?: any) {
|
||||
const anim = this.current;
|
||||
if (!b && anim) {
|
||||
this.behaviors.canApply.next(anim.anim.canApply?.(this.plugin) ?? { canApply: true });
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private plugin: PluginContext) {
|
||||
super();
|
||||
|
||||
|
||||
@@ -514,7 +514,7 @@ namespace Canvas3D {
|
||||
|
||||
if (camera.transition.inTransition || nextCameraResetSnapshot) return false;
|
||||
|
||||
let cameraSphereOverlapsNone = true;
|
||||
let cameraSphereOverlapsNone = true, isEmpty = true;
|
||||
Sphere3D.set(cameraSphere, camera.state.target, camera.state.radius);
|
||||
|
||||
// check if any renderable has moved outside of the old bounding sphere
|
||||
@@ -525,12 +525,13 @@ namespace Canvas3D {
|
||||
const b = r.values.boundingSphere.ref.value;
|
||||
if (!b.radius) continue;
|
||||
|
||||
isEmpty = false;
|
||||
const cameraDist = Vec3.distance(cameraSphere.center, b.center);
|
||||
if ((cameraDist > cameraSphere.radius || cameraDist > b.radius || b.radius > camera.state.radiusMax) && !Sphere3D.includes(oldBoundingSphereVisible, b)) return true;
|
||||
if (Sphere3D.overlaps(cameraSphere, b)) cameraSphereOverlapsNone = false;
|
||||
}
|
||||
|
||||
return cameraSphereOverlapsNone;
|
||||
return cameraSphereOverlapsNone || (!isEmpty && cameraSphere.radius <= 0.1);
|
||||
}
|
||||
|
||||
const sceneCommitTimeoutMs = 250;
|
||||
|
||||
@@ -193,6 +193,7 @@ const PostprocessingSchema = {
|
||||
uFogNear: UniformSpec('f'),
|
||||
uFogFar: UniformSpec('f'),
|
||||
uFogColor: UniformSpec('v3'),
|
||||
uOutlineColor: UniformSpec('v3'),
|
||||
uTransparentBackground: UniformSpec('b'),
|
||||
|
||||
uMaxPossibleViewZDiff: UniformSpec('f'),
|
||||
@@ -220,6 +221,7 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
|
||||
uFogNear: ValueCell.create(10000),
|
||||
uFogFar: ValueCell.create(10000),
|
||||
uFogColor: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uOutlineColor: ValueCell.create(Vec3.create(0, 0, 0)),
|
||||
uTransparentBackground: ValueCell.create(false),
|
||||
|
||||
uMaxPossibleViewZDiff: ValueCell.create(0.5),
|
||||
@@ -252,6 +254,7 @@ export const PostprocessingParams = {
|
||||
on: PD.Group({
|
||||
scale: PD.Numeric(1, { min: 1, max: 5, step: 1 }),
|
||||
threshold: PD.Numeric(0.33, { min: 0.01, max: 1, step: 0.01 }),
|
||||
color: PD.Color(Color(0x000000)),
|
||||
}),
|
||||
off: PD.Group({})
|
||||
}, { cycle: true, description: 'Draw outline around 3D objects' }),
|
||||
@@ -446,6 +449,8 @@ export class PostprocessingPass {
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.uFar, camera.far);
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
|
||||
|
||||
ValueCell.update(this.renderable.values.uOutlineColor, Color.toVec3Normalized(this.renderable.values.uOutlineColor.ref.value, props.outline.params.color));
|
||||
|
||||
ValueCell.updateIfChanged(this.renderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
|
||||
if (this.renderable.values.dOutlineScale.ref.value !== outlineScale) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOutlineScale, outlineScale);
|
||||
|
||||
@@ -105,6 +105,7 @@ export namespace BaseGeometry {
|
||||
drawCount: ValueCell.create(counts.drawCount),
|
||||
uMetalness: ValueCell.create(props.material.metalness),
|
||||
uRoughness: ValueCell.create(props.material.roughness),
|
||||
uBumpiness: ValueCell.create(props.material.bumpiness),
|
||||
dLightCount: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
@@ -113,6 +114,7 @@ export namespace BaseGeometry {
|
||||
ValueCell.updateIfChanged(values.alpha, props.alpha); // `uAlpha` is set in renderable.render
|
||||
ValueCell.updateIfChanged(values.uMetalness, props.material.metalness);
|
||||
ValueCell.updateIfChanged(values.uRoughness, props.material.roughness);
|
||||
ValueCell.updateIfChanged(values.uBumpiness, props.material.bumpiness);
|
||||
}
|
||||
|
||||
export function createRenderableState(props: Partial<PD.Values<Params>> = {}): RenderableState {
|
||||
|
||||
@@ -157,6 +157,8 @@ export namespace Cylinders {
|
||||
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type Params = typeof Params
|
||||
|
||||
@@ -237,6 +239,8 @@ export namespace Cylinders {
|
||||
dDoubleSided: ValueCell.create(props.doubleSided),
|
||||
dIgnoreLight: ValueCell.create(props.ignoreLight),
|
||||
dXrayShaded: ValueCell.create(props.xrayShaded),
|
||||
uBumpFrequency: ValueCell.create(props.bumpFrequency),
|
||||
uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -252,6 +256,8 @@ export namespace Cylinders {
|
||||
ValueCell.updateIfChanged(values.dDoubleSided, props.doubleSided);
|
||||
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
|
||||
ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
|
||||
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
|
||||
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
|
||||
}
|
||||
|
||||
function updateBoundingSphere(values: CylindersValues, cylinders: Cylinders) {
|
||||
|
||||
@@ -376,7 +376,7 @@ export function applyMeshSubstanceSmoothing(values: MeshValues, resolution: numb
|
||||
colorType: values.dSubstanceType.ref.value,
|
||||
boundingSphere: values.boundingSphere.ref.value,
|
||||
invariantBoundingSphere: values.invariantBoundingSphere.ref.value,
|
||||
itemSize: 3
|
||||
itemSize: 4
|
||||
}, resolution, stride, webgl, colorTexture);
|
||||
if (smoothingData.kind === 'volume') {
|
||||
ValueCell.updateIfChanged(values.dSubstanceType, smoothingData.type);
|
||||
|
||||
@@ -625,6 +625,8 @@ export namespace Mesh {
|
||||
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type Params = typeof Params
|
||||
|
||||
@@ -696,6 +698,8 @@ export namespace Mesh {
|
||||
dFlipSided: ValueCell.create(props.flipSided),
|
||||
dIgnoreLight: ValueCell.create(props.ignoreLight),
|
||||
dXrayShaded: ValueCell.create(props.xrayShaded),
|
||||
uBumpFrequency: ValueCell.create(props.bumpFrequency),
|
||||
uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
|
||||
|
||||
meta: ValueCell.create(mesh.meta),
|
||||
};
|
||||
@@ -714,6 +718,8 @@ export namespace Mesh {
|
||||
ValueCell.updateIfChanged(values.dFlipSided, props.flipSided);
|
||||
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
|
||||
ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
|
||||
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
|
||||
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
|
||||
}
|
||||
|
||||
function updateBoundingSphere(values: MeshValues, mesh: Mesh) {
|
||||
|
||||
@@ -129,6 +129,8 @@ export namespace Spheres {
|
||||
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type Params = typeof Params
|
||||
|
||||
@@ -204,6 +206,8 @@ export namespace Spheres {
|
||||
dDoubleSided: ValueCell.create(props.doubleSided),
|
||||
dIgnoreLight: ValueCell.create(props.ignoreLight),
|
||||
dXrayShaded: ValueCell.create(props.xrayShaded),
|
||||
uBumpFrequency: ValueCell.create(props.bumpFrequency),
|
||||
uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -219,6 +223,8 @@ export namespace Spheres {
|
||||
ValueCell.updateIfChanged(values.dDoubleSided, props.doubleSided);
|
||||
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
|
||||
ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
|
||||
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
|
||||
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
|
||||
}
|
||||
|
||||
function updateBoundingSphere(values: SpheresValues, spheres: Spheres) {
|
||||
|
||||
@@ -23,14 +23,14 @@ export type SubstanceData = {
|
||||
|
||||
export function applySubstanceMaterial(array: Uint8Array, start: number, end: number, material: Material) {
|
||||
for (let i = start; i < end; ++i) {
|
||||
Material.toArray(material, array, i * 3);
|
||||
array[i * 3 + 2] = 255;
|
||||
Material.toArray(material, array, i * 4);
|
||||
array[i * 4 + 3] = 255;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function clearSubstance(array: Uint8Array, start: number, end: number) {
|
||||
array.fill(0, start * 3, end * 3);
|
||||
array.fill(0, start * 4, end * 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -510,10 +510,10 @@ export function applyTextureMeshSubstanceSmoothing(values: TextureMeshValues, re
|
||||
|
||||
stride *= 3; // triple because TextureMesh is never indexed (no elements buffer)
|
||||
|
||||
if (!webgl.namedTextures[ColorSmoothingRgbName]) {
|
||||
webgl.namedTextures[ColorSmoothingRgbName] = webgl.resources.texture('image-uint8', 'rgb', 'ubyte', 'nearest');
|
||||
if (!webgl.namedTextures[ColorSmoothingRgbaName]) {
|
||||
webgl.namedTextures[ColorSmoothingRgbaName] = webgl.resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
|
||||
}
|
||||
const colorData = webgl.namedTextures[ColorSmoothingRgbName];
|
||||
const colorData = webgl.namedTextures[ColorSmoothingRgbaName];
|
||||
colorData.load(values.tSubstance.ref.value);
|
||||
|
||||
const smoothingData = calcTextureMeshColorSmoothing({
|
||||
|
||||
@@ -113,6 +113,8 @@ export namespace TextureMesh {
|
||||
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type Params = typeof Params
|
||||
|
||||
@@ -168,6 +170,8 @@ export namespace TextureMesh {
|
||||
dFlipSided: ValueCell.create(props.flipSided),
|
||||
dIgnoreLight: ValueCell.create(props.ignoreLight),
|
||||
dXrayShaded: ValueCell.create(props.xrayShaded),
|
||||
uBumpFrequency: ValueCell.create(props.bumpFrequency),
|
||||
uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
|
||||
dGeoTexture: ValueCell.create(true),
|
||||
|
||||
meta: ValueCell.create(textureMesh.meta),
|
||||
@@ -187,6 +191,8 @@ export namespace TextureMesh {
|
||||
ValueCell.updateIfChanged(values.dFlipSided, props.flipSided);
|
||||
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
|
||||
ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
|
||||
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
|
||||
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
|
||||
}
|
||||
|
||||
function updateBoundingSphere(values: TextureMeshValues, textureMesh: TextureMesh) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -7,7 +7,7 @@
|
||||
import { Renderable, RenderableState, createRenderable } from '../renderable';
|
||||
import { WebGLContext } from '../webgl/context';
|
||||
import { createGraphicsRenderItem } from '../webgl/render-item';
|
||||
import { GlobalUniformSchema, BaseSchema, AttributeSpec, Values, InternalSchema, SizeSchema, InternalValues, ElementsSpec, ValueSpec, DefineSpec, GlobalTextureSchema } from './schema';
|
||||
import { GlobalUniformSchema, BaseSchema, AttributeSpec, Values, InternalSchema, SizeSchema, InternalValues, ElementsSpec, ValueSpec, DefineSpec, GlobalTextureSchema, UniformSpec } from './schema';
|
||||
import { CylindersShaderCode } from '../shader-code';
|
||||
import { ValueCell } from '../../mol-util';
|
||||
|
||||
@@ -26,6 +26,8 @@ export const CylindersSchema = {
|
||||
dDoubleSided: DefineSpec('boolean'),
|
||||
dIgnoreLight: DefineSpec('boolean'),
|
||||
dXrayShaded: DefineSpec('boolean'),
|
||||
uBumpFrequency: UniformSpec('f'),
|
||||
uBumpAmplitude: UniformSpec('f'),
|
||||
};
|
||||
export type CylindersSchema = typeof CylindersSchema
|
||||
export type CylindersValues = Values<CylindersSchema>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -7,7 +7,7 @@
|
||||
import { Renderable, RenderableState, createRenderable } from '../renderable';
|
||||
import { WebGLContext } from '../webgl/context';
|
||||
import { createGraphicsRenderItem } from '../webgl/render-item';
|
||||
import { GlobalUniformSchema, BaseSchema, AttributeSpec, ElementsSpec, DefineSpec, Values, InternalSchema, InternalValues, GlobalTextureSchema, ValueSpec } from './schema';
|
||||
import { GlobalUniformSchema, BaseSchema, AttributeSpec, ElementsSpec, DefineSpec, Values, InternalSchema, InternalValues, GlobalTextureSchema, ValueSpec, UniformSpec } from './schema';
|
||||
import { MeshShaderCode } from '../shader-code';
|
||||
import { ValueCell } from '../../mol-util';
|
||||
|
||||
@@ -22,6 +22,8 @@ export const MeshSchema = {
|
||||
dFlipSided: DefineSpec('boolean'),
|
||||
dIgnoreLight: DefineSpec('boolean'),
|
||||
dXrayShaded: DefineSpec('boolean'),
|
||||
uBumpFrequency: UniformSpec('f'),
|
||||
uBumpAmplitude: UniformSpec('f'),
|
||||
meta: ValueSpec('unknown')
|
||||
} as const;
|
||||
export type MeshSchema = typeof MeshSchema
|
||||
|
||||
@@ -243,12 +243,12 @@ export type TransparencyValues = Values<TransparencySchema>
|
||||
|
||||
export const SubstanceSchema = {
|
||||
uSubstanceTexDim: UniformSpec('v2'),
|
||||
tSubstance: TextureSpec('image-uint8', 'rgb', 'ubyte', 'nearest'),
|
||||
tSubstance: TextureSpec('image-uint8', 'rgba', 'ubyte', 'nearest'),
|
||||
dSubstance: DefineSpec('boolean'),
|
||||
|
||||
uSubstanceGridDim: UniformSpec('v3'),
|
||||
uSubstanceGridTransform: UniformSpec('v4'),
|
||||
tSubstanceGrid: TextureSpec('texture', 'rgb', 'ubyte', 'linear'),
|
||||
tSubstanceGrid: TextureSpec('texture', 'rgba', 'ubyte', 'linear'),
|
||||
dSubstanceType: DefineSpec('string', ['groupInstance', 'volumeInstance']),
|
||||
} as const;
|
||||
export type SubstanceSchema = typeof SubstanceSchema
|
||||
@@ -288,6 +288,7 @@ export const BaseSchema = {
|
||||
uAlpha: UniformSpec('f', 'material'),
|
||||
uMetalness: UniformSpec('f', 'material'),
|
||||
uRoughness: UniformSpec('f', 'material'),
|
||||
uBumpiness: UniformSpec('f', 'material'),
|
||||
|
||||
uVertexCount: UniformSpec('i'),
|
||||
uInstanceCount: UniformSpec('i'),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -7,7 +7,7 @@
|
||||
import { Renderable, RenderableState, createRenderable } from '../renderable';
|
||||
import { WebGLContext } from '../webgl/context';
|
||||
import { createGraphicsRenderItem } from '../webgl/render-item';
|
||||
import { GlobalUniformSchema, BaseSchema, AttributeSpec, Values, InternalSchema, SizeSchema, InternalValues, ElementsSpec, ValueSpec, DefineSpec, GlobalTextureSchema } from './schema';
|
||||
import { GlobalUniformSchema, BaseSchema, AttributeSpec, Values, InternalSchema, SizeSchema, InternalValues, ElementsSpec, ValueSpec, DefineSpec, GlobalTextureSchema, UniformSpec } from './schema';
|
||||
import { SpheresShaderCode } from '../shader-code';
|
||||
import { ValueCell } from '../../mol-util';
|
||||
|
||||
@@ -23,6 +23,8 @@ export const SpheresSchema = {
|
||||
dDoubleSided: DefineSpec('boolean'),
|
||||
dIgnoreLight: DefineSpec('boolean'),
|
||||
dXrayShaded: DefineSpec('boolean'),
|
||||
uBumpFrequency: UniformSpec('f'),
|
||||
uBumpAmplitude: UniformSpec('f'),
|
||||
};
|
||||
export type SpheresSchema = typeof SpheresSchema
|
||||
export type SpheresValues = Values<SpheresSchema>
|
||||
|
||||
@@ -24,6 +24,8 @@ export const TextureMeshSchema = {
|
||||
dIgnoreLight: DefineSpec('boolean'),
|
||||
dXrayShaded: DefineSpec('boolean'),
|
||||
dGeoTexture: DefineSpec('boolean'),
|
||||
uBumpFrequency: UniformSpec('f'),
|
||||
uBumpAmplitude: UniformSpec('f'),
|
||||
meta: ValueSpec('unknown')
|
||||
};
|
||||
export type TextureMeshSchema = typeof TextureMeshSchema
|
||||
|
||||
@@ -8,17 +8,16 @@
|
||||
*/
|
||||
|
||||
export const apply_light_color = `
|
||||
// inputs
|
||||
// - vec4 material
|
||||
// - vec3 vViewPosition
|
||||
// - vec3 normal
|
||||
// - float uMetalness
|
||||
// - float uRoughness
|
||||
// - vec3 uLightColor
|
||||
// - vec3 uAmbientColor
|
||||
|
||||
// outputs
|
||||
// - sets gl_FragColor
|
||||
#ifdef bumpEnabled
|
||||
if (uBumpFrequency > 0.0 && uBumpAmplitude > 0.0) {
|
||||
vec3 bumpNormal = perturbNormal(-vViewPosition, normal, fbm(vModelPosition * uBumpFrequency), (uBumpAmplitude * bumpiness) / uBumpFrequency);
|
||||
#ifdef enabledFragDepth
|
||||
if (!any(isNaN(bumpNormal))) normal = bumpNormal;
|
||||
#else
|
||||
normal = bumpNormal;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
vec4 color = material;
|
||||
|
||||
@@ -26,7 +25,13 @@ ReflectedLight reflectedLight = ReflectedLight(vec3(0.0), vec3(0.0), vec3(0.0),
|
||||
|
||||
PhysicalMaterial physicalMaterial;
|
||||
physicalMaterial.diffuseColor = color.rgb * (1.0 - metalness);
|
||||
physicalMaterial.roughness = max(roughness, 0.0525);
|
||||
#ifdef enabledFragDepth
|
||||
physicalMaterial.roughness = min(max(roughness, 0.0525), 1.0);
|
||||
#else
|
||||
vec3 dxy = max(abs(dFdx(normal)), abs(dFdy(normal)));
|
||||
float geometryRoughness = max(max(dxy.x, dxy.y), dxy.z);
|
||||
physicalMaterial.roughness = min(max(roughness, 0.0525) + geometryRoughness, 1.0);
|
||||
#endif
|
||||
physicalMaterial.specularColor = mix(vec3(0.04), color.rgb, metalness);
|
||||
physicalMaterial.specularF90 = 1.0;
|
||||
|
||||
|
||||
@@ -44,16 +44,16 @@ export const assign_color_varying = `
|
||||
|
||||
#ifdef dSubstance
|
||||
#if defined(dSubstanceType_groupInstance)
|
||||
vSubstance = readFromTexture(tSubstance, aInstance * float(uGroupCount) + group, uSubstanceTexDim).rgb;
|
||||
vSubstance = readFromTexture(tSubstance, aInstance * float(uGroupCount) + group, uSubstanceTexDim);
|
||||
#elif defined(dSubstanceType_vertexInstance)
|
||||
vSubstance = readFromTexture(tSubstance, int(aInstance) * uVertexCount + VertexID, uSubstanceTexDim).rgb;
|
||||
vSubstance = readFromTexture(tSubstance, int(aInstance) * uVertexCount + VertexID, uSubstanceTexDim);
|
||||
#elif defined(dSubstanceType_volumeInstance)
|
||||
vec3 sgridPos = (uSubstanceGridTransform.w * (vModelPosition - uSubstanceGridTransform.xyz)) / uSubstanceGridDim;
|
||||
vSubstance = texture3dFrom2dLinear(tSubstanceGrid, sgridPos, uSubstanceGridDim, uSubstanceTexDim).rgb;
|
||||
vSubstance = texture3dFrom2dLinear(tSubstanceGrid, sgridPos, uSubstanceGridDim, uSubstanceTexDim);
|
||||
#endif
|
||||
|
||||
// pre-mix to avoid artifacts due to empty substance
|
||||
vSubstance.rg = mix(vec2(uMetalness, uRoughness), vSubstance.rg, vSubstance.b);
|
||||
vSubstance.rgb = mix(vec3(uMetalness, uRoughness, uBumpiness), vSubstance.rgb, vSubstance.a);
|
||||
#endif
|
||||
#elif defined(dRenderVariant_pick)
|
||||
#if defined(dRenderVariant_pickObject)
|
||||
|
||||
@@ -23,9 +23,11 @@ export const assign_material_color = `
|
||||
|
||||
float metalness = uMetalness;
|
||||
float roughness = uRoughness;
|
||||
float bumpiness = uBumpiness;
|
||||
#ifdef dSubstance
|
||||
metalness = mix(metalness, vSubstance.r, vSubstance.b);
|
||||
roughness = mix(roughness, vSubstance.g, vSubstance.b);
|
||||
metalness = mix(metalness, vSubstance.r, vSubstance.a);
|
||||
roughness = mix(roughness, vSubstance.g, vSubstance.a);
|
||||
bumpiness = mix(bumpiness, vSubstance.b, vSubstance.a);
|
||||
#endif
|
||||
#elif defined(dRenderVariant_pick)
|
||||
vec4 material = vColor;
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
export const color_frag_params = `
|
||||
uniform float uMetalness;
|
||||
uniform float uRoughness;
|
||||
uniform float uBumpiness;
|
||||
#ifdef bumpEnabled
|
||||
uniform float uBumpFrequency;
|
||||
uniform float uBumpAmplitude;
|
||||
#endif
|
||||
|
||||
#if defined(dRenderVariant_color)
|
||||
#if defined(dColorType_uniform)
|
||||
@@ -14,7 +19,7 @@ uniform float uRoughness;
|
||||
#endif
|
||||
|
||||
#ifdef dSubstance
|
||||
varying vec3 vSubstance;
|
||||
varying vec4 vSubstance;
|
||||
#endif
|
||||
#elif defined(dRenderVariant_pick)
|
||||
#if __VERSION__ == 100
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export const color_vert_params = `
|
||||
uniform float uMetalness;
|
||||
uniform float uRoughness;
|
||||
uniform float uBumpiness;
|
||||
|
||||
#if defined(dRenderVariant_color)
|
||||
#if defined(dColorType_uniform)
|
||||
@@ -36,11 +37,11 @@ uniform float uRoughness;
|
||||
|
||||
#ifdef dSubstance
|
||||
#if defined(dSubstanceType_groupInstance) || defined(dSubstanceType_vertexInstance)
|
||||
varying vec3 vSubstance;
|
||||
varying vec4 vSubstance;
|
||||
uniform vec2 uSubstanceTexDim;
|
||||
uniform sampler2D tSubstance;
|
||||
#elif defined(dSubstanceType_volumeInstance)
|
||||
varying vec3 vSubstance;
|
||||
varying vec4 vSubstance;
|
||||
uniform vec2 uSubstanceTexDim;
|
||||
uniform vec3 uSubstanceGridDim;
|
||||
uniform vec4 uSubstanceGridTransform;
|
||||
|
||||
@@ -76,4 +76,49 @@ float calcDepth(const in vec3 pos) {
|
||||
vec2 clipZW = pos.z * uProjection[2].zw + uProjection[3].zw;
|
||||
return 0.5 + 0.5 * clipZW.x / clipZW.y;
|
||||
}
|
||||
|
||||
// "Bump Mapping Unparametrized Surfaces on the GPU" Morten S. Mikkelsen
|
||||
// https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf
|
||||
vec3 perturbNormal(in vec3 position, in vec3 normal, in float height, in float scale) {
|
||||
vec3 sigmaS = dFdx(position);
|
||||
vec3 sigmaT = dFdy(position);
|
||||
|
||||
vec3 r1 = cross(sigmaT, normal);
|
||||
vec3 r2 = cross(normal, sigmaS);
|
||||
float det = dot(sigmaS, r1);
|
||||
|
||||
float bs = dFdx(height);
|
||||
float bt = dFdy(height);
|
||||
|
||||
vec3 surfGrad = sign(det) * (bs * r1 + bt * r2);
|
||||
return normalize(abs(det) * normal - scale * surfGrad);
|
||||
}
|
||||
|
||||
float hash(in float h) {
|
||||
return fract(sin(h) * 43758.5453123);
|
||||
}
|
||||
|
||||
float noise(in vec3 x) {
|
||||
vec3 p = floor(x);
|
||||
vec3 f = fract(x);
|
||||
f = f * f * (3.0 - 2.0 * f);
|
||||
|
||||
float n = p.x + p.y * 157.0 + 113.0 * p.z;
|
||||
return mix(
|
||||
mix(mix(hash(n + 0.0), hash(n + 1.0), f.x),
|
||||
mix(hash(n + 157.0), hash(n + 158.0), f.x), f.y),
|
||||
mix(mix(hash(n + 113.0), hash(n + 114.0), f.x),
|
||||
mix(hash(n + 270.0), hash(n + 271.0), f.x), f.y), f.z);
|
||||
}
|
||||
|
||||
float fbm(in vec3 p) {
|
||||
float f = 0.0;
|
||||
f += 0.5 * noise(p);
|
||||
p *= 2.01;
|
||||
f += 0.25 * noise(p);
|
||||
p *= 2.02;
|
||||
f += 0.125 * noise(p);
|
||||
|
||||
return f;
|
||||
}
|
||||
`;
|
||||
@@ -214,6 +214,9 @@ float depthToViewZ(const in float isOrtho, const in float linearClipZ, const in
|
||||
a31 * b01 - a30 * b03 - a32 * b00,
|
||||
a20 * b03 - a21 * b01 + a22 * b00) / det;
|
||||
}
|
||||
|
||||
#define isNaN(x) ( (x) != (x) )
|
||||
#define isInf(x) ( (x) == (x)+1. )
|
||||
#else
|
||||
#define transpose2(m) transpose(m)
|
||||
#define transpose3(m) transpose(m)
|
||||
@@ -222,5 +225,8 @@ float depthToViewZ(const in float isOrtho, const in float linearClipZ, const in
|
||||
#define inverse2(m) inverse(m)
|
||||
#define inverse3(m) inverse(m)
|
||||
#define inverse4(m) inverse(m)
|
||||
|
||||
#define isNaN isnan
|
||||
#define isInf isinf
|
||||
#endif
|
||||
`;
|
||||
@@ -8,8 +8,10 @@
|
||||
*/
|
||||
|
||||
export const light_frag_params = `
|
||||
uniform vec3 uLightDirection[dLightCount];
|
||||
uniform vec3 uLightColor[dLightCount];
|
||||
#if dLightCount != 0
|
||||
uniform vec3 uLightDirection[dLightCount];
|
||||
uniform vec3 uLightColor[dLightCount];
|
||||
#endif
|
||||
uniform vec3 uAmbientColor;
|
||||
|
||||
struct PhysicalMaterial {
|
||||
|
||||
@@ -8,6 +8,8 @@ export const cylinders_frag = `
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
|
||||
#define bumpEnabled
|
||||
|
||||
uniform mat4 uView;
|
||||
|
||||
varying mat4 vTransform;
|
||||
@@ -18,6 +20,7 @@ varying float vCap;
|
||||
|
||||
uniform vec3 uCameraDir;
|
||||
uniform vec3 uCameraPosition;
|
||||
uniform mat4 uInvView;
|
||||
|
||||
#include common
|
||||
#include common_frag_params
|
||||
@@ -108,7 +111,8 @@ void main() {
|
||||
vViewPosition = (uView * vec4(vViewPosition, 1.0)).xyz;
|
||||
gl_FragDepthEXT = calcDepth(vViewPosition);
|
||||
|
||||
// bugfix (mac only?)
|
||||
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
|
||||
|
||||
if (gl_FragDepthEXT < 0.0) discard;
|
||||
if (gl_FragDepthEXT > 1.0) discard;
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ export const mesh_frag = `
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
|
||||
#define bumpEnabled
|
||||
|
||||
#include common
|
||||
#include common_frag_params
|
||||
#include color_frag_params
|
||||
|
||||
@@ -21,6 +21,7 @@ uniform float uFar;
|
||||
uniform float uFogNear;
|
||||
uniform float uFogFar;
|
||||
uniform vec3 uFogColor;
|
||||
uniform vec3 uOutlineColor;
|
||||
uniform bool uTransparentBackground;
|
||||
|
||||
uniform float uOcclusionBias;
|
||||
@@ -116,7 +117,7 @@ void main(void) {
|
||||
float outline = getOutline(coords, closestTexel);
|
||||
|
||||
if (outline == 0.0) {
|
||||
color.rgb *= outline;
|
||||
color.rgb = mix(uOutlineColor, color.rgb, outline);
|
||||
viewDist = abs(getViewZ(closestTexel));
|
||||
fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
|
||||
if (!uTransparentBackground) {
|
||||
|
||||
@@ -8,12 +8,16 @@ export const spheres_frag = `
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
|
||||
#define bumpEnabled
|
||||
|
||||
#include common
|
||||
#include common_frag_params
|
||||
#include color_frag_params
|
||||
#include light_frag_params
|
||||
#include common_clip
|
||||
|
||||
uniform mat4 uInvView;
|
||||
|
||||
varying float vRadius;
|
||||
varying float vRadiusSq;
|
||||
varying vec3 vPoint;
|
||||
@@ -73,7 +77,8 @@ void main(void){
|
||||
gl_FragDepthEXT = 0.0 + (0.0000001 / vRadius);
|
||||
}
|
||||
|
||||
// bugfix (mac only?)
|
||||
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
|
||||
|
||||
if (gl_FragDepthEXT < 0.0) discard;
|
||||
if (gl_FragDepthEXT > 1.0) discard;
|
||||
|
||||
|
||||
@@ -283,8 +283,10 @@ export namespace Model {
|
||||
export function isFromPdbArchive(model: Model): boolean {
|
||||
if (!MmcifFormat.is(model.sourceData)) return false;
|
||||
const { db } = model.sourceData.data;
|
||||
for (let i = 0, il = db.database_2.database_id.rowCount; i < il; ++i) {
|
||||
if (db.database_2.database_id.value(i) === 'PDB') return true;
|
||||
}
|
||||
return (
|
||||
db.database_2.database_id.isDefined ||
|
||||
// 4 character PDB id
|
||||
model.entryId.match(/^[1-9][a-z0-9]{3,3}$/i) !== null ||
|
||||
// long PDB id
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
@@ -7,7 +7,9 @@
|
||||
|
||||
import * as React from 'react';
|
||||
import { Mat4, Vec2, Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { ColorListEntry } from '../../mol-util/color/color';
|
||||
import { ColorListName, ColorListOptions, ColorListOptionsScale, ColorListOptionsSet, getColorListFromName } from '../../mol-util/color/lists';
|
||||
import { Legend as LegendData } from '../../mol-util/legend';
|
||||
import { memoize1, memoizeLatest } from '../../mol-util/memoize';
|
||||
@@ -16,16 +18,14 @@ 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 { PluginUIContext } from '../context';
|
||||
import { ActionMenu } from './action-menu';
|
||||
import { ColorOptions, ColorValueOption, CombinedColorControl } from './color';
|
||||
import { Button, ControlGroup, ControlRow, ExpandGroup, IconButton, TextInput, ToggleButton } from './common';
|
||||
import { Icon, HelpOutlineSvg, CheckSvg, ClearSvg, BookmarksOutlinedSvg, MoreHorizSvg, ArrowDropDownSvg, ArrowRightSvg, ArrowDownwardSvg, ArrowUpwardSvg, DeleteOutlinedSvg, TuneSvg } from './icons';
|
||||
import { ArrowDownwardSvg, ArrowDropDownSvg, ArrowRightSvg, ArrowUpwardSvg, BookmarksOutlinedSvg, CheckSvg, ClearSvg, DeleteOutlinedSvg, HelpOutlineSvg, Icon, MoreHorizSvg } from './icons';
|
||||
import { legendFor } from './legend';
|
||||
import { LineGraphComponent } from './line-graph/line-graph-component';
|
||||
import { Slider, Slider2 } from './slider';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import { ColorListEntry } from '../../mol-util/color/color';
|
||||
import { PluginUIContext } from '../context';
|
||||
|
||||
export type ParameterControlsCategoryFilter = string | null | (string | null)[]
|
||||
|
||||
@@ -1100,14 +1100,14 @@ export class GroupControl extends React.PureComponent<ParamProps<PD.Group<any>>
|
||||
this.change(item?.value);
|
||||
}
|
||||
|
||||
presets() {
|
||||
pivotedPresets() {
|
||||
if (!this.props.param.presets) return null;
|
||||
|
||||
const label = this.props.param.label || camelCaseToWords(this.props.name);
|
||||
return <div className='msp-control-group-wrapper'>
|
||||
<div className='msp-control-group-header'>
|
||||
<button className='msp-btn msp-form-control msp-btn-block' onClick={this.toggleShowPresets}>
|
||||
<Icon svg={TuneSvg} />
|
||||
<Icon svg={BookmarksOutlinedSvg} />
|
||||
{label} Presets
|
||||
</button>
|
||||
</div>
|
||||
@@ -1115,6 +1115,22 @@ export class GroupControl extends React.PureComponent<ParamProps<PD.Group<any>>
|
||||
</div>;
|
||||
}
|
||||
|
||||
presets() {
|
||||
if (!this.props.param.presets) return null;
|
||||
|
||||
return <>
|
||||
<div className='msp-control-group-presets-wrapper'>
|
||||
<div className='msp-control-group-header'>
|
||||
<button className='msp-btn msp-form-control msp-btn-block' onClick={this.toggleShowPresets}>
|
||||
<Icon svg={BookmarksOutlinedSvg} />
|
||||
Presets
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{this.state.showPresets && <ActionMenu items={this.presetItems(this.props.param)} onSelect={this.onSelectPreset} />}
|
||||
</>;
|
||||
}
|
||||
|
||||
pivoted() {
|
||||
const key = this.props.param.pivot as string;
|
||||
const params = this.props.param.params;
|
||||
@@ -1139,7 +1155,7 @@ export class GroupControl extends React.PureComponent<ParamProps<PD.Group<any>>
|
||||
{ctrl}
|
||||
<IconButton svg={MoreHorizSvg} onClick={this.toggleExpanded} toggleState={this.state.isExpanded} title={`More Options`} />
|
||||
<div className='msp-control-offset'>
|
||||
{this.presets()}
|
||||
{this.pivotedPresets()}
|
||||
<ParameterControls params={filtered} onEnter={this.props.onEnter} values={this.props.value} onChange={this.onChangeParam} isDisabled={this.props.isDisabled} />
|
||||
</div>
|
||||
</div>;
|
||||
@@ -1165,15 +1181,15 @@ export class GroupControl extends React.PureComponent<ParamProps<PD.Group<any>>
|
||||
return controls;
|
||||
}
|
||||
|
||||
return <div className='msp-control-group-wrapper'>
|
||||
return <div className='msp-control-group-wrapper' style={{ position: 'relative' }}>
|
||||
<div className='msp-control-group-header'>
|
||||
<button className='msp-btn msp-form-control msp-btn-block' onClick={this.toggleExpanded}>
|
||||
<Icon svg={this.state.isExpanded ? ArrowDropDownSvg : ArrowRightSvg} />
|
||||
{label}
|
||||
</button>
|
||||
</div>
|
||||
{this.presets()}
|
||||
{this.state.isExpanded && <div className='msp-control-offset'>
|
||||
{this.presets()}
|
||||
{controls}
|
||||
</div>}
|
||||
</div>;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-21 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
interface Behavior<T> {
|
||||
value: T;
|
||||
@@ -16,26 +16,20 @@ export function useBehavior<T>(s: Behavior<T>): T;
|
||||
export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined;
|
||||
// eslint-disable-next-line
|
||||
export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined {
|
||||
const [value, setValue] = useState(s?.value);
|
||||
const [, next] = useState({});
|
||||
const current = useRef<T>();
|
||||
current.current = s?.value;
|
||||
|
||||
useEffect(() => {
|
||||
if (!s) {
|
||||
if (value !== void 0) setValue(void 0);
|
||||
return;
|
||||
}
|
||||
let fst = true;
|
||||
const sub = s.subscribe((v) => {
|
||||
if (fst) {
|
||||
fst = false;
|
||||
if (v !== value) setValue(v);
|
||||
} else setValue(v);
|
||||
if (current.current !== v) next({});
|
||||
});
|
||||
|
||||
return () => {
|
||||
sub.unsubscribe();
|
||||
};
|
||||
// eslint-disable-next-line
|
||||
return () => sub.unsubscribe();
|
||||
}, [s]);
|
||||
|
||||
return value;
|
||||
return s?.value;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
@@ -18,6 +18,10 @@ import { Toasts } from './toast';
|
||||
import { Viewport, ViewportControls } from './viewport';
|
||||
import { PluginCommands } from '../mol-plugin/commands';
|
||||
import { PluginUIContext } from './context';
|
||||
import { OpenFiles } from '../mol-plugin-state/actions/file';
|
||||
import { Asset } from '../mol-util/assets';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { useBehavior } from './hooks/use-behavior';
|
||||
|
||||
export class Plugin extends React.Component<{ plugin: PluginUIContext }, {}> {
|
||||
region(kind: 'left' | 'right' | 'bottom' | 'main', element: JSX.Element) {
|
||||
@@ -102,22 +106,34 @@ class Layout extends PluginUIComponent {
|
||||
onDrop = (ev: React.DragEvent<HTMLDivElement>) => {
|
||||
ev.preventDefault();
|
||||
|
||||
let file: File | undefined | null;
|
||||
const files: File[] = [];
|
||||
if (ev.dataTransfer.items) {
|
||||
// Use DataTransferItemList interface to access the file(s)
|
||||
for (let i = 0; i < ev.dataTransfer.items.length; i++) {
|
||||
if (ev.dataTransfer.items[i].kind !== 'file') continue;
|
||||
file = ev.dataTransfer.items[i].getAsFile();
|
||||
break;
|
||||
const file = ev.dataTransfer.items[i].getAsFile();
|
||||
if (file) files.push(file);
|
||||
}
|
||||
} else {
|
||||
file = ev.dataTransfer.files[0];
|
||||
for (let i = 0; i < ev.dataTransfer.files.length; i++) {
|
||||
const file = ev.dataTransfer.files[0];
|
||||
if (file) files.push(file);
|
||||
}
|
||||
}
|
||||
if (!file) return;
|
||||
|
||||
const fn = file?.name.toLowerCase() || '';
|
||||
if (fn.endsWith('molx') || fn.endsWith('molj')) {
|
||||
PluginCommands.State.Snapshots.OpenFile(this.plugin, { file });
|
||||
const sessions = files.filter(f => {
|
||||
const fn = f.name.toLowerCase();
|
||||
return fn.endsWith('.molx') || fn.endsWith('.molj');
|
||||
});
|
||||
|
||||
if (sessions.length > 0) {
|
||||
PluginCommands.State.Snapshots.OpenFile(this.plugin, { file: sessions[0] });
|
||||
} else {
|
||||
this.plugin.runTask(this.plugin.state.data.applyAction(OpenFiles, {
|
||||
files: files.map(f => Asset.File(f)),
|
||||
format: { name: 'auto', params: {} },
|
||||
visuals: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,13 +141,16 @@ class Layout extends PluginUIComponent {
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
private showDragOverlay = new BehaviorSubject(false);
|
||||
onDragEnter = () => this.showDragOverlay.next(true);
|
||||
|
||||
render() {
|
||||
const layout = this.plugin.layout.state;
|
||||
const controls = this.plugin.spec.components?.controls || {};
|
||||
const viewport = this.plugin.spec.components?.viewport?.view || DefaultViewport;
|
||||
|
||||
return <div className='msp-plugin' onDrop={this.onDrop} onDragOver={this.onDragOver}>
|
||||
<div className={this.layoutClassName}>
|
||||
return <div className='msp-plugin'>
|
||||
<div className={this.layoutClassName} onDragEnter={this.onDragEnter}>
|
||||
<div className={this.layoutVisibilityClassName}>
|
||||
{this.region('main', viewport)}
|
||||
{layout.showControls && controls.top !== 'none' && this.region('top', controls.top || SequenceView)}
|
||||
@@ -140,11 +159,69 @@ class Layout extends PluginUIComponent {
|
||||
{layout.showControls && controls.bottom !== 'none' && this.region('bottom', controls.bottom || Log)}
|
||||
</div>
|
||||
{!this.plugin.spec.components?.hideTaskOverlay && <OverlayTaskProgress />}
|
||||
<DragOverlay plugin={this.plugin} showDragOverlay={this.showDragOverlay} />
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
function dropFiles(ev: React.DragEvent<HTMLDivElement>, plugin: PluginUIContext, showDragOverlay: BehaviorSubject<boolean>) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
showDragOverlay.next(false);
|
||||
|
||||
const files: File[] = [];
|
||||
if (ev.dataTransfer.items) {
|
||||
// Use DataTransferItemList interface to access the file(s)
|
||||
for (let i = 0; i < ev.dataTransfer.items.length; i++) {
|
||||
if (ev.dataTransfer.items[i].kind !== 'file') continue;
|
||||
const file = ev.dataTransfer.items[i].getAsFile();
|
||||
if (file) files.push(file);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < ev.dataTransfer.files.length; i++) {
|
||||
const file = ev.dataTransfer.files[0];
|
||||
if (file) files.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
const sessions = files.filter(f => {
|
||||
const fn = f.name.toLowerCase();
|
||||
return fn.endsWith('.molx') || fn.endsWith('.molj');
|
||||
});
|
||||
|
||||
if (sessions.length > 0) {
|
||||
PluginCommands.State.Snapshots.OpenFile(plugin, { file: sessions[0] });
|
||||
} else {
|
||||
plugin.runTask(plugin.state.data.applyAction(OpenFiles, {
|
||||
files: files.map(f => Asset.File(f)),
|
||||
format: { name: 'auto', params: {} },
|
||||
visuals: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function DragOverlay({ plugin, showDragOverlay }: { plugin: PluginUIContext, showDragOverlay: BehaviorSubject<boolean> }) {
|
||||
const show = useBehavior(showDragOverlay);
|
||||
|
||||
const preventDrag = (e: React.DragEvent) => {
|
||||
e.dataTransfer.dropEffect = 'copy';
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
return <div
|
||||
className='msp-drag-drop-overlay'
|
||||
style={{ display: show ? 'flex' : 'none' }}
|
||||
onDragEnter={preventDrag}
|
||||
onDragOver={preventDrag}
|
||||
onDragLeave={() => showDragOverlay.next(false)}
|
||||
onDrop={e => dropFiles(e, plugin, showDragOverlay)}
|
||||
>
|
||||
Upload File(s)
|
||||
</div>;
|
||||
}
|
||||
|
||||
export class ControlsWrapper extends PluginUIComponent {
|
||||
render() {
|
||||
const StructureTools = this.plugin.spec.components?.structureTools || DefaultStructureTools;
|
||||
|
||||
@@ -529,6 +529,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.msp-control-group-presets-wrapper {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
.msp-control-group-header {
|
||||
background: transparent;
|
||||
}
|
||||
button {
|
||||
background: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
.msp-parameter-matrix {
|
||||
input {
|
||||
flex: 1 1 auto;
|
||||
@@ -614,4 +626,19 @@
|
||||
.msp-list-unstyled {
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.msp-drag-drop-overlay {
|
||||
border: 12px dashed $font-color;
|
||||
background: rgba(0, 0, 0, 0.36);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -20,12 +20,17 @@ export class PluginConfigItem<T = any> {
|
||||
function item<T>(key: string, defaultValue?: T) { return new PluginConfigItem(key, defaultValue); }
|
||||
|
||||
|
||||
function preferWebGl1() {
|
||||
export function preferWebGl1() {
|
||||
if (typeof navigator === 'undefined' || typeof window === 'undefined') return false;
|
||||
|
||||
// WebGL2 isn't working in MacOS 12.0.1 Safari 15.1 (but is working in Safari tech preview)
|
||||
// WebGL2 isn't working in MacOS 12.0.1 Safari 15.1, 15.2. It is working in Safari 15.4 tech preview, so disabling all versions before that.
|
||||
// prefer webgl 1 based on the userAgent substring
|
||||
if (navigator.userAgent.indexOf('Version/15.1 Safari') > 0) {
|
||||
const unpportedSafariVersions = [
|
||||
'Version/15.1 Safari',
|
||||
'Version/15.2 Safari',
|
||||
'Version/15.3 Safari'
|
||||
];
|
||||
if (unpportedSafariVersions.some(v => navigator.userAgent.indexOf(v) > 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ThemeRegistryContext } from '../../../mol-theme/theme';
|
||||
import { Structure } from '../../../mol-model/structure';
|
||||
import { PolymerBackboneSphereParams, PolymerBackboneSphereVisual } from '../visual/polymer-backbone-sphere';
|
||||
import { PolymerGapParams, PolymerGapVisual } from '../visual/polymer-gap-cylinder';
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
|
||||
const BackboneVisuals = {
|
||||
'polymer-backbone-cylinder': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, PolymerBackboneCylinderParams>) => UnitsRepresentation('Polymer backbone cylinder', ctx, getParams, PolymerBackboneCylinderVisual),
|
||||
@@ -25,7 +26,8 @@ export const BackboneParams = {
|
||||
...PolymerBackboneCylinderParams,
|
||||
...PolymerGapParams,
|
||||
sizeAspectRatio: PD.Numeric(1, { min: 0.1, max: 3, step: 0.1 }),
|
||||
visuals: PD.MultiSelect(['polymer-backbone-cylinder', 'polymer-backbone-sphere', 'polymer-gap'], PD.objectToOptions(BackboneVisuals))
|
||||
visuals: PD.MultiSelect(['polymer-backbone-cylinder', 'polymer-backbone-sphere', 'polymer-gap'], PD.objectToOptions(BackboneVisuals)),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type BackboneParams = typeof BackboneParams
|
||||
export function getBackboneParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Representation, RepresentationParamsGetter, RepresentationContext } fro
|
||||
import { ThemeRegistryContext } from '../../../mol-theme/theme';
|
||||
import { Structure } from '../../../mol-model/structure';
|
||||
import { getUnitKindsParam } from '../params';
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
|
||||
const BallAndStickVisuals = {
|
||||
'element-sphere': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, ElementSphereParams>) => UnitsRepresentation('Element sphere', ctx, getParams, ElementSphereVisual),
|
||||
@@ -31,7 +32,8 @@ export const BallAndStickParams = {
|
||||
unitKinds: getUnitKindsParam(['atomic']),
|
||||
sizeFactor: PD.Numeric(0.15, { min: 0.01, max: 10, step: 0.01 }),
|
||||
sizeAspectRatio: PD.Numeric(2 / 3, { min: 0.01, max: 3, step: 0.01 }),
|
||||
visuals: PD.MultiSelect(['element-sphere', 'intra-bond', 'inter-bond'], PD.objectToOptions(BallAndStickVisuals))
|
||||
visuals: PD.MultiSelect(['element-sphere', 'intra-bond', 'inter-bond'], PD.objectToOptions(BallAndStickVisuals)),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type BallAndStickParams = typeof BallAndStickParams
|
||||
export function getBallAndStickParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
import { Structure, Model } from '../../../mol-model/structure';
|
||||
import { Representation, RepresentationContext, RepresentationParamsGetter } from '../../../mol-repr/representation';
|
||||
import { ThemeRegistryContext } from '../../../mol-theme/theme';
|
||||
@@ -25,6 +26,7 @@ export const CarbohydrateParams = {
|
||||
...CarbohydrateLinkParams,
|
||||
...CarbohydrateTerminalLinkParams,
|
||||
visuals: PD.MultiSelect(['carbohydrate-symbol', 'carbohydrate-link', 'carbohydrate-terminal-link'], PD.objectToOptions(CarbohydrateVisuals)),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type CarbohydrateParams = typeof CarbohydrateParams
|
||||
export function getCarbohydrateParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import { PolymerTraceParams, PolymerTraceVisual } from '../visual/polymer-trace-
|
||||
import { SecondaryStructureProvider } from '../../../mol-model-props/computed/secondary-structure';
|
||||
import { CustomProperty } from '../../../mol-model-props/common/custom-property';
|
||||
import { HelixOrientationProvider } from '../../../mol-model-props/computed/helix-orientation';
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
|
||||
const CartoonVisuals = {
|
||||
'polymer-trace': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, PolymerTraceParams>) => UnitsRepresentation('Polymer trace mesh', ctx, getParams, PolymerTraceVisual),
|
||||
@@ -35,6 +36,7 @@ export const CartoonParams = {
|
||||
...PolymerDirectionParams,
|
||||
sizeFactor: PD.Numeric(0.2, { min: 0, max: 10, step: 0.01 }),
|
||||
visuals: PD.MultiSelect(['polymer-trace', 'polymer-gap', 'nucleotide-block'], PD.objectToOptions(CartoonVisuals)),
|
||||
bumpFrequency: PD.Numeric(2, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
|
||||
export type CartoonParams = typeof CartoonParams
|
||||
|
||||
@@ -14,6 +14,7 @@ import { AtomSiteAnisotrop } from '../../../mol-model-formats/structure/property
|
||||
import { IntraUnitBondCylinderParams, IntraUnitBondCylinderVisual } from '../visual/bond-intra-unit-cylinder';
|
||||
import { InterUnitBondCylinderVisual, InterUnitBondCylinderParams } from '../visual/bond-inter-unit-cylinder';
|
||||
import { getUnitKindsParam } from '../params';
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
|
||||
const EllipsoidVisuals = {
|
||||
'ellipsoid-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, EllipsoidMeshParams>) => UnitsRepresentation('Ellipsoid Mesh', ctx, getParams, EllipsoidMeshVisual),
|
||||
@@ -32,6 +33,7 @@ export const EllipsoidParams = {
|
||||
sizeAspectRatio: PD.Numeric(0.1, { min: 0.01, max: 3, step: 0.01 }),
|
||||
linkCap: PD.Boolean(true),
|
||||
visuals: PD.MultiSelect(['ellipsoid-mesh', 'intra-bond', 'inter-bond'], PD.objectToOptions(EllipsoidVisuals)),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type EllipsoidParams = typeof EllipsoidParams
|
||||
export function getEllipsoidParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { StructureRepresentation, StructureRepresentationProvider, StructureRepr
|
||||
import { Representation, RepresentationParamsGetter, RepresentationContext } from '../../../mol-repr/representation';
|
||||
import { ThemeRegistryContext } from '../../../mol-theme/theme';
|
||||
import { Structure } from '../../../mol-model/structure';
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
|
||||
const GaussianSurfaceVisuals = {
|
||||
'gaussian-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, GaussianSurfaceMeshParams>) => UnitsRepresentation('Gaussian surface mesh', ctx, getParams, GaussianSurfaceVisual),
|
||||
@@ -23,6 +24,7 @@ export const GaussianSurfaceParams = {
|
||||
...GaussianSurfaceMeshParams,
|
||||
...GaussianWireframeParams,
|
||||
visuals: PD.MultiSelect(['gaussian-surface-mesh'], PD.objectToOptions(GaussianSurfaceVisuals)),
|
||||
bumpFrequency: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type GaussianSurfaceParams = typeof GaussianSurfaceParams
|
||||
export function getGaussianSurfaceParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Representation, RepresentationParamsGetter, RepresentationContext } fro
|
||||
import { ThemeRegistryContext } from '../../../mol-theme/theme';
|
||||
import { Structure } from '../../../mol-model/structure';
|
||||
import { MolecularSurfaceWireframeParams, MolecularSurfaceWireframeVisual } from '../visual/molecular-surface-wireframe';
|
||||
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),
|
||||
@@ -22,6 +23,7 @@ export const MolecularSurfaceParams = {
|
||||
...MolecularSurfaceMeshParams,
|
||||
...MolecularSurfaceWireframeParams,
|
||||
visuals: PD.MultiSelect(['molecular-surface-mesh'], PD.objectToOptions(MolecularSurfaceVisuals)),
|
||||
bumpFrequency: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type MolecularSurfaceParams = typeof MolecularSurfaceParams
|
||||
export function getMolecularSurfaceParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Representation, RepresentationParamsGetter, RepresentationContext } fro
|
||||
import { ThemeRegistryContext } from '../../../mol-theme/theme';
|
||||
import { Structure } from '../../../mol-model/structure';
|
||||
import { OrientationEllipsoidMeshParams, OrientationEllipsoidMeshVisual } from '../visual/orientation-ellipsoid-mesh';
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
|
||||
const OrientationVisuals = {
|
||||
'orientation-ellipsoid-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, OrientationEllipsoidMeshParams>) => UnitsRepresentation('Orientation ellipsoid mesh', ctx, getParams, OrientationEllipsoidMeshVisual),
|
||||
@@ -19,6 +20,7 @@ const OrientationVisuals = {
|
||||
export const OrientationParams = {
|
||||
...OrientationEllipsoidMeshParams,
|
||||
visuals: PD.MultiSelect(['orientation-ellipsoid-mesh'], PD.objectToOptions(OrientationVisuals)),
|
||||
bumpFrequency: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type OrientationParams = typeof OrientationParams
|
||||
export function getOrientationParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { StructureRepresentation, StructureRepresentationProvider, StructureRepr
|
||||
import { Representation, RepresentationParamsGetter, RepresentationContext } from '../../../mol-repr/representation';
|
||||
import { Structure, Unit } from '../../../mol-model/structure';
|
||||
import { ThemeRegistryContext } from '../../../mol-theme/theme';
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
|
||||
const PuttyVisuals = {
|
||||
'polymer-tube': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, PolymerTubeParams>) => UnitsRepresentation('Polymer tube mesh', ctx, getParams, PolymerTubeVisual),
|
||||
@@ -23,6 +24,7 @@ export const PuttyParams = {
|
||||
...PolymerGapParams,
|
||||
sizeFactor: PD.Numeric(0.2, { min: 0, max: 10, step: 0.01 }),
|
||||
visuals: PD.MultiSelect(['polymer-tube', 'polymer-gap'], PD.objectToOptions(PuttyVisuals)),
|
||||
bumpFrequency: PD.Numeric(2, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type PuttyParams = typeof PuttyParams
|
||||
export function getPuttyParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { StructureRepresentation, StructureRepresentationProvider, StructureRepr
|
||||
import { RepresentationParamsGetter, RepresentationContext, Representation } from '../../../mol-repr/representation';
|
||||
import { ThemeRegistryContext } from '../../../mol-theme/theme';
|
||||
import { Structure } from '../../../mol-model/structure';
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
|
||||
const SpacefillVisuals = {
|
||||
'element-sphere': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, ElementSphereParams>) => UnitsRepresentation('Sphere mesh', ctx, getParams, ElementSphereVisual),
|
||||
@@ -18,6 +19,7 @@ const SpacefillVisuals = {
|
||||
|
||||
export const SpacefillParams = {
|
||||
...ElementSphereParams,
|
||||
bumpFrequency: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type SpacefillParams = typeof SpacefillParams
|
||||
export function getSpacefillParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
@@ -21,11 +21,12 @@ import { BoundaryHelper } from '../../../mol-math/geometry/boundary-helper';
|
||||
|
||||
export const LabelTextParams = {
|
||||
...ComplexTextParams,
|
||||
background: PD.Boolean(true),
|
||||
background: PD.Boolean(false),
|
||||
backgroundMargin: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }),
|
||||
backgroundColor: PD.Color(ColorNames.black),
|
||||
backgroundOpacity: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
|
||||
level: PD.Select('residue', [['chain', 'Chain'], ['residue', 'Residue'], ['element', 'Element']] as const),
|
||||
borderWidth: PD.Numeric(0.25, { min: 0, max: 0.5, step: 0.01 }),
|
||||
level: PD.Select('residue', [['chain', 'Chain'], ['residue', 'Residue'], ['element', 'Element']] as const, { isEssential: true }),
|
||||
chainScale: PD.Numeric(10, { min: 0, max: 20, step: 0.1 }),
|
||||
residueScale: PD.Numeric(1, { min: 0, max: 20, step: 0.1 }),
|
||||
elementScale: PD.Numeric(0.5, { min: 0, max: 20, step: 0.1 }),
|
||||
|
||||
@@ -28,6 +28,7 @@ import { extractIsosurface } from '../../mol-gl/compute/marching-cubes/isosurfac
|
||||
import { WebGLContext } from '../../mol-gl/webgl/context';
|
||||
import { CustomPropertyDescriptor } from '../../mol-model/custom-property';
|
||||
import { Texture } from '../../mol-gl/webgl/texture';
|
||||
import { BaseGeometry } from '../../mol-geo/geometry/base';
|
||||
|
||||
export const VolumeIsosurfaceParams = {
|
||||
isoValue: Volume.IsoValueParam
|
||||
@@ -260,6 +261,7 @@ export const IsosurfaceParams = {
|
||||
...IsosurfaceMeshParams,
|
||||
...IsosurfaceWireframeParams,
|
||||
visuals: PD.MultiSelect(['solid'], PD.objectToOptions(IsosurfaceVisuals)),
|
||||
bumpFrequency: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
export type IsosurfaceParams = typeof IsosurfaceParams
|
||||
export function getIsosurfaceParams(ctx: ThemeRegistryContext, volume: Volume) {
|
||||
|
||||
@@ -17,7 +17,8 @@ const DefaultIllustrativeColor = Color(0xEEEEEE);
|
||||
const Description = `Assigns an illustrative color that gives every chain a unique color with lighter carbons (inspired by David Goodsell's Molecule of the Month style).`;
|
||||
|
||||
export const IllustrativeColorThemeParams = {
|
||||
...ChainIdColorThemeParams
|
||||
...ChainIdColorThemeParams,
|
||||
carbonLightness: PD.Numeric(0.8, { min: -6, max: 6, step: 0.1 })
|
||||
};
|
||||
export type IllustrativeColorThemeParams = typeof IllustrativeColorThemeParams
|
||||
export function getIllustrativeColorThemeParams(ctx: ThemeDataContext) {
|
||||
@@ -29,7 +30,7 @@ export function IllustrativeColorTheme(ctx: ThemeDataContext, props: PD.Values<I
|
||||
|
||||
function illustrativeColor(location: Location, typeSymbol: ElementSymbol) {
|
||||
const baseColor = chainIdColor(location, false);
|
||||
return typeSymbol === 'C' ? Color.lighten(baseColor, 0.8) : baseColor;
|
||||
return typeSymbol === 'C' ? Color.lighten(baseColor, props.carbonLightness) : baseColor;
|
||||
}
|
||||
|
||||
function color(location: Location): Color {
|
||||
|
||||
@@ -12,6 +12,8 @@ export interface Material {
|
||||
metalness: number,
|
||||
/** Normalized to [0, 1] range */
|
||||
roughness: number
|
||||
/** Normalized to [0, 1] range */
|
||||
bumpiness: number
|
||||
}
|
||||
|
||||
export function Material(values?: Partial<Material>) {
|
||||
@@ -19,29 +21,31 @@ export function Material(values?: Partial<Material>) {
|
||||
}
|
||||
|
||||
export namespace Material {
|
||||
export const Zero: Material = { metalness: 0, roughness: 0 };
|
||||
export const Zero: Material = { metalness: 0, roughness: 0, bumpiness: 0 };
|
||||
|
||||
export function toArray(material: Material, array: NumberArray, offset: number) {
|
||||
array[offset] = material.metalness * 255;
|
||||
array[offset + 1] = material.roughness * 255;
|
||||
array[offset + 2] = material.bumpiness * 255;
|
||||
return array;
|
||||
}
|
||||
|
||||
export function toString({ metalness, roughness }: Material) {
|
||||
return `M ${metalness.toFixed(2)} | R ${roughness.toFixed(2)}`;
|
||||
export function toString({ metalness, roughness, bumpiness }: Material) {
|
||||
return `M ${metalness.toFixed(2)} | R ${roughness.toFixed(2)} | B ${bumpiness.toFixed(2)}`;
|
||||
}
|
||||
|
||||
export function getParam(info?: { isExpanded?: boolean, isFlat?: boolean }) {
|
||||
return PD.Group({
|
||||
metalness: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }),
|
||||
roughness: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }),
|
||||
bumpiness: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }),
|
||||
}, {
|
||||
...info,
|
||||
presets: [
|
||||
[{ metalness: 0, roughness: 1 }, 'Matte'],
|
||||
[{ metalness: 0, roughness: 0.2 }, 'Plastic'],
|
||||
[{ metalness: 0, roughness: 0.6 }, 'Glossy'],
|
||||
[{ metalness: 1.0, roughness: 0.6 }, 'Metallic'],
|
||||
[{ metalness: 0, roughness: 1, bumpiness: 0 }, 'Matte'],
|
||||
[{ metalness: 0, roughness: 0.2, bumpiness: 0 }, 'Plastic'],
|
||||
[{ metalness: 0, roughness: 0.6, bumpiness: 0 }, 'Glossy'],
|
||||
[{ metalness: 1.0, roughness: 0.6, bumpiness: 0 }, 'Metallic'],
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user