David Sehnal пре 4 година
родитељ
комит
ac6b87add4

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

@@ -96,6 +96,11 @@ interface Canvas3D {
      * This function must be called if animate() is not set up so that add/remove actions take place.
      */
     commit(isSynchronous?: boolean): void
+    /**
+     * Funcion for external "animation" control
+     * Calls commit.
+     */
+    tick(t: now.Timestamp, isSynchronous?: boolean): void
     update(repr?: Representation.Any, keepBoundingSphere?: boolean): void
     clear(): void
     syncVisibility(): void
@@ -108,6 +113,7 @@ interface Canvas3D {
     mark(loci: Representation.Loci, action: MarkerAction): void
     getLoci(pickingId: PickingId | undefined): Representation.Loci
 
+    notifyDidDraw: boolean,
     readonly didDraw: BehaviorSubject<now.Timestamp>
     readonly reprCount: BehaviorSubject<number>
 
@@ -231,6 +237,8 @@ namespace Canvas3D {
         let nextCameraResetDuration: number | undefined = void 0;
         let nextCameraResetSnapshot: Partial<Camera.Snapshot> | undefined = void 0;
 
+        let notifyDidDraw = true;
+
         function getLoci(pickingId: PickingId | undefined) {
             let loci: Loci = EmptyLoci;
             let repr: Representation.Any = Representation.Empty;
@@ -305,7 +313,7 @@ namespace Canvas3D {
         let currentTime = 0;
 
         function draw(force?: boolean) {
-            if (render(!!force || forceNextDraw)) {
+            if (render(!!force || forceNextDraw) && notifyDidDraw) {
                 didDraw.next(now() - startTime as now.Timestamp);
             }
             forceNextDraw = false;
@@ -320,15 +328,19 @@ namespace Canvas3D {
 
         let animationFrameHandle = 0;
 
-        function _animate() {
-            currentTime = now();
-            commit();
+        function tick(t: now.Timestamp, isSynchronous?: boolean) {
+            currentTime = t;
+            commit(isSynchronous);
             camera.transition.tick(currentTime);
 
             draw(false);
             if (!camera.transition.inTransition && !webgl.isContextLost) {
                 interactionHelper.tick(currentTime);
             }
+        }
+
+        function _animate() {
+            tick(now());
             animationFrameHandle = requestAnimationFrame(_animate);
         }
 
@@ -553,6 +565,7 @@ namespace Canvas3D {
             },
 
             requestDraw,
+            tick,
             animate,
             pause,
             setCurrentTime: t => currentTime = t,
@@ -573,6 +586,8 @@ namespace Canvas3D {
             },
             camera,
             boundingSphere: scene.boundingSphere,
+            get notifyDidDraw() { return notifyDidDraw; },
+            set notifyDidDraw(v: boolean) { notifyDidDraw = v; },
             didDraw,
             reprCount,
             setProps: (properties, doNotRequestDraw = false) => {

+ 2 - 0
src/mol-canvas3d/controls/trackball.ts

@@ -405,6 +405,8 @@ namespace TrackballControls {
 
         const _spinSpeed = Vec2.create(0.005, 0);
         function spin(deltaT: number) {
+            if (p.spinSpeed === 0) return;
+
             const frameSpeed = (p.spinSpeed || 0) / 1000;
             _spinSpeed[0] = 60 * Math.min(Math.abs(deltaT), 1000 / 8) / 1000 * frameSpeed;
             if (!_isInteracting) Vec2.add(_rotCurr, _rotPrev, _spinSpeed);

+ 41 - 0
src/mol-plugin/animation-loop.ts

@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { PluginContext } from './context';
+import { now } from '../mol-util/now';
+
+export class PluginAnimationLoop {
+    private currentFrame: any = void 0;
+    private _isAnimating = false;
+
+    tick(t: number, isSynchronous?: boolean) {
+        this.plugin.canvas3d?.tick(t as now.Timestamp, isSynchronous);
+    }
+
+    private frame = () => {
+        this.tick(now(), false);
+        if (this._isAnimating) {
+            this.currentFrame = requestAnimationFrame(this.frame);
+        }
+    }
+
+    start() {
+        this._isAnimating = true;
+        this.currentFrame = requestAnimationFrame(this.frame);
+    }
+
+    stop() {
+        this._isAnimating = false;
+        if (this.currentFrame !== void 0) {
+            cancelAnimationFrame(this.currentFrame);
+            this.currentFrame = void 0;
+        }
+    }
+
+    constructor(private plugin: PluginContext) {
+
+    }
+}

+ 3 - 1
src/mol-plugin/context.ts

@@ -60,6 +60,7 @@ import { objectForEach } from '../mol-util/object';
 import { VolumeHierarchyManager } from '../mol-plugin-state/manager/volume/hierarchy';
 import { filter, take } from 'rxjs/operators';
 import { Vec2 } from '../mol-math/linear-algebra';
+import { PluginAnimationLoop } from './animation-loop';
 
 export class PluginContext {
     runTask = <T>(task: Task<T>) => this.managers.task.run(task);
@@ -104,6 +105,7 @@ export class PluginContext {
     } as const;
 
     readonly canvas3d: Canvas3D | undefined;
+    readonly animationLoop = new PluginAnimationLoop(this);
     readonly layout = new PluginLayout(this);
 
     readonly representation = {
@@ -204,7 +206,7 @@ export class PluginContext {
                 }
                 this.canvas3d?.setProps(props);
             }
-            this.canvas3d!.animate();
+            this.animationLoop.start();
             (this.helpers.viewportScreenshot as ViewportScreenshotHelper) = new ViewportScreenshotHelper(this);
             return true;
         } catch (e) {