[
  {
    "path": ".gitattributes",
    "content": "# Normalize EOL for all files that Git considers text files.\n* text=auto eol=lf\n\n/.gitattributes     export-ignore\n/.gitignore         export-ignore\n/LICENSE            export-ignore\n/README.md          export-ignore\n/project.godot      export-ignore\n/icon.png \t    export-ignore\n/*.import \t    export-ignore\n\n"
  },
  {
    "path": ".gitignore",
    "content": "# Godot 4+ specific ignores\n.godot/\n\n# Godot-specific ignores\n.import/\nexport.cfg\nexport_presets.cfg\n\n# Imported translations (automatically generated from CSV files)\n*.translation\n\n# Mono-specific ignores\n.mono/\ndata_*/\nmono_crash.*.json\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 HungryProton\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Monitor Overlay\n\nDisplays data from the Monitor panel at runtime in the game window.\n\n![image](https://user-images.githubusercontent.com/52043844/94171965-310f7b80-fe92-11ea-9420-602d4777389b.png)\n\n## How to install\n\n### From the asset library\n- Search for `Monitor overlay` and click the install button.\n- Enable the addon in `Project > Project Settings > Plugins`\n\n\n### Manually from this repository\n- Clone or download the project.\n- Copy the contents of the `addons/monitor_overlay` folder in your project folder as follow:  \n![image](https://user-images.githubusercontent.com/52043844/157983933-7b58573d-d04d-428e-9842-a89fed7999bf.png)\n- Enable the addon in `Project > Project Settings > Plugins`\n\n\n## How to use\n\n- Add a new `MonitorOverlay` node to a scene.\n  + Make sure it's the last node on the tree otherwise it may be drawn behind other objects.\n- Select the node and enable turn on the monitors you need in the inspector under the `Active monitors` group.\n\n![image](https://user-images.githubusercontent.com/52043844/157984315-183cbc72-98e8-4b34-bb47-49f00ac9f28c.png)\n\n\n### Changing the position and size\n\n- The whole overlay is a regular Control node. You have access to all the options available on UI nodes.\n- Default width is 300px. This can be ajusted from the inspector under `Control > Layout > Minimum Size`.\n- To change the vertical size of the graphs, adjust the `Graph Height` property in the inspector under `Monitor Overlay > Options > Graph Height` \n\n\n## Important notes\n- The overlay is a control node that contains other nodes (one for each graph). Because of this, the reported amount of\nobjects / nodes / memory used / primitives drawn (and potentially others too) will differ if the overlay is enabled or not.\nAlthough the difference is not significant, keep in mind it exists.\n- Plotting a graph requires to keep track of the values history and can impact performance.\n  + If you don't need this feature, you can turn it off by disabling the `Plot Graphs` option in the inspector.\n  + Lowering the `History` parameter also helps.\n\n\n## Licence\nMIT\n"
  },
  {
    "path": "addons/monitor_overlay/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 HungryProton\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "addons/monitor_overlay/icon.svg.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d0x55sc75mob4\"\npath=\"res://.godot/imported/icon.svg-497111bfcdb0b9dd996d646163572e32.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://addons/monitor_overlay/icon.svg\"\ndest_files=[\"res://.godot/imported/icon.svg-497111bfcdb0b9dd996d646163572e32.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/bptc_ldr=0\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\nsvg/scale=1.0\n"
  },
  {
    "path": "addons/monitor_overlay/monitor_overlay.gd",
    "content": "@tool\n@icon(\"./icon.svg\")\nclass_name MonitorOverlay\nextends VBoxContainer\n\nconst DebugGraph := preload(\"./monitor_overlay_debug_graph.gd\")\nvar need_to_rebuild_ui:bool=false\n# Monitors\n@export_group(\"Active Monitors\")\n@export_subgroup(\"Time\")\n@export var fps := true:\n\tset(value):\n\t\tfps = value\n\t\tneed_to_rebuild_ui=true\n@export var process := false:\n\tset(value):\n\t\tprocess = value\n\t\tneed_to_rebuild_ui=true\n@export var physics_process := false:\n\tset(value):\n\t\tphysics_process = value\n\t\tneed_to_rebuild_ui=true\n@export_subgroup(\"Memory\")\n@export var static_memory := false:\n\tset(value):\n\t\tstatic_memory = value\n\t\tneed_to_rebuild_ui=true\n@export var max_static_memory := false:\n\tset(value):\n\t\tmax_static_memory = value\n\t\tneed_to_rebuild_ui=true\n@export var max_message_buffer := false:\n\tset(value):\n\t\tmax_message_buffer = value\n\t\tneed_to_rebuild_ui=true\n@export_subgroup(\"Objects\")\n@export var objects := false:\n\tset(value):\n\t\tobjects = value\n\t\tneed_to_rebuild_ui=true\n@export var resources := false:\n\tset(value):\n\t\tresources = value\n\t\tneed_to_rebuild_ui=true\n@export var nodes := false:\n\tset(value):\n\t\tnodes = value\n\t\tneed_to_rebuild_ui=true\n@export var orphan_nodes := false:\n\tset(value):\n\t\torphan_nodes = value\n\t\tneed_to_rebuild_ui=true\n@export_subgroup(\"Raster\")\n@export var objects_drawn := false:\n\tset(value):\n\t\tobjects_drawn = value\n\t\tneed_to_rebuild_ui=true\n@export var primitives_drawn := false:\n\tset(value):\n\t\tprimitives_drawn = value\n\t\tneed_to_rebuild_ui=true\n@export var total_draw_calls := false:\n\tset(value):\n\t\ttotal_draw_calls = value\n\t\tneed_to_rebuild_ui=true\n@export_subgroup(\"Video\")\n@export var video_memory := false:\n\tset(value):\n\t\tvideo_memory = value\n\t\tneed_to_rebuild_ui=true\n@export var texture_memory := false:\n\tset(value):\n\t\ttexture_memory = value\n\t\tneed_to_rebuild_ui=true\n@export var buffer_memory := false:\n\tset(value):\n\t\tbuffer_memory = value\n\t\tneed_to_rebuild_ui=true\n@export_subgroup(\"Physics 2D\")\n@export var active_objects_2d := false:\n\tset(value):\n\t\tactive_objects_2d = value\n\t\tneed_to_rebuild_ui=true\n@export var collision_pairs_2d := false:\n\tset(value):\n\t\tcollision_pairs_2d = value\n\t\tneed_to_rebuild_ui=true\n@export var islands_2d := false:\n\tset(value):\n\t\tislands_2d = value\n\t\tneed_to_rebuild_ui=true\n@export_subgroup(\"Physics 3D\")\n@export var active_objects_3d := false:\n\tset(value):\n\t\tactive_objects_3d = value\n\t\tneed_to_rebuild_ui=true\n@export var collision_pairs_3d := false:\n\tset(value):\n\t\tcollision_pairs_3d = value\n\t\tneed_to_rebuild_ui=true\n@export var islands_3d := false:\n\tset(value):\n\t\tislands_3d = value\n\t\tneed_to_rebuild_ui=true\n@export_subgroup(\"Audio\")\n@export var audio_output_latency := false:\n\tset(value):\n\t\taudio_output_latency = value\n\t\tneed_to_rebuild_ui=true\n\n# Graph options\n@export_group(\"Options\")\n## Sampling rate in samples per second\n@export_range(0.0, 1000.0) var sampling_rate := 60.0:\n\tset(value):\n\t\tsampling_rate = value\n\t\t# if sampling rate is 0, _t_limit is infinity\n\t\t_t_limit = 1 / sampling_rate\n@export var normalize_units := true:\n\tset(value):\n\t\tnormalize_units = value\n\t\tneed_to_rebuild_ui=true\n@export var plot_graphs := true:\n\tset(value):\n\t\tplot_graphs = value\n\t\tneed_to_rebuild_ui=true\n@export var history := 100:\n\tset(value):\n\t\thistory = value\n\t\tneed_to_rebuild_ui=true\n@export var background_color := Color(0.0, 0.0, 0.0, 0.5):\n\tset(value):\n\t\tbackground_color = value\n\t\tneed_to_rebuild_ui=true\n@export var graph_color := Color.ORANGE:\n\tset(value):\n\t\tgraph_color = value\n\t\tneed_to_rebuild_ui=true\n@export var graph_height := 50:\n\tset(value):\n\t\tgraph_height = value\n\t\tneed_to_rebuild_ui=true\n@export var graph_thickness := 1.0:\n\tset(value):\n\t\tgraph_thickness = value\n\t\tneed_to_rebuild_ui=true\n@export var graph_antialiased := false:\n\tset(value):\n\t\tgraph_antialiased = value\n\t\tneed_to_rebuild_ui=true\n@export var font_size := 14:\n\tset(value):\n\t\tfont_size = value\n\t\tneed_to_rebuild_ui=true\n\nvar _graphs := []\nvar _t := 0.0\nvar _t_limit := 0.0\n\n\nfunc _ready():\n\tif custom_minimum_size.x == 0:\n\t\tcustom_minimum_size.x = 300\n\tneed_to_rebuild_ui=true\n\n\nfunc clear() -> void:\n\tfor graph in _graphs:\n\t\tgraph.queue_free()\n\t_graphs = []\n\n\nfunc rebuild_ui():\n\tclear()\n\tif fps:\n\t\t_create_graph_for(Performance.TIME_FPS, \"FPS\")\n\n\tif process:\n\t\t_create_graph_for(Performance.TIME_PROCESS, \"Process\", \"s\")\n\n\tif physics_process:\n\t\t_create_graph_for(Performance.TIME_PHYSICS_PROCESS, \"Physics Process\", \"s\")\n\n\tif static_memory:\n\t\t_create_graph_for(Performance.MEMORY_STATIC, \"Static Memory\", \"B\")\n\n\tif max_static_memory:\n\t\t_create_graph_for(Performance.MEMORY_STATIC_MAX, \"Max Static Memory\", \"B\")\n\n\tif max_message_buffer:\n\t\t_create_graph_for(Performance.MEMORY_MESSAGE_BUFFER_MAX, \"Message Buffer Max\")\n\n\tif objects:\n\t\t_create_graph_for(Performance.OBJECT_COUNT, \"Objects\")\n\n\tif resources:\n\t\t_create_graph_for(Performance.OBJECT_RESOURCE_COUNT, \"Resources\")\n\n\tif nodes:\n\t\t_create_graph_for(Performance.OBJECT_NODE_COUNT, \"Nodes\")\n\n\tif orphan_nodes:\n\t\t_create_graph_for(Performance.OBJECT_ORPHAN_NODE_COUNT, \"Orphan Nodes\")\n\n\tif objects_drawn:\n\t\t_create_graph_for(Performance.RENDER_TOTAL_OBJECTS_IN_FRAME, \"Objects Drawn\")\n\n\tif primitives_drawn:\n\t\t_create_graph_for(Performance.RENDER_TOTAL_PRIMITIVES_IN_FRAME, \"Primitives Drawn\")\n\n\tif total_draw_calls:\n\t\t_create_graph_for(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME, \"3D Draw Calls\")\n\n\tif video_memory:\n\t\t_create_graph_for(Performance.RENDER_VIDEO_MEM_USED, \"Video Memory\", \"B\")\n\n\tif texture_memory:\n\t\t_create_graph_for(Performance.RENDER_TEXTURE_MEM_USED, \"Texture Memory\", \"B\")\n\n\tif buffer_memory:\n\t\t_create_graph_for(Performance.RENDER_BUFFER_MEM_USED, \"Vertex Memory\", \"B\")\n\n\tif active_objects_2d:\n\t\t_create_graph_for(Performance.PHYSICS_2D_ACTIVE_OBJECTS, \"2D Active Objects\")\n\n\tif collision_pairs_2d:\n\t\t_create_graph_for(Performance.PHYSICS_2D_COLLISION_PAIRS, \" 2D Collision Pairs\")\n\n\tif islands_2d:\n\t\t_create_graph_for(Performance.PHYSICS_2D_ISLAND_COUNT, \"2D Islands\")\n\n\tif active_objects_3d:\n\t\t_create_graph_for(Performance.PHYSICS_3D_ACTIVE_OBJECTS, \" 3D Active Objects\")\n\n\tif collision_pairs_3d:\n\t\t_create_graph_for(Performance.PHYSICS_3D_COLLISION_PAIRS, \"3D Collision Pairs\")\n\n\tif islands_3d:\n\t\t_create_graph_for(Performance.PHYSICS_3D_ISLAND_COUNT, \"3D Islands\")\n\n\tif audio_output_latency:\n\t\t_create_graph_for(Performance.AUDIO_OUTPUT_LATENCY, \"Audio Latency\", \"s\")\n\n\nfunc _process(delta: float) -> void:\n\tif need_to_rebuild_ui:\n\t\trebuild_ui()\n\t\tneed_to_rebuild_ui=false\n\t_t += delta\n\tif _t >= _t_limit:\n\t\t_t = 0\n\t\tfor item in _graphs:\n\t\t\titem.queue_redraw()\n\n\nfunc _create_graph_for(monitor: int, monitor_name: String, unit: String = \"\") -> void:\n\tvar graph = DebugGraph.new()\n\tgraph.monitor = monitor\n\tgraph.monitor_name = monitor_name\n\tgraph.font = get_theme_default_font()\n\tgraph.font_size = font_size\n\tgraph.custom_minimum_size.y = graph_height\n\tgraph.max_points = history\n\tgraph.background_color = background_color\n\tgraph.graph_color = graph_color\n\tgraph.plot_graph = plot_graphs\n\tgraph.unit = unit\n\tgraph.normalize_units = normalize_units\n\tgraph.thickness = graph_thickness\n\tgraph.antialiased = graph_antialiased\n\tgraph.name = monitor_name\n\tgraph.mouse_filter = Control.MOUSE_FILTER_IGNORE\n\tadd_child(graph)\n\t_graphs.push_back(graph)\n"
  },
  {
    "path": "addons/monitor_overlay/monitor_overlay_debug_graph.gd",
    "content": "extends Control\n\n\nvar monitor: int\nvar monitor_name: String\nvar max_points := 100\nvar font: Font\nvar background_color: Color\nvar graph_color: Color\nvar normalize_units := true\nvar plot_graph := true\nvar unit: String\nvar thickness: float\nvar antialiased: bool\n\nvar _history := []\nvar _last_value: float\n\n\nfunc _draw() -> void:\n\t_update_history()\n\t_draw_background_panel()\n\t_draw_graph()\n\t_draw_text()\n\n\nfunc _draw_background_panel() -> void:\n\tvar panel := Rect2()\n\tpanel.position = get_canvas_transform().origin\n\tpanel.size = size\n\tdraw_rect(panel, background_color)\n\n\nvar font_size: int = 14\n\nfunc _draw_text() -> void:\n\tvar s_value := _normalize_value(_last_value)\n\tvar text = monitor_name + \": \" + s_value\n\tvar position = Vector2(0, font_size) # Y offset = font size\n\tdraw_string(font, position, text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size)\n\n# TODO: That function is unoptimized\nfunc _draw_graph() -> void:\n\tif not plot_graph:\n\t\treturn\n\n\t# Get the values range\n\tvar min_value = _history[0]\n\tvar max_value = _history[0]\n\tfor value in _history:\n\t\tmin_value = min(value, min_value)\n\t\tmax_value = max(value, max_value)\n\n\tif min_value == max_value:\n\t\tmin_value -= 1\n\t\tmax_value += 1\n\n\t# Convert to 2D coordinates\n\tvar x := 0.0\n\tvar offset := size.x / max_points\n\tvar height := size.y\n\tvar margin = height / 10.0\n\tvar origin := get_canvas_transform().origin\n\tvar points = PackedVector2Array()\n\t\n\tfor value in _history:\n\t\tvalue = remap(value, min_value, max_value, margin, height - margin)\n\t\tif x > 0:\n\t\t\tpoints.push_back(Vector2(x, height - value) + origin)\n\t\t\n\t\tx += offset\n\t\n\tif points.size() > 1:\n\t\tdraw_polyline(points, graph_color, thickness, antialiased)\n\n\nfunc _update_history():\n\t_last_value = Performance.get_monitor(monitor)\n\tif not plot_graph:\n\t\treturn\n\n\t_history.push_back(_last_value)\n\tif _history.size() >= max_points:\n\t\t_history.pop_front()\n\n\nfunc _normalize_value(value: float) -> String:\n\tvar result := str(value) + unit\n\n\tif not normalize_units or _last_value == 0.0:\n\t\treturn result\n\n\tif _last_value > 1000.0:\n\t\tvar v = _last_value\n\t\tvar index = -1\n\t\twhile v > 1000.0 and index < 3:\n\t\t\tv /= 1000.0\n\t\t\tindex += 1\n\t\tvar scale = [\"K\", \"M\", \"G\", \"T\"]\n\t\tresult = str(snapped(v, 0.001)) + scale[index] + unit\n\n\tif _last_value < 1.0:\n\t\tvar v = _last_value\n\t\tvar index = -1\n\t\twhile v < 1.0 and index < 2:\n\t\t\tv *= 1000.0\n\t\t\tindex += 1\n\t\tvar scale = [\"m\", \"u\", \"n\"]\n\t\tresult = str(snapped(v, 0.001)) + scale[index] + unit\n\n\treturn result\n"
  },
  {
    "path": "addons/monitor_overlay/monitor_overlay_plugin.gd",
    "content": "@tool\nextends EditorPlugin\n\n\nfunc _get_plugin_name() -> String:\n\treturn \"MonitorOverlay\"\n\n\nfunc _get_plugin_icon() -> Texture2D:\n\treturn load(\"./icon.svg\")\n"
  },
  {
    "path": "addons/monitor_overlay/plugin.cfg",
    "content": "[plugin]\n\nname=\"Monitor Overlay\"\ndescription=\"Same as the Monitor tab, but displayed directly in your game\"\nauthor=\"HungryProton\"\nversion=\"1.1.0\"\nscript=\"monitor_overlay_plugin.gd\"\n"
  },
  {
    "path": "icon.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dglmusrwc0o2i\"\npath=\"res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://icon.png\"\ndest_files=[\"res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/bptc_ldr=0\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "project.godot",
    "content": "; Engine configuration file.\n; It's best edited using the editor UI and not directly,\n; since the parameters that go here are not all obvious.\n;\n; Format:\n;   [section] ; section goes between []\n;   param=value ; assign values to parameters\n\nconfig_version=5\n\n[application]\n\nconfig/name=\"Monitor Overlay\"\nconfig/features=PackedStringArray(\"4.0\", \"Vulkan Mobile\")\nconfig/icon=\"res://icon.png\"\n\n[editor_plugins]\n\nenabled=PackedStringArray(\"res://addons/monitor_overlay/plugin.cfg\")\n\n[rendering]\n\nvulkan/rendering/back_end=1\n"
  }
]