PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/MadComponents3D/src/com/danielfreeman/stage3Dacceleration/PageFlipping.as

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