diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cef38d6f9c31c589e0dd89fa3ba0abbb53f3c11..833e1ec5731d551bbf4af55bb18f6e7b4f7e689a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,18 +6,28 @@ Note that since we don't clearly distinguish between a public and private interf ## [Unreleased] +## [v3.25.0] - 2022-11-16 + +- Fix handling of gzipped assets (reverts #615) + +## [v3.24.0] - 2022-11-13 + - Make `PluginContext.initContainer` checkered canvas background optional +- Store URL of downloaded assets to detect zip/gzip based on extension (#615) +- Add optional `operator.key`; can be referenced in `IndexPairBonds` +- Add overpaint/transparency/substance theme strength to representations +- Fix viewport color for transparent background ## [v3.23.0] - 2022-10-19 - Add `PluginContext.initContainer/mount/unmount` methods; these should make it easier to reuse a plugin context with both custom and built-in UI - Add `PluginContext.canvas3dInitialized` - `createPluginUI` now resolves after the 3d canvas has been initialized -- Change EM Volume Streaming default from `Whote Structure` to `Auto` +- Change EM Volume Streaming default from `Whole Structure` to `Auto` ## [v3.22.0] - 2022-10-17 -- Replace `VolumeIsosurfaceParams.pickingGranularity` param with `Volume.PickingGranuality` +- Replace `VolumeIsosurfaceParams.pickingGranularity` param with `Volume.PickingGranuality` ## [v3.21.0] - 2022-10-17 diff --git a/package-lock.json b/package-lock.json index 1f882cb3578af5905d3e9d9c54e0c7fae325e90a..5783bdba84d314108e330689641b73e5e2771926 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/package.json b/package.json index 87946d0b46c5fd22acbd8e9c2a8690b840a22760..7af4063623318644926dc43c10d64fcd19244461 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "molstar", - "version": "3.23.0", + "version": "3.25.0", "description": "A comprehensive macromolecular library.", "homepage": "https://github.com/molstar/molstar#readme", "repository": { @@ -97,44 +97,44 @@ "license": "MIT", "devDependencies": { "@graphql-codegen/add": "^3.2.1", - "@graphql-codegen/cli": "^2.13.7", + "@graphql-codegen/cli": "^2.13.11", "@graphql-codegen/time": "^3.2.1", - "@graphql-codegen/typescript": "^2.7.4", + "@graphql-codegen/typescript": "^2.8.1", "@graphql-codegen/typescript-graphql-files-modules": "^2.2.1", - "@graphql-codegen/typescript-graphql-request": "^4.5.6", - "@graphql-codegen/typescript-operations": "^2.5.4", + "@graphql-codegen/typescript-graphql-request": "^4.5.8", + "@graphql-codegen/typescript-operations": "^2.5.6", "@types/cors": "^2.8.12", - "@types/gl": "^4.1.1", - "@types/jest": "^29.1.2", - "@types/react": "^18.0.21", - "@types/react-dom": "^18.0.6", - "@typescript-eslint/eslint-plugin": "^5.40.0", - "@typescript-eslint/parser": "^5.40.0", + "@types/gl": "^6.0.1", + "@types/jest": "^29.2.2", + "@types/react": "^18.0.25", + "@types/react-dom": "^18.0.8", + "@typescript-eslint/eslint-plugin": "^5.42.1", + "@typescript-eslint/parser": "^5.42.1", "benchmark": "^2.1.4", - "concurrently": "^7.4.0", + "concurrently": "^7.5.0", "cpx2": "^4.2.0", "crypto-browserify": "^3.12.0", - "css-loader": "^6.7.1", - "eslint": "^8.25.0", + "css-loader": "^6.7.2", + "eslint": "^8.27.0", "extra-watch-webpack-plugin": "^1.0.3", "file-loader": "^6.2.0", "fs-extra": "^10.1.0", "graphql": "^16.6.0", "http-server": "^14.1.1", - "jest": "^29.2.0", + "jest": "^29.3.1", "mini-css-extract-plugin": "^2.6.1", "path-browserify": "^1.0.1", "raw-loader": "^4.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "sass": "^1.55.0", - "sass-loader": "^13.1.0", - "simple-git": "^3.14.1", + "sass": "^1.56.1", + "sass-loader": "^13.2.0", + "simple-git": "^3.15.0", "stream-browserify": "^3.0.0", "style-loader": "^3.3.1", "ts-jest": "^29.0.3", "typescript": "^4.8.4", - "webpack": "^5.74.0", + "webpack": "^5.75.0", "webpack-cli": "^4.10.0" }, "dependencies": { @@ -142,7 +142,7 @@ "@types/benchmark": "^2.1.2", "@types/compression": "1.7.2", "@types/express": "^4.17.14", - "@types/node": "^16.11.66", + "@types/node": "^16.18.3", "@types/node-fetch": "^2.6.2", "@types/swagger-ui-dist": "3.30.1", "argparse": "^2.0.1", @@ -151,12 +151,12 @@ "cors": "^2.8.5", "express": "^4.18.2", "h264-mp4-encoder": "^1.0.12", - "immer": "^9.0.15", + "immer": "^9.0.16", "immutable": "^4.1.0", "node-fetch": "^2.6.7", "rxjs": "^7.5.7", - "swagger-ui-dist": "^4.14.3", - "tslib": "^2.4.0", + "swagger-ui-dist": "^4.15.5", + "tslib": "^2.4.1", "util.promisify": "^1.1.1", "xhr2": "^0.2.1" }, diff --git a/src/mol-geo/geometry/overpaint-data.ts b/src/mol-geo/geometry/overpaint-data.ts index 3c90b2bf0d46319461118aa639b47d0fd03a71ad..680a5eafeea9f79e2cbbdc39448f8437896fb7a4 100644 --- a/src/mol-geo/geometry/overpaint-data.ts +++ b/src/mol-geo/geometry/overpaint-data.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -21,6 +21,7 @@ export type OverpaintData = { uOverpaintGridDim: ValueCell<Vec3>, uOverpaintGridTransform: ValueCell<Vec4>, dOverpaintType: ValueCell<string>, + uOverpaintStrength: ValueCell<number>, } export function applyOverpaintColor(array: Uint8Array, start: number, end: number, color: Color) { @@ -54,6 +55,7 @@ export function createOverpaint(count: number, type: OverpaintType, overpaintDat uOverpaintGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uOverpaintGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dOverpaintType: ValueCell.create(type), + uOverpaintStrength: ValueCell.create(1), }; } } @@ -74,6 +76,7 @@ export function createEmptyOverpaint(overpaintData?: OverpaintData): OverpaintDa uOverpaintGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uOverpaintGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dOverpaintType: ValueCell.create('groupInstance'), + uOverpaintStrength: ValueCell.create(1), }; } } \ No newline at end of file diff --git a/src/mol-geo/geometry/substance-data.ts b/src/mol-geo/geometry/substance-data.ts index 554d7e9f40fdcedc413249f5566decb70ad3e56c..d85a724556d636adff0f031e0acddd8fe4a4f4e2 100644 --- a/src/mol-geo/geometry/substance-data.ts +++ b/src/mol-geo/geometry/substance-data.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2021-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -21,6 +21,7 @@ export type SubstanceData = { uSubstanceGridDim: ValueCell<Vec3>, uSubstanceGridTransform: ValueCell<Vec4>, dSubstanceType: ValueCell<string>, + uSubstanceStrength: ValueCell<number>, } export function applySubstanceMaterial(array: Uint8Array, start: number, end: number, material: Material) { @@ -54,6 +55,7 @@ export function createSubstance(count: number, type: SubstanceType, substanceDat uSubstanceGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uSubstanceGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dSubstanceType: ValueCell.create(type), + uSubstanceStrength: ValueCell.create(1), }; } } @@ -74,6 +76,7 @@ export function createEmptySubstance(substanceData?: SubstanceData): SubstanceDa uSubstanceGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uSubstanceGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dSubstanceType: ValueCell.create('groupInstance'), + uSubstanceStrength: ValueCell.create(1), }; } } \ No newline at end of file diff --git a/src/mol-geo/geometry/transparency-data.ts b/src/mol-geo/geometry/transparency-data.ts index a619443a7b99c42efc6db9e6e43f6e6abf6e4f36..942f95c278e6424b012b31fd715a92383d3cf137 100644 --- a/src/mol-geo/geometry/transparency-data.ts +++ b/src/mol-geo/geometry/transparency-data.ts @@ -21,6 +21,7 @@ export type TransparencyData = { uTransparencyGridDim: ValueCell<Vec3>, uTransparencyGridTransform: ValueCell<Vec4>, dTransparencyType: ValueCell<string>, + uTransparencyStrength: ValueCell<number>, } export function applyTransparencyValue(array: Uint8Array, start: number, end: number, value: number) { @@ -63,6 +64,7 @@ export function createTransparency(count: number, type: TransparencyType, transp uTransparencyGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uTransparencyGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dTransparencyType: ValueCell.create(type), + uTransparencyStrength: ValueCell.create(1), }; } } @@ -84,6 +86,7 @@ export function createEmptyTransparency(transparencyData?: TransparencyData): Tr uTransparencyGridDim: ValueCell.create(Vec3.create(1, 1, 1)), uTransparencyGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)), dTransparencyType: ValueCell.create('groupInstance'), + uTransparencyStrength: ValueCell.create(1), }; } } \ No newline at end of file diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index 89b0752120f434019d180a3fab7f4773ab31dd77..23e7cbdb3df7b605f35226b73398fbcc279797c2 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -229,6 +229,7 @@ export const OverpaintSchema = { uOverpaintGridTransform: UniformSpec('v4'), tOverpaintGrid: TextureSpec('texture', 'rgba', 'ubyte', 'linear'), dOverpaintType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']), + uOverpaintStrength: UniformSpec('f', 'material'), } as const; export type OverpaintSchema = typeof OverpaintSchema export type OverpaintValues = Values<OverpaintSchema> @@ -242,7 +243,8 @@ export const TransparencySchema = { uTransparencyGridDim: UniformSpec('v3'), uTransparencyGridTransform: UniformSpec('v4'), tTransparencyGrid: TextureSpec('texture', 'alpha', 'ubyte', 'linear'), - dTransparencyType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']) + dTransparencyType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']), + uTransparencyStrength: UniformSpec('f', 'material'), } as const; export type TransparencySchema = typeof TransparencySchema export type TransparencyValues = Values<TransparencySchema> @@ -256,6 +258,7 @@ export const SubstanceSchema = { uSubstanceGridTransform: UniformSpec('v4'), tSubstanceGrid: TextureSpec('texture', 'rgba', 'ubyte', 'linear'), dSubstanceType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']), + uSubstanceStrength: UniformSpec('f', 'material'), } as const; export type SubstanceSchema = typeof SubstanceSchema export type SubstanceValues = Values<SubstanceSchema> diff --git a/src/mol-gl/shader/chunks/assign-color-varying.glsl.ts b/src/mol-gl/shader/chunks/assign-color-varying.glsl.ts index 7be1d4ff06dad0026c22c578131295e7ea8f37b7..1d7d510a0fdda00f327b7c40e7ea5a0f6a94001e 100644 --- a/src/mol-gl/shader/chunks/assign-color-varying.glsl.ts +++ b/src/mol-gl/shader/chunks/assign-color-varying.glsl.ts @@ -42,6 +42,7 @@ export const assign_color_varying = ` #else vOverpaint.rgb = mix(vColor.rgb, vOverpaint.rgb, vOverpaint.a); #endif + vOverpaint *= uOverpaintStrength; #endif #ifdef dSubstance @@ -58,6 +59,7 @@ export const assign_color_varying = ` // pre-mix to avoid artifacts due to empty substance vSubstance.rgb = mix(vec3(uMetalness, uRoughness, uBumpiness), vSubstance.rgb, vSubstance.a); + vSubstance *= uSubstanceStrength; #endif #elif defined(dRenderVariant_pick) #ifdef requiredDrawBuffers @@ -86,5 +88,6 @@ export const assign_color_varying = ` vec3 tgridPos = (uTransparencyGridTransform.w * (vModelPosition - uTransparencyGridTransform.xyz)) / uTransparencyGridDim; vTransparency = texture3dFrom2dLinear(tTransparencyGrid, tgridPos, uTransparencyGridDim, uTransparencyTexDim).a; #endif + vTransparency *= uTransparencyStrength; #endif `; \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/color-vert-params.glsl.ts b/src/mol-gl/shader/chunks/color-vert-params.glsl.ts index 30a830ad73651982363871cbb3fe8b1fcc20d431..aa9e5dff0b6d14581f917e18d676938398f6ed6d 100644 --- a/src/mol-gl/shader/chunks/color-vert-params.glsl.ts +++ b/src/mol-gl/shader/chunks/color-vert-params.glsl.ts @@ -39,6 +39,7 @@ uniform float uBumpiness; uniform vec4 uOverpaintGridTransform; uniform sampler2D tOverpaintGrid; #endif + uniform float uOverpaintStrength; #endif #ifdef dSubstance @@ -53,6 +54,7 @@ uniform float uBumpiness; uniform vec4 uSubstanceGridTransform; uniform sampler2D tSubstanceGrid; #endif + uniform float uSubstanceStrength; #endif #elif defined(dRenderVariant_pick) #if __VERSION__ == 100 || !defined(dVaryingGroup) @@ -86,5 +88,6 @@ uniform float uBumpiness; uniform vec4 uTransparencyGridTransform; uniform sampler2D tTransparencyGrid; #endif + uniform float uTransparencyStrength; #endif `; \ No newline at end of file diff --git a/src/mol-gl/webgl/compat.ts b/src/mol-gl/webgl/compat.ts index 8fa3aab180bfd5d0ffdded37f45290bb553c964f..48f6b2b67e73dee7c6e4959d8a1eb827cf352df6 100644 --- a/src/mol-gl/webgl/compat.ts +++ b/src/mol-gl/webgl/compat.ts @@ -19,6 +19,9 @@ export function isWebGL2(gl: any): gl is WebGL2RenderingContext { return typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext; } +/** + * See https://registry.khronos.org/webgl/extensions/ANGLE_instanced_arrays/ + */ export interface COMPAT_instanced_arrays { drawArraysInstanced(mode: number, first: number, count: number, primcount: number): void; drawElementsInstanced(mode: number, count: number, type: number, offset: number, primcount: number): void; @@ -46,6 +49,9 @@ export function getInstancedArrays(gl: GLRenderingContext): COMPAT_instanced_arr } } +/** + * See https://registry.khronos.org/webgl/extensions/OES_standard_derivatives/ + */ export interface COMPAT_standard_derivatives { readonly FRAGMENT_SHADER_DERIVATIVE_HINT: number; } @@ -60,6 +66,9 @@ export function getStandardDerivatives(gl: GLRenderingContext): COMPAT_standard_ } } +/** + * See https://registry.khronos.org/webgl/extensions/OES_element_index_uint/ + */ export interface COMPAT_element_index_uint { } @@ -67,6 +76,9 @@ export function getElementIndexUint(gl: GLRenderingContext): COMPAT_element_inde return isWebGL2(gl) ? {} : gl.getExtension('OES_element_index_uint'); } +/** + * See https://registry.khronos.org/webgl/extensions/OES_vertex_array_object/ + */ export interface COMPAT_vertex_array_object { readonly VERTEX_ARRAY_BINDING: number; bindVertexArray(arrayObject: WebGLVertexArrayObject | null): void; @@ -132,6 +144,9 @@ export function getTextureHalfFloatLinear(gl: GLRenderingContext): COMPAT_textur return gl.getExtension('OES_texture_half_float_linear'); } +/** + * See https://registry.khronos.org/webgl/extensions/EXT_blend_minmax/ + */ export interface COMPAT_blend_minmax { readonly MIN: number readonly MAX: number @@ -147,6 +162,9 @@ export function getBlendMinMax(gl: GLRenderingContext): COMPAT_blend_minmax | nu } } +/** + * See https://registry.khronos.org/webgl/extensions/EXT_frag_depth/ + */ export interface COMPAT_frag_depth { } @@ -196,6 +214,9 @@ export function getColorBufferHalfFloat(gl: GLRenderingContext): COMPAT_color_bu } } +/** + * See https://registry.khronos.org/webgl/extensions/WEBGL_draw_buffers/ + */ export interface COMPAT_draw_buffers { drawBuffers(buffers: number[]): void; readonly COLOR_ATTACHMENT0: number; @@ -268,6 +289,73 @@ export function getDrawBuffers(gl: GLRenderingContext): COMPAT_draw_buffers | nu } } +/** + * See https://registry.khronos.org/webgl/extensions/OES_draw_buffers_indexed/ + */ +export interface COMPAT_draw_buffers_indexed { + /** + * Enables blending for an individual draw buffer. + * + * @param target must be BLEND. + * @param index is an integer i specifying the draw buffer associated with the symbolic constant DRAW_BUFFERi. + */ + enablei: (target: number, index: number) => void; + /** + * Disables blending for an individual draw buffer. + * + * @param target must be BLEND. + * @param index is an integer i specifying the draw buffer associated with the symbolic constant DRAW_BUFFERi. + */ + disablei: (buf: number, mode: number) => void; + /** + * The buf argument is an integer i that indicates that the blend equations should be modified for DRAW_BUFFERi. + * + * mode accepts the same tokens as mode in blendEquation. + */ + blendEquationi: (target: number, index: number) => void; + /** + * The buf argument is an integer i that indicates that the blend equations should be modified for DRAW_BUFFERi. + * + * modeRGB and modeAlpha accept the same tokens as modeRGB and modeAlpha in blendEquationSeparate. + */ + blendEquationSeparatei: (buf: number, modeRGB: number, modeAlpha: number) => void; + /** + * The buf argument is an integer i that indicates that the blend functions should be modified for DRAW_BUFFERi. + * + * src and dst accept the same tokens as src and dst in blendFunc. + */ + blendFunci: (buf: number, src: number, dst: number) => void; + /** + * The buf argument is an integer i that indicates that the blend functions should be modified for DRAW_BUFFERi. + * + * srcRGB, dstRGB, srcAlpha, and dstAlpha accept the same tokens as srcRGB, dstRGB, srcAlpha, and dstAlpha parameters in blendEquationSeparate. + */ + blendFuncSeparatei: (buf: number, srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => void; + /** + * The buf argument is an integer i that indicates that the write mask should be modified for DRAW_BUFFERi. + * + * r, g, b, and a indicate whether R, G, B, or A values, respectively, are written or not (a value of TRUE means that the corresponding value is written). + */ + colorMaski: (buf: number, r: boolean, g: boolean, b: boolean, a: boolean) => void; +} + +export function getDrawBuffersIndexed(gl: GLRenderingContext): COMPAT_draw_buffers_indexed | null { + const ext = gl.getExtension('OES_draw_buffers_indexed'); + if (ext === null) return null; + return { + enablei: ext.enableiOES.bind(ext), + disablei: ext.disableiOES.bind(ext), + blendEquationi: ext.blendEquationiOES.bind(ext), + blendEquationSeparatei: ext.blendEquationSeparateiOES.bind(ext), + blendFunci: ext.blendFunciOES.bind(ext), + blendFuncSeparatei: ext.blendFuncSeparateiOES.bind(ext), + colorMaski: ext.colorMaskiOES.bind(ext), + }; +} + +/** + * See https://registry.khronos.org/webgl/extensions/EXT_shader_texture_lod/ + */ export interface COMPAT_shader_texture_lod { } @@ -275,6 +363,9 @@ export function getShaderTextureLod(gl: GLRenderingContext): COMPAT_shader_textu return isWebGL2(gl) ? {} : gl.getExtension('EXT_shader_texture_lod'); } +/** + * See https://registry.khronos.org/webgl/extensions/WEBGL_depth_texture/ + */ export interface COMPAT_depth_texture { readonly UNSIGNED_INT_24_8: number; } @@ -293,6 +384,9 @@ export function getDepthTexture(gl: GLRenderingContext): COMPAT_depth_texture | } } +/** + * See https://registry.khronos.org/webgl/extensions/EXT_sRGB/ + */ export interface COMPAT_sRGB { readonly FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: number; readonly SRGB8_ALPHA8: number; @@ -320,6 +414,9 @@ export function getSRGB(gl: GLRenderingContext): COMPAT_sRGB | null { } } +/** + * See https://registry.khronos.org/webgl/extensions/EXT_disjoint_timer_query/ and https://registry.khronos.org/webgl/extensions/EXT_disjoint_timer_query_webgl2/ + */ export interface COMPAT_disjoint_timer_query { /** A GLint indicating the number of bits used to hold the query result for the given target. */ QUERY_COUNTER_BITS: number @@ -401,6 +498,31 @@ export function getDisjointTimerQuery(gl: GLRenderingContext): COMPAT_disjoint_t } } +/** + * See https://registry.khronos.org/webgl/extensions/KHR_parallel_shader_compile/ + */ +export interface COMPAT_parallel_shader_compile { + readonly COMPLETION_STATUS: number; +} + +export function getParallelShaderCompile(gl: GLRenderingContext): COMPAT_parallel_shader_compile | null { + const ext = gl.getExtension('KHR_parallel_shader_compile'); + if (ext === null) return null; + return { + COMPLETION_STATUS: ext.COMPLETION_STATUS_KHR, + }; +} + +/** + * See https://registry.khronos.org/webgl/extensions/OES_fbo_render_mipmap/ + */ +export interface COMPAT_fboRenderMipmap { +} + +export function getFboRenderMipmap(gl: GLRenderingContext): COMPAT_fboRenderMipmap | null { + return isWebGL2(gl) ? {} : gl.getExtension('OES_fbo_render_mipmap'); +} + export function getNoNonInstancedActiveAttribs(gl: GLRenderingContext): boolean { if (!isWebGL2(gl)) return false; diff --git a/src/mol-gl/webgl/extensions.ts b/src/mol-gl/webgl/extensions.ts index 0d360170b9a09676ff594f1737ed9d949e806fec..e4a4eaf97ac181d14452ac55e7c72d0f1f268dcf 100644 --- a/src/mol-gl/webgl/extensions.ts +++ b/src/mol-gl/webgl/extensions.ts @@ -4,14 +4,14 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture, COMPAT_sRGB, getSRGB, getTextureHalfFloat, getTextureHalfFloatLinear, COMPAT_texture_half_float, COMPAT_texture_half_float_linear, COMPAT_color_buffer_half_float, getColorBufferHalfFloat, getVertexArrayObject, getDisjointTimerQuery, COMPAT_disjoint_timer_query, getNoNonInstancedActiveAttribs } from './compat'; +import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture, COMPAT_sRGB, getSRGB, getTextureHalfFloat, getTextureHalfFloatLinear, COMPAT_texture_half_float, COMPAT_texture_half_float_linear, COMPAT_color_buffer_half_float, getColorBufferHalfFloat, getVertexArrayObject, getDisjointTimerQuery, COMPAT_disjoint_timer_query, getNoNonInstancedActiveAttribs, getDrawBuffersIndexed, COMPAT_draw_buffers_indexed, getParallelShaderCompile, COMPAT_parallel_shader_compile, getFboRenderMipmap, COMPAT_fboRenderMipmap } from './compat'; import { isDebugMode } from '../../mol-util/debug'; export type WebGLExtensions = { instancedArrays: COMPAT_instanced_arrays elementIndexUint: COMPAT_element_index_uint + standardDerivatives: COMPAT_standard_derivatives - standardDerivatives: COMPAT_standard_derivatives | null textureFloat: COMPAT_texture_float | null textureFloatLinear: COMPAT_texture_float_linear | null textureHalfFloat: COMPAT_texture_half_float | null @@ -23,9 +23,12 @@ export type WebGLExtensions = { colorBufferFloat: COMPAT_color_buffer_float | null colorBufferHalfFloat: COMPAT_color_buffer_half_float | null drawBuffers: COMPAT_draw_buffers | null + drawBuffersIndexed: COMPAT_draw_buffers_indexed | null shaderTextureLod: COMPAT_shader_texture_lod | null sRGB: COMPAT_sRGB | null disjointTimerQuery: COMPAT_disjoint_timer_query | null + parallelShaderCompile: COMPAT_parallel_shader_compile | null + fboRenderMipmap: COMPAT_fboRenderMipmap | null noNonInstancedActiveAttribs: boolean } @@ -94,6 +97,10 @@ export function createExtensions(gl: GLRenderingContext): WebGLExtensions { if (isDebugMode && drawBuffers === null) { console.log('Could not find support for "draw_buffers"'); } + const drawBuffersIndexed = getDrawBuffersIndexed(gl); + if (isDebugMode && drawBuffersIndexed === null) { + console.log('Could not find support for "draw_buffers_indexed"'); + } const shaderTextureLod = getShaderTextureLod(gl); if (isDebugMode && shaderTextureLod === null) { console.log('Could not find support for "shader_texture_lod"'); @@ -106,28 +113,39 @@ export function createExtensions(gl: GLRenderingContext): WebGLExtensions { if (isDebugMode && disjointTimerQuery === null) { console.log('Could not find support for "disjoint_timer_query"'); } + const parallelShaderCompile = getParallelShaderCompile(gl); + if (isDebugMode && parallelShaderCompile === null) { + console.log('Could not find support for "parallel_shader_compile"'); + } + const fboRenderMipmap = getFboRenderMipmap(gl); + if (isDebugMode && fboRenderMipmap === null) { + console.log('Could not find support for "fbo_render_mipmap"'); + } const noNonInstancedActiveAttribs = getNoNonInstancedActiveAttribs(gl); return { instancedArrays, standardDerivatives, + elementIndexUint, + textureFloat, textureFloatLinear, textureHalfFloat, textureHalfFloatLinear, - elementIndexUint, depthTexture, - blendMinMax, vertexArrayObject, fragDepth, colorBufferFloat, colorBufferHalfFloat, drawBuffers, + drawBuffersIndexed, shaderTextureLod, sRGB, disjointTimerQuery, + parallelShaderCompile, + fboRenderMipmap, noNonInstancedActiveAttribs, }; diff --git a/src/mol-math/geometry/symmetry-operator.ts b/src/mol-math/geometry/symmetry-operator.ts index 3f848728976d022c1199434f64f17237d9d77db4..cbc2a5eda01f3d26d0f059e3e496d6743f8a4de9 100644 --- a/src/mol-math/geometry/symmetry-operator.ts +++ b/src/mol-math/geometry/symmetry-operator.ts @@ -1,11 +1,11 @@ /** - * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { lerp as scalar_lerp } from '../../mol-math/interpolate'; -import { defaults } from '../../mol-util'; import { Mat3 } from '../linear-algebra/3d/mat3'; import { Mat4 } from '../linear-algebra/3d/mat4'; import { Quat } from '../linear-algebra/3d/quat'; @@ -29,11 +29,13 @@ interface SymmetryOperator { readonly hkl: Vec3, /** spacegroup symmetry operator index, -1 if not applicable */ readonly spgrOp: number, + /** unique (external) key, -1 if not available */ + readonly key: number, readonly matrix: Mat4, - // cache the inverse of the transform + /** cache the inverse of the transform */ readonly inverse: Mat4, - // optimize the identity case + /** optimize the identity case */ readonly isIdentity: boolean, /** @@ -51,19 +53,20 @@ namespace SymmetryOperator { export const RotationTranslationEpsilon = 0.005; - export type CreateInfo = { assembly?: SymmetryOperator['assembly'], ncsId?: number, hkl?: Vec3, spgrOp?: number } + export type CreateInfo = { assembly?: SymmetryOperator['assembly'], ncsId?: number, hkl?: Vec3, spgrOp?: number, key?: number } export function create(name: string, matrix: Mat4, info?: CreateInfo | SymmetryOperator): SymmetryOperator { - let { assembly, ncsId, hkl, spgrOp } = info || { }; + let { assembly, ncsId, hkl, spgrOp, key } = info || { }; const _hkl = hkl ? Vec3.clone(hkl) : Vec3(); - spgrOp = defaults(spgrOp, -1); + spgrOp = spgrOp ?? -1; + key = key ?? -1; ncsId = ncsId || -1; const isIdentity = Mat4.isIdentity(matrix); const suffix = getSuffix(info, isIdentity); - if (isIdentity) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, spgrOp, ncsId, suffix }; + if (isIdentity) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, spgrOp, ncsId, suffix, key }; if (!Mat4.isRotationAndTranslation(matrix, RotationTranslationEpsilon)) { console.warn(`Symmetry operator (${name}) should be a composition of rotation and translation.`); } - return { name, assembly, matrix, inverse: Mat4.invert(Mat4(), matrix), isIdentity: false, hkl: _hkl, spgrOp, ncsId, suffix }; + return { name, assembly, matrix, inverse: Mat4.invert(Mat4(), matrix), isIdentity: false, hkl: _hkl, spgrOp, key, ncsId, suffix }; } function isSymmetryOperator(x: any): x is SymmetryOperator { diff --git a/src/mol-model-formats/structure/property/bonds/index-pair.ts b/src/mol-model-formats/structure/property/bonds/index-pair.ts index c6021eb47183f67a6fee53a8bda06a2183f2e60a..81b3b3759121b290f7d8e706e381784b85764803 100644 --- a/src/mol-model-formats/structure/property/bonds/index-pair.ts +++ b/src/mol-model-formats/structure/property/bonds/index-pair.ts @@ -14,6 +14,8 @@ import { ElementIndex } from '../../../../mol-model/structure'; export type IndexPairsProps = { readonly key: ArrayLike<number> + readonly operatorA: ArrayLike<number> + readonly operatorB: ArrayLike<number> readonly order: ArrayLike<number> readonly distance: ArrayLike<number> readonly flag: ArrayLike<BondType.Flag> @@ -24,18 +26,22 @@ export type IndexPairBonds = { bonds: IndexPairs, maxDistance: number } function getGraph(indexA: ArrayLike<ElementIndex>, indexB: ArrayLike<ElementIndex>, props: Partial<IndexPairsProps>, count: number): IndexPairs { const builder = new IntAdjacencyGraph.EdgeBuilder(count, indexA, indexB); const key = new Int32Array(builder.slotCount); + const operatorA = new Array(builder.slotCount); + const operatorB = new Array(builder.slotCount); const order = new Int8Array(builder.slotCount); const distance = new Array(builder.slotCount); const flag = new Array(builder.slotCount); for (let i = 0, _i = builder.edgeCount; i < _i; i++) { builder.addNextEdge(); builder.assignProperty(key, props.key ? props.key[i] : -1); + builder.assignProperty(operatorA, props.operatorA ? props.operatorA[i] : -1); + builder.assignProperty(operatorB, props.operatorB ? props.operatorB[i] : -1); builder.assignProperty(order, props.order ? props.order[i] : 1); builder.assignProperty(distance, props.distance ? props.distance[i] : -1); builder.assignProperty(flag, props.flag ? props.flag[i] : BondType.Flag.Covalent); } - return builder.createGraph({ key, order, distance, flag }); + return builder.createGraph({ key, operatorA, operatorB, order, distance, flag }); } export namespace IndexPairBonds { @@ -50,6 +56,10 @@ export namespace IndexPairBonds { indexA: Column<number>, indexB: Column<number>, key?: Column<number>, + /** Operator key for indexA. Used in bond computation. */ + operatorA?: Column<number>, + /** Operator key for indexB. Used in bond computation. */ + operatorB?: Column<number>, order?: Column<number>, /** * Useful for bonds in periodic cells. That is, only bonds within the given @@ -83,12 +93,30 @@ export namespace IndexPairBonds { const indexA = pairs.indexA.toArray() as ArrayLike<ElementIndex>; const indexB = pairs.indexB.toArray() as ArrayLike<ElementIndex>; const key = pairs.key && pairs.key.toArray(); + const operatorA = pairs.operatorA && pairs.operatorA.toArray(); + const operatorB = pairs.operatorB && pairs.operatorB.toArray(); const order = pairs.order && pairs.order.toArray(); const distance = pairs.distance && pairs.distance.toArray(); const flag = pairs.flag && pairs.flag.toArray(); return { - bonds: getGraph(indexA, indexB, { key, order, distance, flag }, count), + bonds: getGraph(indexA, indexB, { key, operatorA, operatorB, order, distance, flag }, count), maxDistance: p.maxDistance }; } + + /** Like `getEdgeIndex` but taking `edgeProps.operatorA` and `edgeProps.operatorB` into account */ + export function getEdgeIndexForOperators(bonds: IndexPairs, i: ElementIndex, j: ElementIndex, opI: number, opJ: number): number { + let a, b, opA, opB; + if (i < j) { + a = i; b = j; + opA = opI; opB = opJ; + } else { + a = j; b = i; + opA = opJ; opB = opI; + } + for (let t = bonds.offset[a], _t = bonds.offset[a + 1]; t < _t; t++) { + if (bonds.b[t] === b && bonds.edgeProps.operatorA[t] === opA && bonds.edgeProps.operatorB[t] === opB) return t; + } + return -1; + } } \ No newline at end of file diff --git a/src/mol-model/structure/query/context.ts b/src/mol-model/structure/query/context.ts index c51b441a77da6cfffd623877b0734df8e87fc757..7cf7070a41db2e78ce0fbef36e706b873b872b98 100644 --- a/src/mol-model/structure/query/context.ts +++ b/src/mol-model/structure/query/context.ts @@ -155,6 +155,6 @@ class QueryContextBondInfo<U extends Unit = Unit> { } get length() { - return StructureElement.Location.distance(this.a, this. b); + return StructureElement.Location.distance(this.a, this.b); } } \ No newline at end of file diff --git a/src/mol-model/structure/structure/properties.ts b/src/mol-model/structure/structure/properties.ts index 1ee3110f99cea729f8561224c2056042774763ac..71e003b232d9dd679a624d9162f792b683dc993c 100644 --- a/src/mol-model/structure/structure/properties.ts +++ b/src/mol-model/structure/structure/properties.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -173,6 +173,7 @@ const unit = { multiChain: p(l => Unit.Traits.is(l.unit.traits, Unit.Trait.MultiChain)), object_primitive: p(l => l.unit.objectPrimitive), operator_name: p(l => l.unit.conformation.operator.name), + operator_key: p(l => l.unit.conformation.operator.key), model_index: p(l => l.unit.model.modelNum), model_label: p(l => l.unit.model.label), model_entry_id: p(l => l.unit.model.entryId), diff --git a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts index 74f5127df14aabdc3ba3ec71e6ca40ba1c92804c..ab11f3f7b8598817c9c0ed68a1c953c5395e1686 100644 --- a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts @@ -71,6 +71,8 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput const testDistanceSq = (bRadius + maxRadius) * (bRadius + maxRadius); builder.startUnitPair(unitA.id, unitB.id); + const opKeyA = unitA.conformation.operator.key; + const opKeyB = unitB.conformation.operator.key; for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) { const aI = atomsA[_aI]; @@ -80,7 +82,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput if (!props.forceCompute && indexPairs) { const { maxDistance } = indexPairs; - const { offset, b, edgeProps: { order, distance, flag, key } } = indexPairs.bonds; + const { offset, b, edgeProps: { order, distance, flag, key, operatorA, operatorB } } = indexPairs.bonds; const srcA = sourceIndex.value(aI); const aeI = getElementIdx(type_symbolA.value(aI)); @@ -90,6 +92,11 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput const _bI = SortedArray.indexOf(unitB.elements, bI) as StructureElement.UnitIndex; if (_bI < 0) continue; + const opA = operatorA[i]; + const opB = operatorB[i]; + if ((opA >= 0 && opA !== opKeyA && opA !== opKeyB) || + (opB >= 0 && opB !== opKeyB && opB !== opKeyA)) continue; + const beI = getElementIdx(type_symbolA.value(bI)); const d = distance[i]; diff --git a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts index 29fd505381b21fd4791c49718f3900b8eeb001cb..71bef526e5b8e7c850c46e1c84f180fe907ea976 100644 --- a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts @@ -55,7 +55,7 @@ function findIndexPairBonds(unit: Unit.Atomic) { const { type_symbol } = unit.model.atomicHierarchy.atoms; const atomCount = unit.elements.length; const { maxDistance } = indexPairs; - const { offset, b, edgeProps: { order, distance, flag, key } } = indexPairs.bonds; + const { offset, b, edgeProps: { order, distance, flag, key, operatorA, operatorB } } = indexPairs.bonds; const { atomSourceIndex: sourceIndex } = unit.model.atomicHierarchy; const { invertedIndex } = Model.getInvertedAtomSourceIndex(unit.model); @@ -66,6 +66,8 @@ function findIndexPairBonds(unit: Unit.Atomic) { const orders: number[] = []; const keys: number[] = []; + const opKey = unit.conformation.operator.key; + for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) { const aI = atoms[_aI]; const aeI = getElementIdx(type_symbol.value(aI)); @@ -80,6 +82,10 @@ function findIndexPairBonds(unit: Unit.Atomic) { const _bI = SortedArray.indexOf(unit.elements, bI) as StructureElement.UnitIndex; if (_bI < 0) continue; + const opA = operatorA[i]; + const opB = operatorB[i]; + if ((opA >= 0 && opA !== opKey) || (opB >= 0 && opB !== opKey)) continue; + const beI = getElementIdx(type_symbol.value(bI)); const d = distance[i]; diff --git a/src/mol-plugin-state/transforms/representation.ts b/src/mol-plugin-state/transforms/representation.ts index 32c564437b540369c43419285eb68e579a24a925..a6089db15deb00ce21368622784dfcadcb3731fc 100644 --- a/src/mol-plugin-state/transforms/representation.ts +++ b/src/mol-plugin-state/transforms/representation.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -43,6 +43,7 @@ import { Box3D } from '../../mol-math/geometry'; import { PlaneParams, PlaneRepresentation } from '../../mol-repr/shape/loci/plane'; import { Substance } from '../../mol-theme/substance'; import { Material } from '../../mol-util/material'; +import { lerp } from '../../mol-math/interpolate'; export { StructureRepresentation3D }; export { ExplodeStructureRepresentation3D }; @@ -56,6 +57,7 @@ export { SubstanceStructureRepresentation3DFromScript }; export { SubstanceStructureRepresentation3DFromBundle }; export { ClippingStructureRepresentation3DFromScript }; export { ClippingStructureRepresentation3DFromBundle }; +export { ThemeStrengthRepresentation3D }; export { VolumeRepresentation3D }; type StructureRepresentation3D = typeof StructureRepresentation3D @@ -745,6 +747,62 @@ const ClippingStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn } }); +type ThemeStrengthRepresentation3D = typeof ThemeStrengthRepresentation3D +const ThemeStrengthRepresentation3D = PluginStateTransform.BuiltIn({ + name: 'theme-strength-representation-3d', + display: 'Theme Strength 3D Representation', + from: SO.Molecule.Structure.Representation3D, + to: SO.Molecule.Structure.Representation3DState, + params: () => ({ + overpaintStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }), + transparencyStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }), + substanceStrength: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }), + }) +})({ + canAutoUpdate() { + return true; + }, + apply({ a, params }) { + return new SO.Molecule.Structure.Representation3DState({ + state: { + themeStrength: { + overpaint: params.overpaintStrength, + transparency: params.transparencyStrength, + substance: params.substanceStrength + }, + }, + initialState: { + themeStrength: { overpaint: 1, transparency: 1, substance: 1 }, + }, + info: { }, + repr: a.data.repr + }, { label: 'Theme Strength', description: `${params.overpaintStrength.toFixed(2)}, ${params.transparencyStrength.toFixed(2)}, ${params.substanceStrength.toFixed(2)}` }); + }, + update({ a, b, newParams, oldParams }) { + if (newParams.overpaintStrength === b.data.state.themeStrength?.overpaint && + newParams.transparencyStrength === b.data.state.themeStrength?.transparency && + newParams.substanceStrength === b.data.state.themeStrength?.substance + ) return StateTransformer.UpdateResult.Unchanged; + + b.data.state.themeStrength = { + overpaint: newParams.overpaintStrength, + transparency: newParams.transparencyStrength, + substance: newParams.substanceStrength, + }; + b.data.repr = a.data.repr; + b.label = 'Theme Strength'; + b.description = `${newParams.overpaintStrength.toFixed(2)}, ${newParams.transparencyStrength.toFixed(2)}, ${newParams.substanceStrength.toFixed(2)}`; + return StateTransformer.UpdateResult.Updated; + }, + interpolate(src, tar, t) { + return { + overpaintStrength: lerp(src.overpaintStrength, tar.overpaintStrength, t), + transparencyStrength: lerp(src.transparencyStrength, tar.transparencyStrength, t), + substanceStrength: lerp(src.substanceStrength, tar.substanceStrength, t), + }; + } +}); + // export namespace VolumeRepresentation3DHelpers { diff --git a/src/mol-plugin-ui/skin/base/components/viewport.scss b/src/mol-plugin-ui/skin/base/components/viewport.scss index 2ca2872ace8a899d7e3eaf86ddbdbca392a27935..b5e2098c53ff67916f8295a43a0dee463b35de26 100644 --- a/src/mol-plugin-ui/skin/base/components/viewport.scss +++ b/src/mol-plugin-ui/skin/base/components/viewport.scss @@ -4,7 +4,7 @@ top: 0; right: 0; bottom: 0; - background: black; + background: $default-background; .msp-btn-link { background: rgba(0,0,0,0.2); diff --git a/src/mol-plugin/spec.ts b/src/mol-plugin/spec.ts index 48f3c3fabfcd02942150caf224fafe0b696e3e4b..e0792376d11cca76f6c624226bb77047a368f62a 100644 --- a/src/mol-plugin/spec.ts +++ b/src/mol-plugin/spec.ts @@ -104,6 +104,7 @@ export const DefaultPluginSpec = (): PluginSpec => ({ PluginSpec.Action(StateTransforms.Representation.TransparencyStructureRepresentation3DFromScript), PluginSpec.Action(StateTransforms.Representation.ClippingStructureRepresentation3DFromScript), PluginSpec.Action(StateTransforms.Representation.SubstanceStructureRepresentation3DFromScript), + PluginSpec.Action(StateTransforms.Representation.ThemeStrengthRepresentation3D), PluginSpec.Action(AssignColorVolume), PluginSpec.Action(StateTransforms.Volume.VolumeFromCcp4), diff --git a/src/mol-repr/representation.ts b/src/mol-repr/representation.ts index 17da5156448dd9e75ff88ae586a1106c9386825d..33b452e766d5d80467d38d2582cfdcbce22f9462 100644 --- a/src/mol-repr/representation.ts +++ b/src/mol-repr/representation.ts @@ -191,6 +191,8 @@ namespace Representation { substance: Substance /** Bit mask of per group clipping applied to the representation's renderobjects */ clipping: Clipping + /** Strength of the representations overpaint, transparency, substance*/ + themeStrength: { overpaint: number, transparency: number, substance: number } /** Controls if the representation's renderobjects are synced automatically with GPU or not */ syncManually: boolean /** A transformation applied to the representation's renderobjects */ @@ -199,7 +201,20 @@ namespace Representation { markerActions: MarkerActions } export function createState(): State { - return { visible: true, alphaFactor: 1, pickable: true, colorOnly: false, syncManually: false, transform: Mat4.identity(), overpaint: Overpaint.Empty, transparency: Transparency.Empty, substance: Substance.Empty, clipping: Clipping.Empty, markerActions: MarkerActions.All }; + return { + visible: true, + alphaFactor: 1, + pickable: true, + colorOnly: false, + syncManually: false, + transform: Mat4.identity(), + overpaint: Overpaint.Empty, + transparency: Transparency.Empty, + substance: Substance.Empty, + clipping: Clipping.Empty, + themeStrength: { overpaint: 1, transparency: 1, substance: 1 }, + markerActions: MarkerActions.All + }; } export function updateState(state: State, update: Partial<State>) { if (update.visible !== undefined) state.visible = update.visible; @@ -210,6 +225,7 @@ namespace Representation { if (update.transparency !== undefined) state.transparency = update.transparency; if (update.substance !== undefined) state.substance = update.substance; if (update.clipping !== undefined) state.clipping = update.clipping; + if (update.themeStrength !== undefined) state.themeStrength = update.themeStrength; if (update.syncManually !== undefined) state.syncManually = update.syncManually; if (update.transform !== undefined) Mat4.copy(state.transform, update.transform); if (update.markerActions !== undefined) state.markerActions = update.markerActions; @@ -432,6 +448,7 @@ namespace Representation { if (state.substance !== undefined) { // TODO } + if (state.themeStrength !== undefined) Visual.setThemeStrength(renderObject, state.themeStrength); if (state.transform !== undefined) Visual.setTransform(renderObject, state.transform); Representation.updateState(currentState, state); diff --git a/src/mol-repr/structure/complex-representation.ts b/src/mol-repr/structure/complex-representation.ts index a50d04ae0c47bda3e592bfd93e2aa2b25dcc4de3..e959f918968aaaed200bac13a026db2b64dc6b1d 100644 --- a/src/mol-repr/structure/complex-representation.ts +++ b/src/mol-repr/structure/complex-representation.ts @@ -127,6 +127,7 @@ export function ComplexRepresentation<P extends StructureParams>(label: string, const remappedClipping = Clipping.remap(state.clipping, _structure); visual.setClipping(remappedClipping); } + if (state.themeStrength !== undefined && visual) visual.setThemeStrength(state.themeStrength); if (state.transform !== undefined && visual) visual.setTransform(state.transform); if (state.unitTransforms !== undefined && visual) { // Since ComplexVisuals always renders geometries between units, the application diff --git a/src/mol-repr/structure/complex-visual.ts b/src/mol-repr/structure/complex-visual.ts index 71f5314e921092800bf3a916e11bf2f480776687..526c5be397c93d512b344424b5015d7c8779a68c 100644 --- a/src/mol-repr/structure/complex-visual.ts +++ b/src/mol-repr/structure/complex-visual.ts @@ -299,6 +299,9 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge setClipping(clipping: Clipping) { Visual.setClipping(renderObject, clipping, lociApply, true); }, + setThemeStrength(strength: { overpaint: number, transparency: number, substance: number }) { + Visual.setThemeStrength(renderObject, strength); + }, destroy() { dispose?.(geometry); if (renderObject) { diff --git a/src/mol-repr/structure/units-representation.ts b/src/mol-repr/structure/units-representation.ts index d7a2b6e0634e71156342aff34217ec67b23ac55b..b713ede00253e42f34151a19bd149f1157fd7e06 100644 --- a/src/mol-repr/structure/units-representation.ts +++ b/src/mol-repr/structure/units-representation.ts @@ -222,7 +222,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct } function setVisualState(visual: UnitsVisual<P>, group: Unit.SymmetryGroup, state: Partial<StructureRepresentationState>) { - const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, transform, unitTransforms } = state; + const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, themeStrength, transform, unitTransforms } = state; if (visible !== undefined) visual.setVisibility(visible); if (alphaFactor !== undefined) visual.setAlphaFactor(alphaFactor); @@ -231,6 +231,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct if (transparency !== undefined) visual.setTransparency(transparency, webgl); if (substance !== undefined) visual.setSubstance(substance, webgl); if (clipping !== undefined) visual.setClipping(clipping); + if (themeStrength !== undefined) visual.setThemeStrength(themeStrength); if (transform !== undefined) visual.setTransform(transform); if (unitTransforms !== undefined) { if (unitTransforms) { @@ -243,7 +244,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct } function setState(state: Partial<StructureRepresentationState>) { - const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, transform, unitTransforms, syncManually, markerActions } = state; + const { visible, alphaFactor, pickable, overpaint, transparency, substance, clipping, themeStrength, transform, unitTransforms, syncManually, markerActions } = state; const newState: Partial<StructureRepresentationState> = {}; if (visible !== _state.visible) newState.visible = visible; @@ -261,6 +262,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct if (clipping !== undefined && _structure) { newState.clipping = Clipping.remap(clipping, _structure); } + if (themeStrength !== undefined) newState.themeStrength = themeStrength; if (transform !== undefined && !Mat4.areEqual(transform, _state.transform, EPSILON)) { newState.transform = transform; } diff --git a/src/mol-repr/structure/units-visual.ts b/src/mol-repr/structure/units-visual.ts index 8c0e3a1d8b7e25488410100f02594b508ed4367a..cd5e898e7501affaa640e1b083bf543ebc30cc23 100644 --- a/src/mol-repr/structure/units-visual.ts +++ b/src/mol-repr/structure/units-visual.ts @@ -381,6 +381,9 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom setClipping(clipping: Clipping) { Visual.setClipping(renderObject, clipping, lociApply, true); }, + setThemeStrength(strength: { overpaint: number, transparency: number, substance: number }) { + Visual.setThemeStrength(renderObject, strength); + }, destroy() { dispose?.(geometry); if (renderObject) { diff --git a/src/mol-repr/visual.ts b/src/mol-repr/visual.ts index 924e0fb81fa141c54b0b3e001f4b4fafeb02a3c2..4a3f41ebb38bef03cf66c8ec2d0f4ae026f0ba8b 100644 --- a/src/mol-repr/visual.ts +++ b/src/mol-repr/visual.ts @@ -55,6 +55,7 @@ interface Visual<D, P extends PD.Params> { setTransparency: (transparency: Transparency, webgl?: WebGLContext) => void setSubstance: (substance: Substance, webgl?: WebGLContext) => void setClipping: (clipping: Clipping) => void + setThemeStrength: (strength: { overpaint: number, transparency: number, substance: number }) => void destroy: () => void mustRecreate?: (data: D, props: PD.Values<P>, webgl?: WebGLContext) => boolean } @@ -349,6 +350,14 @@ namespace Visual { ValueCell.updateIfChanged(dClipping, clipping.layers.length > 0); } + export function setThemeStrength(renderObject: GraphicsRenderObject | undefined, strength: { overpaint: number, transparency: number, substance: number }) { + if (renderObject) { + ValueCell.updateIfChanged(renderObject.values.uOverpaintStrength, strength.overpaint); + ValueCell.updateIfChanged(renderObject.values.uTransparencyStrength, strength.transparency); + ValueCell.updateIfChanged(renderObject.values.uSubstanceStrength, strength.substance); + } + } + export function setTransform(renderObject: GraphicsRenderObject | undefined, transform?: Mat4, instanceTransforms?: Float32Array | null) { if (!renderObject || (!transform && !instanceTransforms)) return; diff --git a/src/mol-repr/volume/representation.ts b/src/mol-repr/volume/representation.ts index c6de383731b5f36a097cd321d19660c7e4502651..aa2f336d6208bc5524dff06f74278084c9cdf983 100644 --- a/src/mol-repr/volume/representation.ts +++ b/src/mol-repr/volume/representation.ts @@ -252,6 +252,9 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet setClipping(clipping: Clipping) { return Visual.setClipping(renderObject, clipping, lociApply, true); }, + setThemeStrength(strength: { overpaint: number, transparency: number, substance: number }) { + Visual.setThemeStrength(renderObject, strength); + }, destroy() { dispose?.(geometry); if (renderObject) { diff --git a/src/mol-script/language/symbol-table/structure-query.ts b/src/mol-script/language/symbol-table/structure-query.ts index 209da4376e81c413caada96b2a2b544146e3de48..e7125a35814c22831970ee0571f198158e9df89a 100644 --- a/src/mol-script/language/symbol-table/structure-query.ts +++ b/src/mol-script/language/symbol-table/structure-query.ts @@ -273,6 +273,7 @@ const atomProperty = { sourceIndex: atomProp(Type.Num, 'Index of the atom/element in the input file.'), operatorName: atomProp(Type.Str, 'Name of the symmetry operator applied to this element.'), + operatorKey: atomProp(Type.Num, 'Key of the symmetry operator applied to this element.'), modelIndex: atomProp(Type.Num, 'Index of the model in the input file.'), modelLabel: atomProp(Type.Str, 'Label/header of the model in the input file.') }, diff --git a/src/mol-script/runtime/query/table.ts b/src/mol-script/runtime/query/table.ts index deab2d4baa0c10ab7fc3641b258ef8a1c7a0cce2..a87b23c7e6509c4324585904548578e9f8f10dd6 100644 --- a/src/mol-script/runtime/query/table.ts +++ b/src/mol-script/runtime/query/table.ts @@ -299,6 +299,7 @@ const symbols = [ D(MolScript.structureQuery.atomProperty.core.z, atomProp(StructureProperties.atom.z)), D(MolScript.structureQuery.atomProperty.core.sourceIndex, atomProp(StructureProperties.atom.sourceIndex)), D(MolScript.structureQuery.atomProperty.core.operatorName, atomProp(StructureProperties.unit.operator_name)), + D(MolScript.structureQuery.atomProperty.core.operatorKey, atomProp(StructureProperties.unit.operator_key)), D(MolScript.structureQuery.atomProperty.core.modelIndex, atomProp(StructureProperties.unit.model_index)), D(MolScript.structureQuery.atomProperty.core.modelLabel, atomProp(StructureProperties.unit.model_label)), D(MolScript.structureQuery.atomProperty.core.atomKey, (ctx, xs) => { diff --git a/src/mol-script/script/mol-script/symbols.ts b/src/mol-script/script/mol-script/symbols.ts index c4bd1cfe251bba567bfdd89eabc319cea26ece99..feb891928cd41da4977ee58ffee8132a15ed0601 100644 --- a/src/mol-script/script/mol-script/symbols.ts +++ b/src/mol-script/script/mol-script/symbols.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2018 Mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 Mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { UniqueArray } from '../../../mol-data/generic'; @@ -205,6 +206,7 @@ export const SymbolTable = [ Alias(MolScript.structureQuery.atomProperty.core.z, 'atom.z'), Alias(MolScript.structureQuery.atomProperty.core.sourceIndex, 'atom.src-index'), Alias(MolScript.structureQuery.atomProperty.core.operatorName, 'atom.op-name'), + Alias(MolScript.structureQuery.atomProperty.core.operatorKey, 'atom.op-key'), Alias(MolScript.structureQuery.atomProperty.core.modelIndex, 'atom.model-index'), Alias(MolScript.structureQuery.atomProperty.core.modelLabel, 'atom.model-label'), Alias(MolScript.structureQuery.atomProperty.core.atomKey, 'atom.key'), @@ -253,6 +255,7 @@ export const SymbolTable = [ 'Bond Properties', Alias(MolScript.structureQuery.bondProperty.order, 'bond.order'), Alias(MolScript.structureQuery.bondProperty.length, 'bond.length'), + Alias(MolScript.structureQuery.bondProperty.key, 'bond.key'), Alias(MolScript.structureQuery.bondProperty.atomA, 'bond.atom-a'), Alias(MolScript.structureQuery.bondProperty.atomB, 'bond.atom-b'), Macro(MSymbol('bond.is', Arguments.List(StructureQueryTypes.BondFlag), Type.Bool,