UNPKG

liblooper

Version:

Looper implementation for use in conjonction with the HJS-MESSAGE messaging API. This is the browser version of the

480 lines (433 loc) 15.7 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.MessageLooper = exports.Looper = undefined; var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _events = require('events'); var _events2 = _interopRequireDefault(_events); var _handler = require('hjs-message/lib/handler'); var _queue = require('hjs-message/lib/queue'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var simulationTimestep = 1000 / 60, frameDelta = 0, lastFrameTimeMs = 0, fps = 60, lastFpsUpdate = 0, framesThisSecond = 0, numUpdateSteps = 0, minFrameDelay = 0, running = false, started = false, panic = false; /** @babel */ var requestAnimationFrame = window.requestAnimationFrame || function () { var lastTimestamp = Date.now(), now = void 0, timeout = void 0; return function (callback) { now = Date.now(); timeout = Math.max(0, simulationTimestep - (now - lastTimestamp)); lastTimestamp = now + timeout; return setTimeout(function () { callback(now + timeout); }, timeout); }; }(); var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; var NOOP = function NOOP() {}; var begin = NOOP, update = NOOP, draw = NOOP, end = NOOP, rafHandle = void 0; var loop = function loop(timestamp) { rafHandle = requestAnimationFrame(loop); if (timestamp < lastFrameTimeMs + minFrameDelay) { return; } frameDelta += timestamp - lastFrameTimeMs; lastFrameTimeMs = timestamp; begin(timestamp, frameDelta); if (timestamp > lastFpsUpdate + 1000) { fps = 0.25 * framesThisSecond + 0.75 * fps; lastFpsUpdate = timestamp; framesThisSecond = 0; } framesThisSecond++; numUpdateSteps = 0; while (frameDelta >= simulationTimestep) { update(simulationTimestep); frameDelta -= simulationTimestep; if (++numUpdateSteps >= 240) { panic = true; break; } } draw(frameDelta / simulationTimestep); end(fps, panic); panic = false; }; var MainLoop = { getSimulationTimestep: function getSimulationTimestep() { return simulationTimestep; }, setSimulationTimestep: function setSimulationTimestep(timestep) { simulationTimestep = timestep; return this; }, getFPS: function getFPS() { return fps; }, getMaxAllowedFPS: function getMaxAllowedFPS() { return 1000 / minFrameDelay; }, setMaxAllowedFPS: function setMaxAllowedFPS() { var fps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Infinity; if (fps === 0) { fps = 60; } minFrameDelay = 1000 / fps; return this; }, resetFrameDelta: function resetFrameDelta() { var oldFrameDelta = frameDelta; frameDelta = 0; return oldFrameDelta; }, setBegin: function setBegin(fun) { begin = fun || begin; return this; }, setUpdate: function setUpdate(fun) { update = fun || update; return this; }, setDraw: function setDraw(fun) { draw = fun || draw; return this; }, setEnd: function setEnd(fun) { end = fun || end; return this; }, start: function start() { if (!started) { started = true; rafHandle = requestAnimationFrame(function (timestamp) { draw(1); running = true; lastFrameTimeMs = timestamp; lastFpsUpdate = timestamp; framesThisSecond = 0; rafHandle = requestAnimationFrame(loop); }); } return this; }, stop: function stop() { running = false; started = false; cancelAnimationFrame(rafHandle); return this; }, isRunning: function isRunning() { return running; } }; var PAUSED = false; var MAIN_LOOPER = null; var LOOPER = null; var prepareMainLooper = function prepareMainLooper() { var quitAllowed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; var fps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 60; if (LOOPER) { throw new ReferenceError("RuntimeException Only one Looper may be created per application"); } return LOOPER = new Looper(quitAllowed, fps); }; var EXIT_FRAME = 'exit_frame'; var RENDER_FRAME = 'render_frame'; var Looper = exports.Looper = function (_EventEmitter) { (0, _inherits3.default)(Looper, _EventEmitter); function Looper() { var quitAllowed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; var fps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 60; (0, _classCallCheck3.default)(this, Looper); var _this = (0, _possibleConstructorReturn3.default)(this, (Looper.__proto__ || (0, _getPrototypeOf2.default)(Looper)).call(this)); _this.mQueue = new _queue.MessageQueue(quitAllowed); _this.mQueue.mLooper = _this; MainLoop.setMaxAllowedFPS(fps).setUpdate(function (delta) { _this.loop(delta); }).setDraw(function (interpolation) { _this.render(interpolation); }).setEnd(function (fps, panic) { _this.exit(fps, panic); }); return _this; } (0, _createClass3.default)(Looper, [{ key: 'exit', value: function exit(fps, panic) { this.emit(EXIT_FRAME, { fps: fps, panic: panic }); } }, { key: 'getMainLooper', value: function getMainLooper() { return MainLoop; } }, { key: 'getQueue', value: function getQueue() { return this.mQueue; } }, { key: 'isIdling', value: function isIdling() { return this.mQueue.isIdle(); } }, { key: 'isRunning', value: function isRunning() { return MainLoop.isRunning(); } }, { key: 'loop', value: function loop(delta) { var queue = this.mQueue, msg = queue.nextMessage(); if (msg) { var target = msg.target; if (!target) { return; } var handled = target.dispatchMessage(msg); if (!handled) { target.unHandleMessage(msg); } msg.recycle(); } } }, { key: 'pause', value: function pause() { if (!PAUSED) { PAUSED = !PAUSED; MainLoop.stop(); } } }, { key: 'quit', value: function quit() { var safe = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; MainLoop.stop(); this.mQueue.quit(safe); if (safe) { this.removeAllListeners(EXIT_FRAME); this.removeAllListeners(RENDER_FRAME); this.mQueue = null; } } }, { key: 'quitSafely', value: function quitSafely() { this.quit(true); } }, { key: 'render', value: function render(interpolation) { this.emit(RENDER_FRAME, { interpolation: interpolation }); } }, { key: 'resume', value: function resume() { if (PAUSED) { PAUSED = !PAUSED; MainLoop.start(); } } }, { key: 'start', value: function start() { if (!this.isRunning()) { return MainLoop.start(); } } }, { key: 'toggle', value: function toggle() { PAUSED ? this.resume() : this.pause(); } }], [{ key: 'createLoopHandler', value: function createLoopHandler() { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref$callback = _ref.callback, callback = _ref$callback === undefined ? null : _ref$callback, _ref$asynchronous = _ref.asynchronous, asynchronous = _ref$asynchronous === undefined ? true : _ref$asynchronous, _ref$messenger = _ref.messenger, messenger = _ref$messenger === undefined ? new _handler.Messenger() : _ref$messenger, _ref$handleMessage = _ref.handleMessage, handleMessage = _ref$handleMessage === undefined ? null : _ref$handleMessage, _ref$unHandleMessage = _ref.unHandleMessage, unHandleMessage = _ref$unHandleMessage === undefined ? null : _ref$unHandleMessage, _ref$handleExit = _ref.handleExit, handleExit = _ref$handleExit === undefined ? null : _ref$handleExit, _ref$handleRender = _ref.handleRender, handleRender = _ref$handleRender === undefined ? null : _ref$handleRender, _ref$scheduleTime = _ref.scheduleTime, scheduleTime = _ref$scheduleTime === undefined ? 200 : _ref$scheduleTime, _ref$quitAllowed = _ref.quitAllowed, quitAllowed = _ref$quitAllowed === undefined ? true : _ref$quitAllowed, _ref$fps = _ref.fps, fps = _ref$fps === undefined ? 60 : _ref$fps; var looper = Looper.myLooper(); if (!looper) { looper = Looper.prepare(quitAllowed, fps); } return new MessageLooper({ callback: callback, asynchronous: asynchronous, messenger: messenger, handleMessage: handleMessage, unHandleMessage: unHandleMessage, handleExit: handleExit, handleRender: handleRender, scheduleTime: scheduleTime, looper: looper }); } }, { key: 'myLooper', value: function myLooper() { return LOOPER; } }, { key: 'myQueue', value: function myQueue() { var looper = Looper.myLooper(); if (looper) { return looper.mQueue; } return null; } }, { key: 'prepare', value: function prepare() { var quitAllowed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; var fps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 60; var looper = prepareMainLooper(quitAllowed, fps); if (MAIN_LOOPER) { throw new ReferenceError("IllegalStateException The main Looper has already been prepared."); } MAIN_LOOPER = looper.start(); } }]); return Looper; }(_events2.default); var MessageLooper = exports.MessageLooper = function (_MessageHandler) { (0, _inherits3.default)(MessageLooper, _MessageHandler); function MessageLooper() { var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref2$callback = _ref2.callback, callback = _ref2$callback === undefined ? null : _ref2$callback, _ref2$asynchronous = _ref2.asynchronous, asynchronous = _ref2$asynchronous === undefined ? true : _ref2$asynchronous, _ref2$messenger = _ref2.messenger, messenger = _ref2$messenger === undefined ? new _handler.Messenger() : _ref2$messenger, _ref2$handleMessage = _ref2.handleMessage, handleMessage = _ref2$handleMessage === undefined ? null : _ref2$handleMessage, _ref2$unHandleMessage = _ref2.unHandleMessage, unHandleMessage = _ref2$unHandleMessage === undefined ? null : _ref2$unHandleMessage, _ref2$handleRender = _ref2.handleRender, handleRender = _ref2$handleRender === undefined ? null : _ref2$handleRender, _ref2$handleExit = _ref2.handleExit, handleExit = _ref2$handleExit === undefined ? null : _ref2$handleExit, _ref2$scheduleTime = _ref2.scheduleTime, scheduleTime = _ref2$scheduleTime === undefined ? 200 : _ref2$scheduleTime, _ref2$looper = _ref2.looper, looper = _ref2$looper === undefined ? null : _ref2$looper; (0, _classCallCheck3.default)(this, MessageLooper); var _this2 = (0, _possibleConstructorReturn3.default)(this, (MessageLooper.__proto__ || (0, _getPrototypeOf2.default)(MessageLooper)).call(this, { callback: callback, asynchronous: asynchronous, queue: looper ? looper.getQueue() : Looper.myQueue(), messenger: messenger, handleMessage: handleMessage, unHandleMessage: unHandleMessage, scheduleTime: scheduleTime })); _this2.looper = looper || Looper.myLooper(); if (handleRender) { _this2.handleRender = handleRender; } if (handleExit) { _this2.handleExit = handleExit; } if (_this2.looper) { _this2.looper.on(RENDER_FRAME, function (_ref3) { var interpolation = _ref3.interpolation; _this2.handleRender(interpolation); }); _this2.looper.on(EXIT_FRAME, function (_ref4) { var fps = _ref4.fps, panic = _ref4.panic; _this2.handleRender(fps, panic); }); } return _this2; } (0, _createClass3.default)(MessageLooper, [{ key: 'exit', value: function exit() { if (this.looper) { this.looper.quitSafely(); } } }, { key: 'getLooper', value: function getLooper() { if (this.looper) { return this.looper; } return null; } }, { key: 'getMainLooper', value: function getMainLooper() { if (this.looper) { return this.looper.getMainLooper(); } return null; } }, { key: 'handleExit', value: function handleExit(fps, panic) {} }, { key: 'handleRender', value: function handleRender(interpolation) {} }, { key: 'pause', value: function pause() { if (this.looper) { this.looper.pause(); } } }, { key: 'resume', value: function resume() { if (this.looper) { this.looper.resume(); } } }, { key: 'toggle', value: function toggle() { if (this.looper) { this.looper.toggle(); } } }]); return MessageLooper; }(_handler.MessageHandler);