├── 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 | ![AdvancedStats.png](https://github.com/MindScriptAct/Advanced-hi-res-stats/raw/master/assets/AdvancedStats.png "Advanced Stats") 24 | ### Advanced Stats Context menu ### 25 | ![StatsContextMenu.jpg](https://github.com/MindScriptAct/Advanced-hi-res-stats/raw/master/assets/StatsContextMenu.jpg "Advanced Stats Context menu") 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 | } --------------------------------------------------------------------------------