PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

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

http://mad-components.googlecode.com/
ActionScript | 1081 lines | 758 code | 146 blank | 177 comment | 114 complexity | 5f431c1980d484e15535f3cfd028cbc6 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.IContainerUI;
  29. import com.danielfreeman.madcomponents.UI;
  30. import com.danielfreeman.madcomponents.UINavigation;
  31. import com.danielfreeman.madcomponents.UINavigationBar;
  32. import com.danielfreeman.madcomponents.UIPages;
  33. import flash.display.Bitmap;
  34. import flash.display.BitmapData;
  35. import flash.display.DisplayObject;
  36. import flash.display.Sprite;
  37. import flash.display3D.Context3DProgramType;
  38. import flash.display3D.Context3DTextureFormat;
  39. import flash.display3D.Context3DVertexBufferFormat;
  40. import flash.display3D.IndexBuffer3D;
  41. import flash.display3D.Program3D;
  42. import flash.display3D.VertexBuffer3D;
  43. import flash.display3D.textures.Texture;
  44. import flash.events.Event;
  45. import flash.events.MouseEvent;
  46. import flash.geom.Matrix;
  47. import flash.geom.Matrix3D;
  48. import flash.geom.Point;
  49. import flash.geom.Rectangle;
  50. import flash.trace.Trace;
  51. /**
  52. * This class impliments 3D page flipping capabilities.
  53. * There are four flipping modes. MadPages (2D), MadFlow, MadCircle, and MadSwap
  54. */
  55. public class PageFlipping extends Stage3DAcceleration {
  56. public static const CLICKED:String = "pageFlippingClicked";
  57. public static const FINISHED:String = "pageFlippingFinished";
  58. protected static const TEXTURE_WIDTH:int = 2048;
  59. protected static const TEXTURE_HEIGHT:int = 2048;
  60. protected static const TOUCH_MULTIPLIER:Number = 1.5;
  61. protected static const ZOOM_DELTA:Number = 0.2;
  62. protected static const SPACING:Number = 0.3;
  63. protected static const POWER:Number = 4;
  64. protected static const PAUSE:Number = 0.415;
  65. protected static const TWEEK:Number = 0.3;
  66. protected static const SIDEWAYS:Number = 0.4;
  67. protected static const GAP:Number = 0.05;
  68. protected static const SKEW:Number = 0.1;
  69. protected static const EDGE:Number = 0.2;
  70. protected static const BACK:Number = 1.0;
  71. protected static const UNIT:Number = 0.6;
  72. protected static const ZOOM:Number = 1.73;
  73. protected static const FILL:Number = 1.30;
  74. protected static const BOUNDARY:Number = 1.30;
  75. protected static const MOVE_FACTOR:Number = 2.0;
  76. protected static const BOUNCE_FACTOR:Number = 0.3;
  77. protected static const CLICK_THRESHOLD:Number = 32.0;
  78. protected static const MOVE_THRESHOLD:Number = 0.01;
  79. protected static const DELTA_THRESHOLD:Number = 0.01;
  80. protected static const DECAY:Number = 0.99;
  81. protected static const FASTER_DECAY:Number = 0.60;
  82. protected static const Y:Number = 0.10;
  83. protected static const MAXIMUM_TEXTURE:int = 7;
  84. protected static const DEPTH:Number = 8.0;
  85. protected static const CIRCLE:Number = 4.0;
  86. protected static const CIRCULAR_DELTA:Number = 0.005;
  87. protected static const INDICATOR_GAP:Number = 8.0;
  88. protected static const INDICATOR_SIZE:Number = 8.0;
  89. protected var _textureBitMapData:Vector.<BitmapData> = null;
  90. protected var _vertices:Vector.<Number>;
  91. protected var _uv:Vector.<Number>;
  92. protected var _indices:Vector.<uint>;
  93. protected var _indexBuffer:IndexBuffer3D;
  94. protected var _xyzVertexBuffer:VertexBuffer3D;
  95. protected var _uvVertexBuffer:VertexBuffer3D;
  96. protected var _pageFlippingVertexShader:AGALMiniAssembler = new AGALMiniAssembler();
  97. protected var _pageFlippingFragmentShader:AGALMiniAssembler = new AGALMiniAssembler();
  98. protected var _pageFlippingShaderProgram:Program3D;
  99. protected var _pageFlippingTexture:Vector.<Texture>;
  100. protected var _finalMatrix:Matrix3D = new Matrix3D();
  101. protected var _projectionMatrix:PerspectiveMatrix3D = new PerspectiveMatrix3D();
  102. protected var _count:uint = 0;
  103. protected var _pageWidth:Number;
  104. protected var _pageHeight:Number;
  105. protected var _columns:Number;
  106. protected var _rows:Number;
  107. protected var _position:Number = 0;
  108. protected var _minimumPosition:Number;
  109. protected var _maximumPosition:Number;
  110. protected var _lastX:Number;
  111. protected var _deltaX:Number;
  112. protected var _distanceX:Number;
  113. protected var _destination:Number;
  114. protected var _boundary:Number;
  115. protected var _unit:Number;
  116. protected var _fillScreen:Vector.<Number>;
  117. protected var _zoomIn:Number = 0.0;
  118. protected var _zoomDelta:Number;
  119. protected var _zoomInOnClick:Boolean = false;
  120. protected var _pageTop:Number;
  121. protected var _zoomedColour:uint = 0x000000;
  122. protected var _container:IContainerUI = null;
  123. protected var _textureUpdate:Vector.<uint> = null;
  124. protected var _circular:Boolean = true;
  125. protected var _flavour:Function = makePagesMadFlow;
  126. protected var _index:int = -1;
  127. protected var _numberOfTextures:int = 0;
  128. protected var _rowsPerTexture:Number;
  129. protected var _pagesPerTexture:Number;
  130. protected var _snapToPage:Boolean = true;
  131. protected var _enabled:Boolean = false;
  132. protected var _spin:Boolean = false;
  133. protected var _circularDelta:Number = CIRCULAR_DELTA;
  134. protected var _pageIndicator:PageIndicator = null;
  135. public function PageFlipping() {
  136. initialise();
  137. }
  138. /**
  139. * Page snapping, ensures that the current page in centre on the screen
  140. */
  141. public function set snapToPage(value:Boolean):void {
  142. _snapToPage=value;
  143. if (value) {
  144. _destination = pageNumberToPosition(pageNumber);
  145. onEnterFrame(this, destinationMovement);
  146. }
  147. }
  148. public function get snapToPage():Boolean {
  149. return _snapToPage;
  150. }
  151. protected function textureR(pageNumber:int):int {
  152. return Math.floor(pageNumber/_pagesPerTexture);
  153. }
  154. protected function textureX(pageNumber:int):Number {
  155. return (pageNumber % _columns) * _pageWidth;
  156. }
  157. protected function textureY(pageNumber:int):Number {
  158. pageNumber = pageNumber % _pagesPerTexture;
  159. return Math.floor(pageNumber / _columns) * _pageHeight;
  160. }
  161. /**
  162. * Vertex corners of a 2D page zoomed in
  163. */
  164. protected function fillScreen():Vector.<Number> {
  165. var y:Number = -_pageTop / _screen.stage.stageHeight;
  166. return Vector.<Number> ([
  167. // X, Y, Z,
  168. -FILL*_unit, y-3*FILL*UNIT, -0.1,
  169. FILL*_unit, y-3*FILL*UNIT, -0.1,
  170. FILL*_unit, y+FILL*UNIT, -0.1,
  171. -FILL*_unit, y+FILL*UNIT, -0.1
  172. ]);
  173. }
  174. /**
  175. * Vertex corners of a 2D page at flipping distance
  176. */
  177. protected function centrePanel(position:Number = 0, y:Number = 0.1, z:Number = 0):Vector.<Number> {
  178. return Vector.<Number> ([
  179. // X, Y, Z,
  180. position-_unit, y-3*UNIT, z,
  181. position+_unit, y-3*UNIT, z,
  182. position+_unit, y+UNIT, z,
  183. position-_unit, y+UNIT, z
  184. ]);
  185. }
  186. /**
  187. * Vertex coordinates of MadFlow page to the left of the screen.
  188. */
  189. protected function leftMadFlow(position:Number):Vector.<Number> {
  190. return Vector.<Number> ([
  191. // X, Y, Z,
  192. position, Y-3*UNIT, EDGE,
  193. position + SKEW, Y-3*UNIT, BACK,
  194. position + SKEW, Y+UNIT, BACK,
  195. position, Y+UNIT, EDGE
  196. ]);
  197. }
  198. /**
  199. * Vertex coordinates of MadFlow page to the right of the screen.
  200. */
  201. protected function rightMadFlow(position:Number):Vector.<Number> {
  202. return Vector.<Number> ([
  203. // X, Y, Z,
  204. position - SKEW, Y-3*UNIT, BACK,
  205. position, Y-3*UNIT, EDGE,
  206. position, Y+UNIT, EDGE,
  207. position - SKEW, Y+UNIT, BACK
  208. ]);
  209. }
  210. protected function get rightBoundary():Number {
  211. return toGraphX(_screen.stage.stageWidth * (0.5 + _boundary/2));
  212. }
  213. protected function get leftBoundary():Number {
  214. return toGraphX(_screen.stage.stageWidth * (0.5 - _boundary/2));
  215. }
  216. /**
  217. * Calculate a MadFlow page in the centre of the screen
  218. */
  219. protected function centreCoverFlow(offset:Number, position:Number, flat:Boolean, zoomIn:Number = 0):Vector.<Number> {
  220. var result:Vector.<Number> = new Vector.<Number>();
  221. var sideShape:Vector.<Number> = (offset>0) ? rightMadFlow(_boundary-(1-offset)*TWEEK) : leftMadFlow(position);
  222. var i:int = 0;
  223. var factor:Number = (Math.abs(offset)<PAUSE || flat) ? 1.0 : Math.pow(1.0-(Math.abs(offset)-PAUSE)/(1.0-PAUSE), POWER);
  224. for each (var value:Number in centrePanel(offset*SIDEWAYS)) {
  225. result.push(zoomIn*_fillScreen[i]+(1-zoomIn)*(factor*value + (1-factor) * sideShape[i]));
  226. i++;
  227. }
  228. return result;
  229. }
  230. /**
  231. * Apply a translation matrix
  232. */
  233. protected function translationMatrix():void {
  234. _projectionMatrix.perspectiveFieldOfViewLH(60.0*Math.PI/180, _aspectRatio, 0.1, 1000.0);
  235. _finalMatrix.identity();
  236. _finalMatrix.appendTranslation(0, 0, ZOOM);
  237. _finalMatrix.append(_projectionMatrix);
  238. }
  239. /**
  240. * The vertex shader aloows for horizontal translation (scrolling), and applies the perspective transformation matrix
  241. *
  242. * The fragment shader optionally applies a fading effect to squares to make an inverted page appear like a reflection
  243. */
  244. public function initialise():void {
  245. translationMatrix();
  246. _pageFlippingVertexShader.assemble( Context3DProgramType.VERTEX,
  247. "add vt0, vc4, va0 \n" + // for fast scrolling
  248. "m44 op, vt0, vc0 \n" + // vertex
  249. "mov v0, va1 \n" // interpolate UVT
  250. );
  251. _pageFlippingFragmentShader.assemble( Context3DProgramType.FRAGMENT,
  252. "abs ft0.xy, v0.xy \n" + // |uv|
  253. "sub ft0.y, fc0.y, ft0.y \n" + // pageHeight - u
  254. "mov ft1.xy, ft0.xy \n" +
  255. "add ft1.y, ft1.y, v0.z \n" + // add start page position to u
  256. "tex ft1, ft1.xy, fs0 <2d,linear,nomip> \n" + // output texture
  257. "slt ft2.x, v0.y, fc0.z \n" + // is u < 0 ?
  258. "mul ft0.y, ft0.y, fc0.x \n" + //
  259. "max ft2.x, ft2.x, ft0.y \n" +
  260. "mul oc, ft1, ft2.xxxx \n"
  261. );
  262. _pageFlippingShaderProgram = _context3D.createProgram();
  263. _pageFlippingShaderProgram.upload( _pageFlippingVertexShader.agalcode, _pageFlippingFragmentShader.agalcode);
  264. }
  265. /**
  266. * Capture all of the pages within a MadComponents container. (UIPages, UINavigation, etc.).
  267. * Notice optional showPageIndicator parameter. If true, displays a page indicator at the bottom of the screen.
  268. */
  269. public function containerPageTextures(container:IContainerUI, showPageIndicator:Boolean = false):void {
  270. var pages:Vector.<Sprite> = new Vector.<Sprite>();
  271. for each (var page:Sprite in container.pages) {
  272. pages.push(page);
  273. }
  274. _container = container;
  275. _pageTop = 0;
  276. if (container is UINavigation) {
  277. _zoomedColour = UINavigation(container).navigationBar.colour;
  278. _pageTop = pages[UIPages(_container).pageNumber].y - UINavigationBar.HEIGHT;
  279. }
  280. pageTextures(container.attributes.width, container.attributes.height, pages, showPageIndicator, container.attributes.backgroundColours.length>0 ? container.attributes.backgroundColours[0] : 0xFFFFFF);
  281. }
  282. /**
  283. * Capture all of the pages within specified as a Vector of Sprites.
  284. * Notice optional showPageIndicator parameter. If true, displays a page indicator at the bottom of the screen.
  285. */
  286. public function pageTextures(width:Number, height:Number, pages:Vector.<Sprite>, showPageIndicator:Boolean, backgroundColour:uint = 0xFFFFFF):void {
  287. var textureWidth:Number;
  288. var textureHeight:Number;
  289. _pageWidth = width*scale;
  290. _pageHeight = height*scale;
  291. if (showPageIndicator) {
  292. _pageIndicator = new PageIndicator(_screen.stage.stageHeight - INDICATOR_GAP * UI.scale, INDICATOR_SIZE * UI.scale, pages.length);
  293. }
  294. if (_pageWidth * pages.length > TEXTURE_WIDTH / 2) {
  295. _rowsPerTexture = Math.floor(TEXTURE_HEIGHT / _pageHeight);
  296. _columns = Math.floor(TEXTURE_WIDTH / _pageWidth);
  297. _rows = Math.ceil(pages.length / _columns);
  298. _numberOfTextures = Math.ceil(_rows / _rowsPerTexture);
  299. if (_numberOfTextures==1) {
  300. textureWidth = TEXTURE_WIDTH;
  301. textureHeight = power2(_rows * _pageHeight);
  302. }
  303. else {
  304. var texturesOnLastPage:Number = pages.length - (_numberOfTextures - 1) * _rowsPerTexture * _columns;
  305. if (_pageWidth * texturesOnLastPage > TEXTURE_WIDTH / 2) {
  306. textureWidth = TEXTURE_WIDTH;
  307. textureHeight = power2(Math.ceil(texturesOnLastPage / _columns) * _pageHeight);
  308. }
  309. else {
  310. textureWidth = power2(_pageWidth * texturesOnLastPage);
  311. textureHeight = power2(_pageHeight);
  312. }
  313. }
  314. }
  315. else {
  316. textureWidth = power2(_pageWidth * pages.length);
  317. _columns = pages.length;
  318. _rowsPerTexture = _rows = 1;
  319. _numberOfTextures = 1;
  320. textureHeight = power2(_pageHeight);
  321. }
  322. _pagesPerTexture = _rowsPerTexture * _columns;
  323. if (_textureBitMapData) {
  324. for each (var bitmapData0:BitmapData in _textureBitMapData) {
  325. bitmapData0.dispose();
  326. }
  327. }
  328. _textureBitMapData = new Vector.<BitmapData>();
  329. for (var i:int = 0; i< _numberOfTextures-1; i++) {
  330. _textureBitMapData.push(new BitmapData(TEXTURE_WIDTH, TEXTURE_HEIGHT, true, backgroundColour));
  331. }
  332. _textureBitMapData.push(new BitmapData(textureWidth, textureHeight, true, backgroundColour));
  333. _boundary = 0.8 * _pageWidth / _pageHeight;
  334. _unit = UNIT * _pageWidth / _pageHeight;
  335. _fillScreen = fillScreen();
  336. _indices = new Vector.<uint>();
  337. _uv = new Vector.<Number>();
  338. _count = 0;
  339. for each (var page:Sprite in pages) {
  340. var texWidth:Number = _textureBitMapData[textureR(_count)].width;
  341. var texHeight:Number = _textureBitMapData[textureR(_count)].height;
  342. _uv.push(
  343. // U, V, W
  344. textureX(_count)/texWidth, _pageHeight/texHeight, textureY(_count)/texHeight,
  345. (_pageWidth+textureX(_count))/texWidth, _pageHeight/texHeight, textureY(_count)/texHeight,
  346. (_pageWidth+textureX(_count))/texWidth, -_pageHeight/texHeight, textureY(_count)/texHeight,
  347. textureX(_count)/texWidth, -_pageHeight/texHeight, textureY(_count)/texHeight
  348. );
  349. _indices.push(
  350. _count*4, _count*4+1, _count*4+2, _count*4, _count*4+2, _count*4+3
  351. );
  352. saveTexture(_textureBitMapData[textureR(_count)], page, new Rectangle(textureX(_count), textureY(_count), _pageWidth, _pageHeight ));
  353. _count++;
  354. }
  355. contextResumed(false);
  356. }
  357. /**
  358. * Enable page flipping
  359. */
  360. override public function enable():void {
  361. _enabled = true;
  362. setRegisters();
  363. // _context3D.setTextureAt(0, _pageFlippingTexture[0]); //fs0
  364. make(_position);
  365. onEnterFrame(this, doNothing);
  366. }
  367. /**
  368. * Disable page flipping
  369. */
  370. override public function disable():void {
  371. _enabled = false;
  372. unSetRegisters();
  373. removeListeners();
  374. }
  375. /**
  376. * Restore shaders, streams and textures after context loss.
  377. */
  378. override public function contextResumed(running:Boolean):void {
  379. _pageFlippingShaderProgram = _context3D.createProgram();
  380. _pageFlippingShaderProgram.upload( _pageFlippingVertexShader.agalcode, _pageFlippingFragmentShader.agalcode);
  381. _xyzVertexBuffer = _context3D.createVertexBuffer(_count * 4, 3);
  382. // _xyzVertexBuffer.uploadFromVector(_vertices, 0, _vertices.length / 3);
  383. _uvVertexBuffer = _context3D.createVertexBuffer(_count * 4, 3);
  384. _uvVertexBuffer.uploadFromVector(_uv, 0, _uv.length/3);
  385. _indexBuffer = _context3D.createIndexBuffer( _indices.length );
  386. _indexBuffer.uploadFromVector(_indices, 0, _indices.length );
  387. _pageFlippingTexture = new Vector.<Texture>();
  388. for each (var bitmapData:BitmapData in _textureBitMapData) {
  389. var texture:Texture = _context3D.createTexture(bitmapData.width, bitmapData.height, Context3DTextureFormat.BGRA, false);
  390. texture.uploadFromBitmapData(bitmapData);
  391. _pageFlippingTexture.push(texture);
  392. }
  393. _textureUpdate = null;
  394. if (running) {
  395. show();
  396. onEnterFrame(this, touchMovement);
  397. }
  398. }
  399. /**
  400. * Update the appearance of a component on a particular page.
  401. */
  402. public function updatePage(pageNumber:int, component:DisplayObject = null):void {
  403. var page:Sprite = _container.pages[pageNumber];
  404. var textureIndex:int = textureR(pageNumber);
  405. if (!_textureUpdate) {
  406. _textureUpdate = new Vector.<uint>();
  407. }
  408. if (_textureUpdate.indexOf(textureIndex) < 0) {
  409. _textureUpdate.push(textureIndex);
  410. }
  411. if (!component) {
  412. saveTexture(_textureBitMapData[textureIndex], page, new Rectangle(textureX(pageNumber), textureY(pageNumber), _pageWidth, _pageHeight));
  413. }
  414. else {
  415. var globalPoint:Point = component.localToGlobal(new Point(0,0));
  416. var localPoint:Point = page.globalToLocal(globalPoint);
  417. saveTexture(_textureBitMapData[textureIndex], page, new Rectangle(textureX(pageNumber) + localPoint.x-1, textureY(pageNumber)+localPoint.y-1, Math.min(_pageWidth - (localPoint.x-1), UI.scale*(component.width+2)), Math.min(_pageHeight - (localPoint.y-1), UI.scale*(component.height+2))), - localPoint.x + 1, - localPoint.y + 1);
  418. }
  419. }
  420. protected function setRegisters():void {
  421. _context3D.setVertexBufferAt( 0, _xyzVertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3 ); //va0
  422. _context3D.setVertexBufferAt( 1, _uvVertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3 ); //va1
  423. if (_numberOfTextures == 1) {
  424. _context3D.setTextureAt(0, _pageFlippingTexture[0]); //fs0
  425. _context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([ 0.3*_textureBitMapData[0].height/_pageHeight, _pageHeight/_textureBitMapData[0].height, 0.0, 1.0 ]) ); // fc0
  426. }
  427. updateRegisters();
  428. _context3D.setProgram(_pageFlippingShaderProgram);
  429. _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _finalMatrix, true); //vc0 - vc3
  430. _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, Vector.<Number>([ 0.0, 0.0, 0.0, 0.0 ])); //vc4
  431. }
  432. /**
  433. * Update textures
  434. */
  435. protected function updateRegisters():void {
  436. if (_textureUpdate) {
  437. for each (var textureIndex:uint in _textureUpdate) {
  438. _pageFlippingTexture[textureIndex].uploadFromBitmapData(_textureBitMapData[textureIndex]);
  439. }
  440. _textureUpdate = null;
  441. }
  442. }
  443. protected function unSetRegisters():void {
  444. _context3D.setVertexBufferAt( 0, null ); //va0
  445. _context3D.setVertexBufferAt( 1, null ); //va1
  446. _context3D.setTextureAt(0, null);
  447. }
  448. protected function setPageVertices(i:int, pageVertices:Vector.<Number>):void {
  449. if (i==0) { // Assumed this method called in i sequence
  450. _vertices = new Vector.<Number>();
  451. }
  452. _vertices = _vertices.concat(pageVertices);
  453. }
  454. protected function makePages(position:Number, zoomIn:Number = 0):void {
  455. if (zoomIn == 0) { //faster scrolling
  456. _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, Vector.<Number>([ position, 0.0, 0.0, 0.0 ])); //vc4
  457. }
  458. else {
  459. _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, Vector.<Number>([ 0.0, 0.0, 0.0, 0.0 ])); //vc4
  460. doMakePages(position, zoomIn);
  461. }
  462. }
  463. /**
  464. * Calculate the page vertices for MadPages mode.
  465. */
  466. protected function doMakePages(position:Number = 0.0, zoomIn:Number = 0.0):void {
  467. for (var i:int=0; i<_count; i++) {
  468. var zoom:Number = (i == pageNumber) ? zoomIn : 0.0;
  469. var result:Vector.<Number> = new Vector.<Number>();
  470. var panel:Vector.<Number> = centrePanel(position);
  471. var filled:Vector.<Number> = fillScreen();
  472. for (var j:int=0; j<12; j++) {
  473. result.push((1-zoom) * panel[j] + zoom * filled[j]);
  474. }
  475. setPageVertices(i, result);
  476. position += 2 * _unit + GAP;
  477. }
  478. }
  479. /**
  480. * Calculate the page vertices for MadCircular mode.
  481. */
  482. protected function makePagesMadCircular(position:Number, zoomIn:Number = 0):void {
  483. var theta:Number = -2 * Math.PI * (position - _minimumPosition)/(_maximumPosition - _minimumPosition);
  484. for (var i:int=0; i<_count; i++) {
  485. var delta:Number = 2 * Math.PI * i/_count;
  486. var zoom:Number = (i == _index) ? zoomIn : 0.0;
  487. var result:Vector.<Number> = new Vector.<Number>();
  488. var xCentre:Number = 2 * _pageWidth / _pageHeight * Math.sin(theta+delta);
  489. var yCentre:Number = _circular ? -(CIRCLE + 0.2)*Math.cos(theta+delta) + CIRCLE : Y;
  490. var zCentre:Number = DEPTH - DEPTH*Math.cos(theta+delta);
  491. var panel:Vector.<Number> = centrePanel(xCentre, yCentre, zCentre);
  492. var filled:Vector.<Number> = fillScreen();
  493. for (var j:int=0; j<12; j++) {
  494. result.push((1-zoom) * panel[j] + zoom * filled[j]);
  495. }
  496. setPageVertices(i, result);
  497. position += 2 * _unit + GAP;
  498. }
  499. }
  500. /**
  501. * Calculate the page vertices for MadFlow mode.
  502. */
  503. protected function makePagesMadFlow(position:Number, zoomIn:Number = 0):void {
  504. var start:Boolean = _position > _minimumPosition;
  505. for (var i:int=0; i<_count; i++) {
  506. var zoom:Number = (i == pageNumber) ? zoomIn : 0.0;
  507. if (start) {
  508. if (i==0) {
  509. setPageVertices(i, centreCoverFlow((position - leftBoundary) / SPACING - 1, position, true, zoom));
  510. position += 2 * _boundary - SPACING;
  511. }
  512. else {
  513. setPageVertices(i, rightMadFlow(position));
  514. position += SPACING;
  515. }
  516. }
  517. else if (position <= leftBoundary && i<_count-1) {
  518. setPageVertices(i, leftMadFlow(position));
  519. position += SPACING;
  520. }
  521. else if (position >= rightBoundary) {
  522. setPageVertices(i, rightMadFlow(position));
  523. position += SPACING;
  524. }
  525. else if (position < 0) {
  526. var rotation:Number = (position - leftBoundary) / SPACING - 1;
  527. setPageVertices(i, centreCoverFlow(rotation, position, i==_count-1 && rotation<0, zoom));
  528. position = position - leftBoundary;
  529. }
  530. else if (position > 0) {
  531. setPageVertices(i, centreCoverFlow(position / SPACING, position, false, zoom));
  532. position = rightBoundary + position;
  533. }
  534. }
  535. }
  536. /**
  537. * Calculate the maximum and minimum scroll positions.
  538. */
  539. protected function maximumAndMinimum():void {
  540. if (_flavour == makePagesMadCircular) {
  541. _minimumPosition = 0;
  542. _maximumPosition = -_count * ( 2 *_unit + GAP );
  543. }
  544. else {
  545. _minimumPosition = pageNumberToPosition(0);
  546. _maximumPosition = pageNumberToPosition(_count - 1);
  547. }
  548. }
  549. /**
  550. * Calculate page vertices and render.
  551. */
  552. protected function make(position:Number, zoomIn:Number = 0):void {
  553. maximumAndMinimum();
  554. _flavour(position, zoomIn);
  555. _xyzVertexBuffer.uploadFromVector(_vertices, 0, _vertices.length / 3);
  556. drawPages();
  557. }
  558. /**
  559. * x coordinate of a paricular page.
  560. */
  561. protected function pageNumberToPosition(value:int):Number {
  562. if (_flavour == makePagesMadFlow) {
  563. return leftBoundary - (value - 1.0) * SPACING;
  564. }
  565. else {
  566. return - value * ( 2 *_unit + GAP );
  567. }
  568. }
  569. /**
  570. * Return the page number for a particular Stage3D x-coordinate.
  571. */
  572. protected function positionToPageNumber(value:Number):int {//MadPages, not MadFlow
  573. var result:int = Math.round((value-_position)/(2*_unit+GAP));
  574. return (result < 0) ? 0 : ((result > _count-1) ? _count-1 : result);
  575. }
  576. /**
  577. * Correct the scroll position for MadCircular mode
  578. */
  579. protected function correctCircularPosition():void {
  580. var normalisedPosition:Number = (_position - _minimumPosition)/(_maximumPosition - _minimumPosition);
  581. if (normalisedPosition < 0.0) {
  582. normalisedPosition = normalisedPosition + Math.ceil(-normalisedPosition);
  583. }
  584. else if (normalisedPosition>1.0) {
  585. normalisedPosition = normalisedPosition - Math.floor(normalisedPosition);
  586. }
  587. _position = normalisedPosition * (_maximumPosition - _minimumPosition) + _minimumPosition;
  588. }
  589. /**
  590. * The current foreground page index
  591. */
  592. public function get pageNumber():int {
  593. var result:int;
  594. if (_flavour == makePagesMadFlow) {
  595. result = Math.floor(1.5 + (leftBoundary - _position) / SPACING);
  596. }
  597. else if (_flavour == makePages) {
  598. result = (_unit - _position) / ( 2 *_unit + GAP );
  599. }
  600. else {
  601. result = Math.round(_count * (_position - _minimumPosition)/(_maximumPosition - _minimumPosition));
  602. }
  603. return (result < 0) ? 0 : ((result > _count-1) ? _count-1 : result);
  604. }
  605. /**
  606. * The current foreground page index. MadCircular mode.
  607. */
  608. protected function get circularPageNumber():int {
  609. if (_flavour == makePagesMadCircular) {
  610. return Math.round(_count * (_position - _minimumPosition)/(_maximumPosition - _minimumPosition));
  611. }
  612. else {
  613. return pageNumber;
  614. }
  615. }
  616. /**
  617. * Set the current foreground page index
  618. */
  619. public function set pageNumber(value:int):void {
  620. _index = value;
  621. _position = pageNumberToPosition(value);
  622. make(_position);
  623. }
  624. /**
  625. * Render the pages
  626. */
  627. protected function drawPages():void {
  628. _context3D.clear(_zoomIn*(_zoomedColour>>32 & 0xff)/0xff, _zoomIn*(_zoomedColour>>16 & 0xff)/0xff, _zoomIn*(_zoomedColour & 0xff)/0xff);
  629. if (_numberOfTextures == 1) {
  630. _context3D.drawTriangles(_indexBuffer);
  631. }
  632. else if (_flavour == makePagesMadCircular) {
  633. for (var j:int = 0; j < _count; j++) {
  634. _context3D.setTextureAt(0, _pageFlippingTexture[textureR(j)]); //fs0
  635. _context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([ 0.3*_textureBitMapData[textureR(j)].height/_pageHeight, _pageHeight/_textureBitMapData[textureR(j)].height, 0.0, 1.0 ]) ); // fc0
  636. _context3D.drawTriangles(_indexBuffer, 6 * j, 2);
  637. }
  638. }
  639. else {
  640. var midQuad:int = pageNumber;
  641. var firstQuad:int;
  642. var lastQuad:int;
  643. if (_flavour == makePagesMadFlow) {
  644. var eitherSide:int = Math.ceil((_aspectRatio - _unit/BOUNDARY)/SPACING);
  645. firstQuad = Math.max(0, midQuad - eitherSide);
  646. lastQuad = Math.min(_count, midQuad + eitherSide);
  647. }
  648. else {
  649. firstQuad = positionToPageNumber(-_aspectRatio);
  650. lastQuad = Math.min(_count, positionToPageNumber(+_aspectRatio) + 1);
  651. }
  652. var firstTexture:int = Math.floor(firstQuad/_pagesPerTexture);
  653. var lastTexture:int = Math.ceil(lastQuad/_pagesPerTexture);
  654. for (var i:int = firstTexture; i <= lastTexture; i++) {
  655. _context3D.setTextureAt(0, _pageFlippingTexture[i]); //fs0
  656. _context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([ 0.3*_textureBitMapData[i].height/_pageHeight, _pageHeight/_textureBitMapData[i].height, 0.0, 1.0 ]) ); // fc0
  657. var firstQuadForTexture:int = Math.max(firstQuad, i * _pagesPerTexture);
  658. var lastQuadForTexture:int = Math.min(lastQuad, (i+1) * _pagesPerTexture);
  659. _context3D.drawTriangles(_indexBuffer, 6 * firstQuadForTexture, 2 * (lastQuadForTexture - firstQuadForTexture));
  660. }
  661. }
  662. if (_pageIndicator) {
  663. drawPageIndicator();
  664. }
  665. _context3D.present();
  666. }
  667. /**
  668. * Render the page indicator
  669. */
  670. protected function drawPageIndicator():void {
  671. _context3D.setTextureAt(0, null); //fs0
  672. _pageIndicator.display(circularPageNumber % _count);
  673. setRegisters();
  674. }
  675. /**
  676. * Activate MadPages mode. (No zooming transition animation into this mode)
  677. */
  678. public function madPages(zoomInOnClick:Boolean = false):void {
  679. _flavour = makePages;
  680. doMakePages();
  681. _zoomInOnClick = zoomInOnClick;
  682. show();
  683. }
  684. /**
  685. * Activate MadFlow mode. (No zooming transition animation into this mode)
  686. */
  687. public function madFlow(zoomInOnClick:Boolean = false):void {
  688. _flavour = makePagesMadFlow;
  689. _zoomInOnClick = zoomInOnClick;
  690. show();
  691. }
  692. /**
  693. * Activate MadSwap mode. (No zooming transition animation into this mode)
  694. */
  695. public function madSwap(zoomInOnClick:Boolean = false, spin:Boolean = false):void {
  696. _flavour = makePagesMadCircular;
  697. _circular = false;
  698. _spin = spin;
  699. _zoomInOnClick = zoomInOnClick;
  700. show();
  701. }
  702. /**
  703. * Activate MadCircular mode. (No zooming transition animation into this mode)
  704. */
  705. public function madCircular(zoomInOnClick:Boolean = false, spin:Boolean = false):void {
  706. _flavour = makePagesMadCircular;
  707. _circular = true;
  708. _spin = spin;
  709. _zoomInOnClick = zoomInOnClick;
  710. show();
  711. }
  712. protected function show():void {
  713. setRegisters();
  714. _screen.stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
  715. _screen.stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
  716. _flavour(_position);
  717. }
  718. /**
  719. * Zooming transition animation into a flipping mode
  720. */
  721. protected function zoomOut(zoomInOnClick:Boolean = false):void {
  722. activate(this);
  723. updateRegisters();
  724. _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, Vector.<Number>([ 0.0, 0.0, 0.0, 0.0 ])); //vc4
  725. _zoomInOnClick = zoomInOnClick;
  726. UI.uiLayer.visible = false;
  727. if (_container is UIPages) {
  728. pageNumber = UIPages(_container).pageNumber;
  729. }
  730. _zoomIn = 1.0;
  731. _zoomDelta = -ZOOM_DELTA;
  732. removeListeners();
  733. onEnterFrame(this, zoomInMovement);
  734. }
  735. /**
  736. * Activate MadPages mode. (With zooming transition animation)
  737. */
  738. public function zoomOutToMadPages(zoomInOnClick:Boolean = false):void {
  739. _flavour = makePages;
  740. doMakePages();
  741. zoomOut(zoomInOnClick);
  742. }
  743. /**
  744. * Activate MadFlow mode. (With zooming transition animation)
  745. */
  746. public function zoomOutToMadFlow(zoomInOnClick:Boolean = false):void {
  747. _flavour = makePagesMadFlow;
  748. zoomOut(zoomInOnClick);
  749. }
  750. /**
  751. * Activate MadCircular mode. (With zooming transition animation)
  752. */
  753. public function zoomOutToMadCircular(zoomInOnClick:Boolean = false, spin:Boolean = false):void {
  754. _flavour = makePagesMadCircular;
  755. _circular = true;
  756. _spin = spin;
  757. zoomOut(zoomInOnClick);
  758. }
  759. /**
  760. * Activate MadSwap mode. (With zooming transition animation)
  761. */
  762. public function zoomOutToMadSwap(zoomInOnClick:Boolean = false, spin:Boolean = false):void {
  763. _flavour = makePagesMadCircular;
  764. _circular = false;
  765. _spin = spin;
  766. zoomOut(zoomInOnClick);
  767. }
  768. /**
  769. * A zoom-in transition animation back to conventional MadComponents forms
  770. */
  771. public function zoomInToPage():void {
  772. if (_container is UIPages) {
  773. UIPages(_container).pageNumber = (_flavour != makePagesMadFlow) ? _index : pageNumber;
  774. }
  775. if (_container is UINavigation) {
  776. UINavigation(_container).navigationBar.backButton.visible = false;
  777. }
  778. _zoomDelta = ZOOM_DELTA;
  779. _zoomIn = 0.0;
  780. setRegisters();
  781. removeListeners();
  782. onEnterFrame(this, zoomInMovement);
  783. }
  784. protected function mouseDown(event:MouseEvent):void {
  785. _screen.stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
  786. _lastX = _screen.stage.mouseX;
  787. _distanceX = 0;
  788. _deltaX = 0;
  789. onEnterFrame(this, touchMovement);
  790. }
  791. protected function click():void {
  792. if (_flavour != makePagesMadFlow) {
  793. _index = circularPageNumber % _count;
  794. _screen.dispatchEvent(new Event(CLICKED));
  795. }
  796. if (_zoomInOnClick) {
  797. _screen.stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
  798. zoomInToPage();
  799. }
  800. }
  801. protected function mouseUp(event:MouseEvent):void {
  802. _screen.stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
  803. if (_distanceX < CLICK_THRESHOLD) {
  804. click();
  805. }
  806. else {
  807. onEnterFrame(this, inertiaMovement);
  808. }
  809. }
  810. public function get spinHandler():Function {
  811. return ((_flavour == makePagesMadCircular) && _spin) ? circularMovement : null;
  812. }
  813. /**
  814. * Respond to swipes to scroll the pages
  815. */
  816. protected function touchMovement(event:Event):void {
  817. var delta:Number = TOUCH_MULTIPLIER * (_screen.stage.mouseX - _lastX);
  818. _distanceX += Math.abs(delta);
  819. _deltaX = MOVE_FACTOR * delta / _screen.stage.stageWidth;
  820. _lastX = _screen.stage.mouseX;
  821. _position += _deltaX;
  822. if (_flavour == makePagesMadCircular) {
  823. _circularDelta = (delta<-1.0 ? -CIRCULAR_DELTA : (delta>1.0 ? CIRCULAR_DELTA : _circularDelta));
  824. correctCircularPosition();
  825. }
  826. make(_position);
  827. }
  828. /**
  829. * Scroll to a particular position
  830. */
  831. protected function destinationMovement(event:Event):void {
  832. var distance:Number = _destination - _position;
  833. if (Math.abs(distance) < MOVE_THRESHOLD) {
  834. _position = _destination;
  835. onEnterFrame(this);
  836. }
  837. else {
  838. _position += distance * BOUNCE_FACTOR ;
  839. }
  840. make(_position);
  841. }
  842. /**
  843. * MadCircle scrolling
  844. */
  845. protected function circularMovement(event:Event):void {
  846. _position += _circularDelta;
  847. correctCircularPosition();
  848. make(_position);
  849. }
  850. /**
  851. * The user has swiped the screen, and removed their finger. The scrolling motion has momentum,
  852. */
  853. protected function inertiaMovement(event:Event):void {
  854. _position += _deltaX;
  855. _deltaX *= (_position > _minimumPosition || _position < _maximumPosition) ? FASTER_DECAY : DECAY;
  856. if (Math.abs(_deltaX) < DELTA_THRESHOLD) {
  857. if (_position > _minimumPosition) {
  858. _destination = _minimumPosition;
  859. onEnterFrame(this, destinationMovement);
  860. }
  861. else if (_position < _maximumPosition) {
  862. _destination = _maximumPosition;
  863. onEnterFrame(this, destinationMovement);
  864. }
  865. else if (_snapToPage && !_spin) {
  866. _destination = pageNumberToPosition(circularPageNumber);
  867. onEnterFrame(this, destinationMovement);
  868. }
  869. else {
  870. onEnterFrame(this, spinHandler);
  871. }
  872. }
  873. make(_position);
  874. }
  875. /**
  876. * Keep rendering. Ensure Display list graphics don't freeze up. On mobile, two two are synched.
  877. */
  878. protected function doNothing(event:Event):void {
  879. _context3D.clear(_zoomIn*(_zoomedColour>>32 & 0xff)/0xff, _zoomIn*(_zoomedColour>>16 & 0xff)/0xff, _zoomIn*(_zoomedColour & 0xff)/0xff);
  880. _context3D.drawTriangles(_indexBuffer, 0, 0);
  881. _context3D.present();
  882. }
  883. /**
  884. * Animate zoom transition
  885. */
  886. protected function zoomInMovement(event:Event):void {
  887. _zoomIn += _zoomDelta;
  888. if (!_enabled) {
  889. make(_position, 1.0);
  890. deactivate(this);
  891. }
  892. else if (_zoomIn >= 1.0) {
  893. zoomInComplete();
  894. }
  895. else if (_zoomIn <= 0) {
  896. zoomOutComplete();
  897. }
  898. else {
  899. make(_position, _zoomIn);
  900. }
  901. }
  902. /**
  903. * Zoom-Out transition complete
  904. */
  905. protected function zoomOutComplete():void {
  906. _zoomIn = 0.0;
  907. if (_flavour == makePages) {
  908. doMakePages();
  909. _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, Vector.<Number>([ 0.0, 0.0, 0.0, 0.0 ])); //vc4
  910. }
  911. onEnterFrame(this);
  912. show();
  913. }
  914. /**
  915. * Zoom-In transition complete
  916. */
  917. protected function zoomInComplete():void {
  918. _zoomIn = 1.0;
  919. UI.uiLayer.visible = true;
  920. make(_position, _zoomIn);
  921. _screen.dispatchEvent(new Event(FINISHED));
  922. _enabled = false;
  923. }
  924. protected function removeListeners():void {
  925. _screen.stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
  926. _screen.stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
  927. }
  928. override public function destructor():void {
  929. super.destructor();
  930. for each (var bitmapData:BitmapData in _textureBitMapData) {
  931. bitmapData.dispose();
  932. }
  933. }
  934. }
  935. }