diff --git a/src/examples/proteopedia-wrapper/index.ts b/src/examples/proteopedia-wrapper/index.ts index c590ea69e86dff18ac59ebe0b0d3fea84d80a3f1..d810d2af23f95e9ea863fc5ac859142ca76c84ea 100644 --- a/src/examples/proteopedia-wrapper/index.ts +++ b/src/examples/proteopedia-wrapper/index.ts @@ -403,7 +403,7 @@ class MolStarProteopediaWrapper { }, download: async (type: 'molj' | 'molx' = 'molj', params?: PluginState.SnapshotParams) => { const data = await this.plugin.managers.snapshot.serialize({ type, params }); - download(data, `mol-star_state_${(name || getFormattedTime())}.${type}`); + download(data, `mol-star_state_${getFormattedTime()}.${type}`); }, fetch: async (url: string, type: 'molj' | 'molx' = 'molj') => { try { diff --git a/src/extensions/alpha-orbitals/gpu/compute.ts b/src/extensions/alpha-orbitals/gpu/compute.ts index 709cb52174e5c1ae08584f3c7fa5f770f6688309..cb844f5ebd34fc9fe0b78aa60b64bade6718beb7 100644 --- a/src/extensions/alpha-orbitals/gpu/compute.ts +++ b/src/extensions/alpha-orbitals/gpu/compute.ts @@ -32,7 +32,7 @@ const AlphaOrbitalsSchema = { uNAlpha: UniformSpec('i'), uNCoeff: UniformSpec('i'), uMaxCoeffs: UniformSpec('i'), - uLittleEndian: UniformSpec('i') // TODO: boolean uniforms + uLittleEndian: UniformSpec('b') }; const AlphaOrbitalsShaderCode = ShaderCode('postprocessing', quad_vert, shader_frag); type AlphaOrbitalsRenderable = ComputeRenderable<Values<typeof AlphaOrbitalsSchema>> diff --git a/src/extensions/alpha-orbitals/gpu/shader.frag.ts b/src/extensions/alpha-orbitals/gpu/shader.frag.ts index dd74ec3fa0700c3b83d4ef3b398914512677e067..6386cd83ec0c8c5189dc4e75998777e66689809b 100644 --- a/src/extensions/alpha-orbitals/gpu/shader.frag.ts +++ b/src/extensions/alpha-orbitals/gpu/shader.frag.ts @@ -28,7 +28,7 @@ uniform float uWidth; uniform int uNCoeff; uniform int uNAlpha; -uniform int uLittleEndian; +uniform bool uLittleEndian; float shiftRight (float v, float amt) { v = floor(v) + 0.5; @@ -61,9 +61,9 @@ vec4 floatToRgba(float texelFloat) { float byte2 = (last_bit_of_biased_exponent * 128.0 + extractBits(fraction, 16.0, 23.0)) / 255.0; float byte1 = (sign * 128.0 + remaining_bits_of_biased_exponent) / 255.0; return ( - uLittleEndian > 0 - ? vec4(byte4, byte3, byte2, byte1) - : vec4(byte1, byte2, byte3, byte4) + uLittleEndian + ? vec4(byte4, byte3, byte2, byte1) + : vec4(byte1, byte2, byte3, byte4) ); } @@ -118,13 +118,13 @@ float L4(vec3 p, float a0, float a1, float a2, float a3, float a4, float a5, flo float alpha(float offset, float f) { #ifdef uMaxCoeffs - // in webgl1, the value is in the alpha channel! - return texture2D(tAlpha, vec2(offset * f, 0.5)).a; - #endif + // in webgl1, the value is in the alpha channel! + return texture2D(tAlpha, vec2(offset * f, 0.5)).a; + #endif #ifndef uMaxCoeffs - return texture2D(tAlpha, vec2(offset * f, 0.5)).x; - #endif + return texture2D(tAlpha, vec2(offset * f, 0.5)).x; + #endif } float Y(int L, vec3 X, float aO, float fA) { @@ -140,12 +140,12 @@ float Y(int L, vec3 X, float aO, float fA) { ); } else if (L == 3) { return L3(X, - alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA), alpha(aO + 3.0, fA), alpha(aO + 4.0, fA), + alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA), alpha(aO + 3.0, fA), alpha(aO + 4.0, fA), alpha(aO + 5.0, fA), alpha(aO + 6.0, fA) ); } else if (L == 4) { return L4(X, - alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA), alpha(aO + 3.0, fA), alpha(aO + 4.0, fA), + alpha(aO, fA), alpha(aO + 1.0, fA), alpha(aO + 2.0, fA), alpha(aO + 3.0, fA), alpha(aO + 4.0, fA), alpha(aO + 5.0, fA), alpha(aO + 6.0, fA), alpha(aO + 7.0, fA), alpha(aO + 8.0, fA) ); } @@ -182,15 +182,15 @@ float Y(int L, vec3 X, float aO, float fA) { float intDiv(float a, float b) { return float(int(a) / int(b)); } float intMod(float a, float b) { return a - b * float(int(a) / int(b)); } -void main(void) { +void main(void) { float offset = floor(gl_FragCoord.x) + floor(gl_FragCoord.y) * uWidth; - + // axis order fast to slow Z, Y, X // TODO: support arbitrary axis orders? float k = intMod(offset, uDimensions.z), kk = intDiv(offset, uDimensions.z); float j = intMod(kk, uDimensions.y); float i = intDiv(kk, uDimensions.y); - + vec3 xyz = uMin + uDelta * vec3(i, j, k); float fCenter = 1.0 / float(uNCenters - 1); diff --git a/src/extensions/anvil/representation.ts b/src/extensions/anvil/representation.ts index 9d239291b12899ce6e2357164f5027e43da5b56b..b4bd6b112c33907a56b3e6fa96ff46525f1ab7fc 100644 --- a/src/extensions/anvil/representation.ts +++ b/src/extensions/anvil/representation.ts @@ -106,7 +106,7 @@ function getBilayerRims(ctx: RuntimeContext, data: Structure, props: BilayerRims const builder = LinesBuilder.create(128, 64, shape?.geometry); getLayerCircle(builder, p1, centroid, normal, scaledRadius, props); getLayerCircle(builder, p2, centroid, normal, scaledRadius, props); - return Shape.create(name, data, builder.getLines(), () => props.color, () => props.linesSize, () => membraneLabel(data)); + return Shape.create('Bilayer rims', data, builder.getLines(), () => props.color, () => props.linesSize, () => membraneLabel(data)); } function getLayerCircle(builder: LinesBuilder, p: Vec3, centroid: Vec3, normal: Vec3, radius: number, props: BilayerRimsProps, shape?: Shape<Lines>) { @@ -142,7 +142,7 @@ function getBilayerPlanes(ctx: RuntimeContext, data: Structure, props: BilayerPl const scaledRadius = props.radiusFactor * radius; getLayerPlane(state, p1, centroid, normal, scaledRadius); getLayerPlane(state, p2, centroid, normal, scaledRadius); - return Shape.create(name, data, MeshBuilder.getMesh(state), () => props.color, () => 1, () => membraneLabel(data)); + return Shape.create('Bilayer planes', data, MeshBuilder.getMesh(state), () => props.color, () => 1, () => membraneLabel(data)); } function getLayerPlane(state: MeshBuilder.State, p: Vec3, centroid: Vec3, normal: Vec3, radius: number) { @@ -160,7 +160,7 @@ function getBilayerSpheres(ctx: RuntimeContext, data: Structure, props: BilayerS const spheresBuilder = SpheresBuilder.create(256, 128, shape?.geometry); getLayerSpheres(spheresBuilder, planePoint1, normalVector, density, scaledRadius); getLayerSpheres(spheresBuilder, planePoint2, normalVector, density, scaledRadius); - return Shape.create(name, data, spheresBuilder.getSpheres(), () => props.color, () => props.sphereSize, () => membraneLabel(data)); + return Shape.create('Bilayer spheres', data, spheresBuilder.getSpheres(), () => props.color, () => props.sphereSize, () => membraneLabel(data)); } function getLayerSpheres(spheresBuilder: SpheresBuilder, point: Vec3, normalVector: Vec3, density: number, sqRadius: number) { diff --git a/src/extensions/cellpack/state.ts b/src/extensions/cellpack/state.ts index a01a8938289f2bc185ee0126364599c5bc61a294..b5fabdf4f2080bd1932fdb5e45656e3cf6b284ac 100644 --- a/src/extensions/cellpack/state.ts +++ b/src/extensions/cellpack/state.ts @@ -125,7 +125,7 @@ const StructureFromAssemblies = PluginStateTransform.BuiltIn({ const s = await StructureSymmetry.buildAssembly(initial_structure, a.id).runInContext(ctx); structures.push(s); } - const builder = Structure.Builder({ label: name }); + const builder = Structure.Builder(); let offsetInvariantId = 0; for (const s of structures) { let maxInvariantId = 0; diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index 325eb6a9035ceb1cb074e23e15ec5165adaa9d36..f484230e73473d1dafa2845680a820225ad35696 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -27,7 +27,7 @@ import { Canvas3dInteractionHelper } from './helper/interaction-events'; import { PostprocessingParams, PostprocessingPass } from './passes/postprocessing'; import { MultiSampleParams, MultiSamplePass } from './passes/multi-sample'; import { DrawPass } from './passes/draw'; -import { PickPass } from './passes/pick'; +import { PickData, PickPass } from './passes/pick'; import { ImagePass, ImageProps } from './passes/image'; import { Sphere3D } from '../mol-math/geometry'; import { isDebugMode } from '../mol-util/debug'; @@ -100,7 +100,7 @@ interface Canvas3D { requestDraw(force?: boolean): void animate(): void pause(): void - identify(x: number, y: number): PickingId | undefined + identify(x: number, y: number): PickData | undefined mark(loci: Representation.Loci, action: MarkerAction): void getLoci(pickingId: PickingId | undefined): Representation.Loci @@ -132,9 +132,9 @@ const cancelAnimationFrame = typeof window !== 'undefined' : (handle: number) => clearImmediate(handle as unknown as NodeJS.Immediate); namespace Canvas3D { - export interface HoverEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys } + export interface HoverEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys, page?: Vec2, position?: Vec3 } export interface DragEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys, pageStart: Vec2, pageEnd: Vec2 } - export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys } + export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys, position?: Vec3 } export function fromCanvas(canvas: HTMLCanvasElement, props: PartialCanvas3DProps = {}, attribs: Partial<{ antialias: boolean, pixelScale: number }> = {}) { const gl = getGLContext(canvas, { @@ -346,7 +346,7 @@ namespace Canvas3D { animationFrameHandle = 0; } - function identify(x: number, y: number): PickingId | undefined { + function identify(x: number, y: number): PickData | undefined { return webgl.isContextLost ? undefined : pickPass.identify(x, y); } diff --git a/src/mol-canvas3d/helper/bounding-sphere-helper.ts b/src/mol-canvas3d/helper/bounding-sphere-helper.ts index 1b60e779c2bf835745050444c17154e06febc756..163edef3b215d08bf8fc0c26d7437b802104b282 100644 --- a/src/mol-canvas3d/helper/bounding-sphere-helper.ts +++ b/src/mol-canvas3d/helper/bounding-sphere-helper.ts @@ -160,5 +160,5 @@ const instanceMaterialId = getNextMaterialId(); function createBoundingSphereRenderObject(mesh: Mesh, color: Color, materialId: number, transform?: TransformData) { const values = Mesh.Utils.createValuesSimple(mesh, { alpha: 0.1, doubleSided: false }, color, 1, transform); - return createRenderObject('mesh', values, { visible: true, alphaFactor: 1, pickable: false, opaque: false, writeDepth: false }, materialId); + return createRenderObject('mesh', values, { visible: true, alphaFactor: 1, pickable: false, colorOnly: false, opaque: false, writeDepth: false }, materialId); } \ No newline at end of file diff --git a/src/mol-canvas3d/helper/interaction-events.ts b/src/mol-canvas3d/helper/interaction-events.ts index 5cde1ea863b311a93c4e94f89c4b1dafa9e9e422..53847848e62444af9b73d40bfc5f9dfc00fc32dc 100644 --- a/src/mol-canvas3d/helper/interaction-events.ts +++ b/src/mol-canvas3d/helper/interaction-events.ts @@ -9,7 +9,7 @@ import { PickingId } from '../../mol-geo/geometry/picking'; import { Representation } from '../../mol-repr/representation'; import InputObserver, { ModifiersKeys, ButtonsType } from '../../mol-util/input/input-observer'; import { RxEventHelper } from '../../mol-util/rx-event-helper'; -import { Vec2 } from '../../mol-math/linear-algebra'; +import { Vec2, Vec3 } from '../../mol-math/linear-algebra'; import { Camera } from '../camera'; type Canvas3D = import('../canvas3d').Canvas3D @@ -34,6 +34,7 @@ export class Canvas3dInteractionHelper { private endY = -1; private id: PickingId | undefined = void 0; + private position: Vec3 | undefined = void 0; private currentIdentifyT = 0; private isInteracting = false; @@ -61,14 +62,16 @@ export class Canvas3dInteractionHelper { } if (xyChanged) { - this.id = this.canvasIdentify(this.endX, this.endY); + const pickData = this.canvasIdentify(this.endX, this.endY); + this.id = pickData?.id; + this.position = pickData?.position; this.startX = this.endX; this.startY = this.endY; } if (e === InputEvent.Click) { const loci = this.getLoci(this.id); - this.events.click.next({ current: loci, buttons: this.buttons, button: this.button, modifiers: this.modifiers }); + this.events.click.next({ current: loci, buttons: this.buttons, button: this.button, modifiers: this.modifiers, position: this.position }); this.prevLoci = loci; return; } @@ -78,11 +81,8 @@ export class Canvas3dInteractionHelper { } const loci = this.getLoci(this.id); - // only broadcast the latest hover - if (!Representation.Loci.areEqual(this.prevLoci, loci)) { - this.events.hover.next({ current: loci, buttons: this.buttons, button: this.button, modifiers: this.modifiers }); - this.prevLoci = loci; - } + this.events.hover.next({ current: loci, buttons: this.buttons, button: this.button, modifiers: this.modifiers, page: Vec2.create(this.endX, this.endY), position: this.position }); + this.prevLoci = loci; } tick(t: number) { @@ -129,9 +129,9 @@ export class Canvas3dInteractionHelper { } private modify(modifiers: ModifiersKeys) { - if (Representation.Loci.isEmpty(this.prevLoci) || ModifiersKeys.areEqual(modifiers, this.modifiers)) return; + if (ModifiersKeys.areEqual(modifiers, this.modifiers)) return; this.modifiers = modifiers; - this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers }); + this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers, page: Vec2.create(this.endX, this.endY), position: this.position }); } private outsideViewport(x: number, y: number) { diff --git a/src/mol-canvas3d/passes/pick.ts b/src/mol-canvas3d/passes/pick.ts index 004d003e1d65dcb7330c4bfaf7586d1b6d8ecfbe..7de7688e0ab906dd9de21d2a63fa9efa2192d698 100644 --- a/src/mol-canvas3d/passes/pick.ts +++ b/src/mol-canvas3d/passes/pick.ts @@ -10,26 +10,32 @@ import Scene from '../../mol-gl/scene'; import { WebGLContext } from '../../mol-gl/webgl/context'; import { GraphicsRenderVariant } from '../../mol-gl/webgl/render-item'; import { RenderTarget } from '../../mol-gl/webgl/render-target'; -import { decodeFloatRGB } from '../../mol-util/float-packing'; +import { Vec3 } from '../../mol-math/linear-algebra'; +import { decodeFloatRGB, unpackRGBAToDepth } from '../../mol-util/float-packing'; import { Camera, ICamera } from '../camera'; import { StereoCamera } from '../camera/stereo'; +import { cameraUnproject } from '../camera/util'; import { HandleHelper } from '../helper/handle-helper'; import { DrawPass } from './draw'; const NullId = Math.pow(2, 24) - 2; +export type PickData = { id: PickingId, position: Vec3 } + export class PickPass { pickDirty = true objectPickTarget: RenderTarget instancePickTarget: RenderTarget groupPickTarget: RenderTarget + depthPickTarget: RenderTarget isStereo = false private objectBuffer: Uint8Array private instanceBuffer: Uint8Array private groupBuffer: Uint8Array + private depthBuffer: Uint8Array private pickScale: number private pickWidth: number @@ -43,6 +49,7 @@ export class PickPass { this.objectPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight); this.instancePickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight); this.groupPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight); + this.depthPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight); this.setupBuffers(); } @@ -53,6 +60,7 @@ export class PickPass { this.objectBuffer = new Uint8Array(bufferSize); this.instanceBuffer = new Uint8Array(bufferSize); this.groupBuffer = new Uint8Array(bufferSize); + this.depthBuffer = new Uint8Array(bufferSize); } } @@ -68,6 +76,7 @@ export class PickPass { this.objectPickTarget.setSize(this.pickWidth, this.pickHeight); this.instancePickTarget.setSize(this.pickWidth, this.pickHeight); this.groupPickTarget.setSize(this.pickWidth, this.pickHeight); + this.depthPickTarget.setSize(this.pickWidth, this.pickHeight); this.setupBuffers(); } @@ -107,6 +116,9 @@ export class PickPass { this.groupPickTarget.bind(); this.renderVariant('pickGroup'); + this.depthPickTarget.bind(); + this.renderVariant('depth'); + this.pickDirty = false; } @@ -121,14 +133,27 @@ export class PickPass { this.groupPickTarget.bind(); webgl.readPixels(0, 0, this.pickWidth, this.pickHeight, this.groupBuffer); + + this.depthPickTarget.bind(); + webgl.readPixels(0, 0, this.pickWidth, this.pickHeight, this.depthBuffer); + } + + private getBufferIdx(x: number, y: number): number { + return (y * this.pickWidth + x) * 4; + } + + private getDepth(x: number, y: number): number { + const idx = this.getBufferIdx(x, y); + const b = this.depthBuffer; + return unpackRGBAToDepth(b[idx], b[idx + 1], b[idx + 2], b[idx + 3]); } private getId(x: number, y: number, buffer: Uint8Array) { - const idx = (y * this.pickWidth + x) * 4; + const idx = this.getBufferIdx(x, y); return decodeFloatRGB(buffer[idx], buffer[idx + 1], buffer[idx + 2]); } - identify(x: number, y: number): PickingId | undefined { + identify(x: number, y: number): PickData | undefined { const { webgl, pickScale, camera: { viewport } } = this; if (webgl.isContextLost) return; @@ -168,7 +193,12 @@ export class PickPass { const groupId = this.getId(xp, yp, this.groupBuffer); // console.log('groupId', groupId); if (groupId === -1 || groupId === NullId) return; - // console.log({ objectId, instanceId, groupId }); - return { objectId, instanceId, groupId }; + + const z = this.getDepth(xp, yp); + const position = Vec3.create(x, gl.drawingBufferHeight - y, z); + cameraUnproject(position, position, viewport, this.camera.inverseProjectionView); + + // console.log({ { objectId, instanceId, groupId }, position} ); + return { id: { objectId, instanceId, groupId }, position }; } } \ No newline at end of file diff --git a/src/mol-geo/geometry/base.ts b/src/mol-geo/geometry/base.ts index 3d2b13791bf496945a53058087528f8a96ea4cfc..272add6460f0462f812e94602e6d078c3d272f81 100644 --- a/src/mol-geo/geometry/base.ts +++ b/src/mol-geo/geometry/base.ts @@ -78,6 +78,7 @@ export namespace BaseGeometry { visible: true, alphaFactor: 1, pickable: true, + colorOnly: false, opaque, writeDepth: opaque, }; diff --git a/src/mol-geo/geometry/picking.ts b/src/mol-geo/geometry/picking.ts index 8ae9b751027a9b55470721ca58a0d665ff67bb26..bf7e9a6cd11178b2db52962808d5b867a76121b0 100644 --- a/src/mol-geo/geometry/picking.ts +++ b/src/mol-geo/geometry/picking.ts @@ -15,8 +15,3 @@ export namespace PickingId { return a.objectId === b.objectId && a.instanceId === b.instanceId && a.groupId === b.groupId; } } - -export interface PickingInfo { - label: string - data?: any -} \ No newline at end of file diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts index 5c3eb8fdfc9bbc2f90d1b57340caad1e0cf113b7..7c4872bd3aa1e3cbe6ea35ea917b95bd56147a34 100644 --- a/src/mol-gl/_spec/renderer.spec.ts +++ b/src/mol-gl/_spec/renderer.spec.ts @@ -92,6 +92,7 @@ function createPoints() { visible: true, alphaFactor: 1, pickable: true, + colorOnly: false, opaque: true, writeDepth: true }; diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts index 5f94a857563630e388a93ad3ab04960ee1632b5b..51f087b79b309950499064488082646990a4a909 100644 --- a/src/mol-gl/renderable.ts +++ b/src/mol-gl/renderable.ts @@ -17,6 +17,7 @@ export type RenderableState = { visible: boolean alphaFactor: number pickable: boolean + colorOnly: boolean opaque: boolean writeDepth: boolean, } diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index 104b00b1cd26a9465453d4158733d67e22ebfe5e..b21606fb4f5d42b91c563736dbb682b14de3936f 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -129,7 +129,7 @@ export const GlobalUniformSchema = { uFogFar: UniformSpec('f'), uFogColor: UniformSpec('v3'), - uTransparentBackground: UniformSpec('i'), + uTransparentBackground: UniformSpec('b'), uClipObjectType: UniformSpec('i[]'), uClipObjectPosition: UniformSpec('v3[]'), @@ -149,7 +149,7 @@ export const GlobalUniformSchema = { uPickingAlphaThreshold: UniformSpec('f'), uInteriorDarkening: UniformSpec('f'), - uInteriorColorFlag: UniformSpec('i'), + uInteriorColorFlag: UniformSpec('b'), uInteriorColor: UniformSpec('v3'), uHighlightColor: UniformSpec('v3'), diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index dedea00b3b4c49f6b9c1260435d0377964996d80..32fd6aa12d11d0b14e1a38f20fd569b7364e7882 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -203,7 +203,7 @@ namespace Renderer { uFogNear: ValueCell.create(1), uFogFar: ValueCell.create(10000), uFogColor: ValueCell.create(bgColor), - uTransparentBackground: ValueCell.create(0), + uTransparentBackground: ValueCell.create(false), uClipObjectType: ValueCell.create(clip.objects.type), uClipObjectPosition: ValueCell.create(clip.objects.position), @@ -221,7 +221,7 @@ namespace Renderer { uPickingAlphaThreshold: ValueCell.create(p.pickingAlphaThreshold), uInteriorDarkening: ValueCell.create(p.interiorDarkening), - uInteriorColorFlag: ValueCell.create(p.interiorColorFlag ? 1 : 0), + uInteriorColorFlag: ValueCell.create(p.interiorColorFlag), uInteriorColor: ValueCell.create(Color.toVec3Normalized(Vec3(), p.interiorColor)), uHighlightColor: ValueCell.create(Color.toVec3Normalized(Vec3(), p.highlightColor)), @@ -322,7 +322,7 @@ namespace Renderer { ValueCell.update(globalUniforms.uFogFar, camera.fogFar); ValueCell.update(globalUniforms.uFogNear, camera.fogNear); - ValueCell.update(globalUniforms.uTransparentBackground, transparentBackground ? 1 : 0); + ValueCell.update(globalUniforms.uTransparentBackground, transparentBackground); globalUniformsNeedUpdate = true; state.currentRenderItemId = -1; @@ -368,7 +368,9 @@ namespace Renderer { } } else { // picking & depth for (let i = 0, il = renderables.length; i < il; ++i) { - renderObject(renderables[i], variant, depthTexture); + if (!renderables[i].state.colorOnly) { + renderObject(renderables[i], variant, depthTexture); + } } } @@ -407,7 +409,7 @@ namespace Renderer { } if (props.interiorColorFlag !== undefined && props.interiorColorFlag !== p.interiorColorFlag) { p.interiorColorFlag = props.interiorColorFlag; - ValueCell.update(globalUniforms.uInteriorColorFlag, p.interiorColorFlag ? 1 : 0); + ValueCell.update(globalUniforms.uInteriorColorFlag, p.interiorColorFlag); } if (props.interiorColor !== undefined && props.interiorColor !== p.interiorColor) { p.interiorColor = props.interiorColor; diff --git a/src/mol-gl/shader/chunks/apply-fog.glsl.ts b/src/mol-gl/shader/chunks/apply-fog.glsl.ts index 5045fcf0ac739b137df13888ffc0f4f6a95a9585..e58c39ca1bf7857d5005ae73540cf81e4adadda3 100644 --- a/src/mol-gl/shader/chunks/apply-fog.glsl.ts +++ b/src/mol-gl/shader/chunks/apply-fog.glsl.ts @@ -2,7 +2,7 @@ export default ` float fogDepth = length(vViewPosition); float fogFactor = smoothstep(uFogNear, uFogFar, fogDepth); float fogAlpha = (1.0 - fogFactor) * gl_FragColor.a; -if (uTransparentBackground == 0) { +if (!uTransparentBackground) { gl_FragColor.rgb = mix(gl_FragColor.rgb, uFogColor, fogFactor); if (gl_FragColor.a < 1.0) gl_FragColor.a = fogAlpha; diff --git a/src/mol-gl/shader/chunks/apply-interior-color.glsl.ts b/src/mol-gl/shader/chunks/apply-interior-color.glsl.ts index 40b9a12e0e62e3c73605751e88c83cec97a1520f..37b365fef70cbf7f80ccbbeb0c01dadbc0314d40 100644 --- a/src/mol-gl/shader/chunks/apply-interior-color.glsl.ts +++ b/src/mol-gl/shader/chunks/apply-interior-color.glsl.ts @@ -1,6 +1,6 @@ export default ` if (interior) { - if (uInteriorColorFlag == 1) { + if (uInteriorColorFlag) { gl_FragColor.rgb = uInteriorColor; } else { gl_FragColor.rgb *= 1.0 - uInteriorDarkening; diff --git a/src/mol-gl/shader/chunks/common-frag-params.glsl.ts b/src/mol-gl/shader/chunks/common-frag-params.glsl.ts index a2aeacf42bbe9391077ed8d9bb5208bdd6c3b3d1..e5e44da56106b0c335a4cf7d007e72a2847ab90a 100644 --- a/src/mol-gl/shader/chunks/common-frag-params.glsl.ts +++ b/src/mol-gl/shader/chunks/common-frag-params.glsl.ts @@ -37,10 +37,10 @@ uniform vec3 uFogColor; uniform float uAlpha; uniform float uPickingAlphaThreshold; -uniform int uTransparentBackground; +uniform bool uTransparentBackground; uniform float uInteriorDarkening; -uniform int uInteriorColorFlag; +uniform bool uInteriorColorFlag; uniform vec3 uInteriorColor; bool interior; `; \ No newline at end of file diff --git a/src/mol-gl/shader/direct-volume.frag.ts b/src/mol-gl/shader/direct-volume.frag.ts index 33a61fb1855d74e0370e8a5c5e1b2611a94d9890..a3182c6c35912e22f1ca0808276eb706b4b57b7d 100644 --- a/src/mol-gl/shader/direct-volume.frag.ts +++ b/src/mol-gl/shader/direct-volume.frag.ts @@ -51,10 +51,10 @@ uniform vec3 uFogColor; uniform float uAlpha; uniform float uPickingAlphaThreshold; -uniform int uTransparentBackground; +uniform bool uTransparentBackground; uniform float uInteriorDarkening; -uniform int uInteriorColorFlag; +uniform bool uInteriorColorFlag; uniform vec3 uInteriorColor; bool interior; diff --git a/src/mol-gl/webgl/uniform.ts b/src/mol-gl/webgl/uniform.ts index abc415c5923c7d2635099253a890a0218a57d882..d333fd13b88965d8f12c8915a73c1f63ac4644f4 100644 --- a/src/mol-gl/webgl/uniform.ts +++ b/src/mol-gl/webgl/uniform.ts @@ -11,6 +11,7 @@ import { RenderableSchema } from '../../mol-gl/renderable/schema'; import { ValueOf } from '../../mol-util/type-helpers'; export type UniformKindValue = { + 'b': boolean; 'b[]': boolean[] 'f': number; 'f[]': number[] 'i': number; 'i[]': number[] 'v2': Vec2; 'v2[]': number[] @@ -28,6 +29,7 @@ export type UniformsList = [string, ValueCell<UniformType>][] export function getUniformType(gl: GLRenderingContext, kind: UniformKind) { switch (kind) { + case 'b': case 'b[]': return gl.BOOL; case 'f': case 'f[]': return gl.FLOAT; case 'i': case 'i[]': return gl.INT; case 'v2': case 'v2[]': return gl.FLOAT_VEC2; @@ -56,8 +58,8 @@ function getUniformSetter(kind: UniformKind): UniformSetter { switch (kind) { case 'f': return uniform1f; case 'f[]': return uniform1fv; - case 'i': case 't': return uniform1i; - case 'i[]': case 't[]': return uniform1iv; + case 'i': case 't': case 'b': return uniform1i; + case 'i[]': case 't[]': case 'b[]': return uniform1iv; case 'v2': case 'v2[]': return uniform2fv; case 'v3': case 'v3[]': return uniform3fv; case 'v4': case 'v4[]': return uniform4fv; diff --git a/src/mol-plugin-state/manager/interactivity.ts b/src/mol-plugin-state/manager/interactivity.ts index 12b6a6debb8f2371c6e83316468f4bf3a2d7304a..87fe84af53680ea5c3df72074c20d97586239d60 100644 --- a/src/mol-plugin-state/manager/interactivity.ts +++ b/src/mol-plugin-state/manager/interactivity.ts @@ -15,7 +15,7 @@ import { shallowEqual } from '../../mol-util/object'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { StatefulPluginComponent } from '../component'; import { StructureSelectionManager } from './structure/selection'; -import { Vec2 } from '../../mol-math/linear-algebra'; +import { Vec2, Vec3 } from '../../mol-math/linear-algebra'; export { InteractivityManager }; @@ -70,9 +70,9 @@ namespace InteractivityManager { export type Params = typeof Params export type Props = PD.Values<Params> - export interface HoverEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys } + export interface HoverEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys, page?: Vec2, position?: Vec3 } export interface DragEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys, pageStart: Vec2, pageEnd: Vec2 } - export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys } + export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys, position?: Vec3 } export type LociMarkProvider = (loci: Representation.Loci, action: MarkerAction) => void diff --git a/src/mol-repr/representation.ts b/src/mol-repr/representation.ts index b9e0f19a7e50cf1909b154e1314f1ec64c2da3c2..5c3e5b9e517475c26dfe3821a78774603d15a241 100644 --- a/src/mol-repr/representation.ts +++ b/src/mol-repr/representation.ts @@ -174,6 +174,8 @@ namespace Representation { alphaFactor: number /** Controls if the representation's renderobjects are pickable or not */ pickable: boolean + /** Controls if the representation's renderobjects is rendered in color pass (i.e., not pick and depth) or not */ + colorOnly: boolean /** Overpaint applied to the representation's renderobjects */ overpaint: Overpaint /** Per group transparency applied to the representation's renderobjects */ @@ -188,12 +190,13 @@ namespace Representation { markerActions: MarkerActions } export function createState(): State { - return { visible: true, alphaFactor: 1, pickable: true, syncManually: false, transform: Mat4.identity(), overpaint: Overpaint.Empty, transparency: Transparency.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, clipping: Clipping.Empty, markerActions: MarkerActions.All }; } export function updateState(state: State, update: Partial<State>) { if (update.visible !== undefined) state.visible = update.visible; if (update.alphaFactor !== undefined) state.alphaFactor = update.alphaFactor; if (update.pickable !== undefined) state.pickable = update.pickable; + if (update.colorOnly !== undefined) state.colorOnly = update.colorOnly; if (update.overpaint !== undefined) state.overpaint = update.overpaint; if (update.transparency !== undefined) state.transparency = update.transparency; if (update.clipping !== undefined) state.clipping = update.clipping; @@ -363,6 +366,7 @@ namespace Representation { if (state.visible !== undefined) Visual.setVisibility(renderObject, state.visible); if (state.alphaFactor !== undefined) Visual.setAlphaFactor(renderObject, state.alphaFactor); if (state.pickable !== undefined) Visual.setPickable(renderObject, state.pickable); + if (state.colorOnly !== undefined) Visual.setColorOnly(renderObject, state.colorOnly); if (state.overpaint !== undefined) { // TODO } diff --git a/src/mol-repr/shape/representation.ts b/src/mol-repr/shape/representation.ts index fa3da89a34ae32ec9758b0c0cfac931c86044e3a..3ee72b35acb74a0a582d94046d495a46d916e904 100644 --- a/src/mol-repr/shape/representation.ts +++ b/src/mol-repr/shape/representation.ts @@ -203,6 +203,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa if (state.visible !== undefined) Visual.setVisibility(_renderObject, state.visible); if (state.alphaFactor !== undefined) Visual.setAlphaFactor(_renderObject, state.alphaFactor); if (state.pickable !== undefined) Visual.setPickable(_renderObject, state.pickable); + if (state.colorOnly !== undefined) Visual.setColorOnly(_renderObject, state.colorOnly); if (state.overpaint !== undefined) { Visual.setOverpaint(_renderObject, state.overpaint, lociApply, true); } diff --git a/src/mol-repr/structure/complex-visual.ts b/src/mol-repr/structure/complex-visual.ts index 170e2347fdc92bfb7bae10735dee56fe9bfc548a..6b0b6a8b9079461498ce8613ce86e9082cd04e9f 100644 --- a/src/mol-repr/structure/complex-visual.ts +++ b/src/mol-repr/structure/complex-visual.ts @@ -217,6 +217,9 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge setPickable(pickable: boolean) { Visual.setPickable(renderObject, pickable); }, + setColorOnly(colorOnly: boolean) { + Visual.setColorOnly(renderObject, colorOnly); + }, setTransform(matrix?: Mat4, instanceMatrices?: Float32Array | null) { Visual.setTransform(renderObject, matrix, instanceMatrices); }, diff --git a/src/mol-repr/structure/units-visual.ts b/src/mol-repr/structure/units-visual.ts index 8f928c99b199655dd0b951375e08d8d1f15e1f4a..aa1cb4e1a5164b0b2ef315b9f1303f9d9ee28ef6 100644 --- a/src/mol-repr/structure/units-visual.ts +++ b/src/mol-repr/structure/units-visual.ts @@ -274,6 +274,9 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom setPickable(pickable: boolean) { Visual.setPickable(renderObject, pickable); }, + setColorOnly(colorOnly: boolean) { + Visual.setColorOnly(renderObject, colorOnly); + }, setTransform(matrix?: Mat4, instanceMatrices?: Float32Array | null) { Visual.setTransform(renderObject, matrix, instanceMatrices); }, diff --git a/src/mol-repr/visual.ts b/src/mol-repr/visual.ts index b999b848caefc80e28cb4b618a3dc8cbce27d84e..b163b9f3ba811ec4e237c8dacc43fd4d6632f4dd 100644 --- a/src/mol-repr/visual.ts +++ b/src/mol-repr/visual.ts @@ -41,6 +41,7 @@ interface Visual<D, P extends PD.Params> { setVisibility: (visible: boolean) => void setAlphaFactor: (alphaFactor: number) => void setPickable: (pickable: boolean) => void + setColorOnly: (colorOnly: boolean) => void setTransform: (matrix?: Mat4, instanceMatrices?: Float32Array | null) => void setOverpaint: (overpaint: Overpaint) => void setTransparency: (transparency: Transparency) => void @@ -62,6 +63,10 @@ namespace Visual { if (renderObject) renderObject.state.pickable = pickable; } + export function setColorOnly(renderObject: GraphicsRenderObject | undefined, colorOnly: boolean) { + if (renderObject) renderObject.state.colorOnly = colorOnly; + } + export function mark(renderObject: GraphicsRenderObject | undefined, loci: Loci, action: MarkerAction, lociApply: LociApply) { if (!renderObject) return false; diff --git a/src/mol-repr/volume/representation.ts b/src/mol-repr/volume/representation.ts index 5bb1ffc328e11cac0b32f97b7c91e4e0124b9715..48544c3b3a5788b9991687324651ae0c9402a32d 100644 --- a/src/mol-repr/volume/representation.ts +++ b/src/mol-repr/volume/representation.ts @@ -190,6 +190,9 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet setPickable(pickable: boolean) { Visual.setPickable(renderObject, pickable); }, + setColorOnly(colorOnly: boolean) { + Visual.setColorOnly(renderObject, colorOnly); + }, setTransform(matrix?: Mat4, instanceMatrices?: Float32Array | null) { Visual.setTransform(renderObject, matrix, instanceMatrices); }, diff --git a/src/mol-task/execution/observable.ts b/src/mol-task/execution/observable.ts index 11d013b2377baa6a378d1bf56c9080b6c5cfc3f0..05939f857fb6cf9823a4de4a20f4af5a4568b34c 100644 --- a/src/mol-task/execution/observable.ts +++ b/src/mol-task/execution/observable.ts @@ -110,7 +110,7 @@ async function execute<T>(task: ExposedTask<T>, ctx: ObservableRuntimeContext) { // wait for all child computations to go thru the abort phase. if (ctx.node.children.length > 0) { - await new Promise(res => { ctx.onChildrenFinished = res; }); + await new Promise<void>(res => { ctx.onChildrenFinished = res; }); } if (task.onAbort) { task.onAbort(); diff --git a/src/mol-util/color/color.ts b/src/mol-util/color/color.ts index 6bb9a811a451b2055f9cc6414b5a7e095f383f0e..0e635c4071f5bf07d10217e38e6c965cf42adb08 100644 --- a/src/mol-util/color/color.ts +++ b/src/mol-util/color/color.ts @@ -146,7 +146,7 @@ export namespace Color { } } -export type ColorListEntry = Color | [color: Color, offset: number /** normalized value from 0 to 1 */] +export type ColorListEntry = Color | [Color, number /** normalized value from 0 to 1 */] export interface ColorList { label: string diff --git a/src/mol-util/is-little-endian.ts b/src/mol-util/is-little-endian.ts index 9f82353c61f18dbc26b6b65701b2f65ad9660d96..2573cebf4b7e9eff98d9b5b9ea852987552fb1f7 100644 --- a/src/mol-util/is-little-endian.ts +++ b/src/mol-util/is-little-endian.ts @@ -10,6 +10,5 @@ export function isLittleEndian() { const uint16array = new Uint16Array(arrayBuffer); uint8Array[0] = 0xAA; uint8Array[1] = 0xBB; - if (uint16array[0] === 0xBBAA) return 1; - return 0; + return uint16array[0] === 0xBBAA; } \ No newline at end of file diff --git a/src/tests/browser/render-shape.ts b/src/tests/browser/render-shape.ts index 856293a4aa7f23046a84b76b817b412bf3dc50aa..d342744560c3dfdf65567ce4f73703a175241866 100644 --- a/src/tests/browser/render-shape.ts +++ b/src/tests/browser/render-shape.ts @@ -41,7 +41,7 @@ let prevReprLoci = Representation.Loci.Empty; const canvas3d = Canvas3D.fromCanvas(canvas); canvas3d.animate(); canvas3d.input.move.subscribe(({x, y}) => { - const pickingId = canvas3d.identify(x, y); + const pickingId = canvas3d.identify(x, y)?.id; let label = ''; if (pickingId) { const reprLoci = canvas3d.getLoci(pickingId); diff --git a/src/tests/browser/render-structure.ts b/src/tests/browser/render-structure.ts index 8e155735c17df92c6989bc9e5cf7cf6e39ed8140..9bd232b080728411041cdce7f66fa96d0d31d224 100644 --- a/src/tests/browser/render-structure.ts +++ b/src/tests/browser/render-structure.ts @@ -51,7 +51,7 @@ parent.appendChild(info); let prevReprLoci = Representation.Loci.Empty; canvas3d.input.move.pipe(throttleTime(100)).subscribe(({x, y}) => { - const pickingId = canvas3d.identify(x, y); + const pickingId = canvas3d.identify(x, y)?.id; let label = ''; if (pickingId) { const reprLoci = canvas3d.getLoci(pickingId);