PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/haxe/Away3DLite/src/away3dlite/debug/AwayStats.hx

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