Files
Martin Guillon 1a849f9302 fix: Prior PR (#8904) has bad path for trace modules
* Fix trace path issue

* another path fix
2020-11-12 14:23:03 -06:00

96 lines
2.8 KiB
TypeScript

import { queueMacrotask } from '../utils/macrotask-scheduler';
import { FPSCallback } from '../fps-meter/fps-native';
import { getTimeInFrameBase } from './animation-native';
import { Trace } from '../trace';
export interface FrameRequestCallback {
(time: number): void;
}
type AnimationFrameCallbacks = { [key: string]: FrameRequestCallback };
let animationId = 0;
let currentFrameAnimationCallbacks: AnimationFrameCallbacks = {}; // requests that were scheduled in this frame and must be called ASAP
let currentFrameScheduled = false;
let nextFrameAnimationCallbacks: AnimationFrameCallbacks = {}; // requests there were scheduled in another request and must be called in the next frame
let shouldStop = true;
let inAnimationFrame = false;
let fpsCallback: FPSCallback;
let lastFrameTime = 0;
function getNewId() {
return animationId++;
}
function ensureNative() {
if (fpsCallback) {
return;
}
fpsCallback = new FPSCallback(doFrame);
}
function callAnimationCallbacks(thisFrameCbs: AnimationFrameCallbacks, frameTime: number): void {
inAnimationFrame = true;
for (const animationId in thisFrameCbs) {
if (thisFrameCbs[animationId]) {
try {
thisFrameCbs[animationId](frameTime);
} catch (err) {
const msg = err ? err.stack || err : err;
Trace.write(`Error in requestAnimationFrame: ${msg}`, Trace.categories.Error, Trace.messageType.error);
}
}
}
inAnimationFrame = false;
}
function doCurrentFrame() {
// if we're not getting accurate frame times
// set last frame time as the current time
if (!fpsCallback || !fpsCallback.running) {
lastFrameTime = getTimeInFrameBase();
}
currentFrameScheduled = false;
const thisFrameCbs = currentFrameAnimationCallbacks;
currentFrameAnimationCallbacks = {};
callAnimationCallbacks(thisFrameCbs, lastFrameTime);
}
function doFrame(currentTimeMillis: number) {
lastFrameTime = currentTimeMillis;
shouldStop = true;
const thisFrameCbs = nextFrameAnimationCallbacks;
nextFrameAnimationCallbacks = {};
callAnimationCallbacks(thisFrameCbs, lastFrameTime);
if (shouldStop) {
fpsCallback.stop(); // TODO: check performance without stopping to allow consistent frame times
}
}
function ensureCurrentFrameScheduled() {
if (!currentFrameScheduled) {
currentFrameScheduled = true;
queueMacrotask(doCurrentFrame);
}
}
export function requestAnimationFrame(cb: FrameRequestCallback): number {
const animId = getNewId();
if (!inAnimationFrame) {
ensureCurrentFrameScheduled();
currentFrameAnimationCallbacks[animId] = zonedCallback(cb) as FrameRequestCallback;
return animId;
}
ensureNative();
nextFrameAnimationCallbacks[animId] = zonedCallback(cb) as FrameRequestCallback;
shouldStop = false;
fpsCallback.start();
return animId;
}
export function cancelAnimationFrame(id: number): void {
delete currentFrameAnimationCallbacks[id];
delete nextFrameAnimationCallbacks[id];
}