PageRenderTime 55ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/src/away3d/debug/AwayStats.as

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