1 ////////////////////////////////////////////////////////////////////////////////// 2 // // 3 ////////////////////////////////////////////////////////////////////////////////// 4 5 /** 6 * Handle the rendering loop 7 * 8 * @class This class handle the rendering loop 9 * 10 * @param {THREE.World} world the world to display (optional) 11 */ 12 tQuery.Loop = function() 13 { 14 // internally if world present do that 15 this._hooks = []; 16 this._lastTime = null; 17 }; 18 19 // make it pluginable 20 tQuery.pluginsInstanceOn(tQuery.Loop); 21 22 /** 23 * destructor 24 */ 25 tQuery.Loop.prototype.destroy = function() 26 { 27 this.stop(); 28 } 29 30 ////////////////////////////////////////////////////////////////////////////////// 31 // // 32 ////////////////////////////////////////////////////////////////////////////////// 33 34 /** 35 * start looping 36 * 37 * @returns {tQuery.Loop} chained API 38 */ 39 tQuery.Loop.prototype.start = function() 40 { 41 if( this._timerId ) this.stop(); 42 this._timerId = requestAnimationFrame( this._onAnimationFrame.bind(this) ); 43 // for chained API 44 return this; 45 } 46 47 /** 48 * stop looping 49 * 50 * @returns {tQuery.Loop} chained API 51 */ 52 tQuery.Loop.prototype.stop = function() 53 { 54 cancelAnimationFrame(this._timerId); 55 this._timerId = null; 56 // for chained API 57 return this; 58 } 59 60 tQuery.Loop.prototype._onAnimationFrame = function() 61 { 62 // loop on request animation loop 63 // - it has to be at the begining of the function 64 // - see details at http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 65 this._timerId = requestAnimationFrame( this._onAnimationFrame.bind(this) ); 66 67 // update time values 68 var now = tQuery.now()/1000; 69 if( !this._lastTime ) this._lastTime = now - 1/60; 70 var delta = now - this._lastTime; 71 this._lastTime = now; 72 73 // run all the hooks - from lower priority to higher - in order of registration 74 for(var priority = 0; priority <= this._hooks.length; priority++){ 75 if( this._hooks[priority] === undefined ) continue; 76 var callbacks = this._hooks[priority].slice(0) 77 for(var i = 0; i < callbacks.length; i++){ 78 callbacks[i](delta, now); 79 } 80 } 81 } 82 83 ////////////////////////////////////////////////////////////////////////////////// 84 // Handle the hooks // 85 ////////////////////////////////////////////////////////////////////////////////// 86 87 tQuery.Loop.prototype.PRE_RENDER = 20; 88 tQuery.Loop.prototype.ON_RENDER = 50; 89 tQuery.Loop.prototype.POST_RENDER = 80; 90 91 /** 92 * hook a callback at a given priority 93 * 94 * @param {Number} priority for this callback 95 * @param {Function} callback the function which will be called function(time){} 96 * @returns {Function} the callback function. usefull for this._$callback = loop.hook(this._callback.bind(this)) 97 * and later loop.unhook(this._$callback) 98 */ 99 tQuery.Loop.prototype.hook = function(priority, callback) 100 { 101 // handle parameters 102 if( typeof priority === 'function' ){ 103 callback = priority; 104 priority = this.PRE_RENDER; 105 } 106 107 this._hooks[priority] = this._hooks[priority] || []; 108 console.assert(this._hooks[priority].indexOf(callback) === -1) 109 this._hooks[priority].push(callback); 110 return callback; 111 } 112 113 /** 114 * unhook a callback at a given priority 115 * 116 * @param {Number} priority for this callback 117 * @param {Function} callback the function which will be called function(time){} 118 * @returns {tQuery.Loop} chained API 119 */ 120 tQuery.Loop.prototype.unhook = function(priority, callback) 121 { 122 // handle parameters 123 if( typeof priority === 'function' ){ 124 callback = priority; 125 priority = this.PRE_RENDER; 126 } 127 128 var index = this._hooks[priority].indexOf(callback); 129 console.assert(index !== -1); 130 this._hooks[priority].splice(index, 1); 131 this._hooks[priority].length === 0 && delete this._hooks[priority] 132 // for chained API 133 return this; 134 } 135 136 137 // bunch of shortcut 138 // - TODO should it be in a plugin ? 139 140 tQuery.Loop.prototype.hookPreRender = function(callback){ return this.hook(this.PRE_RENDER, callback); }; 141 tQuery.Loop.prototype.hookOnRender = function(callback){ return this.hook(this.ON_RENDER, callback); }; 142 tQuery.Loop.prototype.hookPostRender = function(callback){ return this.hook(this.POST_RENDER, callback); }; 143 tQuery.Loop.prototype.unhookPreRender = function(callback){ return this.unhook(this.PRE_RENDER, callback); }; 144 tQuery.Loop.prototype.unhookOnRender = function(callback){ return this.unhook(this.ON_RENDER, callback); }; 145 tQuery.Loop.prototype.unhookPostRender = function(callback){ return this.unhook(this.POST_RENDER, callback); }; 146