PageRenderTime 96ms CodeModel.GetById 3ms RepoModel.GetById 0ms app.codeStats 1ms

/src/away3d/debug/AwayStats.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 867 lines | 580 code | 129 blank | 158 comment | 55 complexity | bbdc4c115443c11489578d732453954f MD5 | raw file
Possible License(s): Apache-2.0
  1. package away3d.debug
  2. {
  3. import away3d.arcane;
  4. import away3d.containers.View3D;
  5. import flash.display.BitmapData;
  6. import flash.display.CapsStyle;
  7. import flash.display.Graphics;
  8. import flash.display.LineScaleMode;
  9. import flash.display.Shape;
  10. import flash.display.Sprite;
  11. import flash.events.Event;
  12. import flash.events.MouseEvent;
  13. import flash.system.System;
  14. import flash.text.TextField;
  15. import flash.text.TextFieldAutoSize;
  16. import flash.text.TextFormat;
  17. import flash.utils.Timer;
  18. import flash.utils.getTimer;
  19. use namespace arcane;
  20. /**
  21. * <p>Stats monitor for Away3D or general use in any project. The widget was designed to
  22. * display all the necessary data in ways that are easily readable, while maintaining a
  23. * tiny size.</p>
  24. *
  25. * <p>The following data is displayed by the widget, either graphically, through
  26. * text, or both.</p>
  27. * <ul>
  28. * <li>Current frame rate in FPS (white in graph/bar)</li>
  29. * <li>SWF frame rate (Stage.frameRate)</li>
  30. * <li>Average FPS (blue in graph/bar)</li>
  31. * <li>Min/Max FPS (only on frame rate bar in minimized mode)</li>
  32. * <li>Current RAM usage (pink in graph)</li>
  33. * <li>Maximum RAM usage</li>
  34. * <li>Number of polygons in scene</li>
  35. * <li>Number of polygons last rendered (yellow in graph)</li>
  36. * </ul>
  37. *
  38. * <p>There are two display modes; standard and minimized, which are alternated by clicking
  39. * the button in the upper right corner, at runtime. The widget can also be configured to
  40. * start in minimized mode by setting the relevant constructor parameter.</p>
  41. *
  42. * <p>All data can be reset at any time, by clicking the lower part of the widget (where
  43. * the RAM and POLY counters are located. The average FPS can be reset separately by
  44. * clicking it's ²displayed value. Furthermore, the stage frame rate can be increased or
  45. * decreased by clicking the upper and lower parts of the graph, respectively. Clicking close
  46. * to the center will increment in small values, and further away will increase the steps.
  47. * The graph itself is only visible in standard (as opposed to minimized) display mode.</p>
  48. *
  49. * <p>The average FPS is calculated using one of two methods, configurable via constructor
  50. * parameters. By setting the meanDataLength to a non-zero value, the number of recorded
  51. * frame rate values on which the average is based can be configured. This has a tiny
  52. * impact on CPU usage, which is the reason why the default number is zero, denoting that
  53. * the average is calculated from a running sum since the widget was last reset.</p>
  54. */
  55. public class AwayStats extends Sprite
  56. {
  57. private var _views:Vector.<View3D>;
  58. private var _timer:Timer;
  59. private var _last_frame_timestamp:Number;
  60. private var _fps:uint;
  61. private var _ram:Number;
  62. private var _max_ram:Number;
  63. private var _min_fps:uint;
  64. private var _avg_fps:Number;
  65. private var _max_fps:uint;
  66. private var _tfaces:uint;
  67. private var _rfaces:uint;
  68. private var _num_frames:uint;
  69. private var _fps_sum:uint;
  70. private var _top_bar:Sprite;
  71. private var _btm_bar:Sprite;
  72. private var _btm_bar_hit:Sprite;
  73. private var _data_format:TextFormat;
  74. private var _label_format:TextFormat;
  75. private var _fps_bar:Shape;
  76. private var _afps_bar:Shape;
  77. private var _lfps_bar:Shape;
  78. private var _hfps_bar:Shape;
  79. private var _diagram:Sprite;
  80. private var _dia_bmp:BitmapData;
  81. private var _mem_points:Array;
  82. private var _mem_graph:Shape;
  83. private var _updates:int;
  84. private var _min_max_btn:Sprite;
  85. private var _fps_tf:TextField;
  86. private var _afps_tf:TextField;
  87. private var _ram_tf:TextField;
  88. private var _poly_tf:TextField;
  89. private var _swhw_tf:TextField;
  90. private var _drag_dx:Number;
  91. private var _drag_dy:Number;
  92. private var _dragging:Boolean;
  93. private var _mean_data:Array;
  94. private var _mean_data_length:int;
  95. private var _enable_reset:Boolean;
  96. private var _enable_mod_fr:Boolean;
  97. private var _transparent:Boolean;
  98. private var _minimized:Boolean;
  99. private var _showing_driv_info:Boolean;
  100. private static const _WIDTH:Number = 125;
  101. private static const _MAX_HEIGHT:Number = 85;
  102. private static const _MIN_HEIGHT:Number = 51;
  103. private static const _UPPER_Y:Number = -1;
  104. private static const _MID_Y:Number = 9;
  105. private static const _LOWER_Y:Number = 19;
  106. private static const _DIAG_HEIGHT:Number = _MAX_HEIGHT - 50;
  107. private static const _BOTTOM_BAR_HEIGHT:Number = 31;
  108. private static const _POLY_COL:uint = 0xffcc00;
  109. private static const _MEM_COL:uint = 0xff00cc;
  110. // Singleton instance reference
  111. private static var _INSTANCE:AwayStats;
  112. /**
  113. * <p>Create an Away3D stats widget. The widget can be added to the stage
  114. * and positioned like any other display object. Once on the stage, you
  115. * can drag the widget to re-position it at runtime.</p>
  116. *
  117. * <p>If you pass a View3D instance, the widget will be able to display
  118. * the total number of faces in your scene, and the amount of faces that
  119. * were rendered during the last render() call. Views can also be registered
  120. * after construction using the registerView() method. Omit the view
  121. * constructor parameter to disable this feature altogether.</p>
  122. *
  123. * @param view A reference to your Away3D view. This is required if you
  124. * want the stats widget to display polycounts.
  125. *
  126. * @param minimized Defines whether the widget should start up in minimized
  127. * mode. By default, it is shown in full-size mode on launch.
  128. *
  129. * @param transparent Defines whether to omit the background plate and print
  130. * statistics directly on top of the underlying stage.
  131. *
  132. * @param meanDataLength The number of frames on which to base the average
  133. * frame rate calculation. The default value of zero indicates that all
  134. * frames since the last reset will be used.
  135. *
  136. * @param enableClickToReset Enables interaction allowing you to reset all
  137. * counters by clicking the bottom bar of the widget. When activated, you
  138. * can also click the average frame rate trace-out to reset just that one
  139. * value.
  140. *
  141. * @param enableModifyFramerate When enabled, allows you to click the upper
  142. * and lower parts of the graph area to increase and decrease SWF frame rate
  143. * respectively.
  144. */
  145. public function AwayStats(view3d:View3D = null, minimized:Boolean = false, transparent:Boolean = false, meanDataLength:uint = 0, enableClickToReset:Boolean = true, enableModifyFrameRate:Boolean = true)
  146. {
  147. super();
  148. _minimized = minimized;
  149. _transparent = transparent;
  150. _enable_reset = enableClickToReset;
  151. _enable_mod_fr = enableModifyFrameRate;
  152. _mean_data_length = meanDataLength;
  153. _views = new Vector.<View3D>();
  154. if (view3d)
  155. _views.push(view3d);
  156. // Store instance for singleton access. Singleton status
  157. // is not enforced, since the widget will work anyway.
  158. if (_INSTANCE)
  159. trace('Creating several statistics windows in one project. Is this intentional?');
  160. _INSTANCE = this;
  161. _fps = 0;
  162. _num_frames = 0;
  163. _avg_fps = 0;
  164. _ram = 0;
  165. _max_ram = 0;
  166. _tfaces = 0;
  167. _rfaces = 0;
  168. _init();
  169. }
  170. public function get max_ram():Number
  171. {
  172. return _max_ram;
  173. }
  174. public function get ram():Number
  175. {
  176. return _ram;
  177. }
  178. public function get avg_fps():Number
  179. {
  180. return _avg_fps;
  181. }
  182. public function get max_fps():uint
  183. {
  184. return _max_fps;
  185. }
  186. public function get fps():int
  187. {
  188. return _fps;
  189. }
  190. private function _init():void
  191. {
  192. _initMisc();
  193. _initTopBar();
  194. _initBottomBar();
  195. _initDiagrams();
  196. _initInteraction();
  197. reset();
  198. _redrawWindow();
  199. addEventListener(Event.ADDED_TO_STAGE, _onAddedToStage);
  200. addEventListener(Event.REMOVED_FROM_STAGE, _onRemovedFromStage);
  201. }
  202. /**
  203. * Holds a reference to the stats widget (or if several have been created
  204. * during session, the one that was last instantiated.) Allows you to set
  205. * properties and register views from anywhere in your code.
  206. */
  207. public static function get instance():AwayStats
  208. {
  209. return _INSTANCE? _INSTANCE : _INSTANCE = new AwayStats();
  210. }
  211. /**
  212. * Add a view to the list of those that are taken into account when
  213. * calculating on-screen and total poly counts. Use this method when the
  214. * stats widget is not instantiated in the same place as where you create
  215. * your view, or when using several views, or when views are created and
  216. * destroyed dynamically at runtime.
  217. */
  218. public function registerView(view3d:View3D):void
  219. {
  220. if (view3d && _views.indexOf(view3d) < 0)
  221. _views.push(view3d);
  222. }
  223. /**
  224. * Remove a view from the list of those that are taken into account when
  225. * calculating on-screen and total poly counts. If the supplied view is
  226. * the only one known to the stats widget, calling this will leave the
  227. * list empty, disabling poly count statistics altogether.
  228. */
  229. public function unregisterView(view3d:View3D):void
  230. {
  231. if (view3d) {
  232. var idx:int = _views.indexOf(view3d);
  233. if (idx >= 0)
  234. _views.splice(idx, 1);
  235. }
  236. }
  237. private function _initMisc():void
  238. {
  239. _timer = new Timer(200, 0);
  240. _timer.addEventListener('timer', _onTimer);
  241. _label_format = new TextFormat('_sans', 9, 0xffffff, true);
  242. _data_format = new TextFormat('_sans', 9, 0xffffff, false);
  243. if (_mean_data_length > 0) {
  244. var i:int;
  245. _mean_data = [];
  246. for (i = 0; i < _mean_data_length; i++)
  247. _mean_data[i] = 0.0;
  248. }
  249. }
  250. /**
  251. * @private
  252. * Draw logo and create title textfield.
  253. */
  254. private function _initTopBar():void
  255. {
  256. var logo:Shape;
  257. var markers:Shape;
  258. //var logo_tf : TextField;
  259. var fps_label_tf:TextField;
  260. var afps_label_tf:TextField;
  261. _top_bar = new Sprite;
  262. _top_bar.graphics.beginFill(0, 0);
  263. _top_bar.graphics.drawRect(0, 0, _WIDTH, 20);
  264. addChild(_top_bar);
  265. logo = new Shape;
  266. logo.x = 9;
  267. logo.y = 7.5;
  268. logo.scaleX = 0.6;
  269. logo.scaleY = 0.6;
  270. logo.graphics.beginFill(0xffffff, 1);
  271. // Left
  272. logo.graphics.moveTo(-0.5, -7);
  273. logo.graphics.curveTo(-0.5, -7.7, -1, -7);
  274. logo.graphics.lineTo(-9, 5);
  275. logo.graphics.curveTo(-9.3, 5.5, -8, 5);
  276. logo.graphics.curveTo(-1, 1, -0.5, -7);
  277. // Right
  278. logo.graphics.moveTo(0.5, -7);
  279. logo.graphics.curveTo(0.5, -7.7, 1, -7);
  280. logo.graphics.lineTo(9, 5);
  281. logo.graphics.curveTo(9.3, 5.5, 8, 5);
  282. logo.graphics.curveTo(1, 1, 0.5, -7);
  283. // Bottom
  284. logo.graphics.moveTo(-8, 7);
  285. logo.graphics.curveTo(-8.3, 6.7, -7.5, 6.3);
  286. logo.graphics.curveTo(0, 2, 7.5, 6.3);
  287. logo.graphics.curveTo(8.3, 6.7, 8, 7);
  288. logo.graphics.lineTo(-8, 7);
  289. _top_bar.addChild(logo);
  290. // Color markers
  291. markers = new Shape;
  292. markers.graphics.beginFill(0xffffff);
  293. markers.graphics.drawRect(20, 7, 4, 4);
  294. markers.graphics.beginFill(0x3388dd);
  295. markers.graphics.drawRect(77, 7, 4, 4);
  296. _top_bar.addChild(markers);
  297. // CURRENT FPS
  298. fps_label_tf = new TextField();
  299. fps_label_tf.defaultTextFormat = _label_format;
  300. fps_label_tf.autoSize = TextFieldAutoSize.LEFT;
  301. fps_label_tf.text = 'FR:';
  302. fps_label_tf.x = 24;
  303. fps_label_tf.y = 2;
  304. fps_label_tf.selectable = false;
  305. _top_bar.addChild(fps_label_tf);
  306. _fps_tf = new TextField;
  307. _fps_tf.defaultTextFormat = _data_format;
  308. _fps_tf.autoSize = TextFieldAutoSize.LEFT;
  309. _fps_tf.x = fps_label_tf.x + 16;
  310. _fps_tf.y = fps_label_tf.y;
  311. _fps_tf.selectable = false;
  312. _top_bar.addChild(_fps_tf);
  313. // AVG FPS
  314. afps_label_tf = new TextField;
  315. afps_label_tf.defaultTextFormat = _label_format;
  316. afps_label_tf.autoSize = TextFieldAutoSize.LEFT;
  317. afps_label_tf.text = 'A:';
  318. afps_label_tf.x = 81;
  319. afps_label_tf.y = 2;
  320. afps_label_tf.selectable = false;
  321. _top_bar.addChild(afps_label_tf);
  322. _afps_tf = new TextField;
  323. _afps_tf.defaultTextFormat = _data_format;
  324. _afps_tf.autoSize = TextFieldAutoSize.LEFT;
  325. _afps_tf.x = afps_label_tf.x + 12;
  326. _afps_tf.y = afps_label_tf.y;
  327. _afps_tf.selectable = false;
  328. _top_bar.addChild(_afps_tf);
  329. // Minimize / maximize button
  330. _min_max_btn = new Sprite;
  331. _min_max_btn.x = _WIDTH - 8;
  332. _min_max_btn.y = 7;
  333. _min_max_btn.graphics.beginFill(0, 0);
  334. _min_max_btn.graphics.lineStyle(1, 0xefefef, 1, true);
  335. _min_max_btn.graphics.drawRect(-4, -4, 8, 8);
  336. _min_max_btn.graphics.moveTo(-3, 2);
  337. _min_max_btn.graphics.lineTo(3, 2);
  338. _min_max_btn.buttonMode = true;
  339. _min_max_btn.addEventListener(MouseEvent.CLICK, _onMinMaxBtnClick);
  340. _top_bar.addChild(_min_max_btn);
  341. }
  342. private function _initBottomBar():void
  343. {
  344. var markers:Shape;
  345. var ram_label_tf:TextField;
  346. var poly_label_tf:TextField;
  347. var swhw_label_tf:TextField;
  348. _btm_bar = new Sprite();
  349. _btm_bar.graphics.beginFill(0, 0.2);
  350. _btm_bar.graphics.drawRect(0, 0, _WIDTH, _BOTTOM_BAR_HEIGHT);
  351. addChild(_btm_bar);
  352. // Hit area for bottom bar (to avoid having textfields
  353. // affect interaction badly.)
  354. _btm_bar_hit = new Sprite;
  355. _btm_bar_hit.graphics.beginFill(0xffcc00, 0);
  356. _btm_bar_hit.graphics.drawRect(0, 1, _WIDTH, _BOTTOM_BAR_HEIGHT - 1);
  357. addChild(_btm_bar_hit);
  358. // Color markers
  359. markers = new Shape;
  360. markers.graphics.beginFill(_MEM_COL);
  361. markers.graphics.drawRect(5, 4, 4, 4);
  362. markers.graphics.beginFill(_POLY_COL);
  363. markers.graphics.drawRect(5, 14, 4, 4);
  364. _btm_bar.addChild(markers);
  365. // CURRENT RAM
  366. ram_label_tf = new TextField;
  367. ram_label_tf.defaultTextFormat = _label_format;
  368. ram_label_tf.autoSize = TextFieldAutoSize.LEFT;
  369. ram_label_tf.text = 'RAM:';
  370. ram_label_tf.x = 10;
  371. ram_label_tf.y = _UPPER_Y;
  372. ram_label_tf.selectable = false;
  373. ram_label_tf.mouseEnabled = false;
  374. _btm_bar.addChild(ram_label_tf);
  375. _ram_tf = new TextField;
  376. _ram_tf.defaultTextFormat = _data_format;
  377. _ram_tf.autoSize = TextFieldAutoSize.LEFT;
  378. _ram_tf.x = ram_label_tf.x + 31;
  379. _ram_tf.y = ram_label_tf.y;
  380. _ram_tf.selectable = false;
  381. _ram_tf.mouseEnabled = false;
  382. _btm_bar.addChild(_ram_tf);
  383. // POLY COUNT
  384. poly_label_tf = new TextField;
  385. poly_label_tf.defaultTextFormat = _label_format;
  386. poly_label_tf.autoSize = TextFieldAutoSize.LEFT;
  387. poly_label_tf.text = 'POLY:';
  388. poly_label_tf.x = 10;
  389. poly_label_tf.y = _MID_Y;
  390. poly_label_tf.selectable = false;
  391. poly_label_tf.mouseEnabled = false;
  392. _btm_bar.addChild(poly_label_tf);
  393. _poly_tf = new TextField;
  394. _poly_tf.defaultTextFormat = _data_format;
  395. _poly_tf.autoSize = TextFieldAutoSize.LEFT;
  396. _poly_tf.x = poly_label_tf.x + 31;
  397. _poly_tf.y = poly_label_tf.y;
  398. _poly_tf.selectable = false;
  399. _poly_tf.mouseEnabled = false;
  400. _btm_bar.addChild(_poly_tf);
  401. // SOFTWARE RENDERER WARNING
  402. swhw_label_tf = new TextField;
  403. swhw_label_tf.defaultTextFormat = _label_format;
  404. swhw_label_tf.autoSize = TextFieldAutoSize.LEFT;
  405. swhw_label_tf.text = 'DRIV:';
  406. swhw_label_tf.x = 10;
  407. swhw_label_tf.y = _LOWER_Y;
  408. swhw_label_tf.selectable = false;
  409. swhw_label_tf.mouseEnabled = false;
  410. _btm_bar.addChild(swhw_label_tf);
  411. _swhw_tf = new TextField;
  412. _swhw_tf.defaultTextFormat = _data_format;
  413. _swhw_tf.autoSize = TextFieldAutoSize.LEFT;
  414. _swhw_tf.x = swhw_label_tf.x + 31;
  415. _swhw_tf.y = swhw_label_tf.y;
  416. _swhw_tf.selectable = false;
  417. _swhw_tf.mouseEnabled = false;
  418. _btm_bar.addChild(_swhw_tf);
  419. }
  420. private function _initDiagrams():void
  421. {
  422. _dia_bmp = new BitmapData(_WIDTH, _DIAG_HEIGHT, true, 0);
  423. _diagram = new Sprite;
  424. _diagram.graphics.beginBitmapFill(_dia_bmp);
  425. _diagram.graphics.drawRect(0, 0, _dia_bmp.width, _dia_bmp.height);
  426. _diagram.graphics.endFill();
  427. _diagram.y = 17;
  428. addChild(_diagram);
  429. _diagram.graphics.lineStyle(1, 0xffffff, 0.03);
  430. _diagram.graphics.moveTo(0, 0);
  431. _diagram.graphics.lineTo(_WIDTH, 0);
  432. _diagram.graphics.moveTo(0, Math.floor(_dia_bmp.height/2));
  433. _diagram.graphics.lineTo(_WIDTH, Math.floor(_dia_bmp.height/2));
  434. // FRAME RATE BAR
  435. _fps_bar = new Shape;
  436. _fps_bar.graphics.beginFill(0xffffff);
  437. _fps_bar.graphics.drawRect(0, 0, _WIDTH, 4);
  438. _fps_bar.x = 0;
  439. _fps_bar.y = 16;
  440. addChild(_fps_bar);
  441. // AVERAGE FPS
  442. _afps_bar = new Shape;
  443. _afps_bar.graphics.lineStyle(1, 0x3388dd, 1, false, LineScaleMode.NORMAL, CapsStyle.SQUARE);
  444. _afps_bar.graphics.lineTo(0, 4);
  445. _afps_bar.y = _fps_bar.y;
  446. addChild(_afps_bar);
  447. // MINIMUM FPS
  448. _lfps_bar = new Shape;
  449. _lfps_bar.graphics.lineStyle(1, 0xff0000, 1, false, LineScaleMode.NORMAL, CapsStyle.SQUARE);
  450. _lfps_bar.graphics.lineTo(0, 4);
  451. _lfps_bar.y = _fps_bar.y;
  452. addChild(_lfps_bar);
  453. // MAXIMUM FPS
  454. _hfps_bar = new Shape;
  455. _hfps_bar.graphics.lineStyle(1, 0x00ff00, 1, false, LineScaleMode.NORMAL, CapsStyle.SQUARE);
  456. _hfps_bar.graphics.lineTo(0, 4);
  457. _hfps_bar.y = _fps_bar.y;
  458. addChild(_hfps_bar);
  459. _mem_points = [];
  460. _mem_graph = new Shape;
  461. _mem_graph.y = _diagram.y + _diagram.height;
  462. addChildAt(_mem_graph, 0);
  463. }
  464. private function _initInteraction():void
  465. {
  466. // Mouse down to drag on the title
  467. _top_bar.addEventListener(MouseEvent.MOUSE_DOWN, _onTopBarMouseDown);
  468. // Reset functionality
  469. if (_enable_reset) {
  470. _btm_bar.mouseEnabled = false;
  471. _btm_bar_hit.addEventListener(MouseEvent.CLICK, _onCountersClick_reset);
  472. _afps_tf.addEventListener(MouseEvent.MOUSE_UP, _onAverageFpsClick_reset, false, 1);
  473. }
  474. // Framerate increase/decrease by clicking on the diagram
  475. if (_enable_mod_fr)
  476. _diagram.addEventListener(MouseEvent.CLICK, _onDiagramClick);
  477. }
  478. private function _redrawWindow():void
  479. {
  480. var plate_height:Number;
  481. plate_height = _minimized? _MIN_HEIGHT : _MAX_HEIGHT;
  482. // Main plate
  483. if (!_transparent) {
  484. this.graphics.clear();
  485. this.graphics.beginFill(0, 0.6);
  486. this.graphics.drawRect(0, 0, _WIDTH, plate_height);
  487. }
  488. // Minimize/maximize button
  489. _min_max_btn.rotation = _minimized? 180 : 0;
  490. // Position counters
  491. _btm_bar.y = plate_height - _BOTTOM_BAR_HEIGHT;
  492. _btm_bar_hit.y = _btm_bar.y;
  493. // Hide/show diagram for minimized/maximized view respectively
  494. _diagram.visible = !_minimized;
  495. _mem_graph.visible = !_minimized;
  496. _fps_bar.visible = _minimized;
  497. _afps_bar.visible = _minimized;
  498. _lfps_bar.visible = _minimized;
  499. _hfps_bar.visible = _minimized;
  500. // Redraw memory graph
  501. if (!_minimized)
  502. _redrawMemGraph();
  503. }
  504. private function _redrawStats():void
  505. {
  506. var dia_y:int;
  507. // Redraw counters
  508. _fps_tf.text = _fps.toString().concat('/', int(stage.frameRate));
  509. _afps_tf.text = Math.round(_avg_fps).toString();
  510. _ram_tf.text = _getRamString(_ram).concat(' / ', _getRamString(_max_ram));
  511. // Move entire diagram
  512. _dia_bmp.scroll(1, 0);
  513. // Only redraw polycount if there is a view available
  514. // or they won't have been calculated properly
  515. if (_views.length > 0) {
  516. // _poly_tf.text = _rfaces.toString().concat(' / ', _tfaces); // TODO: Total faces not yet available in 4.x
  517. _poly_tf.text = _rfaces + "";
  518. // Plot rendered faces
  519. dia_y = _dia_bmp.height - Math.floor(_rfaces/_tfaces*_dia_bmp.height);
  520. _dia_bmp.setPixel32(1, dia_y, _POLY_COL + 0xff000000);
  521. } else
  522. _poly_tf.text = 'n/a (no view)';
  523. // Show software (SW) or hardware (HW)
  524. if (!_showing_driv_info) {
  525. if (_views && _views.length && _views[0].renderer.stage3DProxy && _views[0].renderer.stage3DProxy.context3D) {
  526. var di:String = _views[0].renderer.stage3DProxy.context3D.driverInfo;
  527. _swhw_tf.text = di.substr(0, di.indexOf(' '));
  528. _showing_driv_info = true;
  529. } else
  530. _swhw_tf.text = 'n/a (no view)';
  531. }
  532. // Plot current framerate
  533. dia_y = _dia_bmp.height - Math.floor(_fps/stage.frameRate*_dia_bmp.height);
  534. _dia_bmp.setPixel32(1, dia_y, 0xffffffff);
  535. // Plot average framerate
  536. dia_y = _dia_bmp.height - Math.floor(_avg_fps/stage.frameRate*_dia_bmp.height);
  537. _dia_bmp.setPixel32(1, dia_y, 0xff33bbff);
  538. // Redraw diagrams
  539. if (_minimized) {
  540. _fps_bar.scaleX = Math.min(1, _fps/stage.frameRate);
  541. _afps_bar.x = Math.min(1, _avg_fps/stage.frameRate)*_WIDTH;
  542. _lfps_bar.x = Math.min(1, _min_fps/stage.frameRate)*_WIDTH;
  543. _hfps_bar.x = Math.min(1, _max_fps/stage.frameRate)*_WIDTH;
  544. } else if (_updates%5 == 0)
  545. _redrawMemGraph();
  546. // Move along regardless of whether the graph
  547. // was updated this time around
  548. _mem_graph.x = _updates%5;
  549. _updates++;
  550. }
  551. private function _redrawMemGraph():void
  552. {
  553. var i:int;
  554. var g:Graphics;
  555. var max_val:Number = 0;
  556. // Redraw memory graph (only every 5th update)
  557. _mem_graph.scaleY = 1;
  558. g = _mem_graph.graphics;
  559. g.clear();
  560. g.lineStyle(.5, _MEM_COL, 1, true, LineScaleMode.NONE);
  561. g.moveTo(5*(_mem_points.length - 1), -_mem_points[_mem_points.length - 1]);
  562. for (i = _mem_points.length - 1; i >= 0; --i) {
  563. if (_mem_points[i + 1] == 0 || _mem_points[i] == 0) {
  564. g.moveTo(i*5, -_mem_points[i]);
  565. continue;
  566. }
  567. g.lineTo(i*5, -_mem_points[i]);
  568. if (_mem_points[i] > max_val)
  569. max_val = _mem_points[i];
  570. }
  571. _mem_graph.scaleY = _dia_bmp.height/max_val;
  572. }
  573. private function _getRamString(ram:Number):String
  574. {
  575. var ram_unit:String = 'B';
  576. if (ram > 1048576) {
  577. ram /= 1048576;
  578. ram_unit = 'M';
  579. } else if (ram > 1024) {
  580. ram /= 1024;
  581. ram_unit = 'K';
  582. }
  583. return ram.toFixed(1) + ram_unit;
  584. }
  585. public function reset():void
  586. {
  587. var i:int;
  588. // Reset all values
  589. _updates = 0;
  590. _num_frames = 0;
  591. _min_fps = int.MAX_VALUE;
  592. _max_fps = 0;
  593. _avg_fps = 0;
  594. _fps_sum = 0;
  595. _max_ram = 0;
  596. // Reset RAM usage log
  597. for (i = 0; i < _WIDTH/5; i++)
  598. _mem_points[i] = 0;
  599. // Reset FPS log if any
  600. if (_mean_data) {
  601. for (i = 0; i < _mean_data.length; i++)
  602. _mean_data[i] = 0.0;
  603. }
  604. // Clear diagram graphics
  605. _mem_graph.graphics.clear();
  606. _dia_bmp.fillRect(_dia_bmp.rect, 0);
  607. }
  608. private function _endDrag():void
  609. {
  610. if (this.x < -_WIDTH)
  611. this.x = -(_WIDTH - 20);
  612. else if (this.x > stage.stageWidth)
  613. this.x = stage.stageWidth - 20;
  614. if (this.y < 0)
  615. this.y = 0;
  616. else if (this.y > stage.stageHeight)
  617. this.y = stage.stageHeight - 15;
  618. // Round x/y position to make sure it's on
  619. // whole pixels to avoid weird anti-aliasing
  620. this.x = Math.round(this.x);
  621. this.y = Math.round(this.y);
  622. _dragging = false;
  623. stage.removeEventListener(Event.MOUSE_LEAVE, _onMouseUpOrLeave);
  624. stage.removeEventListener(MouseEvent.MOUSE_UP, _onMouseUpOrLeave);
  625. stage.removeEventListener(MouseEvent.MOUSE_MOVE, _onMouseMove);
  626. }
  627. private function _onAddedToStage(ev:Event):void
  628. {
  629. _timer.start();
  630. addEventListener(Event.ENTER_FRAME, _onEnterFrame);
  631. }
  632. private function _onRemovedFromStage(ev:Event):void
  633. {
  634. _timer.stop();
  635. removeEventListener(Event.ENTER_FRAME, _onTimer);
  636. }
  637. private function _onTimer(ev:Event):void
  638. {
  639. // Store current and max RAM
  640. _ram = System.totalMemory;
  641. if (_ram > _max_ram)
  642. _max_ram = _ram;
  643. // Remove first, add last
  644. if (_updates%5 == 0) {
  645. _mem_points.unshift(_ram/1024);
  646. _mem_points.pop();
  647. }
  648. _tfaces = _rfaces = 0;
  649. // Update polycount if views are available
  650. if (_views.length > 0) {
  651. var i:int;
  652. // Sum up poly counts across all registered views
  653. for (i = 0; i < _views.length; i++) {
  654. _rfaces += _views[i].renderedFacesCount;
  655. //_tfaces += 0;// TODO: total faces
  656. }
  657. }
  658. _redrawStats();
  659. }
  660. private function _onEnterFrame(ev:Event):void
  661. {
  662. var time:Number = getTimer() - _last_frame_timestamp;
  663. // Calculate current FPS
  664. _fps = Math.floor(1000/time);
  665. _fps_sum += _fps;
  666. // Update min/max fps
  667. if (_fps > _max_fps)
  668. _max_fps = _fps;
  669. else if (_fps != 0 && _fps < _min_fps)
  670. _min_fps = _fps;
  671. // If using a limited length log of frames
  672. // for the average, push the latest recorded
  673. // framerate onto fifo, shift one off and
  674. // subtract it from the running sum, to keep
  675. // the sum reflecting the log entries.
  676. if (_mean_data) {
  677. _mean_data.push(_fps);
  678. _fps_sum -= Number(_mean_data.shift());
  679. // Average = sum of all log entries over
  680. // number of log entries.
  681. _avg_fps = _fps_sum/_mean_data_length;
  682. } else {
  683. // Regular average calculation, i.e. using
  684. // a running sum since last reset
  685. _num_frames++;
  686. _avg_fps = _fps_sum/_num_frames;
  687. }
  688. _last_frame_timestamp = getTimer();
  689. }
  690. private function _onDiagramClick(ev:MouseEvent):void
  691. {
  692. stage.frameRate -= Math.floor((_diagram.mouseY - _dia_bmp.height/2)/5);
  693. }
  694. /**
  695. * @private
  696. * Reset just the average FPS counter.
  697. */
  698. private function _onAverageFpsClick_reset(ev:MouseEvent):void
  699. {
  700. if (!_dragging) {
  701. var i:int;
  702. _num_frames = 0;
  703. _fps_sum = 0;
  704. if (_mean_data) {
  705. for (i = 0; i < _mean_data.length; i++)
  706. _mean_data[i] = 0.0;
  707. }
  708. }
  709. }
  710. private function _onCountersClick_reset(ev:MouseEvent):void
  711. {
  712. reset();
  713. }
  714. private function _onMinMaxBtnClick(ev:MouseEvent):void
  715. {
  716. _minimized = !_minimized;
  717. _redrawWindow();
  718. }
  719. private function _onTopBarMouseDown(ev:MouseEvent):void
  720. {
  721. _drag_dx = this.mouseX;
  722. _drag_dy = this.mouseY;
  723. stage.addEventListener(MouseEvent.MOUSE_MOVE, _onMouseMove);
  724. stage.addEventListener(MouseEvent.MOUSE_UP, _onMouseUpOrLeave);
  725. stage.addEventListener(Event.MOUSE_LEAVE, _onMouseUpOrLeave);
  726. }
  727. private function _onMouseMove(ev:MouseEvent):void
  728. {
  729. _dragging = true;
  730. this.x = stage.mouseX - _drag_dx;
  731. this.y = stage.mouseY - _drag_dy;
  732. }
  733. private function _onMouseUpOrLeave(ev:Event):void
  734. {
  735. _endDrag();
  736. }
  737. }
  738. }