(function(){ /** * Reticle 3D Sprite * @constructor * @param {THREE.Color} [color=0xfffff] - Color of the reticle sprite * @param {boolean} [autoSelect=true] - Auto selection * @param {string} [idleImageUrl=PANOLENS.DataImage.ReticleIdle] - Image asset url * @param {string} [dwellImageUrl=PANOLENS.DataImage.ReticleDwell] - Image asset url * @param {number} [dwellTime=1500] - Duration for dwelling sequence to complete * @param {number} [dwellSpriteAmount=45] - Number of dwelling sprite sequence */ PANOLENS.Reticle = function ( color, autoSelect, idleImageUrl, dwellImageUrl, dwellTime, dwellSpriteAmount ) { color = color || 0xffffff; this.autoSelect = autoSelect != undefined ? autoSelect : true; this.dwellTime = dwellTime || 1500; this.dwellSpriteAmount = dwellSpriteAmount || 45; this.dwellInterval = this.dwellTime / this.dwellSpriteAmount; this.IDLE = 0; this.DWELLING = 1; this.status; this.scaleIdle = new THREE.Vector3( 0.2, 0.2, 1 ); this.scaleDwell = new THREE.Vector3( 1, 0.8, 1 ); this.textureLoaded = false; this.idleImageUrl = idleImageUrl || PANOLENS.DataImage.ReticleIdle; this.dwellImageUrl = dwellImageUrl || PANOLENS.DataImage.ReticleDwell; this.idleTexture = new THREE.Texture(); this.dwellTexture = new THREE.Texture(); THREE.Sprite.call( this, new THREE.SpriteMaterial( { color: color, depthTest: false } ) ); this.currentTile = 0; this.startTime = 0; this.visible = false; this.renderOrder = 10; this.timerId; // initial update this.updateStatus( this.IDLE ); }; PANOLENS.Reticle.prototype = Object.create( THREE.Sprite.prototype ); PANOLENS.Reticle.prototype.constructor = PANOLENS.Reticle; /** * Make reticle visible */ PANOLENS.Reticle.prototype.show = function () { this.visible = true; }; /** * Make reticle invisible */ PANOLENS.Reticle.prototype.hide = function () { this.visible = false; }; /** * Load reticle textures */ PANOLENS.Reticle.prototype.loadTextures = function () { this.idleTexture = PANOLENS.Utils.TextureLoader.load( this.idleImageUrl ); this.dwellTexture = PANOLENS.Utils.TextureLoader.load( this.dwellImageUrl ); this.material.map = this.idleTexture; this.setupDwellSprite( this.dwellTexture ); this.textureLoaded = true; }; /** * Start reticle timer selection * @param {function} completeCallback - Callback after dwell completes */ PANOLENS.Reticle.prototype.select = function ( completeCallback ) { if ( performance.now() - this.startTime >= this.dwellTime ) { this.completeDwelling(); completeCallback(); } else if ( this.autoSelect ){ this.updateDwelling( performance.now() ); this.timerId = window.requestAnimationFrame( this.select.bind( this, completeCallback ) ); } }; /** * Clear and reset reticle timer */ PANOLENS.Reticle.prototype.clearTimer = function () { window.cancelAnimationFrame( this.timerId ); this.timerId = null; }; /** * Setup dwell sprite animation */ PANOLENS.Reticle.prototype.setupDwellSprite = function ( texture ) { texture.wrapS = THREE.RepeatWrapping; texture.repeat.set( 1 / this.dwellSpriteAmount, 1 ); } /** * Update reticle status * @param {number} status - Reticle status */ PANOLENS.Reticle.prototype.updateStatus = function ( status ) { this.status = status; if ( status === this.IDLE ) { this.scale.copy( this.scaleIdle ); this.material.map = this.idleTexture; } else if ( status === this.DWELLING ) { this.scale.copy( this.scaleDwell ); this.material.map = this.dwellTexture; } this.currentTile = 0; this.material.map.offset.x = 0; }; /** * Start dwelling sequence */ PANOLENS.Reticle.prototype.startDwelling = function ( completeCallback ) { if ( !this.autoSelect ) { return; } this.startTime = performance.now(); this.updateStatus( this.DWELLING ); this.select( completeCallback ); }; /** * Update dwelling sequence * @param {number} time - Timestamp for elasped time */ PANOLENS.Reticle.prototype.updateDwelling = function ( time ) { var elasped = time - this.startTime; if ( this.currentTile <= this.dwellSpriteAmount ) { this.currentTile = Math.floor( elasped / this.dwellTime * this.dwellSpriteAmount ); this.material.map.offset.x = this.currentTile / this.dwellSpriteAmount; } else { this.updateStatus( this.IDLE ); } }; /** * Cancel dwelling */ PANOLENS.Reticle.prototype.cancelDwelling = function () { this.clearTimer(); this.updateStatus( this.IDLE ); }; /** * Complete dwelling */ PANOLENS.Reticle.prototype.completeDwelling = function () { this.clearTimer(); this.updateStatus( this.IDLE ); }; })();