mirror of
https://github.com/molstar/molstar.git
synced 2026-06-07 15:14:22 +08:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae795f8ad3 | ||
|
|
9d3c071689 | ||
|
|
01cb23f566 | ||
|
|
fe8a9799ab | ||
|
|
4f18154681 | ||
|
|
2114c4a3ad | ||
|
|
2ca41b2b51 | ||
|
|
6605a2019e | ||
|
|
8b1ed5f183 | ||
|
|
f11a1b788f | ||
|
|
7928e24c54 | ||
|
|
5dbca41da6 | ||
|
|
e636397f90 | ||
|
|
6d76bf120d | ||
|
|
a50e81551f | ||
|
|
86512bcea1 | ||
|
|
975f45eb01 | ||
|
|
f2399d3179 | ||
|
|
b26d62a067 | ||
|
|
926d6cbd46 | ||
|
|
7ea47d2a99 | ||
|
|
89ad8cfc15 | ||
|
|
302a309aff | ||
|
|
c3e62bc2e5 | ||
|
|
c2ab322bd2 | ||
|
|
aeab0f235c | ||
|
|
ae2285599f | ||
|
|
104ab757d2 | ||
|
|
de84a8c8c5 | ||
|
|
4fa135daf0 | ||
|
|
9870cb4082 | ||
|
|
b2924761ab |
26
CHANGELOG.md
26
CHANGELOG.md
@@ -6,6 +6,32 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v3.32.0] - 2023-03-20
|
||||
|
||||
- Avoid rendering of fully transparent renderables
|
||||
- Add occlusion color parameter
|
||||
- Fix issue with outlines and orthographic camera
|
||||
- Reduce over-blurring occlusion at larger view distances
|
||||
- Fix occlusion artefact with non-canvas viewport and pixel-ratio > 1
|
||||
- Update nodejs-shims conditionals to handle polyfilled document object in NodeJS environment.
|
||||
- Ensure marking edges are at least one pixel wide
|
||||
- Add exposure parameter to renderer
|
||||
- Only trigger marking when mouse is directly over canvas
|
||||
- Fix blurry occlusion in screenshots
|
||||
- [Breaking] Add `setFSModule` to `mol-util/data-source` instead of trying to trick WebPack
|
||||
|
||||
## [v3.31.4] - 2023-02-24
|
||||
|
||||
- Allow link cylinder/line `dashCount` set to '0'
|
||||
- Stop animation loop when disposing `PluginContext` (thanks @gfrn for identifying the issue)
|
||||
|
||||
## [v3.31.3] - 2023-02-22
|
||||
|
||||
- Fix impostor bond visuals not correctly updating on `sizeFactor` changes
|
||||
- Fix degenerate case in PCA
|
||||
- Fix near clipping avoidance in impostor shaders
|
||||
- Update `fs` import in `data-source.ts`
|
||||
|
||||
## [v3.31.2] - 2023-02-12
|
||||
|
||||
- Fix exit code of volume pack executable (pack.ts). Now exits with non-0 status when an error happens
|
||||
|
||||
3449
package-lock.json
generated
3449
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
52
package.json
52
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.31.2",
|
||||
"version": "3.32.0",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -95,51 +95,53 @@
|
||||
"Gianluca Tomasello <giagitom@gmail.com>",
|
||||
"Ke Ma <mark.ma@rcsb.org>",
|
||||
"Jason Pattle <jpattle@exscientia.co.uk>",
|
||||
"David Williams <dwilliams@nobiastx.com>"
|
||||
"David Williams <dwilliams@nobiastx.com>",
|
||||
"Zhenyu Zhang <jump2cn@gmail.com>",
|
||||
"Russell Parker <russell@benchling.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/add": "^4.0.0",
|
||||
"@graphql-codegen/cli": "^3.0.0",
|
||||
"@graphql-codegen/add": "^4.0.1",
|
||||
"@graphql-codegen/cli": "^3.2.2",
|
||||
"@graphql-codegen/time": "^4.0.0",
|
||||
"@graphql-codegen/typescript": "^3.0.0",
|
||||
"@graphql-codegen/typescript": "^3.0.2",
|
||||
"@graphql-codegen/typescript-graphql-files-modules": "^2.2.1",
|
||||
"@graphql-codegen/typescript-graphql-request": "^4.5.8",
|
||||
"@graphql-codegen/typescript-operations": "^3.0.0",
|
||||
"@graphql-codegen/typescript-operations": "^3.0.2",
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/gl": "^6.0.2",
|
||||
"@types/jpeg-js": "^0.3.7",
|
||||
"@types/pngjs": "^6.0.1",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/react": "^18.0.27",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@typescript-eslint/eslint-plugin": "^5.50.0",
|
||||
"@typescript-eslint/parser": "^5.50.0",
|
||||
"@types/jest": "^29.5.0",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.55.0",
|
||||
"@typescript-eslint/parser": "^5.55.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"concurrently": "^7.6.0",
|
||||
"cpx2": "^4.2.0",
|
||||
"cpx2": "^4.2.2",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^6.7.3",
|
||||
"eslint": "^8.33.0",
|
||||
"eslint": "^8.36.0",
|
||||
"extra-watch-webpack-plugin": "^1.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^11.1.0",
|
||||
"graphql": "^16.6.0",
|
||||
"http-server": "^14.1.1",
|
||||
"jest": "^29.4.1",
|
||||
"mini-css-extract-plugin": "^2.7.2",
|
||||
"jest": "^29.5.0",
|
||||
"mini-css-extract-plugin": "^2.7.5",
|
||||
"path-browserify": "^1.0.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"sass": "^1.58.0",
|
||||
"sass-loader": "^13.2.0",
|
||||
"simple-git": "^3.16.0",
|
||||
"sass": "^1.59.3",
|
||||
"sass-loader": "^13.2.1",
|
||||
"simple-git": "^3.17.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"style-loader": "^3.3.2",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "^4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"typescript": "^5.0.2",
|
||||
"webpack": "^5.76.2",
|
||||
"webpack-cli": "^5.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -147,20 +149,20 @@
|
||||
"@types/benchmark": "^2.1.2",
|
||||
"@types/compression": "1.7.2",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/node": "^16.18.12",
|
||||
"@types/node": "^16.18.16",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/swagger-ui-dist": "3.30.1",
|
||||
"argparse": "^2.0.1",
|
||||
"body-parser": "^1.20.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"compression": "^1.7.4",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.2",
|
||||
"h264-mp4-encoder": "^1.0.12",
|
||||
"immer": "^9.0.19",
|
||||
"immutable": "^4.2.3",
|
||||
"immutable": "^4.3.0",
|
||||
"node-fetch": "^2.6.9",
|
||||
"rxjs": "^7.8.0",
|
||||
"swagger-ui-dist": "^4.15.5",
|
||||
"swagger-ui-dist": "^4.18.1",
|
||||
"tslib": "^2.5.0",
|
||||
"util.promisify": "^1.1.1",
|
||||
"xhr2": "^0.2.1"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -50,6 +50,7 @@ function occlusionStyle(plugin: PluginContext) {
|
||||
radius: 5,
|
||||
samples: 32,
|
||||
resolutionScale: 1,
|
||||
color: Color(0x000000),
|
||||
} },
|
||||
outline: { name: 'on', params: {
|
||||
scale: 1.0,
|
||||
|
||||
@@ -19,8 +19,11 @@ import { StructureRepresentation3D } from '../../mol-plugin-state/transforms/rep
|
||||
import { HeadlessPluginContext } from '../../mol-plugin/headless-plugin-context';
|
||||
import { DefaultPluginSpec } from '../../mol-plugin/spec';
|
||||
import { STYLIZED_POSTPROCESSING } from '../../mol-plugin/util/headless-screenshot';
|
||||
import { setFSModule } from '../../mol-util/data-source';
|
||||
|
||||
|
||||
setFSModule(fs);
|
||||
|
||||
interface Args {
|
||||
pdbId: string,
|
||||
outDirectory: string
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -24,7 +24,7 @@ const Canvas3DPresets = {
|
||||
illustrative: {
|
||||
canvas3d: <Preset>{
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } },
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1, color: Color(0x000000) } },
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000), includeTransparent: true, } },
|
||||
shadow: { name: 'off', params: {} },
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Ludovic Autin <ludovic.autin@gmail.com>
|
||||
@@ -604,6 +604,7 @@ export const LoadCellPackModel = StateAction.build({
|
||||
bias: 1,
|
||||
blurKernelSize: 15,
|
||||
resolutionScale: 1,
|
||||
color: Color(0x000000),
|
||||
}
|
||||
},
|
||||
shadow: {
|
||||
|
||||
@@ -202,7 +202,7 @@ export class ZenodoImportUI extends CollapsableControls<{}, State> {
|
||||
}));
|
||||
} else if (t.name === 'trajectory') {
|
||||
const [topologyUrl, topologyFormat, topologyIsBinary] = t.params.topology.split('|');
|
||||
const [coordinatesUrl, coordinatesFormat, coordinatesIsBinary] = t.params.coordinates.split('|');
|
||||
const [coordinatesUrl, coordinatesFormat] = t.params.coordinates.split('|');
|
||||
|
||||
await this.plugin.runTask(this.plugin.state.data.applyAction(LoadTrajectory, {
|
||||
source: {
|
||||
@@ -216,7 +216,6 @@ export class ZenodoImportUI extends CollapsableControls<{}, State> {
|
||||
coordinates: {
|
||||
url: coordinatesUrl,
|
||||
format: coordinatesFormat as any,
|
||||
isBinary: coordinatesIsBinary === 'true',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ export const Canvas3DParams = {
|
||||
cameraClipping: PD.Group({
|
||||
radius: PD.Numeric(100, { min: 0, max: 99, step: 1 }, { label: 'Clipping', description: 'How much of the scene to show.' }),
|
||||
far: PD.Boolean(true, { description: 'Hide scene in the distance' }),
|
||||
minNear: PD.Numeric(5, { min: 0.1, max: 10, step: 0.1 }, { description: 'Note, may cause performance issues rendering impostors when set too small and cause issues with outline rendering when too close to 0.' }),
|
||||
minNear: PD.Numeric(5, { min: 0.1, max: 100, step: 0.1 }, { description: 'Note, may cause performance issues rendering impostors when set too small and cause issues with outline rendering when too close to 0.' }),
|
||||
}, { pivot: 'radius' }),
|
||||
viewport: PD.MappedStatic('canvas', {
|
||||
canvas: PD.Group({}),
|
||||
@@ -908,6 +908,7 @@ namespace Canvas3D {
|
||||
},
|
||||
dispose: () => {
|
||||
contextRestoredSub.unsubscribe();
|
||||
cancelAnimationFrame(animationFrameHandle);
|
||||
|
||||
markBuffer = [];
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2023 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>
|
||||
@@ -197,8 +197,12 @@ export class Canvas3dInteractionHelper {
|
||||
this.drag(x, y, buttons, button, modifiers);
|
||||
});
|
||||
|
||||
input.move.subscribe(({ x, y, inside, buttons, button, modifiers }) => {
|
||||
input.move.subscribe(({ x, y, inside, buttons, button, modifiers, onElement }) => {
|
||||
if (!inside || this.isInteracting) return;
|
||||
if (!onElement) {
|
||||
this.leave();
|
||||
return;
|
||||
}
|
||||
// console.log('move');
|
||||
this.move(x, y, buttons, button, modifiers);
|
||||
});
|
||||
|
||||
@@ -106,7 +106,7 @@ export class MarkingPass {
|
||||
const { highlightEdgeColor, selectEdgeColor, edgeScale, innerEdgeFactor, ghostEdgeStrength, highlightEdgeStrength, selectEdgeStrength } = props;
|
||||
|
||||
const { values: edgeValues } = this.edge;
|
||||
const _edgeScale = Math.round(edgeScale * this.webgl.pixelRatio);
|
||||
const _edgeScale = Math.max(1, Math.round(edgeScale * this.webgl.pixelRatio));
|
||||
if (edgeValues.dEdgeScale.ref.value !== _edgeScale) {
|
||||
ValueCell.update(edgeValues.dEdgeScale, _edgeScale);
|
||||
this.edge.update();
|
||||
|
||||
@@ -43,9 +43,9 @@ const OutlinesSchema = {
|
||||
dOrthographic: DefineSpec('number'),
|
||||
uNear: UniformSpec('f'),
|
||||
uFar: UniformSpec('f'),
|
||||
uInvProjection: UniformSpec('m4'),
|
||||
|
||||
uMaxPossibleViewZDiff: UniformSpec('f'),
|
||||
|
||||
uOutlineThreshold: UniformSpec('f'),
|
||||
dTransparentOutline: DefineSpec('boolean'),
|
||||
};
|
||||
type OutlinesRenderable = ComputeRenderable<Values<typeof OutlinesSchema>>
|
||||
@@ -63,9 +63,9 @@ function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, d
|
||||
dOrthographic: ValueCell.create(0),
|
||||
uNear: ValueCell.create(1),
|
||||
uFar: ValueCell.create(10000),
|
||||
uInvProjection: ValueCell.create(Mat4.identity()),
|
||||
|
||||
uMaxPossibleViewZDiff: ValueCell.create(0.5),
|
||||
|
||||
uOutlineThreshold: ValueCell.create(0.33),
|
||||
dTransparentOutline: ValueCell.create(transparentOutline),
|
||||
};
|
||||
|
||||
@@ -189,8 +189,7 @@ const SsaoBlurSchema = {
|
||||
uBlurDirectionX: UniformSpec('f'),
|
||||
uBlurDirectionY: UniformSpec('f'),
|
||||
|
||||
uMaxPossibleViewZDiff: UniformSpec('f'),
|
||||
|
||||
uInvProjection: UniformSpec('m4'),
|
||||
uNear: UniformSpec('f'),
|
||||
uFar: UniformSpec('f'),
|
||||
uBounds: UniformSpec('v4'),
|
||||
@@ -211,8 +210,7 @@ function getSsaoBlurRenderable(ctx: WebGLContext, ssaoDepthTexture: Texture, dir
|
||||
uBlurDirectionX: ValueCell.create(direction === 'horizontal' ? 1 : 0),
|
||||
uBlurDirectionY: ValueCell.create(direction === 'vertical' ? 1 : 0),
|
||||
|
||||
uMaxPossibleViewZDiff: ValueCell.create(0.5),
|
||||
|
||||
uInvProjection: ValueCell.create(Mat4.identity()),
|
||||
uNear: ValueCell.create(0.0),
|
||||
uFar: ValueCell.create(10000.0),
|
||||
uBounds: ValueCell.create(Vec4()),
|
||||
@@ -280,11 +278,9 @@ const PostprocessingSchema = {
|
||||
uFogFar: UniformSpec('f'),
|
||||
uFogColor: UniformSpec('v3'),
|
||||
uOutlineColor: UniformSpec('v3'),
|
||||
uOcclusionColor: UniformSpec('v3'),
|
||||
uTransparentBackground: UniformSpec('b'),
|
||||
|
||||
uMaxPossibleViewZDiff: UniformSpec('f'),
|
||||
uInvProjection: UniformSpec('m4'),
|
||||
|
||||
dOcclusionEnable: DefineSpec('boolean'),
|
||||
uOcclusionOffset: UniformSpec('v2'),
|
||||
|
||||
@@ -292,8 +288,6 @@ const PostprocessingSchema = {
|
||||
|
||||
dOutlineEnable: DefineSpec('boolean'),
|
||||
dOutlineScale: DefineSpec('number'),
|
||||
uOutlineThreshold: UniformSpec('f'),
|
||||
|
||||
dTransparentOutline: DefineSpec('boolean'),
|
||||
};
|
||||
type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>>
|
||||
@@ -317,11 +311,9 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
|
||||
uFogFar: ValueCell.create(10000),
|
||||
uFogColor: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uOutlineColor: ValueCell.create(Vec3.create(0, 0, 0)),
|
||||
uOcclusionColor: ValueCell.create(Vec3.create(0, 0, 0)),
|
||||
uTransparentBackground: ValueCell.create(false),
|
||||
|
||||
uMaxPossibleViewZDiff: ValueCell.create(0.5),
|
||||
uInvProjection: ValueCell.create(Mat4.identity()),
|
||||
|
||||
dOcclusionEnable: ValueCell.create(true),
|
||||
uOcclusionOffset: ValueCell.create(Vec2.create(0, 0)),
|
||||
|
||||
@@ -329,8 +321,6 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
|
||||
|
||||
dOutlineEnable: ValueCell.create(false),
|
||||
dOutlineScale: ValueCell.create(1),
|
||||
uOutlineThreshold: ValueCell.create(0.33),
|
||||
|
||||
dTransparentOutline: ValueCell.create(transparentOutline),
|
||||
};
|
||||
|
||||
@@ -349,6 +339,7 @@ export const PostprocessingParams = {
|
||||
bias: PD.Numeric(0.8, { min: 0, max: 3, step: 0.1 }),
|
||||
blurKernelSize: PD.Numeric(15, { min: 1, max: 25, step: 2 }),
|
||||
resolutionScale: PD.Numeric(1, { min: 0.1, max: 1, step: 0.05 }, { description: 'Adjust resolution of occlusion calculation' }),
|
||||
color: PD.Color(Color(0x000000)),
|
||||
}),
|
||||
off: PD.Group({})
|
||||
}, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }),
|
||||
@@ -543,11 +534,14 @@ export class PostprocessingPass {
|
||||
ValueCell.updateIfChanged(this.ssaoBlurFirstPassRenderable.values.uFar, camera.far);
|
||||
ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.uFar, camera.far);
|
||||
|
||||
ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uInvProjection, invProjection);
|
||||
ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uInvProjection, invProjection);
|
||||
|
||||
if (this.ssaoBlurFirstPassRenderable.values.dOrthographic.ref.value !== orthographic) {
|
||||
needsUpdateSsaoBlur = true;
|
||||
ValueCell.update(this.ssaoBlurFirstPassRenderable.values.dOrthographic, orthographic);
|
||||
ValueCell.update(this.ssaoBlurSecondPassRenderable.values.dOrthographic, orthographic);
|
||||
}
|
||||
ValueCell.updateIfChanged(this.ssaoBlurFirstPassRenderable.values.dOrthographic, orthographic);
|
||||
ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.dOrthographic, orthographic);
|
||||
|
||||
if (this.nSamples !== props.occlusion.params.samples) {
|
||||
needsUpdateSsao = true;
|
||||
@@ -567,8 +561,8 @@ export class PostprocessingPass {
|
||||
|
||||
ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uKernel, kernel);
|
||||
ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uKernel, kernel);
|
||||
ValueCell.updateIfChanged(this.ssaoBlurFirstPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize);
|
||||
ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize);
|
||||
ValueCell.update(this.ssaoBlurFirstPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize);
|
||||
ValueCell.update(this.ssaoBlurSecondPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize);
|
||||
}
|
||||
|
||||
if (this.downsampleFactor !== props.occlusion.params.resolutionScale) {
|
||||
@@ -595,6 +589,8 @@ export class PostprocessingPass {
|
||||
ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurFirstPassRenderable.values.uTexSize.ref.value, sw, sh));
|
||||
ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurSecondPassRenderable.values.uTexSize.ref.value, sw, sh));
|
||||
}
|
||||
|
||||
ValueCell.update(this.renderable.values.uOcclusionColor, Color.toVec3Normalized(this.renderable.values.uOcclusionColor.ref.value, props.occlusion.params.color));
|
||||
}
|
||||
|
||||
if (props.shadow.name === 'on') {
|
||||
@@ -611,7 +607,10 @@ export class PostprocessingPass {
|
||||
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uNear, camera.near);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uFar, camera.far);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.dOrthographic, orthographic);
|
||||
if (this.shadowsRenderable.values.dOrthographic.ref.value !== orthographic) {
|
||||
ValueCell.update(this.shadowsRenderable.values.dOrthographic, orthographic);
|
||||
needsUpdateShadows = true;
|
||||
}
|
||||
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uMaxDistance, props.shadow.params.maxDistance);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uTolerance, props.shadow.params.tolerance);
|
||||
@@ -630,30 +629,33 @@ export class PostprocessingPass {
|
||||
}
|
||||
|
||||
if (props.outline.name === 'on') {
|
||||
let { threshold, includeTransparent } = props.outline.params;
|
||||
const transparentOutline = includeTransparent ?? true;
|
||||
// orthographic needs lower threshold
|
||||
if (camera.state.mode === 'orthographic') threshold /= 5;
|
||||
const factor = Math.pow(1000, threshold / 10) / 1000;
|
||||
// use radiusMax for stable outlines when zooming
|
||||
const maxPossibleViewZDiff = factor * camera.state.radiusMax;
|
||||
const transparentOutline = props.outline.params.includeTransparent ?? true;
|
||||
const outlineScale = props.outline.params.scale - 1;
|
||||
const outlineThreshold = 50 * props.outline.params.threshold;
|
||||
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.uNear, camera.near);
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.uFar, camera.far);
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
|
||||
if (this.renderable.values.dTransparentOutline.ref.value !== transparentOutline) { needsUpdateOutlines = true; }
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.dTransparentOutline, transparentOutline);
|
||||
ValueCell.update(this.outlinesRenderable.values.uInvProjection, invProjection);
|
||||
if (this.outlinesRenderable.values.dTransparentOutline.ref.value !== transparentOutline) {
|
||||
needsUpdateOutlines = true;
|
||||
ValueCell.update(this.outlinesRenderable.values.dTransparentOutline, transparentOutline);
|
||||
}
|
||||
if (this.outlinesRenderable.values.dOrthographic.ref.value !== orthographic) {
|
||||
needsUpdateOutlines = true;
|
||||
ValueCell.update(this.outlinesRenderable.values.dOrthographic, orthographic);
|
||||
}
|
||||
ValueCell.updateIfChanged(this.outlinesRenderable.values.uOutlineThreshold, outlineThreshold);
|
||||
|
||||
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);
|
||||
ValueCell.update(this.renderable.values.uInvProjection, invProjection);
|
||||
|
||||
if (this.renderable.values.dOutlineScale.ref.value !== outlineScale) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOutlineScale, outlineScale);
|
||||
if (this.renderable.values.dTransparentOutline.ref.value !== transparentOutline) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dTransparentOutline, transparentOutline);
|
||||
if (this.renderable.values.dOutlineScale.ref.value !== outlineScale) {
|
||||
needsUpdateMain = true;
|
||||
ValueCell.update(this.renderable.values.dOutlineScale, outlineScale);
|
||||
}
|
||||
if (this.renderable.values.dTransparentOutline.ref.value !== transparentOutline) {
|
||||
needsUpdateMain = true;
|
||||
ValueCell.update(this.renderable.values.dTransparentOutline, transparentOutline);
|
||||
}
|
||||
}
|
||||
|
||||
ValueCell.updateIfChanged(this.renderable.values.uFar, camera.far);
|
||||
@@ -662,15 +664,23 @@ export class PostprocessingPass {
|
||||
ValueCell.updateIfChanged(this.renderable.values.uFogNear, camera.fogNear);
|
||||
ValueCell.update(this.renderable.values.uFogColor, Color.toVec3Normalized(this.renderable.values.uFogColor.ref.value, backgroundColor));
|
||||
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.dOrthographic.ref.value !== orthographic) {
|
||||
needsUpdateMain = true;
|
||||
ValueCell.update(this.renderable.values.dOrthographic, orthographic);
|
||||
}
|
||||
|
||||
if (this.renderable.values.dOutlineEnable.ref.value !== outlinesEnabled) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOutlineEnable, outlinesEnabled);
|
||||
if (this.renderable.values.dShadowEnable.ref.value !== shadowsEnabled) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dShadowEnable, shadowsEnabled);
|
||||
if (this.renderable.values.dOcclusionEnable.ref.value !== occlusionEnabled) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, occlusionEnabled);
|
||||
if (this.renderable.values.dOutlineEnable.ref.value !== outlinesEnabled) {
|
||||
needsUpdateMain = true;
|
||||
ValueCell.update(this.renderable.values.dOutlineEnable, outlinesEnabled);
|
||||
}
|
||||
if (this.renderable.values.dShadowEnable.ref.value !== shadowsEnabled) {
|
||||
needsUpdateMain = true;
|
||||
ValueCell.update(this.renderable.values.dShadowEnable, shadowsEnabled);
|
||||
}
|
||||
if (this.renderable.values.dOcclusionEnable.ref.value !== occlusionEnabled) {
|
||||
needsUpdateMain = true;
|
||||
ValueCell.update(this.renderable.values.dOcclusionEnable, occlusionEnabled);
|
||||
}
|
||||
|
||||
if (needsUpdateOutlines) {
|
||||
this.outlinesRenderable.update();
|
||||
@@ -699,10 +709,6 @@ export class PostprocessingPass {
|
||||
state.disable(gl.BLEND);
|
||||
state.disable(gl.DEPTH_TEST);
|
||||
state.depthMask(false);
|
||||
|
||||
const { x, y, width, height } = camera.viewport;
|
||||
state.viewport(x, y, width, height);
|
||||
state.scissor(x, y, width, height);
|
||||
}
|
||||
|
||||
private occlusionOffset: [x: number, y: number] = [0, 0];
|
||||
@@ -721,20 +727,21 @@ export class PostprocessingPass {
|
||||
if (isTimingMode) this.webgl.timer.mark('PostprocessingPass.render');
|
||||
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();
|
||||
}
|
||||
const { gl, state } = this.webgl;
|
||||
const { x, y, width, height } = camera.viewport;
|
||||
|
||||
// don't render occlusion if offset is given,
|
||||
// which will reuse the existing occlusion
|
||||
if (props.occlusion.name === 'on' && this.occlusionOffset[0] === 0 && this.occlusionOffset[1] === 0) {
|
||||
if (isTimingMode) this.webgl.timer.mark('SSAO.render');
|
||||
const sx = Math.floor(x * this.ssaoScale);
|
||||
const sy = Math.floor(y * this.ssaoScale);
|
||||
const sw = Math.ceil(width * this.ssaoScale);
|
||||
const sh = Math.ceil(height * this.ssaoScale);
|
||||
|
||||
state.viewport(sx, sy, sw, sh);
|
||||
state.scissor(sx, sy, sw, sh);
|
||||
|
||||
if (this.ssaoScale < 1) {
|
||||
this.downsampledDepthTarget.bind();
|
||||
this.downsampleDepthRenderable.render();
|
||||
@@ -751,14 +758,25 @@ export class PostprocessingPass {
|
||||
if (isTimingMode) this.webgl.timer.markEnd('SSAO.render');
|
||||
}
|
||||
|
||||
state.viewport(x, y, width, height);
|
||||
state.scissor(x, y, width, height);
|
||||
|
||||
if (props.outline.name === 'on') {
|
||||
this.outlinesTarget.bind();
|
||||
this.outlinesRenderable.render();
|
||||
}
|
||||
|
||||
if (props.shadow.name === 'on') {
|
||||
this.shadowsTarget.bind();
|
||||
this.shadowsRenderable.render();
|
||||
}
|
||||
|
||||
if (toDrawingBuffer) {
|
||||
this.webgl.unbindFramebuffer();
|
||||
} else {
|
||||
this.target.bind();
|
||||
}
|
||||
|
||||
const { gl, state } = this.webgl;
|
||||
|
||||
this.background.update(camera, props.background);
|
||||
if (this.background.isEnabled(props.background)) {
|
||||
if (this.transparentBackground) {
|
||||
|
||||
@@ -16,7 +16,7 @@ const c = {
|
||||
|
||||
MAX_TEXTURE_MAX_ANISOTROPY_EXT: 0x84FF,
|
||||
MAX_TEXTURE_IMAGE_UNITS_NV: 0x8872
|
||||
};
|
||||
} as const;
|
||||
|
||||
const gl = {
|
||||
ACTIVE_ATTRIBUTES: 35721,
|
||||
@@ -316,7 +316,7 @@ const gl = {
|
||||
VERTEX_SHADER: 35633,
|
||||
VIEWPORT: 2978,
|
||||
ZERO: 0
|
||||
};
|
||||
} as const;
|
||||
type gl = typeof gl
|
||||
|
||||
export function createGl(width: number, height: number, contextAttributes: WebGLContextAttributes): WebGLRenderingContext {
|
||||
@@ -371,66 +371,66 @@ export function createGl(width: number, height: number, contextAttributes: WebGL
|
||||
case 'EXT_blend_minmax': return {
|
||||
MAX_EXT: 0,
|
||||
MIN_EXT: 0
|
||||
} as EXT_blend_minmax;
|
||||
} as unknown as EXT_blend_minmax;
|
||||
case 'EXT_texture_filter_anisotropic': return {
|
||||
MAX_TEXTURE_MAX_ANISOTROPY_EXT: 0,
|
||||
TEXTURE_MAX_ANISOTROPY_EXT: 0
|
||||
} as EXT_texture_filter_anisotropic;
|
||||
} as unknown as EXT_texture_filter_anisotropic;
|
||||
case 'EXT_frag_depth': return {} as EXT_frag_depth;
|
||||
case 'EXT_shader_texture_lod': return {} as EXT_shader_texture_lod;
|
||||
case 'EXT_shader_texture_lod': return {} as unknown as EXT_shader_texture_lod;
|
||||
case 'EXT_sRGB': return {
|
||||
FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: 0,
|
||||
SRGB8_ALPHA8_EXT: 0,
|
||||
SRGB_ALPHA_EXT: 0,
|
||||
SRGB_EXT: 0
|
||||
} as EXT_sRGB;
|
||||
} as unknown as EXT_sRGB;
|
||||
case 'OES_vertex_array_object': return {
|
||||
VERTEX_ARRAY_BINDING_OES: 0,
|
||||
bindVertexArrayOES: function (arrayObject: WebGLVertexArrayObjectOES) { },
|
||||
createVertexArrayOES: function (): WebGLVertexArrayObjectOES { return {}; },
|
||||
deleteVertexArrayOES: function (arrayObject: WebGLVertexArrayObjectOES) { },
|
||||
isVertexArrayOES: function (value: any) { return true; }
|
||||
} as OES_vertex_array_object;
|
||||
} as unknown as OES_vertex_array_object;
|
||||
case 'WEBGL_color_buffer_float': return {
|
||||
FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT: 0,
|
||||
RGB32F_EXT: 0,
|
||||
RGBA32F_EXT: 0,
|
||||
UNSIGNED_NORMALIZED_EXT: 0
|
||||
} as WEBGL_color_buffer_float;
|
||||
} as unknown as WEBGL_color_buffer_float;
|
||||
case 'WEBGL_compressed_texture_astc': return null;
|
||||
case 'WEBGL_compressed_texture_s3tc_srgb': return null;
|
||||
case 'WEBGL_debug_shaders': return {
|
||||
getTranslatedShaderSource(shader: WebGLShader) { return ''; }
|
||||
} as WEBGL_debug_shaders;
|
||||
} as unknown as WEBGL_debug_shaders;
|
||||
case 'WEBGL_draw_buffers': return null;
|
||||
case 'WEBGL_lose_context': return {
|
||||
loseContext: function () { },
|
||||
restoreContext: function () { },
|
||||
} as WEBGL_lose_context;
|
||||
} as unknown as WEBGL_lose_context;
|
||||
case 'WEBGL_depth_texture': return {
|
||||
UNSIGNED_INT_24_8_WEBGL: 0
|
||||
} as WEBGL_depth_texture;
|
||||
} as unknown as WEBGL_depth_texture;
|
||||
case 'WEBGL_debug_renderer_info': return {
|
||||
UNMASKED_RENDERER_WEBGL: 0,
|
||||
UNMASKED_VENDOR_WEBGL: 0
|
||||
} as WEBGL_debug_renderer_info;
|
||||
} as unknown as WEBGL_debug_renderer_info;
|
||||
case 'WEBGL_compressed_texture_s3tc': return null;
|
||||
case 'OES_texture_half_float_linear': return {} as OES_texture_half_float_linear;
|
||||
case 'OES_texture_half_float_linear': return {} as unknown as OES_texture_half_float_linear;
|
||||
case 'OES_texture_half_float': return {
|
||||
HALF_FLOAT_OES: 0
|
||||
} as OES_texture_half_float;
|
||||
case 'OES_texture_float_linear': return {} as OES_texture_float_linear;
|
||||
case 'OES_texture_float': return {} as OES_texture_float;
|
||||
} as unknown as OES_texture_half_float;
|
||||
case 'OES_texture_float_linear': return {} as unknown as OES_texture_float_linear;
|
||||
case 'OES_texture_float': return {} as unknown as OES_texture_float;
|
||||
case 'OES_standard_derivatives': return {
|
||||
FRAGMENT_SHADER_DERIVATIVE_HINT_OES: 0
|
||||
} as OES_standard_derivatives;
|
||||
case 'OES_element_index_uint': return {} as OES_element_index_uint;
|
||||
} as unknown as OES_standard_derivatives;
|
||||
case 'OES_element_index_uint': return {} as unknown as OES_element_index_uint;
|
||||
case 'ANGLE_instanced_arrays': return {
|
||||
drawArraysInstancedANGLE: function (mode: number, first: number, count: number, primcount: number) {},
|
||||
drawElementsInstancedANGLE: function (mode: number, count: number, type: number, offset: number, primcount: number) {},
|
||||
vertexAttribDivisorANGLE: function (index: number, divisor: number) {},
|
||||
VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: 0
|
||||
} as ANGLE_instanced_arrays;
|
||||
} as unknown as ANGLE_instanced_arrays;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
@@ -160,6 +160,7 @@ export const GlobalUniformSchema = {
|
||||
uMarkerAverage: UniformSpec('f'),
|
||||
|
||||
uXrayEdgeFalloff: UniformSpec('f'),
|
||||
uExposure: UniformSpec('f'),
|
||||
|
||||
uRenderMask: UniformSpec('i'),
|
||||
uMarkingDepthTest: UniformSpec('b'),
|
||||
|
||||
@@ -104,6 +104,7 @@ export const RendererParams = {
|
||||
markerPriority: PD.Select(1, [[1, 'Highlight'], [2, 'Select']]),
|
||||
|
||||
xrayEdgeFalloff: PD.Numeric(1, { min: 0.0, max: 3.0, step: 0.1 }),
|
||||
exposure: PD.Numeric(1, { min: 0.0, max: 3.0, step: 0.01 }),
|
||||
|
||||
light: PD.ObjectList({
|
||||
inclination: PD.Numeric(150, { min: 0, max: 180, step: 1 }),
|
||||
@@ -242,6 +243,7 @@ namespace Renderer {
|
||||
uMarkerAverage: ValueCell.create(0),
|
||||
|
||||
uXrayEdgeFalloff: ValueCell.create(p.xrayEdgeFalloff),
|
||||
uExposure: ValueCell.create(p.exposure),
|
||||
};
|
||||
const globalUniformList = Object.entries(globalUniforms);
|
||||
|
||||
@@ -607,7 +609,7 @@ namespace Renderer {
|
||||
// TODO: simplify, handle in renderable.state???
|
||||
// uAlpha is updated in "render" so we need to recompute it here
|
||||
const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
|
||||
if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || r.values.dGeometryType.ref.value === 'directVolume' || r.values.dPointStyle?.ref.value === 'fuzzy' || r.values.dGeometryType.ref.value === 'text' || r.values.dXrayShaded?.ref.value) {
|
||||
if ((alpha < 1 && alpha !== 0) || r.values.transparencyAverage.ref.value > 0 || r.values.dGeometryType.ref.value === 'directVolume' || r.values.dPointStyle?.ref.value === 'fuzzy' || r.values.dGeometryType.ref.value === 'text' || r.values.dXrayShaded?.ref.value) {
|
||||
renderObject(r, 'colorWboit', Flag.None);
|
||||
}
|
||||
}
|
||||
@@ -655,7 +657,7 @@ namespace Renderer {
|
||||
// TODO: simplify, handle in renderable.state???
|
||||
// uAlpha is updated in "render" so we need to recompute it here
|
||||
const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
|
||||
if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || r.values.dPointStyle?.ref.value === 'fuzzy' || !!r.values.uBackgroundColor || r.values.dXrayShaded?.ref.value) {
|
||||
if ((alpha < 1 && alpha !== 0) || r.values.transparencyAverage.ref.value > 0 || r.values.dPointStyle?.ref.value === 'fuzzy' || r.values.dGeometryType.ref.value === 'text' || r.values.dXrayShaded?.ref.value) {
|
||||
renderObject(r, 'colorDpoit', Flag.None);
|
||||
}
|
||||
}
|
||||
@@ -787,6 +789,10 @@ namespace Renderer {
|
||||
p.xrayEdgeFalloff = props.xrayEdgeFalloff;
|
||||
ValueCell.update(globalUniforms.uXrayEdgeFalloff, p.xrayEdgeFalloff);
|
||||
}
|
||||
if (props.exposure !== undefined && props.exposure !== p.exposure) {
|
||||
p.exposure = props.exposure;
|
||||
ValueCell.update(globalUniforms.uExposure, p.exposure);
|
||||
}
|
||||
|
||||
if (props.light !== undefined && !deepEqual(props.light, p.light)) {
|
||||
p.light = props.light;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*
|
||||
@@ -65,4 +65,6 @@ export const apply_light_color = `
|
||||
#ifdef dXrayShaded
|
||||
gl_FragColor.a *= 1.0 - pow(abs(dot(normal, vec3(0.0, 0.0, 1.0))), uXrayEdgeFalloff);
|
||||
#endif
|
||||
|
||||
gl_FragColor.rgb *= uExposure;
|
||||
`;
|
||||
@@ -72,6 +72,7 @@ uniform vec3 uInteriorColor;
|
||||
bool interior;
|
||||
|
||||
uniform float uXrayEdgeFalloff;
|
||||
uniform float uExposure;
|
||||
|
||||
uniform mat4 uProjection;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -71,8 +71,10 @@ void main() {
|
||||
vViewPosition = mvPosition.xyz;
|
||||
gl_Position = uProjection * mvPosition;
|
||||
|
||||
mvPosition.z -= 2.0 * (length(vEnd - vStart) + vSize); // avoid clipping
|
||||
gl_Position.z = (uProjection * mvPosition).z;
|
||||
if (gl_Position.z < -gl_Position.w) {
|
||||
mvPosition.z -= 2.0 * (length(vEnd - vStart) + vSize); // avoid clipping
|
||||
gl_Position.z = (uProjection * mvPosition).z;
|
||||
}
|
||||
|
||||
#include clip_instance
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ uniform vec3 uFogColor;
|
||||
uniform float uAlpha;
|
||||
uniform bool uTransparentBackground;
|
||||
uniform float uXrayEdgeFalloff;
|
||||
uniform float uExposure;
|
||||
|
||||
uniform int uRenderMask;
|
||||
|
||||
|
||||
@@ -16,8 +16,9 @@ uniform vec2 uTexSize;
|
||||
|
||||
uniform float uNear;
|
||||
uniform float uFar;
|
||||
uniform mat4 uInvProjection;
|
||||
|
||||
uniform float uMaxPossibleViewZDiff;
|
||||
uniform float uOutlineThreshold;
|
||||
|
||||
#include common
|
||||
|
||||
@@ -49,17 +50,25 @@ bool isBackground(const in float depth) {
|
||||
return depth == 1.0;
|
||||
}
|
||||
|
||||
float getPixelSize(const in vec2 coords, const in float depth) {
|
||||
vec3 viewPos0 = screenSpaceToViewSpace(vec3(coords, depth), uInvProjection);
|
||||
vec3 viewPos1 = screenSpaceToViewSpace(vec3(coords + vec2(1.0, 0.0) / uTexSize, depth), uInvProjection);
|
||||
return distance(viewPos0, viewPos1);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
float backgroundViewZ = uFar + 3.0 * uMaxPossibleViewZDiff;
|
||||
float backgroundViewZ = 2.0 * uFar;
|
||||
|
||||
vec2 coords = gl_FragCoord.xy / uTexSize;
|
||||
vec2 invTexSize = 1.0 / uTexSize;
|
||||
|
||||
float selfDepthOpaque = getDepthOpaque(coords);
|
||||
float selfViewZOpaque = isBackground(selfDepthOpaque) ? backgroundViewZ : getViewZ(selfDepthOpaque);
|
||||
float pixelSizeOpaque = getPixelSize(coords, selfDepthOpaque) * uOutlineThreshold;
|
||||
|
||||
float selfDepthTransparent = getDepthTransparent(coords);
|
||||
float selfViewZTransparent = isBackground(selfDepthTransparent) ? backgroundViewZ : getViewZ(selfDepthTransparent);
|
||||
float pixelSizeTransparent = getPixelSize(coords, selfDepthTransparent) * uOutlineThreshold;
|
||||
|
||||
float outline = 1.0;
|
||||
float bestDepth = 1.0;
|
||||
@@ -73,14 +82,14 @@ void main(void) {
|
||||
float sampleDepthTransparent = getDepthTransparent(sampleCoords);
|
||||
|
||||
float sampleViewZOpaque = isBackground(sampleDepthOpaque) ? backgroundViewZ : getViewZ(sampleDepthOpaque);
|
||||
if (abs(selfViewZOpaque - sampleViewZOpaque) > uMaxPossibleViewZDiff && selfDepthOpaque > sampleDepthOpaque && sampleDepthOpaque <= bestDepth) {
|
||||
if (abs(selfViewZOpaque - sampleViewZOpaque) > pixelSizeOpaque && selfDepthOpaque > sampleDepthOpaque && sampleDepthOpaque <= bestDepth) {
|
||||
outline = 0.0;
|
||||
bestDepth = sampleDepthOpaque;
|
||||
}
|
||||
|
||||
if (sampleDepthTransparent < sampleDepthOpaque) {
|
||||
float sampleViewZTransparent = isBackground(sampleDepthTransparent) ? backgroundViewZ : getViewZ(sampleDepthTransparent);
|
||||
if (abs(selfViewZTransparent - sampleViewZTransparent) > uMaxPossibleViewZDiff && selfDepthTransparent > sampleDepthTransparent && sampleDepthTransparent <= bestDepth) {
|
||||
if (abs(selfViewZTransparent - sampleViewZTransparent) > pixelSizeTransparent && selfDepthTransparent > sampleDepthTransparent && sampleDepthTransparent <= bestDepth) {
|
||||
outline = 0.0;
|
||||
bestDepth = sampleDepthTransparent;
|
||||
transparentFlag = 1.0;
|
||||
|
||||
@@ -24,16 +24,10 @@ uniform float uFogNear;
|
||||
uniform float uFogFar;
|
||||
uniform vec3 uFogColor;
|
||||
uniform vec3 uOutlineColor;
|
||||
uniform vec3 uOcclusionColor;
|
||||
uniform bool uTransparentBackground;
|
||||
|
||||
uniform vec2 uOcclusionOffset;
|
||||
|
||||
uniform float uMaxPossibleViewZDiff;
|
||||
uniform mat4 uInvProjection;
|
||||
|
||||
const float outlineDistanceFactor = 5.0;
|
||||
const vec3 occlusionColor = vec3(0.0);
|
||||
|
||||
#include common
|
||||
|
||||
float getViewZ(const in float depth) {
|
||||
@@ -64,21 +58,14 @@ bool isBackground(const in float depth) {
|
||||
return depth == 1.0;
|
||||
}
|
||||
|
||||
float getPixelSize(const in vec2 coords, const in float depth) {
|
||||
vec3 viewPos0 = screenSpaceToViewSpace(vec3(coords, depth), uInvProjection);
|
||||
vec3 viewPos1 = screenSpaceToViewSpace(vec3(coords + vec2(1.0, 0.0) / uTexSize, depth), uInvProjection);
|
||||
return distance(viewPos0, viewPos1);
|
||||
}
|
||||
|
||||
float getOutline(const in vec2 coords, const in float opaqueDepth, out float closestTexel) {
|
||||
float backgroundViewZ = uFar + 3.0 * uMaxPossibleViewZDiff;
|
||||
float backgroundViewZ = 2.0 * uFar;
|
||||
vec2 invTexSize = 1.0 / uTexSize;
|
||||
|
||||
float transparentDepth = getDepthTransparent(coords);
|
||||
float opaqueSelfViewZ = isBackground(opaqueDepth) ? backgroundViewZ : getViewZ(opaqueDepth);
|
||||
float transparentSelfViewZ = isBackground(transparentDepth) ? backgroundViewZ : getViewZ(transparentDepth);
|
||||
float selfDepth = min(opaqueDepth, transparentDepth);
|
||||
float pixelSize = getPixelSize(coords, selfDepth);
|
||||
|
||||
float outline = 1.0;
|
||||
closestTexel = 1.0;
|
||||
@@ -96,7 +83,7 @@ float getOutline(const in vec2 coords, const in float opaqueDepth, out float clo
|
||||
float sampleOutlineViewZ = isBackground(sampleOutlineDepth) ? backgroundViewZ : getViewZ(sampleOutlineDepth);
|
||||
|
||||
float selfViewZ = sampleOutlineCombined.a == 0.0 ? opaqueSelfViewZ : transparentSelfViewZ;
|
||||
if (sampleOutline == 0.0 && sampleOutlineDepth < closestTexel && abs(selfViewZ - sampleOutlineViewZ) > uMaxPossibleViewZDiff + (pixelSize * outlineDistanceFactor)) {
|
||||
if (sampleOutline == 0.0 && sampleOutlineDepth < closestTexel) {
|
||||
outline = 0.0;
|
||||
closestTexel = sampleOutlineDepth;
|
||||
}
|
||||
@@ -130,9 +117,9 @@ void main(void) {
|
||||
fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
|
||||
float occlusionFactor = getSsao(coords + uOcclusionOffset);
|
||||
if (!uTransparentBackground) {
|
||||
color.rgb = mix(mix(occlusionColor, uFogColor, fogFactor), color.rgb, occlusionFactor);
|
||||
color.rgb = mix(mix(uOcclusionColor, uFogColor, fogFactor), color.rgb, occlusionFactor);
|
||||
} else {
|
||||
color.rgb = mix(occlusionColor * (1.0 - fogFactor), color.rgb, occlusionFactor);
|
||||
color.rgb = mix(uOcclusionColor * (1.0 - fogFactor), color.rgb, occlusionFactor);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -96,8 +96,10 @@ void main(void){
|
||||
|
||||
vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader
|
||||
|
||||
mvPosition.z -= 2.0 * vRadius; // avoid clipping
|
||||
gl_Position.z = (uProjection * vec4(mvPosition.xyz, 1.0)).z;
|
||||
if (gl_Position.z < -gl_Position.w) {
|
||||
mvPosition.z -= 2.0 * vRadius; // avoid clipping
|
||||
gl_Position.z = (uProjection * vec4(mvPosition.xyz, 1.0)).z;
|
||||
}
|
||||
|
||||
#include clip_instance
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
@@ -19,8 +19,7 @@ uniform float uKernel[dOcclusionKernelSize];
|
||||
uniform float uBlurDirectionX;
|
||||
uniform float uBlurDirectionY;
|
||||
|
||||
uniform float uMaxPossibleViewZDiff;
|
||||
|
||||
uniform mat4 uInvProjection;
|
||||
uniform float uNear;
|
||||
uniform float uFar;
|
||||
|
||||
@@ -42,6 +41,12 @@ bool outsideBounds(const in vec2 p) {
|
||||
return p.x < uBounds.x || p.y < uBounds.y || p.x > uBounds.z || p.y > uBounds.w;
|
||||
}
|
||||
|
||||
float getPixelSize(const in vec2 coords, const in float depth) {
|
||||
vec3 viewPos0 = screenSpaceToViewSpace(vec3(coords, depth), uInvProjection);
|
||||
vec3 viewPos1 = screenSpaceToViewSpace(vec3(coords + vec2(1.0, 0.0) / uTexSize, depth), uInvProjection);
|
||||
return distance(viewPos0, viewPos1);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 coords = gl_FragCoord.xy / uTexSize;
|
||||
|
||||
@@ -60,6 +65,8 @@ void main(void) {
|
||||
}
|
||||
|
||||
float selfViewZ = getViewZ(selfDepth);
|
||||
float pixelSize = getPixelSize(coords, selfDepth);
|
||||
float maxDiffViewZ = pixelSize * 10.0;
|
||||
|
||||
vec2 offset = vec2(uBlurDirectionX, uBlurDirectionY) / uTexSize;
|
||||
|
||||
@@ -67,6 +74,8 @@ void main(void) {
|
||||
float kernelSum = 0.0;
|
||||
// only if kernelSize is odd
|
||||
for (int i = -dOcclusionKernelSize / 2; i <= dOcclusionKernelSize / 2; i++) {
|
||||
if (abs(float(i)) > 1.0 && abs(float(i)) * pixelSize > 0.8) continue;
|
||||
|
||||
vec2 sampleCoords = coords + float(i) * offset;
|
||||
if (outsideBounds(sampleCoords)) {
|
||||
continue;
|
||||
@@ -79,9 +88,9 @@ void main(void) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (abs(float(i)) > 1.0) { // abs is not defined for int in webgl1
|
||||
if (abs(float(i)) > 1.0) {
|
||||
float sampleViewZ = getViewZ(sampleDepth);
|
||||
if (abs(selfViewZ - sampleViewZ) > uMaxPossibleViewZDiff) {
|
||||
if (abs(selfViewZ - sampleViewZ) > maxDiffViewZ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace PrincipalAxes {
|
||||
|
||||
export function calculateMomentsAxes(positions: NumberArray): Axes3D {
|
||||
if (positions.length === 3) {
|
||||
return Axes3D.create(Vec3.fromArray(Vec3(), positions, 0), Vec3.create(1, 0, 0), Vec3.create(0, 1, 0), Vec3.create(0, 1, 0));
|
||||
return Axes3D.create(Vec3.fromArray(Vec3(), positions, 0), Vec3.create(1, 0, 0), Vec3.create(0, 1, 0), Vec3.create(0, 0, 1));
|
||||
}
|
||||
|
||||
const points = Matrix.fromArray(positions, 3, positions.length / 3);
|
||||
@@ -143,4 +143,4 @@ namespace PrincipalAxes {
|
||||
|
||||
return Axes3D.create(origin, dirA, dirB, dirC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ const ParseCif = PluginStateTransform.BuiltIn({
|
||||
})({
|
||||
apply({ a }) {
|
||||
return Task.create('Parse CIF', async ctx => {
|
||||
const parsed = await (SO.Data.String.is(a) ? CIF.parse(a.data) : CIF.parseBinary(a.data)).runInContext(ctx);
|
||||
const parsed = await (typeof a.data === 'string' ? CIF.parse(a.data) : CIF.parseBinary(a.data)).runInContext(ctx);
|
||||
if (parsed.isError) throw new Error(parsed.message);
|
||||
return new SO.Format.Cif(parsed.result);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2023 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>
|
||||
@@ -240,14 +240,9 @@ export class SelectionViewportControls extends PluginUIComponent {
|
||||
this.subscribe(this.plugin.behaviors.interaction.selectionMode, () => this.forceUpdate());
|
||||
}
|
||||
|
||||
onMouseMove = (e: React.MouseEvent) => {
|
||||
// ignore mouse moves when no button is held
|
||||
if (e.buttons === 0) e.stopPropagation();
|
||||
};
|
||||
|
||||
render() {
|
||||
if (!this.plugin.selectionMode) return null;
|
||||
return <div className='msp-selection-viewport-controls' onMouseMove={this.onMouseMove}>
|
||||
return <div className='msp-selection-viewport-controls'>
|
||||
<StructureSelectionActionsControls />
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -626,9 +626,9 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
|
||||
const value = bounds[handle];
|
||||
|
||||
let direction = 0;
|
||||
if (bounds[handle + 1] - value < threshold!) {
|
||||
if (bounds[handle + 1] - value < +threshold!) {
|
||||
direction = +1;
|
||||
} else if (value - bounds[handle - 1] < threshold!) {
|
||||
} else if (value - bounds[handle - 1] < +threshold!) {
|
||||
direction = -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2022-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -60,7 +60,7 @@ export class QuickStyles extends PurePluginUIComponent {
|
||||
},
|
||||
occlusion: {
|
||||
name: 'on',
|
||||
params: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1 }
|
||||
params: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1, color: Color(0x000000) }
|
||||
},
|
||||
shadow: { name: 'off', params: {} },
|
||||
}
|
||||
@@ -85,7 +85,7 @@ export class QuickStyles extends PurePluginUIComponent {
|
||||
name: 'on',
|
||||
params: pp.occlusion.name === 'on'
|
||||
? pp.occlusion.params
|
||||
: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1 }
|
||||
: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1, color: Color(0x000000) }
|
||||
},
|
||||
shadow: { name: 'off', params: {} },
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2023 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>
|
||||
@@ -76,13 +76,8 @@ export class ViewportControls extends PluginUIComponent<ViewportControlsProps, V
|
||||
return <IconButton svg={icon} toggleState={isOn} onClick={onClick} title={title} style={{ background: 'transparent' }} />;
|
||||
}
|
||||
|
||||
onMouseMove = (e: React.MouseEvent) => {
|
||||
// ignore mouse moves when no button is held
|
||||
if (e.buttons === 0) e.stopPropagation();
|
||||
};
|
||||
|
||||
render() {
|
||||
return <div className={'msp-viewport-controls'} onMouseMove={this.onMouseMove}>
|
||||
return <div className={'msp-viewport-controls'}>
|
||||
<div className='msp-viewport-controls-buttons'>
|
||||
<div>
|
||||
<div className='msp-semi-transparent-background' />
|
||||
|
||||
@@ -362,6 +362,7 @@ export class PluginContext {
|
||||
}
|
||||
this.subs = [];
|
||||
|
||||
this.animationLoop.stop();
|
||||
this.commands.dispose();
|
||||
this.canvas3d?.dispose();
|
||||
this.canvas3dContext?.dispose(options);
|
||||
|
||||
@@ -210,6 +210,7 @@ export const STYLIZED_POSTPROCESSING: Partial<PostprocessingProps> = {
|
||||
bias: 0.8,
|
||||
blurKernelSize: 15,
|
||||
resolutionScale: 1,
|
||||
color: ColorNames.black,
|
||||
}
|
||||
}, outline: {
|
||||
name: 'on' as const, params: {
|
||||
|
||||
@@ -119,7 +119,7 @@ class ViewportScreenshotHelper extends PluginComponent {
|
||||
postprocessing: {
|
||||
...c.props.postprocessing,
|
||||
occlusion: aoProps.name === 'on'
|
||||
? { name: 'on', params: { ...aoProps.params, samples: 128, resolutionScale: 1 } }
|
||||
? { name: 'on', params: { ...aoProps.params, samples: 128, resolutionScale: c.webgl.pixelRatio } }
|
||||
: aoProps
|
||||
},
|
||||
marking: { ...c.props.marking }
|
||||
@@ -143,7 +143,7 @@ class ViewportScreenshotHelper extends PluginComponent {
|
||||
postprocessing: {
|
||||
...c.props.postprocessing,
|
||||
occlusion: aoProps.name === 'on'
|
||||
? { name: 'on', params: { ...aoProps.params, samples: 128, resolutionScale: 1 } }
|
||||
? { name: 'on', params: { ...aoProps.params, samples: 128, resolutionScale: c.webgl.pixelRatio } }
|
||||
: aoProps
|
||||
},
|
||||
marking: { ...c.props.marking }
|
||||
|
||||
@@ -218,6 +218,7 @@ export function InterUnitBondCylinderImpostorVisual(materialId: number): Complex
|
||||
eachLocation: eachInterBond,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<InterUnitBondCylinderParams>, currentProps: PD.Values<InterUnitBondCylinderParams>, newTheme: Theme, currentTheme: Theme, newStructure: Structure, currentStructure: Structure) => {
|
||||
state.createGeometry = (
|
||||
newProps.sizeFactor !== currentProps.sizeFactor ||
|
||||
newProps.sizeAspectRatio !== currentProps.sizeAspectRatio ||
|
||||
newProps.linkScale !== currentProps.linkScale ||
|
||||
newProps.linkSpacing !== currentProps.linkSpacing ||
|
||||
|
||||
@@ -235,6 +235,7 @@ export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVi
|
||||
eachLocation: eachIntraBond,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<IntraUnitBondCylinderParams>, currentProps: PD.Values<IntraUnitBondCylinderParams>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup) => {
|
||||
state.createGeometry = (
|
||||
newProps.sizeFactor !== currentProps.sizeFactor ||
|
||||
newProps.sizeAspectRatio !== currentProps.sizeAspectRatio ||
|
||||
newProps.linkScale !== currentProps.linkScale ||
|
||||
newProps.linkSpacing !== currentProps.linkSpacing ||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Zhenyu Zhang <jump2cn@gmail.com>
|
||||
*/
|
||||
|
||||
import { Vec3 } from '../../../../mol-math/linear-algebra';
|
||||
@@ -25,7 +26,7 @@ export const LinkCylinderParams = {
|
||||
aromaticScale: PD.Numeric(0.3, { min: 0, max: 1, step: 0.01 }),
|
||||
aromaticSpacing: PD.Numeric(1.5, { min: 0, max: 3, step: 0.01 }),
|
||||
aromaticDashCount: PD.Numeric(2, { min: 2, max: 6, step: 2 }),
|
||||
dashCount: PD.Numeric(4, { min: 2, max: 10, step: 2 }),
|
||||
dashCount: PD.Numeric(4, { min: 0, max: 10, step: 2 }),
|
||||
dashScale: PD.Numeric(0.8, { min: 0, max: 2, step: 0.1 }),
|
||||
dashCap: PD.Boolean(true),
|
||||
stubCap: PD.Boolean(true),
|
||||
@@ -38,7 +39,7 @@ export const LinkLineParams = {
|
||||
linkScale: PD.Numeric(0.5, { min: 0, max: 1, step: 0.1 }),
|
||||
linkSpacing: PD.Numeric(0.1, { min: 0, max: 2, step: 0.01 }),
|
||||
aromaticDashCount: PD.Numeric(2, { min: 2, max: 6, step: 2 }),
|
||||
dashCount: PD.Numeric(4, { min: 2, max: 10, step: 2 }),
|
||||
dashCount: PD.Numeric(4, { min: 0, max: 10, step: 2 }),
|
||||
};
|
||||
export const DefaultLinkLineProps = PD.getDefaultValues(LinkLineParams);
|
||||
export type LinkLineProps = typeof DefaultLinkLineProps
|
||||
@@ -164,7 +165,11 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
||||
cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius * dashScale;
|
||||
cylinderProps.topCap = cylinderProps.bottomCap = dashCap;
|
||||
|
||||
addFixedCountDashedCylinder(builderState, va, vb, 0.5, segmentCount, cylinderProps);
|
||||
if (segmentCount > 1) {
|
||||
addFixedCountDashedCylinder(builderState, va, vb, 0.5, segmentCount, cylinderProps);
|
||||
} else {
|
||||
addCylinder(builderState, va, vb, 0.5, cylinderProps);
|
||||
}
|
||||
} else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
|
||||
const order = (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble) ? 2 :
|
||||
(linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple) ? 3 : 1.5;
|
||||
@@ -303,9 +308,14 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
||||
v3scale(vm, v3add(vm, va, vb), 0.5);
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
|
||||
} else if (linkStyle === LinkStyle.Dashed) {
|
||||
v3scale(tmpV12, v3sub(tmpV12, vb, va), lengthScale);
|
||||
v3sub(vb, vb, tmpV12);
|
||||
builder.addFixedCountDashes(va, vb, segmentCount, dashScale, dashCap, dashCap, edgeIndex);
|
||||
if (segmentCount > 1) {
|
||||
v3scale(tmpV12, v3sub(tmpV12, vb, va), lengthScale);
|
||||
v3sub(vb, vb, tmpV12);
|
||||
builder.addFixedCountDashes(va, vb, segmentCount, dashScale, dashCap, dashCap, edgeIndex);
|
||||
} else {
|
||||
v3scale(vm, v3add(vm, va, vb), 0.5);
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], dashScale, dashCap, dashCap, edgeIndex);
|
||||
}
|
||||
} else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
|
||||
const order = (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble) ? 2 :
|
||||
(linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple) ? 3 : 1.5;
|
||||
@@ -423,9 +433,14 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
||||
v3scale(vm, v3add(vm, va, vb), 0.5);
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], edgeIndex);
|
||||
} else if (linkStyle === LinkStyle.Dashed) {
|
||||
v3scale(tmpV12, v3sub(tmpV12, vb, va), lengthScale);
|
||||
v3sub(vb, vb, tmpV12);
|
||||
builder.addFixedCountDashes(va, vb, segmentCount, edgeIndex);
|
||||
if (segmentCount > 1) {
|
||||
v3scale(tmpV12, v3sub(tmpV12, vb, va), lengthScale);
|
||||
v3sub(vb, vb, tmpV12);
|
||||
builder.addFixedCountDashes(va, vb, segmentCount, edgeIndex);
|
||||
} else {
|
||||
v3scale(vm, v3add(vm, va, vb), 0.5);
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], edgeIndex);
|
||||
}
|
||||
} else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
|
||||
const order = linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble ? 2 :
|
||||
linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple ? 3 : 1.5;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace StateObject {
|
||||
export function create<Data, T extends Type>(type: T) {
|
||||
return class O implements StateObject<Data, T> {
|
||||
static type = type;
|
||||
static is(obj?: StateObject): obj is O { return !!obj && type === obj.type; }
|
||||
static is(obj?: StateObject): obj is StateObject<Data, T> { return !!obj && type === obj.type; }
|
||||
id = UUID.create22();
|
||||
type = type;
|
||||
label: string;
|
||||
|
||||
@@ -300,13 +300,17 @@ function ajaxGetInternal<T extends DataType>(title: string | undefined, url: str
|
||||
});
|
||||
}
|
||||
|
||||
// NOTE: lazy imports cannot be used here because WebPack complains since this
|
||||
// is part of the "browser" build.
|
||||
// NOTE: a workaround for using this in Node.js
|
||||
let _fs: (typeof import ('fs')) | undefined = undefined;
|
||||
function getFS() {
|
||||
if (_fs) return _fs!;
|
||||
_fs = require('fs');
|
||||
return _fs!;
|
||||
if (!_fs) {
|
||||
throw new Error('When running in Node.js and reading from files, call mol-util/data-source\'s setFSModule function first.');
|
||||
}
|
||||
return _fs;
|
||||
}
|
||||
|
||||
export function setFSModule(fs: typeof import ('fs')) {
|
||||
_fs = fs;
|
||||
}
|
||||
|
||||
/** Alternative implementation of ajaxGetInternal (because xhr2 does not support file:// protocol) */
|
||||
|
||||
@@ -163,6 +163,9 @@ export type MoveInput = {
|
||||
pageX: number,
|
||||
pageY: number,
|
||||
inside: boolean,
|
||||
// Move is subscribed to window element
|
||||
// This indicates that the event originated from the element the InputObserver was created on
|
||||
onElement: boolean
|
||||
} & BaseInput
|
||||
|
||||
export type PinchInput = {
|
||||
@@ -202,6 +205,7 @@ type PointerEvent = {
|
||||
clientY: number
|
||||
pageX: number
|
||||
pageY: number
|
||||
target: EventTarget | null
|
||||
|
||||
preventDefault?: () => void
|
||||
}
|
||||
@@ -446,7 +450,8 @@ namespace InputObserver {
|
||||
clientX: (t0.clientX + t1.clientX) / 2,
|
||||
clientY: (t0.clientY + t1.clientY) / 2,
|
||||
pageX: (t0.pageX + t1.pageX) / 2,
|
||||
pageY: (t0.pageY + t1.pageY) / 2
|
||||
pageY: (t0.pageY + t1.pageY) / 2,
|
||||
target: ev.target
|
||||
};
|
||||
}
|
||||
|
||||
@@ -592,7 +597,7 @@ namespace InputObserver {
|
||||
const { pageX, pageY } = ev;
|
||||
const [x, y] = pointerEnd;
|
||||
const inside = insideBounds(pointerEnd);
|
||||
move.next({ x, y, pageX, pageY, buttons, button, modifiers: getModifierKeys(), inside });
|
||||
move.next({ x, y, pageX, pageY, buttons, button, modifiers: getModifierKeys(), inside, onElement: ev.target === element });
|
||||
|
||||
if (dragging === DraggingState.Stopped) return;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
* @author Russell Parker <russell@benchling.com>
|
||||
*
|
||||
* Implements some browser-only global variables for Node.js environment.
|
||||
* These workarounds will also work in browsers as usual.
|
||||
@@ -19,7 +20,7 @@ export const File_ = getFile();
|
||||
|
||||
|
||||
function getXMLHttpRequest(): typeof XMLHttpRequest {
|
||||
if (typeof document === 'undefined') {
|
||||
if (typeof XMLHttpRequest === 'undefined' || RUNNING_IN_NODEJS) {
|
||||
return require('xhr2');
|
||||
} else {
|
||||
return XMLHttpRequest;
|
||||
@@ -27,7 +28,7 @@ function getXMLHttpRequest(): typeof XMLHttpRequest {
|
||||
}
|
||||
|
||||
function getFile(): typeof File {
|
||||
if (typeof document === 'undefined') {
|
||||
if (typeof File === 'undefined' || RUNNING_IN_NODEJS) {
|
||||
class File_NodeJs implements File {
|
||||
private readonly blob: Blob;
|
||||
// Blob fields
|
||||
|
||||
Reference in New Issue
Block a user