PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

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

http://mad-components.googlecode.com/
ActionScript | 822 lines | 557 code | 127 blank | 138 comment | 104 complexity | db6c20ad9c0db594fc46bd1525990035 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.danielfreeman.madcomponents.*;
  27. import flash.display.Bitmap;
  28. import flash.display.BitmapData;
  29. import flash.display.DisplayObject;
  30. import flash.display.IBitmapDrawable;
  31. import flash.display.Sprite;
  32. import flash.display3D.Context3DBlendFactor;
  33. import flash.display3D.Context3DProgramType;
  34. import flash.display3D.Context3DTextureFormat;
  35. import flash.display3D.Context3DVertexBufferFormat;
  36. import flash.display3D.IndexBuffer3D;
  37. import flash.display3D.Program3D;
  38. import flash.display3D.VertexBuffer3D;
  39. import flash.display3D.textures.Texture;
  40. import flash.events.Event;
  41. import flash.events.MouseEvent;
  42. import flash.geom.Matrix;
  43. import flash.geom.Point;
  44. import flash.geom.Rectangle;
  45. import flash.utils.Dictionary;
  46. public class LongListScrolling extends ListScrolling {
  47. protected static const STRIP_HEIGHT:Number = 128.0;
  48. protected static const MOTION_BLUR_DIVISOR:Number = 16.0;
  49. protected static const MOTION_K0:Number = 0.5;
  50. protected static const MOTION_K1:Number = 0.15;
  51. protected static const MOTION_K2:Number = 0.1; // k0 + 2 ( k1 + k2 ) always = 1.0
  52. protected static const FAST_MOTION_K0:Number = 0.09;
  53. protected static const FAST_MOTION_K1:Number = 0.19;
  54. protected static const FAST_MOTION_K2:Number = 0.24;
  55. protected static const FAST_MOTION_AMOUNT:Number = 0.3;
  56. protected static const EXTRA:Number = 16.0;
  57. protected static const SCROLLBAR_POSITION:Number = 1.0;
  58. protected static const SCROLLBAR_WIDTH:Number = 6.0;
  59. protected static const FAST_INDEX_DIFFERENCE:int = 1;
  60. protected static const SHOW_SCROLLBAR_DELTA:Number = 2.0;
  61. protected static const VERY_FAST_SCHEME:Boolean = true;
  62. protected static const SLOW:Number = 32.0;
  63. protected static const QUALITY:Number = 1.0;
  64. protected static const DEBUG:Boolean = false;
  65. protected var _listRowBitmapData:Vector.<Vector.<BitmapData>> = new Vector.<Vector.<BitmapData>>();
  66. protected var _listRowTextures:Vector.<Vector.<Texture>> = new Vector.<Vector.<Texture>>();
  67. protected var _recycleRow:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>();
  68. protected var _scrollbarTextures:Vector.<Texture> = new Vector.<Texture>();
  69. protected var _xyzVertexBuffersAll:Vector.<VertexBuffer3D>;
  70. protected var _uvVertexBuffersAll:Vector.<VertexBuffer3D>;
  71. protected var _positionCurrent:Number = 0;
  72. protected var _positionNext:Number = 0;
  73. protected var _backgroundColour:uint = 0xFFFFFF;
  74. protected var _showCursor:Boolean = true;
  75. protected var _cursorVertices:VertexBuffer3D = null;
  76. protected var _cursorUV:VertexBuffer3D = null;
  77. protected var _cursorTexture:Texture;
  78. protected var _fastScrolling:Boolean = VERY_FAST_SCHEME;
  79. protected var _fastScrollingThreshold:int = FAST_INDEX_DIFFERENCE;
  80. protected var _wasGoingVeryFast:Boolean = false;
  81. protected var _reloadIncremental:int = -1;
  82. protected var _quality:Number = QUALITY;
  83. /**
  84. * This refinement on the PageFlipping class divides every list into strips, each with a height of 128 pixels.
  85. * This is likely to make texture uploads faster, as subdividing a large texture into smaller areas is faster.
  86. *
  87. * You can set the list to lazily load texture strips, as the list is scrolled. Use the lazyRender attribute:- <list lazyRender="true"...
  88. * To reduce memory - you may remove list textures dynamically when not on the screen. Use the recycle attribute:- <list recycle="true"...
  89. * By default, without the lazyRender, or recycle attribute - all list textures are pre-loaded.
  90. *
  91. * This class allows you to update list rows that change appearance. (This is fast as you need only update relevant texture strips - not the whole list texture ).
  92. * But it may incur penalties with geometry (more points to deal with), and renderring (swapping texture buffers more frequently), and we can't do UV animation now.
  93. *
  94. * Note that lists must have a clearance above and below of 128 pixels from any other Stage3D animated are - due to the lack of masking in the shaders.
  95. * (This won't usually be a problem).
  96. *
  97. **/
  98. public function LongListScrolling() {
  99. super();
  100. _supportedLists.push("longList", "tickList", "tickOneList");
  101. }
  102. /**
  103. * This scheme doesn't allow us to do UV animation - but we add the scroll offset within the vertex shader - so it is still fast.
  104. *
  105. * The fragment shader implements variable motion blur which is put into effect when the list scrolls.
  106. * The faster the list scrolls, the more motion blur we apply.
  107. */
  108. override public function initialise():void {
  109. _listScrollingVertexShader.assemble( Context3DProgramType.VERTEX,
  110. "add op, va0, vc0 \n" + // scroll
  111. "mov v0, va1 \n" // interpolate UV
  112. );
  113. _listScrollingFragmentShader.assemble( Context3DProgramType.FRAGMENT,
  114. "mov ft0, v0 \n" +
  115. "tex ft1, v0.xy, fs0 <2d,linear,nomip> \n" + // output texture
  116. "mul ft1.xyzw, ft1.xyzw, fc0.xxxx \n" +
  117. "sub ft0.y, ft0.y, fc0.w \n" +
  118. "tex ft2, ft0.xy, fs0 <2d,linear,nomip> \n" +
  119. "mul ft2.xyzw, ft2.xyzw, fc0.yyyy \n" +
  120. "add ft1, ft1, ft2 \n" +
  121. "sub ft0.y, ft0.y, fc0.w \n" +
  122. "tex ft2, ft0.xy, fs0 <2d,linear,nomip> \n" +
  123. "mul ft2.xyzw, ft2.xyzw, fc0.zzzz \n" +
  124. "add ft1, ft1, ft2 \n" +
  125. "mov ft0, v0 \n" +
  126. "add ft0.y, ft0.y, fc0.w \n" +
  127. "tex ft2, ft0.xy, fs0 <2d,linear,nomip> \n" +
  128. "mul ft2.xyzw, ft2.xyzw, fc0.yyyy \n" +
  129. "add ft1, ft1, ft2 \n" +
  130. "add ft0.y, ft0.y, fc0.w \n" +
  131. "tex ft2, ft0.xy, fs0 <2d,linear,nomip> \n" +
  132. "mul ft2.xyzw, ft2.xyzw, fc0.zzzz \n" +
  133. "add oc, ft1, ft2 \n"
  134. );
  135. _listScrollingShaderProgram = _context3D.createProgram();
  136. _listScrollingShaderProgram.upload( _listScrollingVertexShader.agalcode, _listScrollingFragmentShader.agalcode);
  137. _indexBuffer = _context3D.createIndexBuffer(6);
  138. _indexBuffer.uploadFromVector(Vector.<uint>([0, 1, 2, 0, 2, 3]), 0, 6);
  139. }
  140. /**
  141. * Set quality. 0 > value >= 1. 1 = full quality, 0.1 is terrible.
  142. */
  143. public function set quality(value:Number):void {
  144. _quality = value;
  145. }
  146. public function get quality():Number {
  147. return _quality;
  148. }
  149. /**
  150. * Show row highlight, or not (default is show)
  151. */
  152. public function set showCursor(value:Boolean):void {
  153. _showCursor = value;
  154. }
  155. /**
  156. * Fast scrolling effect for lazyRender mode (default is on)
  157. */
  158. public function set fastScrolling(value:Boolean):void {
  159. _fastScrolling = value;
  160. }
  161. /**
  162. * Fast scrolling threshold. If you have amore powerful device - set it higher.
  163. */
  164. public function set fastScrollingThreshold(value:int):void {
  165. _fastScrollingThreshold = value;
  166. }
  167. public function get fastScrollingThreshold():int {
  168. return _fastScrollingThreshold;
  169. }
  170. /**
  171. * Vertices of a list strip quad
  172. */
  173. protected function pushVerticesAndUV(listRecord:ListRecord, listWidth:Number):void {
  174. var pointList:Point = Sprite(listRecord.container).localToGlobal(new Point(0, 0));
  175. var left:Number = 2 * pointList.x / _screen.stage.stageWidth - 1.0;
  176. var top:Number = - 2 * pointList.y / _screen.stage.stageHeight + 1.0;
  177. var right:Number = left + 2 * listWidth / _screen.stage.stageWidth;
  178. var bottom:Number = top - 2 * STRIP_HEIGHT / (_screen.stage.stageHeight * _quality);
  179. var xyzVertexBuffer:VertexBuffer3D = _context3D.createVertexBuffer(4, 3);
  180. xyzVertexBuffer.uploadFromVector(Vector.<Number>([
  181. left, bottom, 0.02,
  182. right, bottom, 0.02,
  183. right, top, 0.02,
  184. left, top, 0.02 ]), 0, 4);
  185. _xyzVertexBuffersAll.push(xyzVertexBuffer);
  186. var uvVertexBuffer:VertexBuffer3D = _context3D.createVertexBuffer(4, 2);
  187. uvVertexBuffer.uploadFromVector(Vector.<Number>([
  188. 0, 1,
  189. listRecord.uvWidth, 1,
  190. listRecord.uvWidth, 0,
  191. 0, 0 ]), 0, 4);
  192. _uvVertexBuffersAll.push(uvVertexBuffer);
  193. }
  194. /**
  195. * Remove and dispose of a particular texture strip bitmapdata and texture.
  196. */
  197. protected function removeRow(listRecord:ListRecord, index:int):void {
  198. removeListRow(_recycleRow[listRecord.textureIndex], index);
  199. }
  200. /**
  201. * Remove and dispose of a particular texture strip bitmapdata and texture.
  202. */
  203. protected function removeListRow(recycleRow:Vector.<uint>, index:int):void {
  204. if (recycleRow.indexOf(index) < 0) {
  205. recycleRow.push(index);
  206. }
  207. }
  208. /**
  209. * Recycle a bitmapdata if available - or create a new one. (Not sure how much more efficient it is to recycle rather than reinstanciate bitmapdata).
  210. */
  211. protected function newRowBitmapData(listRowBitmapData:Vector.<BitmapData>, recycleRow:Vector.<uint>, index:int, listWidth:Number, backgroundColour:uint = 0xFFFFFF, background:BitmapData = null):BitmapData {
  212. var result:BitmapData;
  213. if (recycleRow.length > 0) {
  214. var copyIndex:uint = recycleRow[0];
  215. result = listRowBitmapData[copyIndex];
  216. if (background) {
  217. result.copyPixels(background, new Rectangle(0, 0, listWidth, STRIP_HEIGHT), new Point(0, 0));
  218. }
  219. else {
  220. result.floodFill(0, 0, backgroundColour);
  221. }
  222. listRowBitmapData[copyIndex] = null;
  223. }
  224. else {
  225. result = background ? background.clone() : new BitmapData(power2(listWidth), STRIP_HEIGHT, false, DEBUG ? 0xffff00 : backgroundColour);
  226. }
  227. listRowBitmapData[index] = result;
  228. return result;
  229. }
  230. /**
  231. * Remove recycle flag for a row.
  232. */
  233. protected function removeRecycle(recycleRow:Vector.<uint>, index:int):void {
  234. var pos:int = recycleRow.indexOf(index);
  235. if (pos >= 0) {
  236. recycleRow.splice(pos, 1);
  237. }
  238. }
  239. /**
  240. * Recycle a Texture if available - or create a new one
  241. */
  242. protected function newRowTexture(listRowTexture:Vector.<Texture>, recycleRow:Vector.<uint>, index:int, bitmapData:BitmapData):Texture {
  243. var result:Texture;
  244. if (recycleRow.length > 0) {
  245. var copyIndex:uint = recycleRow.shift();
  246. result = listRowTexture[copyIndex];
  247. listRowTexture[copyIndex] = null;
  248. }
  249. else {
  250. result = _context3D.createTexture(bitmapData.width, bitmapData.height, Context3DTextureFormat.BGRA, false);
  251. }
  252. removeRecycle(recycleRow, index);
  253. result.uploadFromBitmapData(bitmapData);
  254. listRowTexture[index] = result;
  255. return result;
  256. }
  257. /**
  258. * Dynamically create a new list row
  259. */
  260. protected function loadNewRow(listRecord:ListRecord, newRowIndex:int, from:Number = 0, overwrite:Boolean = false):void {
  261. var list:IContainerUI = listRecord.container;
  262. var isScrolling:Boolean = list is UIScrollVertical;
  263. var listWidth:Number = _quality * UI.scale * theWidth(list);
  264. var updated:Boolean = false;
  265. var listRowBitmapData:Vector.<BitmapData> = _listRowBitmapData[listRecord.textureIndex];
  266. var listRowTextures:Vector.<Texture> = _listRowTextures[listRecord.textureIndex];
  267. var recycleRow:Vector.<uint> = _recycleRow[listRecord.textureIndex];
  268. var y:Number = newRowIndex * STRIP_HEIGHT;
  269. if (newRowIndex >= listRowBitmapData.length) {
  270. listRowBitmapData.push(null);
  271. _listRowTextures[listRecord.textureIndex].push(null);
  272. }
  273. if (overwrite && listRowBitmapData[newRowIndex]) {
  274. removeRow(listRecord, newRowIndex);
  275. }
  276. if ((overwrite || !listRowBitmapData[newRowIndex]) && newRowIndex >= from) {
  277. var slider:Sprite = isScrolling ? Sprite(list.pages[0]) : Sprite(list);
  278. var backgroundColour:uint = list.attributes.backgroundColours.length > 0 ? list.attributes.backgroundColours[0] : 0xFFFFFF;
  279. var bitmapData:BitmapData = newRowBitmapData(listRowBitmapData, recycleRow, newRowIndex, listWidth, backgroundColour, listRecord.background);
  280. saveTexture(bitmapData, slider, new Rectangle(0, 0, listWidth, STRIP_HEIGHT), 0, -y, _quality);
  281. newRowTexture(listRowTextures, recycleRow, newRowIndex, bitmapData);
  282. if (newRowIndex == 0) {
  283. bitmapData.fillRect(
  284. new Rectangle(0, 0, listWidth, 1),
  285. 0xFF000000 | backgroundColour
  286. );
  287. }
  288. }
  289. else {
  290. removeRecycle(recycleRow, newRowIndex);
  291. }
  292. }
  293. /**
  294. * Store the background texture of a list.
  295. */
  296. protected function saveBackgroundBitmap(listRecord:ListRecord, listWidth:Number):void {
  297. var list:UIScrollVertical = UIScrollVertical(listRecord.container);
  298. var backgroundColour:uint = list.attributes.backgroundColours.length>0 ? list.attributes.backgroundColours[0] : 0xFFFFFF;
  299. var scroller:Sprite = Sprite(list.pages[0]);
  300. scroller.visible = false;
  301. list.drawComponent();
  302. listRecord.background = new BitmapData(power2(listWidth), STRIP_HEIGHT, false, DEBUG ? 0xffff00 : backgroundColour);
  303. saveTexture(listRecord.background, list, new Rectangle(0, 0, listWidth, STRIP_HEIGHT), 0, 0, _quality);
  304. scroller.visible = true;
  305. }
  306. /**
  307. * Provide a list of the specific lists in your layout that you want to accelerate
  308. */
  309. override public function listTextures(lists:Vector.<IContainerUI>):Boolean {
  310. _xyzVertexBuffersAll = new Vector.<VertexBuffer3D>;
  311. _uvVertexBuffersAll = new Vector.<VertexBuffer3D>;
  312. for each (var list:IContainerUI in lists) {
  313. var listWidth:Number = UI.scale*theWidth(list);
  314. var textureWidth:Number = power2(listWidth);
  315. var listRecord:ListRecord = new ListRecord(list, _listRecords.length, list is UIList && UIList(list).showPressed, _quality * listWidth/textureWidth);
  316. if (list is UIGroupedList) {
  317. saveBackgroundBitmap(listRecord, listWidth);
  318. }
  319. listRecord.lazyRender = list.xml.@lazyRender == "true" || list is UILongList;
  320. listRecord.recycle = listRecord.lazyRender && list.xml.@recycle == "true";
  321. _listRecords.push(listRecord);
  322. var isScrolling:Boolean = list is UIScrollVertical;
  323. var length:int = Math.ceil((isScrolling ? Sprite(list.pages[0]).height : theHeight(list))/STRIP_HEIGHT);
  324. _listRowBitmapData.push(new Vector.<BitmapData>(length));
  325. _listRowTextures.push(new Vector.<Texture>(length));
  326. _recycleRow.push(new Vector.<uint>);
  327. pushVerticesAndUV(listRecord, listWidth);
  328. newScrollbarTexture(list);
  329. }
  330. renderCursorBuffers();
  331. if (ALTERNATIVE_SCHEME) {
  332. for each (var listRecord0:ListRecord in _listRecords) {
  333. if (listRecord0.onScreen) {
  334. takeOverFromListScroller(listRecord0);
  335. }
  336. if (!listRecord0.lazyRender) {
  337. preloadTextures(listRecord0);
  338. }
  339. }
  340. }
  341. isDefault(this);
  342. activate(this);
  343. onEnterFrame(this, updateLists);
  344. return false;
  345. }
  346. /**
  347. * Restore shaders, streams and textures after context loss.
  348. */
  349. override public function contextResumed(running:Boolean):void {
  350. _listScrollingShaderProgram = _context3D.createProgram();
  351. _listScrollingShaderProgram.upload( _listScrollingVertexShader.agalcode, _listScrollingFragmentShader.agalcode);
  352. _xyzVertexBuffersAll = new Vector.<VertexBuffer3D>;
  353. _uvVertexBuffersAll = new Vector.<VertexBuffer3D>;
  354. for each (var listRecord:ListRecord in _listRecords) {
  355. var listRowBitmapData:Vector.<BitmapData> = _listRowBitmapData[listRecord.textureIndex];
  356. var listRowTextures:Vector.<Texture> = _listRowTextures[listRecord.textureIndex];
  357. for (var i:int = 0; i<= listRowBitmapData.length; i++) {
  358. pushVerticesAndUV(listRecord, UI.scale * theWidth(listRecord.container));
  359. var bitmapData:BitmapData = listRowBitmapData[i];
  360. if (bitmapData) {
  361. var texture:Texture = _context3D.createTexture(bitmapData.width, bitmapData.height, Context3DTextureFormat.BGRA, false);
  362. texture.uploadFromBitmapData(bitmapData);
  363. listRowTextures[i] = texture;
  364. }
  365. else {
  366. listRowTextures[i] = null;
  367. }
  368. }
  369. }
  370. _indexBuffer = _context3D.createIndexBuffer(6);
  371. _indexBuffer.uploadFromVector(Vector.<uint>([0, 1, 2, 0, 2, 3]), 0, 6);
  372. renderCursorBuffers();
  373. if (running) {
  374. enable();
  375. }
  376. }
  377. /**
  378. * Preload textures if lazyRender="false" (default).
  379. */
  380. protected function preloadTextures(listRecord:ListRecord):void {
  381. var list:IContainerUI = listRecord.container;
  382. var isScrolling:Boolean = list is UIScrollVertical;
  383. var length:int = Math.ceil(UI.scale * (isScrolling ? Sprite(list.pages[0]).height : theHeight(list))/STRIP_HEIGHT);
  384. for (var i:int = 0; i <= length; i++) {
  385. loadNewRow(listRecord, i);
  386. }
  387. }
  388. /**
  389. * If the list is scrolled, dynamically remove and add texture strips
  390. */
  391. protected function updateTextures(listRecord:ListRecord, isScrolling:Boolean, topStrip:Number, bottomStrip:Number, length:Number):void {
  392. if (topStrip == listRecord.firstRowIndex && bottomStrip == listRecord.lastRowIndex) {
  393. return;
  394. }
  395. if (isScrolling) {
  396. var listRowBitmapData:Vector.<BitmapData> = _listRowBitmapData[listRecord.textureIndex];
  397. var listRowTextures:Vector.<Texture> = _listRowTextures[listRecord.textureIndex];
  398. var recycleRow:Vector.<uint> = _recycleRow[listRecord.textureIndex];
  399. if (topStrip > listRecord.lastRowIndex || bottomStrip < listRecord.firstRowIndex) {
  400. if (listRecord.recycle) {
  401. for (var m:int = Math.max(listRecord.firstRowIndex, 0); m <= Math.min(listRecord.lastRowIndex, length); m++) {
  402. removeListRow(recycleRow, m);
  403. }
  404. }
  405. for (var n:int = Math.max( Math.min(topStrip, listRecord.finalTexture), 0); n <= Math.min(bottomStrip, length); n++) {
  406. loadNewRow(listRecord, n, topStrip);
  407. }
  408. }
  409. else {
  410. if (listRecord.recycle) {
  411. for (var k:int = Math.max(listRecord.firstRowIndex, 0); k < Math.min(topStrip, length); k++) {
  412. removeListRow(recycleRow, k);
  413. }
  414. for (var l:int = Math.max(bottomStrip + 1, 0); l <= Math.min(listRecord.lastRowIndex, length); l++) {
  415. removeListRow(recycleRow, l);
  416. }
  417. }
  418. for (var j:int = Math.max( topStrip, 0); j < Math.min(listRecord.firstRowIndex, length + 1); j++) { // list scrolled down (new rows higher than old)
  419. loadNewRow(listRecord, j);
  420. }
  421. for (var i:int = Math.max( Math.min(listRecord.lastRowIndex + 1, listRecord.finalTexture), 0); i <= Math.min(bottomStrip, length); i++) { // list scrolled up (new rows lower than old)
  422. loadNewRow(listRecord, i, topStrip);
  423. }
  424. }
  425. }
  426. listRecord.firstRowIndex = topStrip;
  427. listRecord.lastRowIndex = bottomStrip;
  428. listRecord.finalTexture = Math.max(listRecord.finalTexture, bottomStrip + 1);
  429. }
  430. override protected function makeUV():void {
  431. }
  432. /**
  433. * Set streams and textures
  434. */
  435. protected function setBuffers(listRecord:ListRecord):void {
  436. _context3D.setVertexBufferAt( 0, _xyzVertexBuffersAll[listRecord.textureIndex], 0, Context3DVertexBufferFormat.FLOAT_3 ); //va0
  437. _context3D.setVertexBufferAt( 1, _uvVertexBuffersAll[listRecord.textureIndex], 0, Context3DVertexBufferFormat.FLOAT_2 ); //va1
  438. }
  439. override protected function setRegisters():void {
  440. _context3D.setProgram(_listScrollingShaderProgram);
  441. clearMotionBlur();
  442. }
  443. /**
  444. * Apply motion blur.
  445. */
  446. protected function setMotionBlur(listRecord:ListRecord):void {
  447. var motionBlur:int = Math.floor(Math.abs(listRecord.delta/MOTION_BLUR_DIVISOR));
  448. _context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([ MOTION_K0, MOTION_K1, MOTION_K2, motionBlur / STRIP_HEIGHT]) ); // fc0
  449. }
  450. /**
  451. * Fast motion blur.
  452. */
  453. protected function fastMotionBlur():void {
  454. _context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([ FAST_MOTION_K0, FAST_MOTION_K1, FAST_MOTION_K2, FAST_MOTION_AMOUNT + FAST_MOTION_AMOUNT * Math.random() ]) ); // fc0
  455. }
  456. /**
  457. * Clear motion blur.
  458. */
  459. protected function clearMotionBlur():void {
  460. _context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([ 1.0, 0.0, 0.0, 0.0]) ); // fc0
  461. }
  462. override protected function startMovement(listRecord:ListRecord):void {
  463. super.startMovement(listRecord);
  464. clearMotionBlur();
  465. }
  466. protected function incrementalUpdateTextures(listRecord:ListRecord, isScrolling:Boolean, fromTexture:int, toTexture:int, currentIndex:int, length:Number):int {
  467. updateTextures(listRecord, isScrolling, fromTexture, fromTexture + currentIndex + _fastScrollingThreshold - 1 , length);
  468. return (currentIndex >= toTexture - fromTexture) ? -1 : currentIndex + _fastScrollingThreshold;
  469. }
  470. /**
  471. * Render lists
  472. */
  473. override protected function drawLists():void {
  474. _context3D.clear((_backgroundColour>>32 & 0xff)/0xff, (_backgroundColour>>16 & 0xff)/0xff, (_backgroundColour & 0xff)/0xff);
  475. for each (var listRecord:ListRecord in _listRecords) {
  476. if (listRecord.onScreen || listRecord == _listRecordCurrent || listRecord == _listRecordNext) {
  477. var list:IContainerUI = listRecord.container;
  478. var isScrolling:Boolean = list is UIScrollVertical;
  479. var length:int = Math.ceil(_quality * UI.scale * (isScrolling ? Sprite(list.pages[0]).height : theHeight(list))/STRIP_HEIGHT);
  480. var scrollPositionY:Number = (isScrolling ? UI.scale * UIScrollVertical(list).scrollPositionY : -_centre.y);
  481. var topStrip:int = Math.max(Math.floor(_quality * scrollPositionY/STRIP_HEIGHT), 0);
  482. var bottomStrip:int = Math.min(topStrip + Math.ceil(_quality * UI.scale * theHeight(list)/STRIP_HEIGHT), length);
  483. var renderCursorCondition:Boolean = _frameCount <= CLICK_FRAMES && _notTooFastForClick && isScrolling && _showCursor && _activeList == listRecord;
  484. var goingVeryFast:Boolean = _fastScrolling && listRecord.lazyRender && Math.abs(listRecord.delta) > _fastScrollingThreshold * STRIP_HEIGHT;
  485. var aboveOrBelow:Boolean = isScrolling && (scrollPositionY < 0 || scrollPositionY > UI.scale * UIScrollVertical(list).maximumSlide);
  486. setBuffers(listRecord);
  487. if (goingVeryFast && !aboveOrBelow) {
  488. fastMotionBlur();
  489. _reloadIncremental = -1;
  490. }
  491. else if (listRecord.lazyRender) {
  492. if (aboveOrBelow) {
  493. _reloadIncremental = -1;
  494. _wasGoingVeryFast = goingVeryFast = false;
  495. }
  496. if (_reloadIncremental >= 0) {
  497. _reloadIncremental = incrementalUpdateTextures(listRecord, isScrolling, topStrip, bottomStrip, _reloadIncremental, length);
  498. fastMotionBlur();
  499. }
  500. else if (_wasGoingVeryFast) { // To avoid list stuttering as we need to load a lot of texture strips - so slow it down and preload some textures
  501. listRecord.delta = (listRecord.delta > 0) ? SLOW : -SLOW;
  502. _reloadIncremental = incrementalUpdateTextures(listRecord, isScrolling, topStrip, bottomStrip, 0, length);
  503. fastMotionBlur();
  504. }
  505. else {
  506. updateTextures(listRecord, isScrolling, topStrip, bottomStrip, length);
  507. setMotionBlur(listRecord);
  508. }
  509. }
  510. else {
  511. setMotionBlur(listRecord);
  512. }
  513. _wasGoingVeryFast = goingVeryFast;
  514. var xPosition:Number = (listRecord == _listRecordCurrent) ? _positionCurrent : ((listRecord == _listRecordNext) ? _positionNext : 0);
  515. var yPosition:Number = 2 * scrollPositionY/_screen.stage.stageHeight;
  516. if (goingVeryFast || _reloadIncremental >= 0) {
  517. trace("going very fast");
  518. var textureIndex:int = Math.max(listRecord.firstRowIndex, 0);
  519. var numberOfTextures:int = listRecord.lastRowIndex - listRecord.firstRowIndex;
  520. var count:int = Math.floor(Math.random() * numberOfTextures);
  521. for (var i:int = topStrip; i <= bottomStrip; i++) {
  522. _context3D.setTextureAt(0, _listRowTextures[listRecord.textureIndex][textureIndex + count]);
  523. count = Math.max((count + 1) % numberOfTextures, 1);
  524. _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, Vector.<Number>([ xPosition, yPosition - i * 2 * STRIP_HEIGHT / (_screen.stage.stageHeight * _quality) , 0.0, 0.0 ]) ); // vc0
  525. _context3D.drawTriangles(_indexBuffer, 0, 2);
  526. }
  527. }
  528. else {
  529. for (var j:int = topStrip; j <= bottomStrip; j++) {
  530. _context3D.setTextureAt(0, _listRowTextures[listRecord.textureIndex][j]);
  531. _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, Vector.<Number>([ xPosition, yPosition - j * 2 * STRIP_HEIGHT / (_screen.stage.stageHeight * _quality) , 0.0, 0.0 ]) ); // vc0
  532. _context3D.drawTriangles(_indexBuffer, 0, 2);
  533. }
  534. }
  535. _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, Vector.<Number>([ xPosition, yPosition, 0.0, 0.0 ]) );
  536. if (renderCursorCondition) {
  537. renderCursor(listRecord);
  538. }
  539. else if (!(listRecord.container is UIPicker) && (listRecord == _activeList || Math.abs(listRecord.delta) > SHOW_SCROLLBAR_DELTA || !isNaN(listRecord.destination))) {
  540. renderScrollbar(listRecord);
  541. }
  542. }
  543. }
  544. _context3D.present();
  545. }
  546. /**
  547. * Clear bitmaps and textures
  548. */
  549. override protected function disposeOfTextures():void {
  550. for each (var listRowBitmapData:Vector.<BitmapData> in _listRowBitmapData) {
  551. for each (var bitmapData:BitmapData in listRowBitmapData) {
  552. bitmapData.dispose();
  553. }
  554. }
  555. for each (var listRowTextures:Vector.<Texture> in _listRowTextures) {
  556. for each (var texture:Texture in listRowTextures) {
  557. texture.dispose();
  558. }
  559. }
  560. }
  561. /**
  562. * Sliding transition from currentPage to nextPage. If back=true, slide right.
  563. */
  564. override public function slidePage(currentPage:uint, nextPage:uint, back:Boolean = false):void {
  565. _listRecordCurrent = _listRecords[currentPage];
  566. Sprite(_listRecordCurrent.container).visible = false;
  567. _listRecordNext = _listRecords[nextPage];
  568. _back = back;
  569. _count = - 2*INCREMENT;
  570. _enabled = false;
  571. _stopping = false;
  572. onEnterFrame(this, onEnterFrameSlide);
  573. }
  574. /**
  575. * Update a component appearance within the list.
  576. */
  577. override public function updateComponent(pageNumber:int, component:DisplayObject = null):void {
  578. var listRecord:ListRecord = _listRecords[pageNumber];
  579. var page:Sprite = Sprite(listRecord.container);
  580. var globalPoint:Point = component.localToGlobal(new Point(0,0));
  581. var localPoint:Point = Sprite(page).globalToLocal(globalPoint);
  582. if (page is UIScrollVertical) {
  583. localPoint.y -= UIScrollVertical(page).sliderY;
  584. if (page is UIList) {
  585. UIList(page).clearPressed();
  586. }
  587. }
  588. var fromStrip:int = Math.floor(UI.scale * (localPoint.y - EXTRA) / STRIP_HEIGHT);
  589. var toStrip:int = Math.floor(UI.scale * (localPoint.y + component.height + 2 * EXTRA) / STRIP_HEIGHT);
  590. var listRowBitmapData:Vector.<BitmapData> = _listRowBitmapData[listRecord.textureIndex];
  591. for (var i:int = fromStrip; i <= toStrip; i++) {
  592. if (listRowBitmapData[i]) {
  593. loadNewRow(listRecord, i, 0, true);
  594. }
  595. }
  596. }
  597. /**
  598. * Set Stage3D background colour
  599. */
  600. public function set backgroundColour(value:uint):void {
  601. _backgroundColour = value;
  602. }
  603. /**
  604. * Render sliding transition
  605. */
  606. override protected function drawSlideFrame(event:Event = null):void {
  607. var shift:Number = (_back ? 1.0 : -1.0) * easing(_count) * _centre.width;
  608. _positionCurrent = 2.0 * shift / _screen.stage.stageWidth;
  609. _positionNext = 2.0 * ((_back ? -1.0 : 1.0) * _centre.width + shift) / _screen.stage.stageWidth;
  610. drawLists();
  611. }
  612. /**
  613. * Initialise cursor buffers
  614. */
  615. protected function renderCursorBuffers():void {
  616. _context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
  617. _cursorVertices = _context3D.createVertexBuffer(4, 3);
  618. _cursorUV = _context3D.createVertexBuffer(4, 2);
  619. _cursorUV.uploadFromVector(Vector.<Number>([0, 1, 1, 1, 1, 0, 0, 0]), 0, 4);
  620. var cursorBitmap:BitmapData = new BitmapData(1, 1, true, 0x22000000 | UIList.HIGHLIGHT);
  621. _cursorTexture = _context3D.createTexture(1, 1, Context3DTextureFormat.BGRA, false);
  622. _cursorTexture.uploadFromBitmapData(cursorBitmap);
  623. }
  624. /**
  625. * Render a rectangle, either a row highlight, or a scrollbar
  626. */
  627. protected function renderRectangle(left:Number, top:Number, right:Number, bottom:Number):void {
  628. _cursorVertices.uploadFromVector(Vector.<Number>([
  629. left, bottom, 0.01,
  630. right, bottom, 0.01,
  631. right, top, 0.01,
  632. left, top, 0.01 ]), 0, 4);
  633. clearMotionBlur();
  634. _context3D.setVertexBufferAt( 0, _cursorVertices, 0, Context3DVertexBufferFormat.FLOAT_3 ); //va0
  635. _context3D.setVertexBufferAt( 1, _cursorUV, 0, Context3DVertexBufferFormat.FLOAT_2 ); //va1
  636. _context3D.drawTriangles(_indexBuffer, 0, 2);
  637. }
  638. /**
  639. * Render a row hightlight
  640. */
  641. protected function renderCursor(listRecord:ListRecord):void {
  642. var list:UIScrollVertical = UIScrollVertical(listRecord.container);
  643. var point:Point = list.globalToLocal(new Point(_screen.stage.mouseX, _screen.stage.mouseY));
  644. var rectangle:Rectangle = list.rowRectangle(point.y - list.sliderY);
  645. if (rectangle) {
  646. var globalPoint:Point = list.localToGlobal(new Point(rectangle.x, rectangle.y));
  647. var left:Number = 2 * globalPoint.x / _screen.stage.stageWidth - 1.0;
  648. var top:Number = - 2 * globalPoint.y / _screen.stage.stageHeight + 1.0;
  649. var right:Number = left + 2 * UI.scale * rectangle.width / _screen.stage.stageWidth;
  650. var bottom:Number = top - 2 * UI.scale * rectangle.height / _screen.stage.stageHeight;
  651. _context3D.setTextureAt(0, _cursorTexture);
  652. renderRectangle(left, top, right, bottom);
  653. }
  654. }
  655. /**
  656. * Initialise scrollbar texture
  657. */
  658. protected function newScrollbarTexture(list:IContainerUI):void {
  659. var scrollbarTexture:Texture = null;
  660. if (list is UIScrollVertical && !(list is UIPicker)) {
  661. var colour:uint = list.xml.@scrollBarColour.length() > 0 ? UI.toColourValue(list.xml.@scrollBarColour) : 0x555555;
  662. var scrollbarBitmap:BitmapData = new BitmapData(1, 1, false, 0xFF000000 | colour);
  663. scrollbarTexture = _context3D.createTexture(1, 1, Context3DTextureFormat.BGRA, false);
  664. scrollbarTexture.uploadFromBitmapData(scrollbarBitmap);
  665. }
  666. _scrollbarTextures.push(scrollbarTexture);
  667. }
  668. /**
  669. * Render scrollbar
  670. */
  671. protected function renderScrollbar(listRecord:ListRecord):void {
  672. var list:UIScrollVertical = UIScrollVertical(listRecord.container);
  673. var scroller:Sprite = Sprite(list.pages[0]);
  674. var height:Number = theHeight(list);
  675. var barHeight:Number = (height / scroller.height) * height;
  676. var barPosition:Number = (- list.sliderY / scroller.height) * height + 2 * SCROLLBAR_POSITION;
  677. if (barPosition < SCROLLBAR_POSITION) {
  678. barHeight += barPosition;
  679. barPosition = SCROLLBAR_POSITION;
  680. }
  681. if (barPosition + barHeight > height - 4 * SCROLLBAR_POSITION) {
  682. barHeight -= barPosition + barHeight - height + 4 * SCROLLBAR_POSITION;
  683. }
  684. if (barHeight > 0 && barPosition >= 0) {
  685. var globalPoint:Point = list.localToGlobal(new Point(theWidth(list), barPosition));
  686. var left:Number = 2 * (globalPoint.x - (SCROLLBAR_POSITION + SCROLLBAR_WIDTH) * UI.scale) / _screen.stage.stageWidth - 1.0;
  687. var top:Number = - 2 * (globalPoint.y - UI.scale * list.sliderY) / _screen.stage.stageHeight + 1.0;
  688. var right:Number = left + SCROLLBAR_WIDTH * UI.scale / _screen.stage.stageWidth;
  689. var bottom:Number = top - 2 * UI.scale * barHeight / _screen.stage.stageHeight;
  690. _context3D.setTextureAt(0, _scrollbarTextures[listRecord.textureIndex]);
  691. renderRectangle(left, top, right, bottom );
  692. }
  693. }
  694. }
  695. }