├── LICENSE
├── README.md
├── assets
├── AdvancedStats.png
└── StatsContextMenu.jpg
└── src
└── utils
└── debug
└── Stats.as
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2010 Mr.doob, Theo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Advanced Hi-Res-Stats
2 | ========
3 |
4 | Features
5 | --------
6 |
7 | - fps counter.
8 | - current and max memory counters.
9 | - frame 'work' time (in ms) counter.
10 | - Graph of fps,frame time,memory counters.
11 | - increase/decrease width of Stats graph with mouse wheel.
12 | - Monitoring feature. (shows frame code execution time and frame render time.)
13 | - Minimize stats to compact mode. (graph is still drawn in background.)
14 | - can be dragged.
15 | - buttons to change fps count and toggle monitoring feature, and minimize.
16 | - Context menu
17 |
18 |
19 | Screen-shots
20 | ----------
21 |
22 | ### Advanced Stats ###
23 | 
24 | ### Advanced Stats Context menu ###
25 | 
26 |
27 |
28 | Monitoring feature
29 | ------------------
30 |
31 | Monitoring feture is added to better understand how your application performes.
32 |
33 | * Yellow vertical line shows how much total time your frame has for code execution and rendering. If you go over this line your frame rate will drop.
34 | * Red graph will show how much time your running code takes.
35 | * Green graph will show how much time your application takes to render stage view, **AND** idle time if any.
36 | * If you have performance problems - check this graph. It will show how much and then your application is stessed out on executing code or rendering your view.
37 |
38 | Usage
39 | -----
40 |
41 | Simplest:
42 |
43 | this.addChild(new Stats());
44 |
45 |
46 | Make it bigger, smallest possible value is 70.(width):
47 |
48 | addChild(new Stats(150));
49 |
50 | Change initial position (x, y):
51 |
52 | addChild(new Stats(150, 10, 20));
53 |
54 | Make it minimized(isMinimized):
55 |
56 | addChild(new Stats(150, 10, 20, true));
57 |
58 | Make it not draggable(isDraggable):
59 |
60 | addChild(new Stats(150, 10, 20, false, false));
61 |
62 | Enable monitoring feature(isMonitoring):
63 |
64 | addChild(new Stats(150, 10, 20, false, true, true));
65 |
66 | Scale it easily(scale):
67 |
68 | addChild(new Stats(150, 10, 20, false, true, true, 2));
69 |
70 | OR :
71 |
72 | var stats:Stats = new Stats();
73 | this.addChild(stats);
74 | stats.width = 150;
75 | stats.x = 10;
76 | stats.y = 20;
77 | //stats.isMinimized = true;
78 | //stats.isDraggable = false;
79 | stats.isMonitoring = true;
80 | //stats.scale = 2;
81 |
82 |
83 | Controls
84 | --------
85 |
86 | * **BUTTONS plus/minus** - changes frame per second speed application is running.
87 | * **BUTTON toggle monitoring**. - toggle monitoring feature(tracks execution and rendering time in ms)
88 | * **BUTTON toggle mode** - switch between minimized and maximized modes.
89 | * **Mouse wheel**. - increase/decrease width of Stats graph.
90 | * **Drag** - drags if dragging is enabled.
91 | * **RIGHT CLICK** opens context menu.
92 |
93 |
94 |
95 | History
96 | ------
97 | * Fork of https://github.com/mrdoob/Hi-ReS-Stats
98 | * Merged with : https://github.com/rafaelrinaldi/Hi-ReS-Stats AND https://github.com/shamruk/Hi-ReS-Stats
99 |
--------------------------------------------------------------------------------
/assets/AdvancedStats.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MindScriptAct/Advanced-hi-res-stats/c6844447d02024c73d421d6cff4552ba08f37a0c/assets/AdvancedStats.png
--------------------------------------------------------------------------------
/assets/StatsContextMenu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MindScriptAct/Advanced-hi-res-stats/c6844447d02024c73d421d6cff4552ba08f37a0c/assets/StatsContextMenu.jpg
--------------------------------------------------------------------------------
/src/utils/debug/Stats.as:
--------------------------------------------------------------------------------
1 | package utils.debug {
2 | import flash.display.Bitmap;
3 | import flash.display.BitmapData;
4 | import flash.display.CapsStyle;
5 | import flash.display.JointStyle;
6 | import flash.display.LineScaleMode;
7 | import flash.display.Sprite;
8 | import flash.events.ContextMenuEvent;
9 | import flash.events.Event;
10 | import flash.events.MouseEvent;
11 | import flash.geom.Matrix;
12 | import flash.geom.Point;
13 | import flash.geom.Rectangle;
14 | import flash.system.System;
15 | import flash.text.StyleSheet;
16 | import flash.text.TextField;
17 | import flash.text.TextFieldAutoSize;
18 | import flash.ui.ContextMenu;
19 | import flash.ui.ContextMenuItem;
20 | import flash.utils.getTimer;
21 |
22 | /**
23 | * Improved Stats
24 | * https://github.com/MindScriptAct/Hi-ReS-Stats(fork of https://github.com/mrdoob/Hi-ReS-Stats)
25 | * Merged with : https://github.com/rafaelrinaldi/Hi-ReS-Stats AND https://github.com/shamruk/Hi-ReS-Stats
26 | *
27 | * Released under MIT license:
28 | * http://www.opensource.org/licenses/mit-license.php
29 | *
30 | * How to use:
31 | *
32 | * Simplest:
33 | * this.addChild(new Stats());
34 | *
35 | * Make it bigger, smallest possible value is 70.(width):
36 | * addChild(new Stats(150));
37 | *
38 | * Change initial position (x, y):
39 | * addChild(new Stats(150, 10, 20));
40 | *
41 | * Make it minimized(isMinimized):
42 | * addChild(new Stats(150, 10, 20, true));
43 | *
44 | * Make it not draggable(isDraggable):
45 | * addChild(new Stats(150, 10, 20, false, false));
46 | *
47 | * Enable monitoring feature(isMonitoring):
48 | * addChild(new Stats(150, 10, 20, false, true, true));
49 | *
50 | * Scale it easealy(scale):
51 | * addChild(new Stats(150, 10, 20, false, true, true, 2));
52 | *
53 | * OR :
54 | *
55 | * var stats:Stats = new Stats();
56 | * this.addChild(stats);
57 | * stats.width = 150;
58 | * stats.x = 10;
59 | * stats.y = 200;
60 | * //stats.isMinimized = true;
61 | * //stats.isDraggable = false;
62 | * stats.isMonitoring = true;
63 | * //stats.scale = 2;
64 | *
65 | **/
66 |
67 | public class Stats extends Sprite {
68 |
69 | // stats default size.
70 | private const DEFAULT_WIDTH:int = 70;
71 | private const DEFAULT_HEIGHT:int = 100;
72 | private const MINIMIZED_WIDTH:int = 62;
73 | private const MINIMIZED_HEIGHT:int = 13;
74 | private const MONITOR_WIDTH:int = 500;
75 | // fps button consts
76 | private const BUTTON_XPOS:int = 62;
77 | private const BUTTON_YPOS:int = 2;
78 | private const BUTTON_SIZE:Number = 6;
79 | private const BUTTON_GAP:int = 9;
80 | private const BUTTON_MONITOR_GAP:int = 21;
81 | //
82 | private const SCROLL_SIZE:Number = 10;
83 | private const MINIMIZE_BUTTON_SIZE:Number = 5;
84 |
85 | // context menu captions
86 | private const ZOOM_CAPTION_x2:String = "Zoom to *2";
87 | private const ZOOM_CAPTION_x1:String = "Zoom to *1";
88 | private const MINIMIZE_CAPTION_ON:String = "Maximize.";
89 | private const MINIMIZE_CAPTION_OFF:String = "Minimize.";
90 | private const DRAG_CAPTION_ON:String = "Disable dragging.";
91 | private const DRAG_CAPTION_OFF:String = "Enable dragging.";
92 | private const MONITOR_CAPTION_ON:String = "Disable monitoring.";
93 | private const MONITOR_CAPTION_OFF:String = "Enable monitoring.";
94 | private const KILL_CAPTION:String = " !!! Kill Stats object. ಠ_ಠ";
95 |
96 | // bonus width addet to default WIDTH.
97 | private var _bonusWidth:int = 0;
98 |
99 | // stats data in XML format.
100 | private var statData:XML;
101 | private var statDataMinimized:XML;
102 |
103 | // textField for stats information
104 | private var statsText:TextField;
105 | private var style:StyleSheet;
106 |
107 | // reacent getTimer value.
108 | private var timer:uint = 0;
109 |
110 | // current stat data
111 | private var fps:int = 0;
112 | private var lastTimer:int = 0;
113 | private var tickTimer:int = 0;
114 | private var mem:Number = 0;
115 | private var memMax:Number = 0;
116 |
117 | // data for monitoring
118 | private var frameRateTime:int;
119 | private var codeTime:uint;
120 | private var frameTime:uint;
121 |
122 | // graph draw object
123 | private var graph_BD:BitmapData;
124 | private var clearRect:Rectangle;
125 |
126 | // monitoring draw object
127 | private var monitorView_BD:BitmapData;
128 | private var monitorView:Bitmap;
129 | private var codeRect:Rectangle;
130 | private var renderRect:Rectangle;
131 | private var clearMonitorRect:Rectangle;
132 | private var frameRateRect:Rectangle;
133 | private var monitoringHistoryRect:Rectangle;
134 | private var monitoringHistoryNewPoint:Point;
135 | private var monitorSeparatorRect:Rectangle;
136 |
137 | // context menu items.
138 | private var zoomMenuItem:ContextMenuItem;
139 | private var minimizeMenuItem:ContextMenuItem;
140 | private var dragMenuItem:ContextMenuItem;
141 | private var monitorMenuItem:ContextMenuItem;
142 |
143 | // current graph draw value.
144 | private var fpsGraph:int = 0;
145 | private var memGraph:int = 0;
146 | private var memMaxGraph:int = 0;
147 |
148 | // object for collor values. (it performs tini bit faster then constants.)
149 | private var colors:StatColors = new StatColors();
150 |
151 | // flag for counter to be in minimized state. (stats are still tracked, but not shown.)
152 | private var _isMinimized:Boolean;
153 |
154 | // flag for stats beeing dragable or not.
155 | private var _isDraggable:Boolean = false;
156 |
157 | // flag to show application execution and render monitoring.
158 | private var _isMonitoring:Boolean = false;
159 |
160 | // scaling parameter for simple scaling.
161 | private var _scale:Number = 1;
162 |
163 | /**
164 | * Stats - FPS, MS and MEM, all in one.
165 | * @param width Starting width of Stats object. If it is less then 70 - it will be set to default(70).
166 | * @param x initial x position
167 | * @param y initial y position
168 | * @param isMinimized initial minimize status. (not minimized by default)
169 | * @param isDraggable makes stats dragable or not. (dragable by default)
170 | * @param isMonitoring flag to start monitoring frame execution time. (will not monitor by default.)
171 | * @param scale simplified scaling of stat object.
172 | */
173 | public function Stats(width:int = 70, x:int = 0, y:int = 0, isMinimized:Boolean = false, isDraggable:Boolean = true, isMonitoring:Boolean = false, scale:Number = 1):void {
174 | //
175 | this._isDraggable = isDraggable;
176 | this._isMonitoring = isMonitoring;
177 | this._isMinimized = isMinimized;
178 | this._scale = scale;
179 |
180 | initContextMenu();
181 |
182 | // calculate increased width.
183 | bonusWidth = width - DEFAULT_WIDTH;
184 |
185 | // initial positioning
186 | this.x = x;
187 | this.y = y;
188 |
189 | // stat data stored in XML formated text.
190 | statData =
191 | FPS:
192 | MS:
193 | MEM:
194 | MAX:
195 | ;
196 |
197 | statDataMinimized =
198 | FPS:
199 | ;
200 |
201 | // text fild to show all stats.
202 | // TODO : test if it's not more simple just to have 4 text fields without xml and css...
203 | statsText = new TextField();
204 | statsText.autoSize = TextFieldAutoSize.LEFT;
205 | statsText.styleSheet = style;
206 | statsText.condenseWhite = true;
207 | statsText.selectable = false;
208 | statsText.mouseEnabled = false;
209 |
210 | // style for stats.
211 | style = new StyleSheet();
212 | style.setStyle('xmlData', {fontSize: '9px', fontFamily: '_sans', leading: '-2px'});
213 | style.setStyle('fps', {color: "#" + (colors.fps).toString(16)});
214 | style.setStyle('ms', {color: "#" + (colors.ms).toString(16)});
215 | style.setStyle('mem', {color: "#" + (colors.mem).toString(16)});
216 | style.setStyle('memMax', {color: "#" + (colors.memMax).toString(16)});
217 | statsText.styleSheet = style;
218 |
219 | //
220 | graph_BD = new BitmapData(DEFAULT_WIDTH + _bonusWidth, DEFAULT_HEIGHT - 50, false, colors.bg);
221 |
222 | //
223 | addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
224 | addEventListener(Event.REMOVED_FROM_STAGE, destroy, false, 0, true);
225 | //
226 | this.mouseChildren = false;
227 | }
228 |
229 | // init righth button click menu.
230 | private function initContextMenu():void {
231 | var menu:ContextMenu = new ContextMenu();
232 | zoomMenuItem = new ContextMenuItem(ZOOM_CAPTION_x2);
233 | zoomMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handleTogleZoom, false, 0, true);
234 | if (_scale != 1) {
235 | zoomMenuItem.caption = ZOOM_CAPTION_x1;
236 | }
237 | minimizeMenuItem = new ContextMenuItem(MINIMIZE_CAPTION_OFF, true);
238 | minimizeMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, toggleMinimize, false, 0, true);
239 | if (_isMinimized) {
240 | minimizeMenuItem.caption = MINIMIZE_CAPTION_ON;
241 | }
242 | dragMenuItem = new ContextMenuItem(DRAG_CAPTION_ON);
243 | dragMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, toggleDrag, false, 0, true);
244 | if (!_isDraggable) {
245 | dragMenuItem.caption = DRAG_CAPTION_ON;
246 | }
247 | monitorMenuItem = new ContextMenuItem(MONITOR_CAPTION_OFF);
248 | monitorMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, toggleMonitor, false, 0, true);
249 | if (_isMonitoring) {
250 | monitorMenuItem.caption = MONITOR_CAPTION_ON;
251 | }
252 | var killMenuItem:ContextMenuItem = new ContextMenuItem(KILL_CAPTION, true);
253 | killMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, destroy, false, 0, true);
254 | if(menu.customItems != null){
255 | menu.customItems.push( //
256 | zoomMenuItem, //
257 | minimizeMenuItem, //
258 | dragMenuItem, //
259 | monitorMenuItem, //
260 | killMenuItem //
261 | );
262 | }
263 |
264 | this.contextMenu = menu;
265 | }
266 |
267 | //----------------------------------
268 | // Context menu click handlers
269 | //----------------------------------
270 |
271 | private function handleTogleZoom(event:ContextMenuEvent):void {
272 | if (_scale == 1) {
273 | scale = 2;
274 | } else {
275 | scale = 1;
276 | }
277 | }
278 |
279 | private function toggleMinimize(event:ContextMenuEvent):void {
280 | isMinimized = !_isMinimized;
281 | }
282 |
283 | private function toggleDrag(event:ContextMenuEvent):void {
284 | isDraggable = !_isDraggable;
285 | }
286 |
287 | private function toggleMonitor(event:ContextMenuEvent):void {
288 | isMonitoring = !_isMonitoring;
289 | }
290 |
291 | //----------------------------------
292 | // init
293 | //----------------------------------
294 |
295 | // stats are initialized then put tu stage.
296 | private function init(event:Event):void {
297 | // add text
298 | addChild(statsText);
299 | // set initial time in ms for 1 frame.
300 | frameRateTime = Math.round(1000 / this.stage.frameRate);
301 |
302 | // init objects for later reuse.
303 | codeRect = new Rectangle(0, 0, -1, 10);
304 | renderRect = new Rectangle(-1, 0, -1, 10);
305 | clearMonitorRect = new Rectangle(-1, 0, MONITOR_WIDTH, 10);
306 | frameRateRect = new Rectangle(frameRateTime, 0, 1, 10);
307 | monitoringHistoryRect = new Rectangle(0, 9, MONITOR_WIDTH, DEFAULT_HEIGHT);
308 | monitoringHistoryNewPoint = new Point(0, 10);
309 | monitorSeparatorRect = new Rectangle(0, 8, MONITOR_WIDTH, 1)
310 |
311 | // add events.
312 | addEventListener(MouseEvent.CLICK, handleClick);
313 | addEventListener(Event.ENTER_FRAME, handleFrameTick);
314 | addEventListener(MouseEvent.MOUSE_WHEEL, handleMouseWheel);
315 |
316 | // init draging feature by using setter.
317 | isDraggable = _isDraggable;
318 |
319 | // activate scaling setter.
320 | scale = _scale;
321 |
322 | // draw bg and graph
323 | initDrawArea();
324 |
325 | }
326 |
327 | // funciton to init or reInit all visuol object.
328 | private function initDrawArea():void {
329 | initBackground();
330 | initGraph();
331 | initMonitoring();
332 | initMinimizeButton();
333 | }
334 |
335 | // draw bg with buttons
336 | private function initBackground():void {
337 | graphics.clear();
338 | graphics.beginFill(colors.bg);
339 | if (_isMinimized) {
340 | graphics.drawRect(0, 0, MINIMIZED_WIDTH, MINIMIZED_HEIGHT);
341 | } else {
342 | graphics.drawRect(0, 0, DEFAULT_WIDTH + _bonusWidth, DEFAULT_HEIGHT);
343 | }
344 | graphics.endFill();
345 |
346 | if (!_isMinimized) {
347 | // draw fps UP/DOWN buttons
348 | graphics.lineStyle(1, colors.fps, 1, true, LineScaleMode.NORMAL, CapsStyle.SQUARE, JointStyle.MITER);
349 | // plus sign button
350 | graphics.drawRect(BUTTON_XPOS, BUTTON_YPOS, BUTTON_SIZE, BUTTON_SIZE);
351 | graphics.moveTo(BUTTON_XPOS + BUTTON_SIZE / 2, BUTTON_YPOS);
352 | graphics.lineTo(BUTTON_XPOS + BUTTON_SIZE / 2, BUTTON_YPOS + BUTTON_SIZE);
353 | graphics.moveTo(BUTTON_XPOS, BUTTON_YPOS + BUTTON_SIZE / 2);
354 | graphics.lineTo(BUTTON_XPOS + BUTTON_SIZE, BUTTON_YPOS + BUTTON_SIZE / 2);
355 | // minus sign button
356 | graphics.drawRect(BUTTON_XPOS, BUTTON_YPOS + BUTTON_GAP, BUTTON_SIZE, BUTTON_SIZE);
357 | graphics.moveTo(BUTTON_XPOS, BUTTON_YPOS + BUTTON_SIZE / 2 + BUTTON_GAP);
358 | graphics.lineTo(BUTTON_XPOS + BUTTON_SIZE, BUTTON_YPOS + BUTTON_SIZE / 2 + BUTTON_GAP);
359 | // monitoring on/off button.
360 | graphics.lineStyle(1, colors.monitorSeparator, 1, true, LineScaleMode.NORMAL, CapsStyle.SQUARE, JointStyle.MITER);
361 | graphics.drawRect(BUTTON_XPOS, BUTTON_YPOS + BUTTON_MONITOR_GAP, BUTTON_SIZE, BUTTON_SIZE);
362 | graphics.lineStyle(1, colors.executionTime, 1, true, LineScaleMode.NORMAL, CapsStyle.SQUARE, JointStyle.MITER);
363 | graphics.moveTo(BUTTON_XPOS + 1, BUTTON_YPOS + BUTTON_MONITOR_GAP + 1);
364 | graphics.lineTo(BUTTON_XPOS + 1, BUTTON_YPOS + BUTTON_MONITOR_GAP + BUTTON_SIZE - 1);
365 | graphics.moveTo(BUTTON_XPOS + 2, BUTTON_YPOS + BUTTON_MONITOR_GAP + 1);
366 | graphics.lineTo(BUTTON_XPOS + 2, BUTTON_YPOS + BUTTON_MONITOR_GAP + BUTTON_SIZE - 1);
367 | graphics.lineStyle(1, colors.ms, 1, true, LineScaleMode.NORMAL, CapsStyle.SQUARE, JointStyle.MITER);
368 | graphics.moveTo(BUTTON_XPOS + 2, BUTTON_YPOS + BUTTON_MONITOR_GAP + 1);
369 | graphics.lineTo(BUTTON_XPOS + 3, BUTTON_YPOS + BUTTON_MONITOR_GAP + 1);
370 | graphics.moveTo(BUTTON_XPOS + 3, BUTTON_YPOS + BUTTON_MONITOR_GAP + 2);
371 | graphics.lineTo(BUTTON_XPOS + 4, BUTTON_YPOS + BUTTON_MONITOR_GAP + 2);
372 | graphics.moveTo(BUTTON_XPOS + 3, BUTTON_YPOS + BUTTON_MONITOR_GAP + 2);
373 | graphics.lineTo(BUTTON_XPOS + 3, BUTTON_YPOS + BUTTON_MONITOR_GAP + 3);
374 | graphics.moveTo(BUTTON_XPOS + 2, BUTTON_YPOS + BUTTON_MONITOR_GAP + 4);
375 | graphics.lineTo(BUTTON_XPOS + 4, BUTTON_YPOS + BUTTON_MONITOR_GAP + 4);
376 | graphics.moveTo(BUTTON_XPOS + 2, BUTTON_YPOS + BUTTON_MONITOR_GAP + 5);
377 | graphics.lineTo(BUTTON_XPOS + 3, BUTTON_YPOS + BUTTON_MONITOR_GAP + 5);
378 | }
379 | //
380 | graphics.lineStyle();
381 | }
382 |
383 | // draw graph
384 | private function initGraph():void {
385 | if (!_isMinimized) {
386 | if (graph_BD) {
387 | var oldGraph_BD:BitmapData = graph_BD;
388 | }
389 | graph_BD = new BitmapData(DEFAULT_WIDTH + _bonusWidth, DEFAULT_HEIGHT - 50, false, colors.bg);
390 |
391 | graphics.beginBitmapFill(graph_BD, new Matrix(1, 0, 0, 1, 0, 50));
392 | graphics.drawRect(0, 50, DEFAULT_WIDTH + _bonusWidth, DEFAULT_HEIGHT - 50);
393 | // if oldGraph is set - drow its content into new graph.
394 | if (oldGraph_BD) {
395 | graph_BD.copyPixels(oldGraph_BD, oldGraph_BD.rect, new Point(graph_BD.width - oldGraph_BD.width, 0));
396 | oldGraph_BD.dispose();
397 | }
398 | }
399 | }
400 |
401 | // init monitoring feature
402 | private function initMonitoring():void {
403 | // draw button outline.
404 | if (!_isMinimized) {
405 | if (_isMonitoring) {
406 | graphics.lineStyle(1, 0xFFFFFF, 1, true, LineScaleMode.NORMAL, CapsStyle.SQUARE, JointStyle.MITER);
407 | graphics.drawRect(BUTTON_XPOS, BUTTON_YPOS + BUTTON_MONITOR_GAP, BUTTON_SIZE, BUTTON_SIZE);
408 | graphics.drawRect(BUTTON_XPOS - 1, BUTTON_YPOS - 1 + BUTTON_MONITOR_GAP, BUTTON_SIZE + 2, BUTTON_SIZE + 2);
409 | } else {
410 | graphics.lineStyle(1, colors.monitorSeparator, 1, true, LineScaleMode.NORMAL, CapsStyle.SQUARE, JointStyle.MITER);
411 | graphics.drawRect(BUTTON_XPOS, BUTTON_YPOS + BUTTON_MONITOR_GAP, BUTTON_SIZE, BUTTON_SIZE);
412 | graphics.lineStyle(1, colors.bg, 1, true, LineScaleMode.NORMAL, CapsStyle.SQUARE, JointStyle.MITER);
413 | graphics.drawRect(BUTTON_XPOS - 1, BUTTON_YPOS - 1 + BUTTON_MONITOR_GAP, BUTTON_SIZE + 2, BUTTON_SIZE + 2);
414 | }
415 | }
416 | graphics.lineStyle();
417 |
418 | // handle monitorView
419 | if (_isMonitoring) {
420 | if (!monitorView) {
421 | monitorView_BD = new BitmapData(MONITOR_WIDTH, DEFAULT_HEIGHT, false, colors.bg);
422 | monitorView = new Bitmap(monitorView_BD);
423 | }
424 | if (!this.contains(monitorView)) {
425 | this.addChild(monitorView);
426 | }
427 | monitorView.x = DEFAULT_WIDTH + _bonusWidth + 5;
428 | } else {
429 | if (monitorView_BD) {
430 | monitorView_BD.fillRect(monitorView_BD.rect, colors.bg);
431 | }
432 | if (monitorView) {
433 | if (this.contains(monitorView)) {
434 | this.removeChild(monitorView);
435 | }
436 | }
437 | }
438 |
439 | // hide monitoring if minimized.
440 | if (_isMinimized) {
441 | if (monitorView) {
442 | if (this.contains(monitorView)) {
443 | this.removeChild(monitorView);
444 | }
445 | }
446 | }
447 |
448 | // handle events
449 | if (_isMonitoring) {
450 | if (!this.stage.hasEventListener(Event.RENDER)) {
451 | this.stage.addEventListener(Event.RENDER, handleFrameRender);
452 | }
453 | } else {
454 | if (this.stage.hasEventListener(Event.RENDER)) {
455 | this.stage.removeEventListener(Event.RENDER, handleFrameRender);
456 | }
457 | }
458 | }
459 |
460 | // draw minimize button.
461 | private function initMinimizeButton():void {
462 | graphics.beginFill(0xFF0000)
463 | graphics.moveTo(-1, 4);
464 | if (_isMinimized) {
465 | graphics.lineTo(4, 4);
466 | } else {
467 | graphics.lineTo(-1, -1);
468 | }
469 | graphics.lineTo(4, -1);
470 | graphics.lineTo(-1, 4);
471 | graphics.endFill();
472 |
473 | if (_isMinimized) {
474 | // resize text field down. (so it will not increase boundary area for mouse clicks..)
475 | statsText.text = "...";
476 | statsText.height = statsText.textWidth;
477 | }
478 | }
479 |
480 | //----------------------------------
481 | //
482 | //----------------------------------
483 |
484 | private function destroy(event:Event):void {
485 | // clear bg
486 | graphics.clear();
487 |
488 | // remove all childs.
489 | while (numChildren > 0) {
490 | removeChildAt(0);
491 | }
492 |
493 | // dispose graph bitmap.
494 | graph_BD.dispose();
495 |
496 | // remove listeners.
497 | removeEventListener(MouseEvent.CLICK, handleClick);
498 | removeEventListener(Event.ENTER_FRAME, handleFrameTick);
499 |
500 | if (_isDraggable) {
501 | stage.removeEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
502 | stage.removeEventListener(Event.MOUSE_LEAVE, mouseLeaveHandler);
503 | removeEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
504 | }
505 | }
506 |
507 | // every frame calculate frame stats.
508 | private function handleFrameTick(event:Event):void {
509 |
510 | frameTime = getTimer() - timer;
511 | timer = getTimer();
512 |
513 | // calculate time change from last tick in ms.
514 | var tickTime:uint = timer - tickTimer;
515 |
516 | // check if more then 1 second passed.
517 | if (tickTime >= 1000) {
518 | //
519 | tickTimer = timer;
520 |
521 | // calculate ammount of missed seconds. (this can happen then player hangs more then 2 seccond on a job.)
522 | var missedTicks:uint = (tickTime - 1000) / 1000;
523 |
524 | // get current memory.
525 | mem = Number((System.totalMemory * 0.000000954).toFixed(3));
526 |
527 | // update max memory.
528 | if (memMax < mem) {
529 | memMax = mem;
530 | }
531 |
532 | // calculate graph point positios.
533 | fpsGraph = Math.min(graph_BD.height, (fps / stage.frameRate) * graph_BD.height);
534 | memGraph = Math.min(graph_BD.height, Math.sqrt(Math.sqrt(mem * 5000))) - 2;
535 | memMaxGraph = Math.min(graph_BD.height, Math.sqrt(Math.sqrt(memMax * 5000))) - 2;
536 |
537 | // move graph by 1 pixels for every second passed.
538 | graph_BD.scroll(-1 - missedTicks, 0);
539 |
540 | // clear rectangle area for new graph data.
541 | if (missedTicks) {
542 | graph_BD.fillRect(new Rectangle(graph_BD.width - 1 - missedTicks, 0, 1 + missedTicks, DEFAULT_HEIGHT - 50), colors.bg);
543 | } else {
544 | graph_BD.fillRect(clearRect, colors.bg);
545 | }
546 |
547 | // draw missed seconds. (if player failed to respond for more then 1 second that means it was hanging, and FPS was < 1 for that time.)
548 | while (missedTicks) {
549 | graph_BD.setPixel(graph_BD.width - 1 - missedTicks, graph_BD.height - 1, colors.fps);
550 | missedTicks--;
551 | }
552 |
553 | // draw current graph data.
554 | graph_BD.setPixel(graph_BD.width - 1, graph_BD.height - ((timer - lastTimer) >> 1), colors.ms);
555 | graph_BD.setPixel(graph_BD.width - 1, graph_BD.height - memGraph, colors.mem);
556 | graph_BD.setPixel(graph_BD.width - 1, graph_BD.height - memMaxGraph, colors.memMax);
557 | graph_BD.setPixel(graph_BD.width - 1, graph_BD.height - fpsGraph, colors.fps);
558 |
559 | // update data for new frame stats.
560 | if (_isMinimized) {
561 | statDataMinimized.fps = "FPS: " + fps + " / " + stage.frameRate;
562 | } else {
563 | statData.fps = "FPS: " + fps + " / " + stage.frameRate;
564 | statData.mem = "MEM: " + mem;
565 | statData.memMax = "MAX: " + memMax;
566 | }
567 |
568 | // frame count for 1 second handled - reset it.
569 | fps = 0;
570 | }
571 |
572 | // handle monitoring
573 | if (_isMonitoring) {
574 | this.stage.invalidate();
575 |
576 | // drawCodeTime
577 | codeRect.width = codeTime;
578 | monitorView_BD.fillRect(codeRect, colors.executionTime);
579 | // draw frameTime
580 | renderRect.x = codeTime;
581 | renderRect.width = frameTime - codeTime;
582 | monitorView_BD.fillRect(renderRect, colors.ms);
583 | // clean rest of the line
584 | clearMonitorRect.x = frameTime;
585 | monitorView_BD.fillRect(clearMonitorRect, colors.bg);
586 | // frame time delimeter
587 | monitorView_BD.fillRect(frameRateRect, colors.fps);
588 | //
589 | // move monitoring history one line down
590 | monitorView_BD.copyPixels(monitorView_BD, monitoringHistoryRect, monitoringHistoryNewPoint);
591 | // separator for main graph and log.
592 | monitorView_BD.fillRect(monitorSeparatorRect, colors.monitorSeparator);
593 | }
594 |
595 | // time in ms for one frame tick.
596 | statData.ms = "MS: " + frameTime;
597 |
598 | // update data text.
599 | if (_isMinimized) {
600 | statsText.htmlText = statDataMinimized;
601 | } else {
602 | statsText.htmlText = statData;
603 | }
604 | // increse frame tick count by 1.
605 | fps++;
606 | //
607 | lastTimer = timer;
608 | }
609 |
610 | // handle click over stat object.
611 | private function handleClick(event:MouseEvent):void {
612 | // check if click is in button area.
613 | if (!_isMinimized) {
614 | if (this.mouseX > BUTTON_XPOS) {
615 | if (this.mouseX < BUTTON_XPOS + BUTTON_SIZE) {
616 | // add fps button
617 | if (this.mouseY > BUTTON_YPOS) {
618 | if (this.mouseY < BUTTON_YPOS + BUTTON_SIZE) {
619 | stage.frameRate = Math.round(stage.frameRate + 1);
620 | statData.fps = "FPS: " + fps + " / " + stage.frameRate;
621 | statsText.htmlText = statData;
622 | }
623 | }
624 | // remove fps button
625 | if (this.mouseY > BUTTON_YPOS + BUTTON_GAP) {
626 | if (this.mouseY < BUTTON_YPOS + BUTTON_SIZE + BUTTON_GAP) {
627 | stage.frameRate = Math.round(stage.frameRate - 1);
628 | statData.fps = "FPS: " + fps + " / " + stage.frameRate;
629 | statsText.htmlText = statData;
630 | }
631 | }
632 | // toggle monitoring button
633 | if (this.mouseY > BUTTON_YPOS + BUTTON_MONITOR_GAP) {
634 | if (this.mouseY < BUTTON_YPOS + BUTTON_SIZE + BUTTON_MONITOR_GAP) {
635 | isMonitoring = !_isMonitoring;
636 | }
637 | }
638 | // recalculate fpsRate. (needed if it is changed.)
639 | if (_isMonitoring) {
640 | frameRateTime = Math.round(1000 / this.stage.frameRate);
641 | frameRateRect.x = frameRateTime;
642 | }
643 | }
644 | }
645 | }
646 | // minimize button
647 | if (this.mouseX < MINIMIZE_BUTTON_SIZE) {
648 | if (this.mouseY < MINIMIZE_BUTTON_SIZE) {
649 | isMinimized = !_isMinimized;
650 | }
651 | }
652 | }
653 |
654 | // handle mouseWheel
655 | private function handleMouseWheel(event:MouseEvent):void {
656 | if (event.delta > 0) {
657 | bonusWidth = _bonusWidth + SCROLL_SIZE;
658 | } else {
659 | bonusWidth = _bonusWidth - SCROLL_SIZE;
660 | }
661 | // redraw bg
662 | initDrawArea();
663 | }
664 |
665 | //
666 | private function handleFrameRender(event:Event):void {
667 | codeTime = getTimer() - timer;
668 | }
669 |
670 | //----------------------------------
671 | // Dragging functions
672 | //----------------------------------
673 |
674 | // start dragging
675 | private function handleMouseDown(event:MouseEvent):void {
676 | this.stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
677 | }
678 |
679 | // stop dragging
680 | private function handleMouseUp(event:MouseEvent):void {
681 | this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
682 | }
683 |
684 | // handle dragging
685 | private function mouseMoveHandler(event:MouseEvent):void {
686 | // calculete new possitions.
687 | if (_isMinimized) {
688 | this.x = this.stage.mouseX - MINIMIZED_WIDTH * 0.5;
689 | this.y = this.stage.mouseY - MINIMIZED_HEIGHT * 0.5;
690 | } else {
691 | this.x = this.stage.mouseX - DEFAULT_WIDTH * 0.5;
692 | this.y = this.stage.mouseY - DEFAULT_HEIGHT * 0.5;
693 | }
694 | fitToStage();
695 | }
696 |
697 | private function fitToStage():void {
698 | // handle x bounds
699 | if (this.x > this.stage.stageWidth - this.width) {
700 | this.x = this.stage.stageWidth - this.width;
701 | }
702 | if (this.x < 0) {
703 | this.x = 0;
704 | }
705 | // handle y bounds.
706 | if (this.y > this.stage.stageHeight - this.height) {
707 | this.y = this.stage.stageHeight - this.height;
708 | }
709 | if (this.y < 0) {
710 | this.y = 0;
711 | }
712 | }
713 |
714 | // handle mouse leaving the screen.
715 | private function mouseLeaveHandler(event:Event):void {
716 | this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
717 | }
718 |
719 | //----------------------------------
720 | // get/set
721 | //----------------------------------
722 |
723 | /**
724 | * flag for stats beeing dragable or not.
725 | */
726 | public function get isDraggable():Boolean {
727 | return _isDraggable;
728 | }
729 |
730 | /**
731 | * flag for stats beeing dragable or not.
732 | */
733 | public function set isDraggable(value:Boolean):void {
734 | _isDraggable = value;
735 | if (_isDraggable) {
736 | dragMenuItem.caption = DRAG_CAPTION_ON;
737 | if (stage) {
738 | if (!stage.hasEventListener(MouseEvent.MOUSE_UP)) {
739 | stage.addEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
740 | stage.addEventListener(Event.MOUSE_LEAVE, mouseLeaveHandler);
741 | addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
742 | }
743 | }
744 | } else {
745 | dragMenuItem.caption = DRAG_CAPTION_OFF;
746 | if (stage) {
747 | if (stage.hasEventListener(MouseEvent.MOUSE_UP)) {
748 | stage.removeEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
749 | stage.removeEventListener(Event.MOUSE_LEAVE, mouseLeaveHandler);
750 | removeEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
751 | }
752 | }
753 | }
754 | }
755 |
756 | /**
757 | * flag to show application execution and render monitoring.
758 | */
759 | public function get isMonitoring():Boolean {
760 | return _isMonitoring;
761 | }
762 |
763 | /**
764 | * flag to show application execution and render monitoring.
765 | */
766 | public function set isMonitoring(value:Boolean):void {
767 | _isMonitoring = value;
768 | initMonitoring();
769 | fitToStage();
770 | if (_isMonitoring) {
771 | monitorMenuItem.caption = MONITOR_CAPTION_ON;
772 | } else {
773 | monitorMenuItem.caption = MONITOR_CAPTION_OFF;
774 | }
775 | }
776 |
777 | /**
778 | * flag for counter to be in minimized state. (stats are still tracked, but not shown.)
779 | */
780 | public function get isMinimized():Boolean {
781 | return _isMinimized;
782 | }
783 |
784 | /**
785 | * flag for counter to be in minimized state. (stats are still tracked, but not shown.)
786 | */
787 | public function set isMinimized(value:Boolean):void {
788 | _isMinimized = value;
789 | initDrawArea();
790 | fitToStage();
791 | if (_isMinimized) {
792 | minimizeMenuItem.caption = MINIMIZE_CAPTION_ON;
793 | } else {
794 | minimizeMenuItem.caption = MINIMIZE_CAPTION_OFF;
795 | }
796 | }
797 |
798 | /**
799 | * Change width. If it is less then 70 - it will be set to default value - 70.
800 | */
801 | override public function set width(value:Number):void {
802 | // calculate increased width.
803 | bonusWidth = value - DEFAULT_WIDTH;
804 | initDrawArea();
805 | fitToStage();
806 | }
807 |
808 | private function set bonusWidth(value:int):void {
809 | _bonusWidth = value;
810 | if (_bonusWidth < 0) {
811 | _bonusWidth = 0;
812 | }
813 | clearRect = new Rectangle(DEFAULT_WIDTH + _bonusWidth - 1, 0, 1, DEFAULT_HEIGHT - 50);
814 | }
815 |
816 | override public function set height(value:Number):void {
817 | throw Error("It's not possible to change Stats object height. Sorry.");
818 | }
819 |
820 | /**
821 | * Shortcut to chang scaleX and ScaleY at same time.
822 | */
823 | public function get scale():Number {
824 | return _scale;
825 | }
826 |
827 | public function set scale(value:Number):void {
828 | _scale = value;
829 | super.scaleX = _scale;
830 | super.scaleY = _scale;
831 | if (_scale != 1) {
832 | zoomMenuItem.caption = ZOOM_CAPTION_x1;
833 | } else {
834 | zoomMenuItem.caption = ZOOM_CAPTION_x2;
835 | }
836 | }
837 |
838 | }
839 | }
840 |
841 | // helper class to store graph colors.
842 | class StatColors {
843 | public var bg:uint = 0x000033;
844 | public var fps:uint = 0xFFFF00;
845 | public var ms:uint = 0x00FF00;
846 | public var mem:uint = 0x00FFFF;
847 | public var memMax:uint = 0xFF0070;
848 |
849 | public var executionTime:uint = 0xFF0000;
850 | public var monitorSeparator:int = 0xD8D8D8;
851 |
852 | }
--------------------------------------------------------------------------------