import { CircularQueue } from '@uino/base-thing';
import { Utils } from './Utils';
const __ = {
private: Symbol('private'),
}
/**
* @class FPSTimer
* The FPS timer.
* @memberof THING
*/
class FPSTimer {
/**
* Control render's FPS(frame pre second), we can limited max FPS also.
*/
constructor() {
this[__.private] = {};
let _private = this[__.private];
const maxFPS = 120;
// Initialize core
_private.fixedDeltaTime = null;
_private.deltaTime = 0;
_private.elapsedTime = 0;
_private.currentFrameCount = 0;
_private.enableFpsCounter = true;
_private.fpsTimes = new CircularQueue(maxFPS);
// FPS limited
_private.maxFPS = null;
_private.fpsLimitedDelta = 0;
_private.fpsLimitedPreviousDelta = 0;
}
// #region Private Functions
_updateFPSCounter() {
let _private = this[__.private];
let fpsTimes = _private.fpsTimes;
// Thanks for sharing code: https://www.growingwiththeweb.com/2017/12/fast-simple-js-fps-counter.html
const now = Utils.getCurrentTimeMilliseconds();
while (fpsTimes.size > 0 && fpsTimes.front <= now - 1000) {
fpsTimes.dequeue();
}
fpsTimes.enqueue(now);
}
/**
* Check whether it's in FPS limited state.
* @param {Number} deltaTime The delta time in milliseconds.
* @returns {Boolean}
* @private
*/
_isInLimitedState(deltaTime) {
let _private = this[__.private];
let maxFPS = _private.maxFPS;
if (!maxFPS) {
return false;
}
_private.fpsLimitedDelta += deltaTime;
let delta = _private.fpsLimitedDelta - _private.fpsLimitedPreviousDelta;
let interval = 1 / maxFPS;
let needsUpdate = maxFPS && delta >= interval;
if (needsUpdate) {
_private.fpsLimitedPreviousDelta = _private.fpsLimitedDelta - (delta % interval);
}
return !needsUpdate;
}
// #endregion
/**
* Update timer.
* @param {Number} deltaTime The delta time in seconds.
* @private
*/
update(deltaTime) {
let _private = this[__.private];
// Check whether use fixed delta time
if (_private.fixedDeltaTime) {
deltaTime = _private.fixedDeltaTime;
}
// Check whether it's in limited state
if (this._isInLimitedState(deltaTime)) {
return 0;
}
// Get the clock time
_private.deltaTime = deltaTime;
_private.elapsedTime += deltaTime;
// Update FPS
_private.currentFrameCount++;
// Update FPS counter
if (_private.enableFpsCounter) {
this._updateFPSCounter();
}
return deltaTime;
}
// #region Accessor
/**
* Get the elapsed time(seconds) since started.
* @type {Number}
* @example
* // Print elapsed time(seconds) since started.
* console.log(fpsTimer.elapsedTime);
*/
get elapsedTime() {
return this[__.private].elapsedTime;
}
/**
* Get the delta time(seconds) from previous frame.
* @type {Number}
* @example
* // Print delta time(seconds) from previous frame.
* console.log(fpsTimer.deltaTime);
*/
get deltaTime() {
return this[__.private].deltaTime;
}
/**
* Get the elapsed time(milliseconds) when started.
* @type {Number}
* @private
*/
get elapsedTimeMilliseconds() {
return Math.floor(this.elapsedTime * 1000);
}
/**
* Get the delta time(milliseconds) of previous frame.
* @type {Number}
* @private
*/
get deltaTimeMilliseconds() {
return Math.floor(this.deltaTime * 1000);
}
/**
* Get the current total frame count since started.
* @type {Number}
* @example
* // Print current frame count since started.
* console.log(fpsTimer.currentFrameCount);
*/
get currentFrameCount() {
return this[__.private].currentFrameCount;
}
/**
* Get/Set fixed delta time in seconds.
* @type {Number}
*/
get fixedDeltaTime() {
return this[__.private].fixedDeltaTime;
}
set fixedDeltaTime(value) {
this[__.private].fixedDeltaTime = value;
}
/**
* Get/Set the max FPS number, null indicates unlimited.
* @type {Number}
* @example
* // Limited the max FPS to 30 fps
* fpsTimer.maxFPS = 30;
* // Unlimited the FPS
* fpsTimer.maxFPS = null;
*/
get maxFPS() {
return this[__.private].maxFPS;
}
set maxFPS(value) {
this[__.private].maxFPS = value;
}
/**
* Enable/Disable fps counter.
* @type {Boolean}
* @example
* // Disable the FPS counter, if we disable then we can not get the FPS Counter info
* fpsTimer.enableFpsCounter = false;
*/
get enableFpsCounter() {
return this[__.private].enableFpsCounter;
}
set enableFpsCounter(value) {
let _private = this[__.private];
_private.enableFpsCounter = value;
}
/**
* Get the FPS Counter.
* @type {Number}
* @example
* // Print the current FPS counter
* console.log(fpsTimer.fpsCounter);
*/
get fpsCounter() {
let _private = this[__.private];
return _private.fpsTimes.size;
}
// #endregion
}
export { FPSTimer }