[
  {
    "path": ".gitignore",
    "content": "# 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_*/\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Yukita Mayako\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": "# Integer Resolution Handler\n\nAlternative stretch handler for low resolution (pixel art) games in high resolution windows. Restricts the game resolution to integer steps, keeping pixels square.\n\n## Usage\n\n1. Enable the plugin. Close Project Settings.\n2. Navigate Project Settings to the `display/window` category.\n3. In the new section \"Integer Resolution Handler\", set Base Width and Base Height to your game's native pixel resolution.\n\nThe IntegerResolutionHandler also works with all of the existing `stretch` settings, so fiddle there if you don't like how it behaves. Notably, setting `stretch/aspect` to \"Keep\" will enforce strict screen resolutions, while \"Expand\" will allow the viewable area to extend dramatically in all directions between scale steps.\n\nIf you set Base Width and Base Height to a 4:3 aspect ratio and use the \"Keep Height\" or \"Expand\" aspect handling modes, your game will extend horizontally to support widescreen aspects as well. Just make sure your game is fully playable at its base resolution and GUI elements properly stretch and move, the same as you would for a non-pixel art game.\n"
  },
  {
    "path": "addons/integer_resolution_handler/integer_resolution_handler.gd",
    "content": "extends Node\n# IntegerResolutionHandler autoload.\n# Watches for window size changes and handles\n# game screen scaling with exact integer\n# multiples of a base resolution in mind.\n\nconst SETTING_BASE_WIDTH = \"display/window/integer_resolution_handler/base_width\"\nconst SETTING_BASE_HEIGHT = \"display/window/integer_resolution_handler/base_height\"\n\nvar base_resolution := Vector2(320, 240)\nvar stretch_mode: int\nvar stretch_aspect: int\nonready var stretch_shrink: float = ProjectSettings.get_setting(\"display/window/stretch/shrink\")\n\nonready var _root: Viewport = get_node(\"/root\")\n\n\nfunc _ready():\n\t# Parse project settings\n\tif ProjectSettings.has_setting(SETTING_BASE_WIDTH):\n\t\tbase_resolution.x = ProjectSettings.get_setting(SETTING_BASE_WIDTH)\n\tif ProjectSettings.has_setting(SETTING_BASE_HEIGHT):\n\t\tbase_resolution.y = ProjectSettings.get_setting(SETTING_BASE_HEIGHT)\n\n\tmatch ProjectSettings.get_setting(\"display/window/stretch/mode\"):\n\t\t\"2d\":\n\t\t\tstretch_mode = SceneTree.STRETCH_MODE_2D\n\t\t\"viewport\":\n\t\t\tstretch_mode = SceneTree.STRETCH_MODE_VIEWPORT\n\t\t_:\n\t\t\tstretch_mode = SceneTree.STRETCH_MODE_DISABLED\n\n\tmatch ProjectSettings.get_setting(\"display/window/stretch/aspect\"):\n\t\t\"keep\":\n\t\t\tstretch_aspect = SceneTree.STRETCH_ASPECT_KEEP\n\t\t\"keep_height\":\n\t\t\tstretch_aspect = SceneTree.STRETCH_ASPECT_KEEP_HEIGHT\n\t\t\"keep_width\":\n\t\t\tstretch_aspect = SceneTree.STRETCH_ASPECT_KEEP_WIDTH\n\t\t\"expand\":\n\t\t\tstretch_aspect = SceneTree.STRETCH_ASPECT_EXPAND\n\t\t_:\n\t\t\tstretch_aspect = SceneTree.STRETCH_ASPECT_IGNORE\n\n\t# Enforce minimum resolution.\n\tOS.min_window_size = base_resolution\n\n\t# Remove default stretch behavior.\n\tvar tree: SceneTree = get_tree()\n\ttree.set_screen_stretch(SceneTree.STRETCH_MODE_DISABLED, SceneTree.STRETCH_ASPECT_IGNORE, base_resolution, 1)\n\n\t# Start tracking resolution changes and scaling the screen.\n\tupdate_resolution()\n\t# warning-ignore:return_value_discarded\n\ttree.connect(\"screen_resized\", self, \"update_resolution\")\n\n\nfunc update_resolution():\n\tvar video_mode: Vector2 = OS.window_size\n\tif OS.window_fullscreen:\n\t\tvideo_mode = OS.get_screen_size()\n\n\tvar scale := int(max(floor(min(video_mode.x / base_resolution.x, video_mode.y / base_resolution.y)), 1))\n\tvar screen_size: Vector2 = base_resolution\n\tvar viewport_size: Vector2 = screen_size * scale\n\tvar overscan: Vector2 = ((video_mode - viewport_size) / scale).floor()\n\tvar margin: Vector2\n\tvar margin2: Vector2\n\n\tmatch stretch_aspect:\n\t\tSceneTree.STRETCH_ASPECT_KEEP_WIDTH:\n\t\t\tscreen_size.y += overscan.y\n\t\tSceneTree.STRETCH_ASPECT_KEEP_HEIGHT:\n\t\t\tscreen_size.x += overscan.x\n\t\tSceneTree.STRETCH_ASPECT_EXPAND, SceneTree.STRETCH_ASPECT_IGNORE:\n\t\t\tscreen_size += overscan\n\tviewport_size = screen_size * scale\n\tmargin = (video_mode - viewport_size) / 2\n\tmargin2 = margin.ceil()\n\tmargin = margin.floor()\n\n\tmatch stretch_mode:\n\t\tSceneTree.STRETCH_MODE_VIEWPORT:\n\t\t\t_root.set_size((screen_size / stretch_shrink).floor())\n\t\t\t_root.set_attach_to_screen_rect(Rect2(margin, viewport_size))\n\t\t\t_root.set_size_override_stretch(false)\n\t\t\t_root.set_size_override(false)\n\t\tSceneTree.STRETCH_MODE_2D, _:\n\t\t\t_root.set_size((viewport_size / stretch_shrink).floor())\n\t\t\t_root.set_attach_to_screen_rect(Rect2(margin, viewport_size))\n\t\t\t_root.set_size_override_stretch(true)\n\t\t\t_root.set_size_override(true, (screen_size / stretch_shrink).floor())\n\n\tif margin.x < 0:\n\t\tmargin.x = 0\n\tif margin.y < 0:\n\t\tmargin.y = 0\n\tif margin2.x < 0:\n\t\tmargin2.x = 0\n\tif margin2.y < 0:\n\t\tmargin2.y = 0\n\tVisualServer.black_bars_set_margins(int(margin.x), int(margin.y), int(margin2.x), int(margin2.y))\n"
  },
  {
    "path": "addons/integer_resolution_handler/plugin.cfg",
    "content": "[plugin]\n\nname=\"IntegerResolutionHandler\"\ndescription=\"Alternative stretch handler for low resolution (pixel art) games in high resolution windows. Restricts the game resolution to integer steps, keeping pixels square.\"\nauthor=\"Yukitty\"\nversion=\"1.1.1\"\nscript=\"plugin.gd\"\n"
  },
  {
    "path": "addons/integer_resolution_handler/plugin.gd",
    "content": "tool\nextends EditorPlugin\n\n\nconst SETTING_BASE_WIDTH := \"display/window/integer_resolution_handler/base_width\"\nconst SETTING_BASE_HEIGHT := \"display/window/integer_resolution_handler/base_height\"\nconst DEFAULT_BASE_WIDTH: int = 320\nconst DEFAULT_BASE_HEIGHT: int = 240\n\n\nfunc _enter_tree():\n\tadd_autoload_singleton(\"IntegerResolutionHandler\", \"res://addons/integer_resolution_handler/integer_resolution_handler.gd\")\n\n\tif not ProjectSettings.has_setting(SETTING_BASE_WIDTH):\n\t\tProjectSettings.set_setting(SETTING_BASE_WIDTH, DEFAULT_BASE_WIDTH)\n\tProjectSettings.set_initial_value(SETTING_BASE_WIDTH, DEFAULT_BASE_WIDTH)\n\tProjectSettings.add_property_info({\n\t\t\"name\": SETTING_BASE_WIDTH,\n\t\t\"type\": TYPE_INT,\n\t\t\"hint\": PROPERTY_HINT_RANGE,\n\t\t\"hint_string\": \"1,1024,1,or_greater\"\n\t})\n\n\tif not ProjectSettings.has_setting(SETTING_BASE_HEIGHT):\n\t\tProjectSettings.set_setting(SETTING_BASE_HEIGHT, DEFAULT_BASE_HEIGHT)\n\tProjectSettings.set_initial_value(SETTING_BASE_HEIGHT, DEFAULT_BASE_HEIGHT)\n\tProjectSettings.add_property_info({\n\t\t\"name\": SETTING_BASE_HEIGHT,\n\t\t\"type\": TYPE_INT,\n\t\t\"hint\": PROPERTY_HINT_RANGE,\n\t\t\"hint_string\": \"1,600,1,or_greater\"\n\t})\n\n\tvar order: int = ProjectSettings.get_order(\"display/window/size/width\") - 2\n\tProjectSettings.set_order(SETTING_BASE_WIDTH, order)\n\tProjectSettings.set_order(SETTING_BASE_HEIGHT, order + 1)\n\tProjectSettings.save()\n\n\nfunc disable_plugin():\n\tremove_autoload_singleton(\"IntegerResolutionHandler\")\n\tProjectSettings.clear(\"display/window/integer_resolution_handler/base_width\")\n\tProjectSettings.clear(\"display/window/integer_resolution_handler/base_height\")\n\tProjectSettings.save()\n\n"
  }
]