PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/mad-components/MadComponentsStage3D/src/com/danielfreeman/stage3Dacceleration/GridScrolling.as

http://mad-components.googlecode.com/
ActionScript | 659 lines | 472 code | 91 blank | 96 comment | 58 complexity | d2579d40f6acb46c713667303e82060b MD5 | raw file
  1. /**
  2. * <p>Original Author: Daniel Freeman</p>
  3. *
  4. * <p>Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:</p>
  10. *
  11. * <p>The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.</p>
  13. *
  14. * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.</p>
  21. *
  22. * <p>Licensed under The MIT License</p>
  23. * <p>Redistributions of files must retain the above copyright notice.</p>
  24. */
  25. package com.danielfreeman.stage3Dacceleration {
  26. import com.adobe.utils.AGALMiniAssembler;
  27. import com.adobe.utils.PerspectiveMatrix3D;
  28. import com.danielfreeman.madcomponents.Attributes;
  29. import com.danielfreeman.madcomponents.UI;
  30. import com.danielfreeman.madcomponents.UIForm;
  31. import com.danielfreeman.madcomponents.UIWindow;
  32. import flash.display.Bitmap;
  33. import flash.display.BitmapData;
  34. import flash.display.DisplayObject;
  35. import flash.display.Sprite;
  36. import flash.display3D.Context3DProgramType;
  37. import flash.display3D.Context3DTextureFormat;
  38. import flash.display3D.Context3DVertexBufferFormat;
  39. import flash.display3D.IndexBuffer3D;
  40. import flash.display3D.Program3D;
  41. import flash.display3D.VertexBuffer3D;
  42. import flash.display3D.textures.Texture;
  43. import flash.events.Event;
  44. import flash.events.MouseEvent;
  45. import flash.geom.Matrix;
  46. import flash.geom.Matrix3D;
  47. import flash.geom.Point;
  48. import flash.geom.Rectangle;
  49. import flash.geom.Vector3D;
  50. import flash.trace.Trace;
  51. /**
  52. * A scrolling grid of panels inspired by Windows-8 Touch
  53. */
  54. public class GridScrolling extends Stage3DAcceleration {
  55. public static const CLICKED:String = "gridScrollingClicked";
  56. protected static const CELL_WIDTH:Number = 256.0;
  57. protected static const CELL_HEIGHT:Number = 256.0;
  58. protected static const GAP:Number = 10.0;
  59. protected static const ZOOM:Number = 1.1;
  60. protected static const RECESSED:Number = 1.3;
  61. protected static const SIDE_GAP:Number = CELL_WIDTH/8;
  62. protected static const TOP_GAP:Number = CELL_HEIGHT/4;
  63. protected static const CLICK_THRESHOLD:Number = 32.0;
  64. protected static const DECAY:Number = 0.99;
  65. protected static const FASTER_DECAY:Number = 0.60;
  66. protected static const DELTA_THRESHOLD:Number = 0.1;
  67. protected static const MOVE_THRESHOLD:Number = 0.01;
  68. protected static const BOUNCE_FACTOR:Number = 0.3;
  69. protected static const TOUCH_MULTIPLIER:Number = 1.0;
  70. protected static const MOVE_FACTOR:Number = 2.0;
  71. protected static const ANIMATION_FRAMES:Number = 2.0;
  72. protected static const STAGGER:int = 4;
  73. protected static const ANIMATION:int = 16;
  74. protected static const INITIAL_ROTATION:Number = 90;
  75. protected static const QUALITY_SCALE:Number = 0.5;
  76. protected var _textureBitMapData:Vector.<BitmapData> = new Vector.<BitmapData>();
  77. protected var _indexBuffer:IndexBuffer3D;
  78. protected var _xyzVertexBuffer:VertexBuffer3D;
  79. protected var _uvVertexBuffer:VertexBuffer3D;
  80. protected var _tiledVertexShader:AGALMiniAssembler = new AGALMiniAssembler();
  81. protected var _tiledFragmentShader:AGALMiniAssembler = new AGALMiniAssembler();
  82. protected var _tiledShaderProgram:Program3D;
  83. protected var _tiledTexture:Vector.<Texture> = new Vector.<Texture>();
  84. protected var _backgroundColour:uint = 0x000000;
  85. protected var _cellWidth:Number = CELL_WIDTH;
  86. protected var _cellHeight:Number = CELL_HEIGHT;
  87. protected var _finalMatrix:Matrix3D = new Matrix3D();
  88. protected var _secondMatrix:Matrix3D = new Matrix3D();
  89. protected var _projectionMatrix:PerspectiveMatrix3D = new PerspectiveMatrix3D();
  90. protected var _count:int = 0;
  91. protected var _scale:Number = 1.0;
  92. protected var _position:Number = 0.0;
  93. protected var _distanceX:Number;
  94. protected var _lastX:Number;
  95. protected var _mouseDown:Boolean;
  96. protected var _deltaX:Number;
  97. protected var _minimumPosition:Number = 0;
  98. protected var _maximumPosition:Number = 0;
  99. protected var _destination:Number;
  100. protected var _animationInitial:Vector.<int> = new Vector.<int>();
  101. protected var _animation:Vector.<int>;
  102. protected var _vertices:Vector.<Number> = new Vector.<Number>();
  103. protected var _uv:Vector.<Number> = new Vector.<Number>();
  104. protected var _indices:Vector.<uint> = new Vector.<uint>();
  105. protected var _topGap:Number;
  106. protected var _sideGap:Number;
  107. protected var _screenEdge:Point;
  108. protected var _widthIndices:int;
  109. protected var _heightIndices:int;
  110. protected var _indexPoint:Point = null;
  111. protected var _arrayIndex:int = -1;
  112. protected var _gridPositionToArrayIndex:Vector.<Vector.<int>>;
  113. protected var _cellSize:Vector.<Point>;
  114. protected var _start:Boolean = false;
  115. protected var _zoomInOnClick:Boolean = false;
  116. protected var _finish:Boolean = false;
  117. protected var _gridPageWidth:int;
  118. protected var _snapToPage:Boolean = false;
  119. protected var _enabled:Boolean = false;
  120. protected var _moving:int;
  121. public function GridScrolling(hasPageIndicator:Boolean = false) {
  122. initialise();
  123. }
  124. public function setCellSize(width:Number, height:Number):void {
  125. _cellWidth = width;
  126. _cellHeight = height;
  127. }
  128. /**
  129. * Translation matrix. Scaling and Perspective.
  130. */
  131. protected function translationMatrix():void {
  132. _finalMatrix.identity();
  133. _finalMatrix.appendTranslation(0, 0, ZOOM);
  134. _finalMatrix.appendScale(_scale, _scale, 1.0);
  135. _finalMatrix.append(_projectionMatrix);
  136. }
  137. /**
  138. * Second transformation matrix that defines the initial transition, and pressed state.
  139. */
  140. protected function secondTranslationMatrix(rotationDegrees:Number = 0.0):void {
  141. _secondMatrix.identity();
  142. _secondMatrix.appendRotation(rotationDegrees, Vector3D.Y_AXIS);
  143. _secondMatrix.appendTranslation(0, 0, RECESSED);
  144. _secondMatrix.appendScale(_scale, _scale, 1.0);
  145. _secondMatrix.append(_projectionMatrix);
  146. }
  147. /**
  148. * The vertex shader is designed to transform each vertex by both transformation matrices,
  149. * then linear interpolation to animate between the two positions.
  150. *
  151. * The fragment shader is a standard simple texture shader.
  152. */
  153. public function initialise():void {
  154. _tiledVertexShader.assemble( Context3DProgramType.VERTEX,
  155. "add vt0, va0, vc8.zwww \n" + // scroll
  156. "m44 vt1, vt0, vc0 \n" + // vertex0
  157. "m44 vt2, vt0, vc4 \n" + // vertex1
  158. "mul vt1, vt1, vc8.xxxx \n" +
  159. "mul vt2, vt2, vc8.yyyy \n" +
  160. "add op, vt1, vt2 \n" +
  161. "mov v0, va1 \n" // interpolate UV
  162. );
  163. _tiledFragmentShader.assemble( Context3DProgramType.FRAGMENT,
  164. "tex oc, v0.xy, fs0 <2d,linear,nomip> \n" // output texture
  165. );
  166. _tiledShaderProgram = _context3D.createProgram();
  167. _tiledShaderProgram.upload( _tiledVertexShader.agalcode, _tiledFragmentShader.agalcode);
  168. _projectionMatrix.perspectiveFieldOfViewLH(60.0*Math.PI/180, _aspectRatio, 0.1, 1000.0);
  169. translationMatrix();
  170. }
  171. /**
  172. * Estimate the maximum and minimum x-coordinates at a particular depth.
  173. * A rough estimation - not accurate, but adequate for some calculations.
  174. */
  175. protected function screenRangeAtDepth(depth:Number):Point {
  176. var pointInSpace:Vector3D = _finalMatrix.transformVector(new Vector3D(1.0, 1.0, depth, 1.0));
  177. return new Point(pointInSpace.w/pointInSpace.x, pointInSpace.w/pointInSpace.y);
  178. }
  179. /**
  180. * From stage coordinates to grid row and column
  181. */
  182. protected function toGridIndices(value:Vector3D):Point {
  183. var inverseTransform:Matrix3D = _finalMatrix.clone();
  184. inverseTransform.invert();
  185. var pointInSpace:Vector3D = inverseTransform.transformVector(value);
  186. var xx:Number = pointInSpace.x - _position/_scale - _sideGap + _screenEdge.x;
  187. pointInSpace.x = _screen.stage.stageWidth*xx/_aspectRatio;
  188. pointInSpace.y = -_screen.stage.stageHeight*(pointInSpace.y + _topGap - _screenEdge.y);
  189. if (_gridPageWidth>0) {
  190. var page:int = Math.floor((value.x-_position + 1) / (_scale * 2*_screenEdge.x));
  191. pointInSpace.x = pointInSpace.x - page * 2 * _sideGap * _screen.stage.stageWidth / (_aspectRatio);
  192. }
  193. var i:int = Math.floor(pointInSpace.x/(_cellWidth+GAP/2));
  194. var j:int = _heightIndices - Math.floor(pointInSpace.y/(_cellHeight+GAP/2))-1;
  195. if (i < 0) {
  196. i=0;
  197. }
  198. else if (i > _widthIndices - 1) {
  199. i = _widthIndices - 1;
  200. }
  201. if (j < 0) {
  202. j = 0;
  203. }
  204. else if (j > _heightIndices - 1) {
  205. j = _heightIndices - 1;
  206. }
  207. return new Point(i, j);
  208. }
  209. /**
  210. * Set background colour
  211. */
  212. public function set backgroundColour(value:uint):void {
  213. _backgroundColour = value;
  214. }
  215. /**
  216. * Insert a column of empty grid cells.
  217. * On some screen resolutions/density, If a grid pages can't fit onto a screen, this is how we seperate it into pages.
  218. */
  219. protected function insertNulls(grid:Vector.<Vector.<XML>>, gridPageWidth:int):void {
  220. for each (var row:Vector.<XML> in grid) {
  221. for (var i:int = 1; i< Math.floor(row.length/gridPageWidth); i++) {
  222. row.splice(i*gridPageWidth+(i-1), 0, null);
  223. }
  224. }
  225. }
  226. /**
  227. * Define the grid interface with a 2D vector of MadComponents Layout XML.
  228. */
  229. public function defineGrid(grid:Vector.<Vector.<XML>>, gridPageWidth:int = 0):void {
  230. _gridPageWidth = gridPageWidth;
  231. translationMatrix();
  232. _screenEdge = screenRangeAtDepth(0.0);
  233. var gridHeight:Number = (_cellHeight + (grid.length-1)*(_cellHeight + GAP))/(2 * _screen.stage.stageHeight);
  234. _topGap = _screenEdge.y - gridHeight;
  235. if (_topGap < 0) {
  236. _scale = (_screenEdge.y-TOP_GAP/_screen.stage.stageHeight)/gridHeight;
  237. _scale = (_screenEdge.y-_scale*TOP_GAP/_screen.stage.stageHeight)/gridHeight; // two pass
  238. translationMatrix();
  239. _screenEdge = screenRangeAtDepth(0.0);
  240. _topGap = _screenEdge.y - gridHeight;
  241. }
  242. var gridWidth:Number = _aspectRatio*(_cellWidth + (grid[0].length-1)*(_cellWidth + GAP))/(2 * _screen.stage.stageWidth);
  243. _sideGap = _screenEdge.x - gridWidth;
  244. if (gridPageWidth > 0) {
  245. var pageWidth:Number = _aspectRatio*(_cellWidth + (gridPageWidth-1)*(_cellWidth + GAP))/(2 * _screen.stage.stageWidth);
  246. _sideGap = _screenEdge.x - pageWidth;
  247. var gapsBetweenPages:Number = (Math.ceil(grid[0].length / gridPageWidth)-1) * _sideGap;
  248. _maximumPosition = -2 * _scale * ((gridWidth - pageWidth) + gapsBetweenPages);
  249. _snapToPage = true;
  250. }
  251. if (_sideGap < 0) {
  252. if (_snapToPage) { // We have pages, but page width longer than screen width
  253. _snapToPage = false;
  254. _gridPageWidth = 0;
  255. insertNulls(grid, gridPageWidth);
  256. gridWidth = _aspectRatio*(_cellWidth + (grid[0].length-1)*(_cellWidth + GAP))/(2 * _screen.stage.stageWidth);
  257. }
  258. _maximumPosition = 2 * _scale * (_screenEdge.x - gridWidth) - 2 * SIDE_GAP/_screen.stage.stageWidth;
  259. _sideGap = SIDE_GAP/_screen.stage.stageWidth;
  260. }
  261. _widthIndices = grid[0].length;
  262. _heightIndices = grid.length;
  263. _gridPositionToArrayIndex = new Vector.<Vector.<int>>();
  264. _cellSize = new Vector.<Point>();
  265. for (var j0:int = 0; j0 < grid.length ; j0++) {
  266. var row:Vector.<int> = new Vector.<int>();
  267. for (var i0:int = 0; i0 < grid[j0].length ; i0++) {
  268. row.push(-1);
  269. }
  270. _gridPositionToArrayIndex.push(row);
  271. }
  272. for (var j:int = 0; j < grid.length ; j++) {
  273. for (var i:int = 0; i < grid[j].length ; i++) {
  274. var cellWidth:Number = _cellWidth;
  275. var cellHeight:Number = _cellHeight;
  276. var item:XML = grid[j][i];
  277. var pageOffset:Number = (_gridPageWidth>0) ? Math.floor(i / _gridPageWidth) * 2 * _sideGap : 0;
  278. if (item) {
  279. if (item.@tile.length()>0) {
  280. var tileSize:Array = String(item.@tile).split("x");
  281. cellWidth = _cellWidth + (tileSize[0]-1)*(_cellWidth + GAP);
  282. cellHeight = _cellHeight + (tileSize[1]-1)*(_cellHeight + GAP);
  283. for (var jj:int = 0; jj < tileSize[0] ; jj++) {
  284. for (var ii:int = 0; ii < tileSize[1] ; ii++) {
  285. _gridPositionToArrayIndex[j+jj][i+ii] = _count;
  286. }
  287. }
  288. }
  289. else {
  290. _gridPositionToArrayIndex[j][i] = _count;
  291. }
  292. var x:Number = pageOffset - _screenEdge.x + (_aspectRatio*i*(_cellWidth + GAP))/_screen.stage.stageWidth + _sideGap;
  293. var y:Number = _screenEdge.y-j*(_cellHeight + GAP)/_screen.stage.stageHeight - _topGap;
  294. var madRendered:UIForm = new UIForm(new Sprite(), item, new Attributes(0, 0, cellWidth, cellHeight));
  295. var bitmapData:BitmapData = new BitmapData(power2(QUALITY_SCALE*cellWidth*UI.scale), power2(QUALITY_SCALE*cellHeight*UI.scale));
  296. _cellSize.push(new Point(cellWidth*UI.scale, cellHeight*UI.scale));
  297. saveTexture(bitmapData, madRendered, new Rectangle(0, 0, QUALITY_SCALE*cellWidth*UI.scale, QUALITY_SCALE*cellHeight*UI.scale), 0, 0, QUALITY_SCALE);
  298. var texture:Texture = _context3D.createTexture(bitmapData.width, bitmapData.height, Context3DTextureFormat.BGRA, false);
  299. texture.uploadFromBitmapData(bitmapData);
  300. _tiledTexture.push(texture);
  301. _textureBitMapData.push(bitmapData);
  302. var quadWidth:Number = cellWidth/_screen.stage.stageWidth;
  303. var quadHeight:Number = cellHeight/_screen.stage.stageHeight;
  304. _vertices.push(
  305. // X, Y, Z,
  306. x, y-quadHeight, 0,
  307. x+_aspectRatio*quadWidth, y-quadHeight, 0,
  308. x+_aspectRatio*quadWidth, y, 0,
  309. x, y, 0
  310. );
  311. var u:Number = UI.scale*cellWidth*QUALITY_SCALE/bitmapData.width;
  312. var v:Number = UI.scale*cellHeight*QUALITY_SCALE/bitmapData.height;
  313. _uv.push(
  314. 0, v,
  315. u, v,
  316. u, 0,
  317. 0, 0
  318. );
  319. _indices.push(
  320. 4*_count, 4*_count+1, 4*_count+2, 4*_count, 4*_count+2, 4*_count+3
  321. );
  322. _animationInitial.push((x > _screenEdge.x) ? ANIMATION : (-i*STAGGER));
  323. _count++;
  324. }
  325. }
  326. }
  327. contextResumed(false);
  328. }
  329. /**
  330. * Restore shaders, streams and textures after context loss.
  331. */
  332. override public function contextResumed(running:Boolean):void {
  333. _tiledShaderProgram = _context3D.createProgram();
  334. _tiledShaderProgram.upload( _tiledVertexShader.agalcode, _tiledFragmentShader.agalcode);
  335. _xyzVertexBuffer = _context3D.createVertexBuffer(_count * 4, 3);
  336. _xyzVertexBuffer.uploadFromVector(_vertices, 0, _vertices.length / 3);
  337. _uvVertexBuffer = _context3D.createVertexBuffer(_uv.length/2, 2);
  338. _uvVertexBuffer.uploadFromVector(_uv, 0, _uv.length/2);
  339. _indexBuffer = _context3D.createIndexBuffer( _indices.length );
  340. _indexBuffer.uploadFromVector(_indices, 0, _indices.length );
  341. _tiledTexture = new Vector.<Texture>();
  342. for each (var bitmapData:BitmapData in _textureBitMapData) {
  343. var texture:Texture = _context3D.createTexture(bitmapData.width, bitmapData.height, Context3DTextureFormat.BGRA, false);
  344. texture.uploadFromBitmapData(bitmapData);
  345. _tiledTexture.push(texture);
  346. }
  347. if (running) {
  348. enable();
  349. onEnterFrame(this, drawTiles);
  350. }
  351. }
  352. /**
  353. * Replace a tile texture.
  354. */
  355. public function replaceTileTexture(row:int, column:int, layout:XML):void {
  356. var index:uint = _gridPositionToArrayIndex[column][row];
  357. var cellSize:Point = _cellSize[index];
  358. var bitmapData:BitmapData = _textureBitMapData[index];
  359. var madRendered:UIForm = new UIForm(new Sprite(), layout, new Attributes(0, 0, cellSize.x/UI.scale, cellSize.y/UI.scale));
  360. saveTexture(bitmapData, madRendered, new Rectangle(0, 0, cellSize.x, cellSize.y), 0, 0, QUALITY_SCALE);
  361. _tiledTexture[index].uploadFromBitmapData(bitmapData);
  362. }
  363. /**
  364. * Start grid UI. If zoomInOnClick is true, clicking on a grid square will take you back to display list view
  365. */
  366. public function start(zoomInOnClick:Boolean = false, alt:Boolean = false):void {
  367. _zoomInOnClick = zoomInOnClick;
  368. _start = true;
  369. _animation = _animationInitial.concat();
  370. _position = 0;
  371. secondTranslationMatrix(alt ? 0 : INITIAL_ROTATION);
  372. _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 4, _secondMatrix, true); //vc4 - vc7
  373. activate(this);
  374. onEnterFrame(this, drawTiles);
  375. if (UI.uiLayer) {
  376. UI.uiLayer.visible = false;
  377. }
  378. if (UI.windowLayer) {
  379. UI.windowLayer.visible = false;
  380. }
  381. }
  382. /**
  383. * Stop grid UI.
  384. */
  385. public function stop():void {
  386. _enabled = false;
  387. _screen.stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
  388. _screen.stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
  389. if (UI.uiLayer) {
  390. UI.uiLayer.visible = true;
  391. }
  392. if (UI.windowLayer) {
  393. UI.windowLayer.visible = true;
  394. }
  395. }
  396. override public function enable():void {
  397. _enabled = true;
  398. _context3D.setVertexBufferAt( 0, _xyzVertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3 ); //va0
  399. _context3D.setVertexBufferAt( 1, _uvVertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2 ); //va1
  400. _context3D.setProgram(_tiledShaderProgram);
  401. _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _finalMatrix, true); //vc0 - vc3
  402. _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 4, _secondMatrix, true); //vc4 - vc7
  403. }
  404. override public function disable():void {
  405. _enabled = false;
  406. _context3D.setVertexBufferAt( 0, null ); //va0
  407. _context3D.setVertexBufferAt( 1, null ); //va1
  408. _context3D.setTextureAt(0, null);
  409. }
  410. protected function makeInteractive():void {
  411. secondTranslationMatrix();
  412. _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 4, _secondMatrix, true); //vc4 - vc7
  413. _screen.stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
  414. }
  415. protected function doTheDrawForTile(index:int):void {
  416. var frame:int = _animation[index];
  417. if (frame < 0) {
  418. _animation[index]++;
  419. _moving++;
  420. }
  421. else {
  422. _context3D.setTextureAt(0, _tiledTexture[index]); //fs0
  423. if (frame < ANIMATION) {
  424. _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 8, Vector.<Number>([ frame/ANIMATION, (1.0 - frame/ANIMATION), _position/_scale, 0.0 ]) ); // fc4
  425. _animation[index]++;
  426. _moving++;
  427. }
  428. else {
  429. _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 8, Vector.<Number>([ 1.0, 0.0, _position/_scale, 0.0 ]) ); // fc4
  430. }
  431. _context3D.drawTriangles(_indexBuffer, 6 * index, 2);
  432. }
  433. }
  434. /**
  435. * Render the grid
  436. */
  437. protected function doTheDraw(present:Boolean = true):void {
  438. _moving = 0;
  439. _context3D.clear((_backgroundColour>>32 & 0xff)/0xff, (_backgroundColour>>16 & 0xff)/0xff, (_backgroundColour & 0xff)/0xff);
  440. for (var j:int = 0; j < _count; j++) {
  441. doTheDrawForTile(j);
  442. }
  443. if (present) {
  444. _context3D.present();
  445. }
  446. if (!_enabled) {
  447. deactivate(this);
  448. }
  449. else if (_moving == 0 && _start) {
  450. _start = false;
  451. makeInteractive();
  452. }
  453. else if (_moving == 0 && _finish) {
  454. _finish = false;
  455. stop();
  456. }
  457. }
  458. /**
  459. * Horizontal scroll in response to touch swipe
  460. */
  461. protected function drawTiles(event:Event):void {
  462. if (_mouseDown) {
  463. var delta:Number = TOUCH_MULTIPLIER * (_screen.stage.mouseX - _lastX);
  464. _distanceX += Math.abs(delta);
  465. _deltaX = MOVE_FACTOR * delta / _screen.stage.stageWidth;
  466. _lastX = _screen.stage.mouseX;
  467. _position += _deltaX;
  468. }
  469. doTheDraw();
  470. }
  471. /**
  472. * Mouse down handler
  473. */
  474. protected function mouseDown(event:MouseEvent):void {
  475. _mouseDown = true;
  476. _screen.stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
  477. _lastX = _screen.stage.mouseX;
  478. _distanceX = 0;
  479. onEnterFrame(this, drawTiles);
  480. }
  481. /**
  482. * Mouse up handler
  483. */
  484. protected function mouseUp(event:MouseEvent):void {
  485. _mouseDown = false;
  486. _screen.stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
  487. if (_distanceX < CLICK_THRESHOLD) {
  488. click();
  489. }
  490. else {
  491. onEnterFrame(this, inertiaMovement);
  492. }
  493. }
  494. /**
  495. * Click handler
  496. */
  497. protected function click():void {
  498. var indices:Point = toGridIndices(new Vector3D(toGraphX(_screen.stage.mouseX), toGraphY(_screen.stage.mouseY)));
  499. var arrayIndex:int = _gridPositionToArrayIndex[indices.y][indices.x];
  500. if (arrayIndex >= 0) {
  501. _indexPoint = indices;
  502. _arrayIndex = arrayIndex;
  503. _animation[_arrayIndex] = 0;
  504. _finish = _zoomInOnClick;
  505. _screen.dispatchEvent(new Event(CLICKED));
  506. }
  507. }
  508. /**
  509. * Row and column of last grid cell clicked
  510. */
  511. public function get gridIndices():Point {
  512. return _indexPoint;
  513. }
  514. /**
  515. * Array index of last grid cell clicked
  516. */
  517. public function get arrayIndex():int {
  518. return _arrayIndex;
  519. }
  520. protected function positionToPageStart():Number {
  521. return - _scale * 2 * _screenEdge.x * Math.round(-_position / (_scale * 2 * _screenEdge.x));
  522. }
  523. /**
  524. * The user has swiped the screen, and removed their finger. The scrolling motion has momentum,
  525. */
  526. protected function inertiaMovement(event:Event):void {
  527. _position += _deltaX;
  528. _deltaX *= (_position > _minimumPosition || _position < _maximumPosition) ? FASTER_DECAY : DECAY;
  529. if (Math.abs(_deltaX) < DELTA_THRESHOLD) {
  530. if (_position > _minimumPosition) {
  531. _destination = _minimumPosition;
  532. onEnterFrame(this, destinationMovement);
  533. }
  534. else if (_position < _maximumPosition) {
  535. _destination = _maximumPosition;
  536. onEnterFrame(this, destinationMovement);
  537. }
  538. else if (_snapToPage) {
  539. _destination = _minimumPosition + positionToPageStart();
  540. onEnterFrame(this, destinationMovement);
  541. } else {
  542. onEnterFrame(this, drawTiles);
  543. }
  544. }
  545. doTheDraw();
  546. }
  547. /**
  548. * Scroll to a position
  549. */
  550. protected function destinationMovement(event:Event):void {
  551. var distance:Number = _destination - _position;
  552. if (Math.abs(distance) < MOVE_THRESHOLD) {
  553. _position = _destination;
  554. onEnterFrame(this, drawTiles);
  555. }
  556. else {
  557. _position += distance * BOUNCE_FACTOR ;
  558. }
  559. doTheDraw();
  560. }
  561. override public function destructor():void {
  562. super.destructor();
  563. for each (var bitmapData:BitmapData in _textureBitMapData) {
  564. bitmapData.dispose();
  565. }
  566. }
  567. }
  568. }