Browse Source

canvas3d: fixes for custom pixel-scale & viewport

Alexander Rose 4 năm trước cách đây
mục cha
commit
ad6cebc59b

+ 2 - 0
src/apps/viewer/index.html

@@ -49,11 +49,13 @@
             if (debugMode) molstar.setDebugMode(debugMode, debugMode);
 
             var disableAntialiasing = getParam('disable-antialiasing', '[^&]+').trim() === '1';
+            var pixelScale = parseFloat(getParam('pixel-scale', '[^&]+').trim() || '1');
             var hideControls = getParam('hide-controls', '[^&]+').trim() === '1';
             var pdbProvider = getParam('pdb-provider', '[^&]+').trim().toLowerCase();
             var emdbProvider = getParam('emdb-provider', '[^&]+').trim().toLowerCase();
             var viewer = new molstar.Viewer('app', {
                 disableAntialiasing: disableAntialiasing,
+                pixelScale: pixelScale,
                 layoutShowControls: !hideControls,
                 viewportShowExpand: false,
                 pdbProvider: pdbProvider || 'pdbe',

+ 4 - 4
src/mol-canvas3d/camera.ts

@@ -218,10 +218,10 @@ namespace Camera {
 function updateOrtho(camera: Camera) {
     const { viewport, zoom, near, far, viewOffset } = camera;
 
-    const fullLeft = -(viewport.width - viewport.x) / 2;
-    const fullRight = (viewport.width - viewport.x) / 2;
-    const fullTop = (viewport.height - viewport.y) / 2;
-    const fullBottom = -(viewport.height - viewport.y) / 2;
+    const fullLeft = -viewport.width / 2;
+    const fullRight = viewport.width / 2;
+    const fullTop = viewport.height / 2;
+    const fullBottom = -viewport.height / 2;
 
     const dx = (fullRight - fullLeft) / (2 * zoom);
     const dy = (fullTop - fullBottom) / (2 * zoom);

+ 1 - 1
src/mol-canvas3d/canvas3d.ts

@@ -212,7 +212,7 @@ namespace Canvas3D {
         const renderer = Renderer.create(webgl, p.renderer);
         const debugHelper = new BoundingSphereHelper(webgl, scene, p.debug);
         const handleHelper = new HandleHelper(webgl, p.handle);
-        const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input);
+        const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input, camera);
 
         const drawPass = new DrawPass(webgl, renderer, scene, camera, debugHelper, handleHelper, {
             cameraHelper: p.camera.helper

+ 1 - 1
src/mol-canvas3d/controls/trackball.ts

@@ -137,7 +137,7 @@ namespace TrackballControls {
             const dy = _rotCurr[1] - _rotPrev[1];
             Vec3.set(rotMoveDir, dx, dy, 0);
 
-            const angle = Vec3.magnitude(rotMoveDir) * p.rotateSpeed;
+            const angle = Vec3.magnitude(rotMoveDir) * p.rotateSpeed * input.pixelRatio;
 
             if (angle) {
                 Vec3.sub(_eye, camera.position, camera.target);

+ 20 - 6
src/mol-canvas3d/helper/interaction-events.ts

@@ -10,6 +10,7 @@ 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 { Camera } from '../camera';
 
 type Canvas3D = import('../canvas3d').Canvas3D
 type HoverEvent = import('../canvas3d').Canvas3D.HoverEvent
@@ -92,7 +93,7 @@ export class Canvas3dInteractionHelper {
         }
     }
 
-    leave() {
+    private leave() {
         this.inside = false;
         if (Representation.Loci.isEmpty(this.prevLoci)) {
             this.prevLoci = Representation.Loci.Empty;
@@ -100,7 +101,7 @@ export class Canvas3dInteractionHelper {
         }
     }
 
-    move(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
+    private move(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
         this.inside = true;
         this.buttons = buttons;
         this.button = button;
@@ -109,7 +110,7 @@ export class Canvas3dInteractionHelper {
         this.endY = y;
     }
 
-    click(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
+    private click(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
         this.endX = x;
         this.endY = y;
         this.buttons = buttons;
@@ -118,7 +119,7 @@ export class Canvas3dInteractionHelper {
         this.identify(InputEvent.Click, 0);
     }
 
-    drag(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
+    private drag(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
         this.endX = x;
         this.endY = y;
         this.buttons = buttons;
@@ -127,17 +128,29 @@ export class Canvas3dInteractionHelper {
         this.identify(InputEvent.Drag, 0);
     }
 
-    modify(modifiers: ModifiersKeys) {
+    private modify(modifiers: ModifiersKeys) {
         if (Representation.Loci.isEmpty(this.prevLoci) || 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 });
     }
 
+    private outsideViewport(x: number, y: number) {
+        const { input, camera: { viewport } } = this;
+        x *= input.pixelRatio;
+        y *= input.pixelRatio;
+        return (
+            x > viewport.x + viewport.width ||
+            input.height - y > viewport.y + viewport.height ||
+            x < viewport.x ||
+            input.height - y < viewport.y
+        );
+    }
+
     dispose() {
         this.ev.dispose();
     }
 
-    constructor(private canvasIdentify: Canvas3D['identify'], private getLoci: Canvas3D['getLoci'], input: InputObserver, private maxFps: number = 30) {
+    constructor(private canvasIdentify: Canvas3D['identify'], private getLoci: Canvas3D['getLoci'], private input: InputObserver, private camera: Camera, private maxFps: number = 30) {
         input.drag.subscribe(({x, y, buttons, button, modifiers }) => {
             this.isInteracting = true;
             // console.log('drag');
@@ -156,6 +169,7 @@ export class Canvas3dInteractionHelper {
         });
 
         input.click.subscribe(({x, y, buttons, button, modifiers }) => {
+            if (this.outsideViewport(x, y)) return;
             // console.log('click');
             this.click(x, y, buttons, button, modifiers);
         });

+ 6 - 0
src/mol-canvas3d/passes/multi-sample.ts

@@ -161,6 +161,7 @@ export class MultiSamplePass {
             }
             this.setQuadShift(0, 0);
             gl.viewport(0, 0, width, height);
+            gl.scissor(0, 0, width, height);
             compose.render();
         }
 
@@ -175,6 +176,7 @@ export class MultiSamplePass {
         }
         this.setQuadShift(x / width, y / height);
         gl.viewport(x, y, width, height);
+        gl.scissor(x, y, width, height);
         state.disable(gl.BLEND);
         compose.render();
 
@@ -216,6 +218,7 @@ export class MultiSamplePass {
             state.depthMask(false);
             this.setQuadShift(0, 0);
             gl.viewport(0, 0, width, height);
+            gl.scissor(0, 0, width, height);
             compose.render();
             this.sampleIndex += 1;
         } else {
@@ -251,6 +254,7 @@ export class MultiSamplePass {
                 }
                 this.setQuadShift(0, 0);
                 gl.viewport(0, 0, width, height);
+                gl.scissor(0, 0, width, height);
                 compose.render();
 
                 this.sampleIndex += 1;
@@ -262,10 +266,12 @@ export class MultiSamplePass {
             webgl.unbindFramebuffer();
             this.setQuadShift(x / width, y / height);
             gl.viewport(x, y, width, height);
+            gl.scissor(x, y, width, height);
         } else {
             this.colorTarget.bind();
             this.setQuadShift(0, 0);
             gl.viewport(0, 0, width, height);
+            gl.scissor(0, 0, width, height);
         }
 
         const accumulationWeight = this.sampleIndex * sampleWeight;

+ 2 - 2
src/mol-canvas3d/passes/pick.ts

@@ -130,8 +130,8 @@ export class PickPass {
             this.syncBuffers();
         }
 
-        x -= viewport.x * pixelRatio;
-        y += viewport.y * pixelRatio; // plus because of flipped y
+        x -= viewport.x;
+        y += viewport.y; // plus because of flipped y
         y = gl.drawingBufferHeight - y; // flip y
 
         const xp = Math.floor(x * pickScale);

+ 2 - 0
src/mol-canvas3d/passes/postprocessing.ts

@@ -172,10 +172,12 @@ export class PostprocessingPass {
             this.webgl.unbindFramebuffer();
             this.setQuadShift(x / width, y / height);
             gl.viewport(x, y, width, height);
+            gl.scissor(x, y, width, height);
         } else {
             this.target.bind();
             this.setQuadShift(0, 0);
             gl.viewport(0, 0, width, height);
+            gl.scissor(0, 0, width, height);
         }
         state.disable(gl.SCISSOR_TEST);
         state.disable(gl.BLEND);

+ 1 - 0
src/mol-gl/renderer.ts

@@ -377,6 +377,7 @@ namespace Renderer {
 
         return {
             clear: (transparentBackground: boolean) => {
+                ctx.unbindFramebuffer();
                 state.enable(gl.SCISSOR_TEST);
                 state.depthMask(true);
                 state.colorMask(true, true, true, true);

+ 4 - 0
src/mol-plugin-ui/viewport/canvas.tsx

@@ -11,6 +11,7 @@ import { resizeCanvas } from '../../mol-canvas3d/util';
 import { Subject } from 'rxjs';
 import { debounceTime } from 'rxjs/internal/operators/debounceTime';
 import { PluginConfig } from '../../mol-plugin/config';
+import { Color } from '../../mol-util/color';
 
 interface ViewportCanvasState {
     noWebGl: boolean
@@ -46,6 +47,9 @@ export class ViewportCanvas extends PluginUIComponent<ViewportCanvasParams, View
         if (container && canvas) {
             const pixelScale = this.plugin.config.get(PluginConfig.General.PixelScale) || 1;
             resizeCanvas(canvas, container, pixelScale);
+            const [r, g, b] = Color.toRgbNormalized(this.plugin.canvas3d!.props.renderer.backgroundColor);
+            const a = this.plugin.canvas3d!.props.transparentBackground ? 0 : 1;
+            this.plugin.canvas3d!.webgl.clear(r, g, b, a);
             this.plugin.canvas3d!.handleResize();
         }
     }

+ 5 - 2
src/mol-util/input/input-observer.ts

@@ -525,9 +525,10 @@ namespace InputObserver {
         }
 
         function onPointerDown(ev: PointerEvent) {
+            if (!mask(ev.clientX, ev.clientY)) return;
+
             eventOffset(pointerStart, ev);
             Vec2.copy(pointerDown, pointerStart);
-            if (!mask(ev.clientX, ev.clientY)) return;
 
             if (insideBounds(pointerStart)) {
                 dragging = DraggingState.Started;
@@ -536,6 +537,7 @@ namespace InputObserver {
 
         function onPointerUp(ev: PointerEvent) {
             dragging = DraggingState.Stopped;
+            if (!mask(ev.clientX, ev.clientY)) return;
 
             eventOffset(pointerEnd, ev);
             if (Vec2.distance(pointerEnd, pointerDown) < 4) {
@@ -573,9 +575,10 @@ namespace InputObserver {
         }
 
         function onMouseWheel(ev: WheelEvent) {
+            if (!mask(ev.clientX, ev.clientY)) return;
+
             eventOffset(pointerEnd, ev);
             const [ x, y ] = pointerEnd;
-            if (!mask(ev.clientX, ev.clientY)) return;
 
             if (noScroll) {
                 ev.preventDefault();