PageRenderTime 90ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/fp9/Away3D/src/away3d/debug/AwayStats.as

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